text:
#include "AssimpPCH.h"

#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
#include "ColladaExporter.h"

using namespace Assimp;

namespace Assimp
{

// ------------------------------------------------------------------------------------------------
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
{
	// invoke the exporter
	ColladaExporter iDoTheExportThing( pScene);

	// we're still here - export successfully completed. Write result to the given IOSYstem
	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
	if(outfile == NULL) {
		throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
	}

	// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
	outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
}

} // end of namespace Assimp

// ------------------------------------------------------------------------------------------------
// Constructor for a specific scene to export
ColladaExporter::ColladaExporter( const aiScene* pScene)
{
	// make sure that all formatting happens using the standard, C locale and not the user's current locale
	mOutput.imbue( std::locale("C") );

	mScene = pScene;

	// set up strings
	endstr = "\n";

	// start writing
	WriteFile();
}

// ------------------------------------------------------------------------------------------------
// Starts writing the contents
void ColladaExporter::WriteFile()
{
	// write the DTD
	mOutput << "<?xml version=\"1.0\"?>" << endstr;
	// COLLADA element start
	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
	PushTag();

	WriteHeader();

  WriteMaterials();
	WriteGeometryLibrary();

	WriteSceneLibrary();

	// useless Collada fu at the end, just in case we haven't had enough indirections, yet.
	mOutput << startstr << "<scene>" << endstr;
	PushTag();
	mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr;
	PopTag();
	mOutput << startstr << "</scene>" << endstr;
	PopTag();
	mOutput << "</COLLADA>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Writes the asset header
void ColladaExporter::WriteHeader()
{
	// Dummy stuff. Nobody actually cares for it anyways
	mOutput << startstr << "<asset>" << endstr;
	PushTag();
	mOutput << startstr << "<contributor>" << endstr;
	PushTag();
	mOutput << startstr << "<author>Someone</author>" << endstr;
	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
	PopTag();
	mOutput << startstr << "</contributor>" << endstr;
  mOutput << startstr << "<created>2000-01-01T23:59:59</created>" << endstr;
  mOutput << startstr << "<modified>2000-01-01T23:59:59</modified>" << endstr;
	mOutput << startstr << "<unit name=\"centimeter\" meter=\"0.01\" />" << endstr;
	mOutput << startstr << "<up_axis>Y_UP</up_axis>" << endstr;
	PopTag();
	mOutput << startstr << "</asset>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Reads a single surface entry from the given material keys
void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
{
  if( pSrcMat->GetTextureCount( pTexture) > 0 )
  {
    aiString texfile;
    unsigned int uvChannel = 0;
    pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
    poSurface.texture = texfile.C_Str();
    poSurface.channel = uvChannel;
  } else
  {
    if( pKey )
      pSrcMat->Get( pKey, pType, pIndex, poSurface.color);
  }
}

// ------------------------------------------------------------------------------------------------
// Writes an image entry for the given surface
void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd)
{
  if( !pSurface.texture.empty() )
  {
    mOutput << startstr << "<image id=\"" << pNameAdd << "\">" << endstr;
    PushTag();
    mOutput << startstr << "<init_from>";
    for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it )
    {
      if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' )
        mOutput << *it;
      else
        mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec;
    }
    mOutput << "</init_from>" << endstr;
    PopTag();
    mOutput << startstr << "</image>" << endstr;
  }
}

// ------------------------------------------------------------------------------------------------
// Writes a color-or-texture entry into an effect definition
void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
{
  mOutput << startstr << "<" << pTypeName << ">" << endstr;
  PushTag();
  if( pSurface.texture.empty() )
  {
    mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
  } else
  {
    mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
  }
  PopTag();
  mOutput << startstr << "</" << pTypeName << ">" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Writes the two parameters necessary for referencing a texture in an effect entry
void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName)
{
  // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
  if( !pSurface.texture.empty() )
  {
    mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-surface\">" << endstr;
    PushTag();
    mOutput << startstr << "<surface type=\"2D\">" << endstr;
    PushTag();
    mOutput << startstr << "<init_from>" << pMatName << "-" << pTypeName << "-image</init_from>" << endstr;
    PopTag();
    mOutput << startstr << "</surface>" << endstr;
    PopTag();
    mOutput << startstr << "</newparam>" << endstr;

    mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-sampler\">" << endstr;
    PushTag();
    mOutput << startstr << "<sampler2D>" << endstr;
    PushTag();
    mOutput << startstr << "<source>" << pMatName << "-" << pTypeName << "-surface</source>" << endstr;
    PopTag();
    mOutput << startstr << "</sampler2D>" << endstr;
    PopTag();
    mOutput << startstr << "</newparam>" << endstr;
  }
}

// ------------------------------------------------------------------------------------------------
// Writes the material setup
void ColladaExporter::WriteMaterials()
{
  materials.resize( mScene->mNumMaterials);

  /// collect all materials from the scene
  size_t numTextures = 0;
  for( size_t a = 0; a < mScene->mNumMaterials; ++a )
  {
    const aiMaterial* mat = mScene->mMaterials[a];

    aiString name;
    if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
      name = "mat";
    materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
    for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
		// isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion
		// of char to signed int and take the unsigned char value.
      if( !isalnum( static_cast<uint8_t>(*it) ) ) {
        *it = '_';
	  }
	}

    ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
    if( !materials[a].ambient.texture.empty() ) numTextures++;
    ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
    if( !materials[a].diffuse.texture.empty() ) numTextures++;
    ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
    if( !materials[a].specular.texture.empty() ) numTextures++;
    ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
    if( !materials[a].emissive.texture.empty() ) numTextures++;
    ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
    if( !materials[a].reflective.texture.empty() ) numTextures++;
    ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
    if( !materials[a].normal.texture.empty() ) numTextures++;

    mat->Get( AI_MATKEY_SHININESS, materials[a].shininess);
  }

  // output textures if present
  if( numTextures > 0 )
  {
    mOutput << startstr << "<library_images>" << endstr;
    PushTag();
    for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
    {
      const Material& mat = *it;
      WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
      WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
      WriteImageEntry( mat.specular, mat.name + "-specular-image");
      WriteImageEntry( mat.emissive, mat.name + "-emissive-image");
      WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
      WriteImageEntry( mat.normal, mat.name + "-normal-image");
    }
    PopTag();
    mOutput << startstr << "</library_images>" << endstr;
  }

  // output effects - those are the actual carriers of information
  if( !materials.empty() )
  {
    mOutput << startstr << "<library_effects>" << endstr;
    PushTag();
    for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
    {
      const Material& mat = *it;
      // this is so ridiculous it must be right
      mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr;
      PushTag();
      mOutput << startstr << "<profile_COMMON>" << endstr;
      PushTag();

      // write sampler- and surface params for the texture entries
      WriteTextureParamEntry( mat.emissive, "emissive", mat.name);
      WriteTextureParamEntry( mat.ambient, "ambient", mat.name);
      WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
      WriteTextureParamEntry( mat.specular, "specular", mat.name);
      WriteTextureParamEntry( mat.reflective, "reflective", mat.name);

      mOutput << startstr << "<technique sid=\"standard\">" << endstr;
      PushTag();
      mOutput << startstr << "<phong>" << endstr;
      PushTag();

      WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emissive-sampler");
      WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
      WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
      WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");

      mOutput << startstr << "<shininess>" << endstr;
      PushTag();
      mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr;
      PopTag();
      mOutput << startstr << "</shininess>" << endstr;

      WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");

  // deactivated because the Collada spec PHONG model does not allow other textures.
  //    if( !mat.normal.texture.empty() )
  //      WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");

      PopTag();
      mOutput << startstr << "</phong>" << endstr;
      PopTag();
      mOutput << startstr << "</technique>" << endstr;
      PopTag();
      mOutput << startstr << "</profile_COMMON>" << endstr;
      PopTag();
      mOutput << startstr << "</effect>" << endstr;
    }
    PopTag();
    mOutput << startstr << "</library_effects>" << endstr;

    // write materials - they're just effect references
    mOutput << startstr << "<library_materials>" << endstr;
    PushTag();
    for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
    {
      const Material& mat = *it;
      mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr;
      PushTag();
      mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr;
      PopTag();
      mOutput << startstr << "</material>" << endstr;
    }
    PopTag();
    mOutput << startstr << "</library_materials>" << endstr;
  }
}

// ------------------------------------------------------------------------------------------------
// Writes the geometry library
void ColladaExporter::WriteGeometryLibrary()
{
	mOutput << startstr << "<library_geometries>" << endstr;
	PushTag();

	for( size_t a = 0; a < mScene->mNumMeshes; ++a)
		WriteGeometry( a);

	PopTag();
	mOutput << startstr << "</library_geometries>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Writes the given mesh
void ColladaExporter::WriteGeometry( size_t pIndex)
{
	const aiMesh* mesh = mScene->mMeshes[pIndex];
	std::string idstr = GetMeshId( pIndex);

  if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
    return;

	// opening tag
	mOutput << startstr << "<geometry id=\"" << idstr << "\" name=\"" << idstr << "_name\" >" << endstr;
	PushTag();

	mOutput << startstr << "<mesh>" << endstr;
	PushTag();

	// Positions
	WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices);
	// Normals, if any
	if( mesh->HasNormals() )
		WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices);

	// texture coords
	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
	{
		if( mesh->HasTextureCoords( a) )
		{
			WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
				(float*) mesh->mTextureCoords[a], mesh->mNumVertices);
		}
	}

	// vertex colors
	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
	{
		if( mesh->HasVertexColors( a) )
			WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices);
	}

	// assemble vertex structure
	mOutput << startstr << "<vertices id=\"" << idstr << "-vertices" << "\">" << endstr;
	PushTag();
	mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstr << "-positions\" />" << endstr;
	if( mesh->HasNormals() )
		mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstr << "-normals\" />" << endstr;
	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
	{
		if( mesh->HasTextureCoords( a) )
			mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstr << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
	}
	for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
	{
		if( mesh->HasVertexColors( a) )
			mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstr << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
	}

	PopTag();
	mOutput << startstr << "</vertices>" << endstr;

	// write face setup
	mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr;
	PushTag();
	mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;

	mOutput << startstr << "<vcount>";
	for( size_t a = 0; a < mesh->mNumFaces; ++a )
		mOutput << mesh->mFaces[a].mNumIndices << " ";
	mOutput << "</vcount>" << endstr;

	mOutput << startstr << "<p>";
	for( size_t a = 0; a < mesh->mNumFaces; ++a )
	{
		const aiFace& face = mesh->mFaces[a];
		for( size_t b = 0; b < face.mNumIndices; ++b )
			mOutput << face.mIndices[b] << " ";
	}
	mOutput << "</p>" << endstr;
	PopTag();
	mOutput << startstr << "</polylist>" << endstr;

	// closing tags
	PopTag();
	mOutput << startstr << "</mesh>" << endstr;
	PopTag();
	mOutput << startstr << "</geometry>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Writes a float array of the given type
void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount)
{
	size_t floatsPerElement = 0;
	switch( pType )
	{
		case FloatType_Vector: floatsPerElement = 3; break;
		case FloatType_TexCoord2: floatsPerElement = 2; break;
		case FloatType_TexCoord3: floatsPerElement = 3; break;
		case FloatType_Color: floatsPerElement = 3; break;
		default:
			return;
	}

	std::string arrayId = pIdString + "-array";

	mOutput << startstr << "<source id=\"" << pIdString << "\" name=\"" << pIdString << "\">" << endstr;
	PushTag();

	// source array
	mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
	PushTag();

	if( pType == FloatType_TexCoord2 )
	{
		for( size_t a = 0; a < pElementCount; ++a )
		{
			mOutput << pData[a*3+0] << " ";
			mOutput << pData[a*3+1] << " ";
		}
	}
	else if( pType == FloatType_Color )
	{
		for( size_t a = 0; a < pElementCount; ++a )
		{
			mOutput << pData[a*4+0] << " ";
			mOutput << pData[a*4+1] << " ";
			mOutput << pData[a*4+2] << " ";
		}
	}
	else
	{
		for( size_t a = 0; a < pElementCount * floatsPerElement; ++a )
			mOutput << pData[a] << " ";
	}
	mOutput << "</float_array>" << endstr;
	PopTag();

	// the usual Collada fun. Let's bloat it even more!
	mOutput << startstr << "<technique_common>" << endstr;
	PushTag();
	mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr;
	PushTag();

	switch( pType )
	{
		case FloatType_Vector:
			mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr;
			break;

		case FloatType_TexCoord2:
			mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
			break;

		case FloatType_TexCoord3:
			mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr;
			break;

		case FloatType_Color:
			mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr;
			mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr;
			break;
	}

	PopTag();
	mOutput << startstr << "</accessor>" << endstr;
	PopTag();
	mOutput << startstr << "</technique_common>" << endstr;
	PopTag();
	mOutput << startstr << "</source>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Writes the scene library
void ColladaExporter::WriteSceneLibrary()
{
	mOutput << startstr << "<library_visual_scenes>" << endstr;
	PushTag();
	mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr;
	PushTag();

	// start recursive write at the root node
	WriteNode( mScene->mRootNode);

	PopTag();
	mOutput << startstr << "</visual_scene>" << endstr;
	PopTag();
	mOutput << startstr << "</library_visual_scenes>" << endstr;
}

// ------------------------------------------------------------------------------------------------
// Recursively writes the given node
void ColladaExporter::WriteNode( const aiNode* pNode)
{
	mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr;
	PushTag();

	// write transformation - we can directly put the matrix there
	// TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards
	const aiMatrix4x4& mat = pNode->mTransformation;
	mOutput << startstr << "<matrix>";
	mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
	mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
	mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
	mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4;
	mOutput << "</matrix>" << endstr;

	// instance every geometry
	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
	{
		const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
    // do not instanciate mesh if empty. I wonder how this could happen
    if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
      continue;

		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
		PushTag();
    mOutput << startstr << "<bind_material>" << endstr;
    PushTag();
    mOutput << startstr << "<technique_common>" << endstr;
    PushTag();
    mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
		PopTag();
    mOutput << startstr << "</technique_common>" << endstr;
    PopTag();
    mOutput << startstr << "</bind_material>" << endstr;
    PopTag();
		mOutput << startstr << "</instance_geometry>" << endstr;
	}

	// recurse into subnodes
	for( size_t a = 0; a < pNode->mNumChildren; ++a )
		WriteNode( pNode->mChildren[a]);

	PopTag();
	mOutput << startstr << "</node>" << endstr;
}

#endif
#endif


text:
namespace Azure.ResourceManager.Automation.Models
{
    /// <summary> The Dsc configuration property associated with the entity. </summary>
    public partial class DscConfigurationAssociationProperty
    {
        /// <summary> Initializes a new instance of DscConfigurationAssociationProperty. </summary>
        public DscConfigurationAssociationProperty()
        {
        }

        /// <summary> Initializes a new instance of DscConfigurationAssociationProperty. </summary>
        /// <param name="configurationName"> Gets or sets the name of the Dsc configuration. </param>
        internal DscConfigurationAssociationProperty(string configurationName)
        {
            ConfigurationName = configurationName;
        }

        /// <summary> Gets or sets the name of the Dsc configuration. </summary>
        public string ConfigurationName { get; set; }
    }
}

redpajama_set_name: RedPajamaGithub


text:
Ext.define('Mba.ux.DateTimePicker.AbstractPicker', {
    singleton: true,

    setValue: function(scope, newValue) {
        scope.config.date = newValue;
        scope.config.value = newValue;
        if (newValue === null || newValue === '') {
            scope.config.date = new Date();
        }
        return newValue;
    },

    focus: function(scope) {
        if (scope.isFocused) {
            scope.isFocused = false;
            return;
        }

        scope.isFocused = true;

        var onSuccess, onError;

        onSuccess = function(res) {
            scope.setValue(res);
            scope.isFocused = false;
        };

        onError = function() {
            scope.isFocused = false;
            scope.applyValue(scope.getValue());
        };

        try {
            datePicker.show(scope.config, onSuccess, onError);
        } catch (ex) {
            console.log(ex);
            throw 'Error';
        }
    }

});


text:
#include "call/adaptation/test/fake_frame_rate_provider.h"

#include "test/gmock.h"

using ::testing::Return;

namespace webrtc {

FakeFrameRateProvider::FakeFrameRateProvider() {
  set_fps(0);
}

void FakeFrameRateProvider::set_fps(int fps) {
  EXPECT_CALL(*this, GetInputFrameRate()).WillRepeatedly(Return(fps));
}

}  // namespace webrtc


text:
namespace EncompassRest.Loans.Attachments
{
    /// <summary>
    /// Base Image class.
    /// </summary>
    public abstract class Image : DirtyExtensibleObject, IIdentifiable
    {
        private DirtyValue<string?>? _imageKey;
        private DirtyValue<string?>? _zipKey;
        private DirtyValue<int?>? _width;
        private DirtyValue<int?>? _height;
        private DirtyValue<float?>? _horizontalResolution;
        private DirtyValue<float?>? _verticalResolution;
        private DirtyValue<string?>? _mediaUrl;

        /// <summary>
        /// The identifier of the image or thumbnail file.
        /// </summary>
        public string? ImageKey { get => _imageKey; set => SetField(ref _imageKey, value); }

        /// <summary>
        /// The identifier of the zip file that contains the image or thumbnail.
        /// </summary>
        public string? ZipKey { get => _zipKey; set => SetField(ref _zipKey, value); }

        /// <summary>
        /// The width of the annotation.
        /// </summary>
        public int? Width { get => _width; set => SetField(ref _width, value); }

        /// <summary>
        /// The height of the annotation.
        /// </summary>
        public int? Height { get => _height; set => SetField(ref _height, value); }

        /// <summary>
        /// The horizontal resolution of the image or thumbnail.
        /// </summary>
        public float? HorizontalResolution { get => _horizontalResolution; set => SetField(ref _horizontalResolution, value); }

        /// <summary>
        /// The vertical resolution of the image or thumbnail.
        /// </summary>
        public float? VeriticalResolution { get => _verticalResolution; set => SetField(ref _verticalResolution, value); }

        /// <summary>
        /// The location or path where the media attachment is located.
        /// </summary>
        public string? MediaUrl { get => _mediaUrl; set => SetField(ref _mediaUrl, value); }

        [IdPropertyName(nameof(ImageKey))]
        string? IIdentifiable.Id { get => ImageKey; set => ImageKey = value; }
    }
}


text:
"""
 Base package for Proton Decay Study
 :author: Kevin Wierman
"""


text:
import { min, ascending, max, mean, sum } from 'd3-array';
import { map, nest } from 'd3-collection';
import { linkHorizontal } from 'd3-shape';
import findCircuits from 'elementary-circuits-directed-graph';

// For a given link, return the target node's depth
function targetDepth(d) {
  return d.target.depth;
}

// The depth of a node when the nodeAlign (align) is set to 'left'
function left(node) {
  return node.depth;
}

// The depth of a node when the nodeAlign (align) is set to 'right'
function right(node, n) {
  return n - 1 - node.height;
}

// The depth of a node when the nodeAlign (align) is set to 'justify'
function justify(node, n) {
  return node.sourceLinks.length ? node.depth : n - 1;
}

// The depth of a node when the nodeAlign (align) is set to 'center'
function center(node) {
  return node.targetLinks.length ? node.depth : node.sourceLinks.length ? min(node.sourceLinks, targetDepth) - 1 : 0;
}

// returns a function, using the parameter given to the sankey setting
function constant(x) {
  return function () {
    return x;
  };
}

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  return typeof obj;
} : function (obj) {
  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};

/// https://github.com/tomshanley/d3-sankeyCircular-circular

// sort links' breadth (ie top to bottom in a column), based on their source nodes' breadths
function ascendingSourceBreadth(a, b) {
  return ascendingBreadth(a.source, b.source) || a.index - b.index;
}

// sort links' breadth (ie top to bottom in a column), based on their target nodes' breadths
function ascendingTargetBreadth(a, b) {
  return ascendingBreadth(a.target, b.target) || a.index - b.index;
}

// sort nodes' breadth (ie top to bottom in a column)
// if both nodes have circular links, or both don't have circular links, then sort by the top (y0) of the node
// else push nodes that have top circular links to the top, and nodes that have bottom circular links to the bottom
function ascendingBreadth(a, b) {
  if (a.partOfCycle === b.partOfCycle) {
    return a.y0 - b.y0;
  } else {
    if (a.circularLinkType === 'top' || b.circularLinkType === 'bottom') {
      return -1;
    } else {
      return 1;
    }
  }
}

// return the value of a node or link
function value(d) {
  return d.value;
}

// return the vertical center of a node
function nodeCenter(node) {
  return (node.y0 + node.y1) / 2;
}

// return the vertical center of a link's source node
function linkSourceCenter(link) {
  return nodeCenter(link.source);
}

// return the vertical center of a link's target node
function linkTargetCenter(link) {
  return nodeCenter(link.target);
}

// Return the default value for ID for node, d.index
function defaultId(d) {
  return d.index;
}

// Return the default object the graph's nodes, graph.nodes
function defaultNodes(graph) {
  return graph.nodes;
}

// Return the default object the graph's nodes, graph.links
function defaultLinks(graph) {
  return graph.links;
}

// Return the node from the collection that matches the provided ID, or throw an error if no match
function find(nodeById, id) {
  var node = nodeById.get(id);
  if (!node) throw new Error('missing: ' + id);
  return node;
}

function getNodeID(node, id) {
  return id(node);
}

// The main sankeyCircular functions

// Some constants for circular link calculations
var verticalMargin = 25;
var baseRadius = 10;
var scale = 0.3; //Possibly let user control this, although anything over 0.5 starts to get too cramped

function sankeyCircular () {
  // Set the default values
  var x0 = 0,
      y0 = 0,
      x1 = 1,
      y1 = 1,
      // extent
  dx = 24,
      // nodeWidth
  py,
      // nodePadding, for vertical postioning
  id = defaultId,
      align = justify,
      nodes = defaultNodes,
      links = defaultLinks,
      iterations = 32,
      circularLinkGap = 2,
      paddingRatio,
      sortNodes = null;

  function sankeyCircular() {
    var graph = {
      nodes: nodes.apply(null, arguments),
      links: links.apply(null, arguments)

      // Process the graph's nodes and links, setting their positions

      // 1.  Associate the nodes with their respective links, and vice versa
    };computeNodeLinks(graph);

    // 2.  Determine which links result in a circular path in the graph
    identifyCircles(graph, id, sortNodes);

    // 4. Calculate the nodes' values, based on the values of the incoming and outgoing links
    computeNodeValues(graph);

    // 5.  Calculate the nodes' depth based on the incoming and outgoing links
    //     Sets the nodes':
    //     - depth:  the depth in the graph
    //     - column: the depth (0, 1, 2, etc), as is relates to visual position from left to right
    //     - x0, x1: the x coordinates, as is relates to visual position from left to right
    computeNodeDepths(graph);

    // 3.  Determine how the circular links will be drawn,
    //     either travelling back above the main chart ("top")
    //     or below the main chart ("bottom")
    selectCircularLinkTypes(graph, id);

    // 6.  Calculate the nodes' and links' vertical position within their respective column
    //     Also readjusts sankeyCircular size if circular links are needed, and node x's
    computeNodeBreadths(graph, iterations, id);
    computeLinkBreadths(graph);

    // 7.  Sort links per node, based on the links' source/target nodes' breadths
    // 8.  Adjust nodes that overlap links that span 2+ columns
    var linkSortingIterations = 4; //Possibly let user control this number, like the iterations over node placement
    for (var iteration = 0; iteration < linkSortingIterations; iteration++) {

      sortSourceLinks(graph, y1, id);
      sortTargetLinks(graph, y1, id);
      resolveNodeLinkOverlaps(graph, y0, y1, id);
      sortSourceLinks(graph, y1, id);
      sortTargetLinks(graph, y1, id);
    }

    // 8.1  Fix nodes overlapping after sortNodes
    resolveNodesOverlap(graph, y0, py);

    // 8.2  Adjust node and link positions back to fill height of chart area if compressed
    fillHeight(graph, y0, y1);

    // 9. Calculate visually appealling path for the circular paths, and create the "d" string
    addCircularPathData(graph, circularLinkGap, y1, id);

    return graph;
  } // end of sankeyCircular function

  // Set the sankeyCircular parameters
  // nodeID, nodeAlign, nodeWidth, nodePadding, nodes, links, size, extent, iterations, nodePaddingRatio, circularLinkGap
  sankeyCircular.nodeId = function (_) {
    return arguments.length ? (id = typeof _ === 'function' ? _ : constant(_), sankeyCircular) : id;
  };

  sankeyCircular.nodeAlign = function (_) {
    return arguments.length ? (align = typeof _ === 'function' ? _ : constant(_), sankeyCircular) : align;
  };

  sankeyCircular.nodeWidth = function (_) {
    return arguments.length ? (dx = +_, sankeyCircular) : dx;
  };

  sankeyCircular.nodePadding = function (_) {
    return arguments.length ? (py = +_, sankeyCircular) : py;
  };

  sankeyCircular.nodes = function (_) {
    return arguments.length ? (nodes = typeof _ === 'function' ? _ : constant(_), sankeyCircular) : nodes;
  };

  sankeyCircular.links = function (_) {
    return arguments.length ? (links = typeof _ === 'function' ? _ : constant(_), sankeyCircular) : links;
  };

  sankeyCircular.size = function (_) {
    return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankeyCircular) : [x1 - x0, y1 - y0];
  };

  sankeyCircular.extent = function (_) {
    return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankeyCircular) : [[x0, y0], [x1, y1]];
  };

  sankeyCircular.iterations = function (_) {
    return arguments.length ? (iterations = +_, sankeyCircular) : iterations;
  };

  sankeyCircular.circularLinkGap = function (_) {
    return arguments.length ? (circularLinkGap = +_, sankeyCircular) : circularLinkGap;
  };

  sankeyCircular.nodePaddingRatio = function (_) {
    return arguments.length ? (paddingRatio = +_, sankeyCircular) : paddingRatio;
  };

  sankeyCircular.sortNodes = function (_) {
    return arguments.length ? (sortNodes = _, sankeyCircular) : sortNodes;
  };

  sankeyCircular.update = function (graph) {
    // 5.  Calculate the nodes' depth based on the incoming and outgoing links
    //     Sets the nodes':
    //     - depth:  the depth in the graph
    //     - column: the depth (0, 1, 2, etc), as is relates to visual position from left to right
    //     - x0, x1: the x coordinates, as is relates to visual position from left to right
    // computeNodeDepths(graph)

    // 3.  Determine how the circular links will be drawn,
    //     either travelling back above the main chart ("top")
    //     or below the main chart ("bottom")
    selectCircularLinkTypes(graph, id);

    // 6.  Calculate the nodes' and links' vertical position within their respective column
    //     Also readjusts sankeyCircular size if circular links are needed, and node x's
    // computeNodeBreadths(graph, iterations, id)
    computeLinkBreadths(graph);

    // Force position of circular link type based on position
    graph.links.forEach(function (link) {
      if (link.circular) {
        link.circularLinkType = link.y0 + link.y1 < y1 ? 'top' : 'bottom';

        link.source.circularLinkType = link.circularLinkType;
        link.target.circularLinkType = link.circularLinkType;
      }
    });

    sortSourceLinks(graph, y1, id, false); // Sort links but do not move nodes
    sortTargetLinks(graph, y1, id);

    // 7.  Sort links per node, based on the links' source/target nodes' breadths
    // 8.  Adjust nodes that overlap links that span 2+ columns
    // var linkSortingIterations = 4; //Possibly let user control this number, like the iterations over node placement
    // for (var iteration = 0; iteration < linkSortingIterations; iteration++) {
    //
    //   sortSourceLinks(graph, y1, id)
    //   sortTargetLinks(graph, y1, id)
    //   resolveNodeLinkOverlaps(graph, y0, y1, id)
    //   sortSourceLinks(graph, y1, id)
    //   sortTargetLinks(graph, y1, id)
    //
    // }

    // 8.1  Adjust node and link positions back to fill height of chart area if compressed
    // fillHeight(graph, y0, y1)

    // 9. Calculate visually appealling path for the circular paths, and create the "d" string
    addCircularPathData(graph, circularLinkGap, y1, id);
    return graph;
  };

  // Populate the sourceLinks and targetLinks for each node.
  // Also, if the source and target are not objects, assume they are indices.
  function computeNodeLinks(graph) {
    graph.nodes.forEach(function (node, i) {
      node.index = i;
      node.sourceLinks = [];
      node.targetLinks = [];
    });
    var nodeById = map(graph.nodes, id);
    graph.links.forEach(function (link, i) {
      link.index = i;
      var source = link.source;
      var target = link.target;
      if ((typeof source === "undefined" ? "undefined" : _typeof(source)) !== 'object') {
        source = link.source = find(nodeById, source);
      }
      if ((typeof target === "undefined" ? "undefined" : _typeof(target)) !== 'object') {
        target = link.target = find(nodeById, target);
      }
      source.sourceLinks.push(link);
      target.targetLinks.push(link);
    });
    return graph;
  }

  // Compute the value (size) and cycleness of each node by summing the associated links.
  function computeNodeValues(graph) {
    graph.nodes.forEach(function (node) {
      node.partOfCycle = false;
      node.value = Math.max(sum(node.sourceLinks, value), sum(node.targetLinks, value));
      node.sourceLinks.forEach(function (link) {
        if (link.circular) {
          node.partOfCycle = true;
          node.circularLinkType = link.circularLinkType;
        }
      });
      node.targetLinks.forEach(function (link) {
        if (link.circular) {
          node.partOfCycle = true;
          node.circularLinkType = link.circularLinkType;
        }
      });
    });
  }

  function getCircleMargins(graph) {
    var totalTopLinksWidth = 0,
        totalBottomLinksWidth = 0,
        totalRightLinksWidth = 0,
        totalLeftLinksWidth = 0;

    var maxColumn = max(graph.nodes, function (node) {
      return node.column;
    });

    graph.links.forEach(function (link) {
      if (link.circular) {
        if (link.circularLinkType == 'top') {
          totalTopLinksWidth = totalTopLinksWidth + link.width;
        } else {
          totalBottomLinksWidth = totalBottomLinksWidth + link.width;
        }

        if (link.target.column == 0) {
          totalLeftLinksWidth = totalLeftLinksWidth + link.width;
        }

        if (link.source.column == maxColumn) {
          totalRightLinksWidth = totalRightLinksWidth + link.width;
        }
      }
    });

    //account for radius of curves and padding between links
    totalTopLinksWidth = totalTopLinksWidth > 0 ? totalTopLinksWidth + verticalMargin + baseRadius : totalTopLinksWidth;
    totalBottomLinksWidth = totalBottomLinksWidth > 0 ? totalBottomLinksWidth + verticalMargin + baseRadius : totalBottomLinksWidth;
    totalRightLinksWidth = totalRightLinksWidth > 0 ? totalRightLinksWidth + verticalMargin + baseRadius : totalRightLinksWidth;
    totalLeftLinksWidth = totalLeftLinksWidth > 0 ? totalLeftLinksWidth + verticalMargin + baseRadius : totalLeftLinksWidth;

    return { "top": totalTopLinksWidth, "bottom": totalBottomLinksWidth, "left": totalLeftLinksWidth, "right": totalRightLinksWidth };
  }

  // Update the x0, y0, x1 and y1 for the sankeyCircular, to allow space for any circular links
  function scaleSankeySize(graph, margin) {

    var maxColumn = max(graph.nodes, function (node) {
      return node.column;
    });

    var currentWidth = x1 - x0;
    var currentHeight = y1 - y0;

    var newWidth = currentWidth + margin.right + margin.left;
    var newHeight = currentHeight + margin.top + margin.bottom;

    var scaleX = currentWidth / newWidth;
    var scaleY = currentHeight / newHeight;

    x0 = x0 * scaleX + margin.left;
    x1 = margin.right == 0 ? x1 : x1 * scaleX;
    y0 = y0 * scaleY + margin.top;
    y1 = y1 * scaleY;

    graph.nodes.forEach(function (node) {
      node.x0 = x0 + node.column * ((x1 - x0 - dx) / maxColumn);
      node.x1 = node.x0 + dx;
    });

    return scaleY;
  }

  // Iteratively assign the depth for each node.
  // Nodes are assigned the maximum depth of incoming neighbors plus one;
  // nodes with no incoming links are assigned depth zero, while
  // nodes with no outgoing links are assigned the maximum depth.
  function computeNodeDepths(graph) {
    var nodes, next, x;

    for (nodes = graph.nodes, next = [], x = 0; nodes.length; ++x, nodes = next, next = []) {
      nodes.forEach(function (node) {
        node.depth = x;
        node.sourceLinks.forEach(function (link) {
          if (next.indexOf(link.target) < 0 && !link.circular) {
            next.push(link.target);
          }
        });
      });
    }

    for (nodes = graph.nodes, next = [], x = 0; nodes.length; ++x, nodes = next, next = []) {
      nodes.forEach(function (node) {
        node.height = x;
        node.targetLinks.forEach(function (link) {
          if (next.indexOf(link.source) < 0 && !link.circular) {
            next.push(link.source);
          }
        });
      });
    }

    // assign column numbers, and get max value
    graph.nodes.forEach(function (node) {
      node.column = sortNodes !== null ? node[sortNodes] : Math.floor(align.call(null, node, x));
    });
  }

  // Assign nodes' breadths, and then shift nodes that overlap (resolveCollisions)
  function computeNodeBreadths(graph, iterations, id) {
    var columns = nest().key(function (d) {
      return d.column;
    }).sortKeys(ascending).entries(graph.nodes).map(function (d) {
      return d.values;
    });

    initializeNodeBreadth(id);
    resolveCollisions();

    for (var alpha = 1, n = iterations; n > 0; --n) {
      relaxLeftAndRight(alpha *= 0.99, id);
      resolveCollisions();
    }

    function initializeNodeBreadth(id) {

      //override py if nodePadding has been set
      if (paddingRatio) {
        var padding = Infinity;
        columns.forEach(function (nodes) {
          var thisPadding = y1 * paddingRatio / (nodes.length + 1);
          padding = thisPadding < padding ? thisPadding : padding;
        });
        py = padding;
      }

      var ky = min(columns, function (nodes) {
        return (y1 - y0 - (nodes.length - 1) * py) / sum(nodes, value);
      });

      //calculate the widths of the links
      ky = ky * scale;

      graph.links.forEach(function (link) {
        link.width = link.value * ky;
      });

      //determine how much to scale down the chart, based on circular links
      var margin = getCircleMargins(graph);
      var ratio = scaleSankeySize(graph, margin);

      //re-calculate widths
      ky = ky * ratio;

      graph.links.forEach(function (link) {
        link.width = link.value * ky;
      });

      columns.forEach(function (nodes) {
        var nodesLength = nodes.length;
        nodes.forEach(function (node, i) {
          if (node.depth == columns.length - 1 && nodesLength == 1) {
            node.y0 = y1 / 2 - node.value * ky;
            node.y1 = node.y0 + node.value * ky;
          } else if (node.depth == 0 && nodesLength == 1) {
            node.y0 = y1 / 2 - node.value * ky;
            node.y1 = node.y0 + node.value * ky;
          } else if (node.partOfCycle) {
            if (numberOfNonSelfLinkingCycles(node, id) == 0) {
              node.y0 = y1 / 2 + i;
              node.y1 = node.y0 + node.value * ky;
            } else if (node.circularLinkType == 'top') {
              node.y0 = y0 + i;
              node.y1 = node.y0 + node.value * ky;
            } else {
              node.y0 = y1 - node.value * ky - i;
              node.y1 = node.y0 + node.value * ky;
            }
          } else {
            if (margin.top == 0 || margin.bottom == 0) {
              node.y0 = (y1 - y0) / nodesLength * i;
              node.y1 = node.y0 + node.value * ky;
            } else {
              node.y0 = (y1 - y0) / 2 - nodesLength / 2 + i;
              node.y1 = node.y0 + node.value * ky;
            }
          }
        });
      });
    }

    // For each node in each column, check the node's vertical position in relation to its targets and sources vertical position
    // and shift up/down to be closer to the vertical middle of those targets and sources
    function relaxLeftAndRight(alpha) {
      columns.forEach(function (nodes) {
        nodes.forEach(function (node) {
          // check the node is not an orphan
          var nodeHeight;
          if (node.sourceLinks.length || node.targetLinks.length) {
            nodeHeight = node.y1 - node.y0;
            node.y0 = y1 / 2 - nodeHeight / 2;
            node.y1 = y1 / 2 + nodeHeight / 2;
            var avg = 0;

            var avgTargetY = mean(node.sourceLinks, linkTargetCenter);
            var avgSourceY = mean(node.targetLinks, linkSourceCenter);
            if (avgTargetY && avgSourceY) {
              avg = (avgTargetY + avgSourceY) / 2;
            } else {
              avg = avgTargetY || avgSourceY;
            }
            var dy = (avg - nodeCenter(node)) * alpha;
            // positive if it node needs to move down
            node.y0 += dy;
            node.y1 += dy;
          }
        });
      });
    }

    // For each column, check if nodes are overlapping, and if so, shift up/down
    function resolveCollisions() {
      columns.forEach(function (nodes) {
        var node,
            dy,
            y = y0,
            n = nodes.length,
            i;

        // Push any overlapping nodes down.
        nodes.sort(ascendingBreadth);

        for (i = 0; i < n; ++i) {
          node = nodes[i];
          dy = y - node.y0;

          if (dy > 0) {
            node.y0 += dy;
            node.y1 += dy;
          }
          y = node.y1 + py;
        }

        // If the bottommost node goes outside the bounds, push it back up.
        dy = y - py - y1;
        if (dy > 0) {
          y = node.y0 -= dy, node.y1 -= dy;

          // Push any overlapping nodes back up.
          for (i = n - 2; i >= 0; --i) {
            node = nodes[i];
            dy = node.y1 + py - y;
            if (dy > 0) node.y0 -= dy, node.y1 -= dy;
            y = node.y0;
          }
        }
      });
    }
  }

  // Assign the links y0 and y1 based on source/target nodes position,
  // plus the link's relative position to other links to the same node
  function computeLinkBreadths(graph) {
    graph.nodes.forEach(function (node) {
      node.sourceLinks.sort(ascendingTargetBreadth);
      node.targetLinks.sort(ascendingSourceBreadth);
    });
    graph.nodes.forEach(function (node) {
      var y0 = node.y0;
      var y1 = y0;

      // start from the bottom of the node for cycle links
      var y0cycle = node.y1;
      var y1cycle = y0cycle;

      node.sourceLinks.forEach(function (link) {
        if (link.circular) {
          link.y0 = y0cycle - link.width / 2;
          y0cycle = y0cycle - link.width;
        } else {
          link.y0 = y0 + link.width / 2;
          y0 += link.width;
        }
      });
      node.targetLinks.forEach(function (link) {
        if (link.circular) {
          link.y1 = y1cycle - link.width / 2;
          y1cycle = y1cycle - link.width;
        } else {
          link.y1 = y1 + link.width / 2;
          y1 += link.width;
        }
      });
    });
  }

  return sankeyCircular;
}

/// /////////////////////////////////////////////////////////////////////////////////
// Cycle functions
// portion of code to detect circular links based on Colin Fergus' bl.ock https://gist.github.com/cfergus/3956043

// Identify circles in the link objects
function identifyCircles(graph, id, sortNodes) {
  var circularLinkID = 0;
  if (sortNodes === null) {

    // Building adjacency graph
    var adjList = [];
    for (var i = 0; i < graph.links.length; i++) {
      var link = graph.links[i];
      var source = link.source.index;
      var target = link.target.index;
      if (!adjList[source]) adjList[source] = [];
      if (!adjList[target]) adjList[target] = [];

      // Add links if not already in set
      if (adjList[source].indexOf(target) === -1) adjList[source].push(target);
    }

    // Find all elementary circuits
    var cycles = findCircuits(adjList);

    // Sort by circuits length
    cycles.sort(function (a, b) {
      return a.length - b.length;
    });

    var circularLinks = {};
    for (i = 0; i < cycles.length; i++) {
      var cycle = cycles[i];
      var last = cycle.slice(-2);
      if (!circularLinks[last[0]]) circularLinks[last[0]] = {};
      circularLinks[last[0]][last[1]] = true;
    }

    graph.links.forEach(function (link) {
      var target = link.target.index;
      var source = link.source.index;
      // If self-linking or a back-edge
      if (target === source || circularLinks[source] && circularLinks[source][target]) {
        link.circular = true;
        link.circularLinkID = circularLinkID;
        circularLinkID = circularLinkID + 1;
      } else {
        link.circular = false;
      }
    });
  } else {
    graph.links.forEach(function (link) {
      if (link.source[sortNodes] < link.target[sortNodes]) {
        link.circular = false;
      } else {
        link.circular = true;
        link.circularLinkID = circularLinkID;
        circularLinkID = circularLinkID + 1;
      }
    });
  }
}

// Assign a circular link type (top or bottom), based on:
// - if the source/target node already has circular links, then use the same type
// - if not, choose the type with fewer links
function selectCircularLinkTypes(graph, id) {
  var numberOfTops = 0;
  var numberOfBottoms = 0;
  graph.links.forEach(function (link) {
    if (link.circular) {
      // if either souce or target has type already use that
      if (link.source.circularLinkType || link.target.circularLinkType) {
        // default to source type if available
        link.circularLinkType = link.source.circularLinkType ? link.source.circularLinkType : link.target.circularLinkType;
      } else {
        link.circularLinkType = numberOfTops < numberOfBottoms ? 'top' : 'bottom';
      }

      if (link.circularLinkType == 'top') {
        numberOfTops = numberOfTops + 1;
      } else {
        numberOfBottoms = numberOfBottoms + 1;
      }

      graph.nodes.forEach(function (node) {
        if (getNodeID(node, id) == getNodeID(link.source, id) || getNodeID(node, id) == getNodeID(link.target, id)) {
          node.circularLinkType = link.circularLinkType;
        }
      });
    }
  });

  //correct self-linking links to be same direction as node
  graph.links.forEach(function (link) {
    if (link.circular) {
      //if both source and target node are same type, then link should have same type
      if (link.source.circularLinkType == link.target.circularLinkType) {
        link.circularLinkType = link.source.circularLinkType;
      }
      //if link is selflinking, then link should have same type as node
      if (selfLinking(link, id)) {
        link.circularLinkType = link.source.circularLinkType;
      }
    }
  });
}

// Return the angle between a straight line between the source and target of the link, and the vertical plane of the node
function linkAngle(link) {
  var adjacent = Math.abs(link.y1 - link.y0);
  var opposite = Math.abs(link.target.x0 - link.source.x1);

  return Math.atan(opposite / adjacent);
}

// Check if two circular links potentially overlap
function circularLinksCross(link1, link2) {
  if (link1.source.column < link2.target.column) {
    return false;
  } else if (link1.target.column > link2.source.column) {
    return false;
  } else {
    return true;
  }
}

// Return the number of circular links for node, not including self linking links
function numberOfNonSelfLinkingCycles(node, id) {
  var sourceCount = 0;
  node.sourceLinks.forEach(function (l) {
    sourceCount = l.circular && !selfLinking(l, id) ? sourceCount + 1 : sourceCount;
  });

  var targetCount = 0;
  node.targetLinks.forEach(function (l) {
    targetCount = l.circular && !selfLinking(l, id) ? targetCount + 1 : targetCount;
  });

  return sourceCount + targetCount;
}

// Check if a circular link is the only circular link for both its source and target node
function onlyCircularLink(link) {
  var nodeSourceLinks = link.source.sourceLinks;
  var sourceCount = 0;
  nodeSourceLinks.forEach(function (l) {
    sourceCount = l.circular ? sourceCount + 1 : sourceCount;
  });

  var nodeTargetLinks = link.target.targetLinks;
  var targetCount = 0;
  nodeTargetLinks.forEach(function (l) {
    targetCount = l.circular ? targetCount + 1 : targetCount;
  });

  if (sourceCount > 1 || targetCount > 1) {
    return false;
  } else {
    return true;
  }
}

// creates vertical buffer values per set of top/bottom links
function calcVerticalBuffer(links, circularLinkGap, id) {
  links.sort(sortLinkColumnAscending);
  links.forEach(function (link, i) {
    var buffer = 0;

    if (selfLinking(link, id) && onlyCircularLink(link)) {
      link.circularPathData.verticalBuffer = buffer + link.width / 2;
    } else {
      var j = 0;
      for (j; j < i; j++) {
        if (circularLinksCross(links[i], links[j])) {
          var bufferOverThisLink = links[j].circularPathData.verticalBuffer + links[j].width / 2 + circularLinkGap;
          buffer = bufferOverThisLink > buffer ? bufferOverThisLink : buffer;
        }
      }

      link.circularPathData.verticalBuffer = buffer + link.width / 2;
    }
  });

  return links;
}

// calculate the optimum path for a link to reduce overlaps
function addCircularPathData(graph, circularLinkGap, y1, id) {
  //var baseRadius = 10
  var buffer = 5;
  //var verticalMargin = 25

  var minY = min(graph.links, function (link) {
    return link.source.y0;
  });

  // create object for circular Path Data
  graph.links.forEach(function (link) {
    if (link.circular) {
      link.circularPathData = {};
    }
  });

  // calc vertical offsets per top/bottom links
  var topLinks = graph.links.filter(function (l) {
    return l.circularLinkType == 'top';
  });
  /* topLinks = */calcVerticalBuffer(topLinks, circularLinkGap, id);

  var bottomLinks = graph.links.filter(function (l) {
    return l.circularLinkType == 'bottom';
  });
  /* bottomLinks = */calcVerticalBuffer(bottomLinks, circularLinkGap, id);

  // add the base data for each link
  graph.links.forEach(function (link) {
    if (link.circular) {
      link.circularPathData.arcRadius = link.width + baseRadius;
      link.circularPathData.leftNodeBuffer = buffer;
      link.circularPathData.rightNodeBuffer = buffer;
      link.circularPathData.sourceWidth = link.source.x1 - link.source.x0;
      link.circularPathData.sourceX = link.source.x0 + link.circularPathData.sourceWidth;
      link.circularPathData.targetX = link.target.x0;
      link.circularPathData.sourceY = link.y0;
      link.circularPathData.targetY = link.y1;

      // for self linking paths, and that the only circular link in/out of that node
      if (selfLinking(link, id) && onlyCircularLink(link)) {
        link.circularPathData.leftSmallArcRadius = baseRadius + link.width / 2;
        link.circularPathData.leftLargeArcRadius = baseRadius + link.width / 2;
        link.circularPathData.rightSmallArcRadius = baseRadius + link.width / 2;
        link.circularPathData.rightLargeArcRadius = baseRadius + link.width / 2;

        if (link.circularLinkType == 'bottom') {
          link.circularPathData.verticalFullExtent = link.source.y1 + verticalMargin + link.circularPathData.verticalBuffer;
          link.circularPathData.verticalLeftInnerExtent = link.circularPathData.verticalFullExtent - link.circularPathData.leftLargeArcRadius;
          link.circularPathData.verticalRightInnerExtent = link.circularPathData.verticalFullExtent - link.circularPathData.rightLargeArcRadius;
        } else {
          // top links
          link.circularPathData.verticalFullExtent = link.source.y0 - verticalMargin - link.circularPathData.verticalBuffer;
          link.circularPathData.verticalLeftInnerExtent = link.circularPathData.verticalFullExtent + link.circularPathData.leftLargeArcRadius;
          link.circularPathData.verticalRightInnerExtent = link.circularPathData.verticalFullExtent + link.circularPathData.rightLargeArcRadius;
        }
      } else {
        // else calculate normally
        // add left extent coordinates, based on links with same source column and circularLink type
        var thisColumn = link.source.column;
        var thisCircularLinkType = link.circularLinkType;
        var sameColumnLinks = graph.links.filter(function (l) {
          return l.source.column == thisColumn && l.circularLinkType == thisCircularLinkType;
        });

        if (link.circularLinkType == 'bottom') {
          sameColumnLinks.sort(sortLinkSourceYDescending);
        } else {
          sameColumnLinks.sort(sortLinkSourceYAscending);
        }

        var radiusOffset = 0;
        sameColumnLinks.forEach(function (l, i) {
          if (l.circularLinkID == link.circularLinkID) {
            link.circularPathData.leftSmallArcRadius = baseRadius + link.width / 2 + radiusOffset;
            link.circularPathData.leftLargeArcRadius = baseRadius + link.width / 2 + i * circularLinkGap + radiusOffset;
          }
          radiusOffset = radiusOffset + l.width;
        });

        // add right extent coordinates, based on links with same target column and circularLink type
        thisColumn = link.target.column;
        sameColumnLinks = graph.links.filter(function (l) {
          return l.target.column == thisColumn && l.circularLinkType == thisCircularLinkType;
        });
        if (link.circularLinkType == 'bottom') {
          sameColumnLinks.sort(sortLinkTargetYDescending);
        } else {
          sameColumnLinks.sort(sortLinkTargetYAscending);
        }

        radiusOffset = 0;
        sameColumnLinks.forEach(function (l, i) {
          if (l.circularLinkID == link.circularLinkID) {
            link.circularPathData.rightSmallArcRadius = baseRadius + link.width / 2 + radiusOffset;
            link.circularPathData.rightLargeArcRadius = baseRadius + link.width / 2 + i * circularLinkGap + radiusOffset;
          }
          radiusOffset = radiusOffset + l.width;
        });

        // bottom links
        if (link.circularLinkType == 'bottom') {
          link.circularPathData.verticalFullExtent = Math.max(y1, link.source.y1, link.target.y1) + verticalMargin + link.circularPathData.verticalBuffer;
          link.circularPathData.verticalLeftInnerExtent = link.circularPathData.verticalFullExtent - link.circularPathData.leftLargeArcRadius;
          link.circularPathData.verticalRightInnerExtent = link.circularPathData.verticalFullExtent - link.circularPathData.rightLargeArcRadius;
        } else {
          // top links
          link.circularPathData.verticalFullExtent = minY - verticalMargin - link.circularPathData.verticalBuffer;
          link.circularPathData.verticalLeftInnerExtent = link.circularPathData.verticalFullExtent + link.circularPathData.leftLargeArcRadius;
          link.circularPathData.verticalRightInnerExtent = link.circularPathData.verticalFullExtent + link.circularPathData.rightLargeArcRadius;
        }
      }

      // all links
      link.circularPathData.leftInnerExtent = link.circularPathData.sourceX + link.circularPathData.leftNodeBuffer;
      link.circularPathData.rightInnerExtent = link.circularPathData.targetX - link.circularPathData.rightNodeBuffer;
      link.circularPathData.leftFullExtent = link.circularPathData.sourceX + link.circularPathData.leftLargeArcRadius + link.circularPathData.leftNodeBuffer;
      link.circularPathData.rightFullExtent = link.circularPathData.targetX - link.circularPathData.rightLargeArcRadius - link.circularPathData.rightNodeBuffer;
    }

    if (link.circular) {
      link.path = createCircularPathString(link);
    } else {
      var normalPath = linkHorizontal().source(function (d) {
        var x = d.source.x0 + (d.source.x1 - d.source.x0);
        var y = d.y0;
        return [x, y];
      }).target(function (d) {
        var x = d.target.x0;
        var y = d.y1;
        return [x, y];
      });
      link.path = normalPath(link);
    }
  });
}

// create a d path using the addCircularPathData
function createCircularPathString(link) {
  var pathString = '';
  // 'pathData' is assigned a value but never used
  // var pathData = {}

  if (link.circularLinkType == 'top') {
    pathString =
    // start at the right of the source node
    'M' + link.circularPathData.sourceX + ' ' + link.circularPathData.sourceY + ' ' +
    // line right to buffer point
    'L' + link.circularPathData.leftInnerExtent + ' ' + link.circularPathData.sourceY + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.leftLargeArcRadius + ' ' + link.circularPathData.leftSmallArcRadius + ' 0 0 0 ' +
    // End of arc X //End of arc Y
    link.circularPathData.leftFullExtent + ' ' + (link.circularPathData.sourceY - link.circularPathData.leftSmallArcRadius) + ' ' + // End of arc X
    // line up to buffer point
    'L' + link.circularPathData.leftFullExtent + ' ' + link.circularPathData.verticalLeftInnerExtent + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.leftLargeArcRadius + ' ' + link.circularPathData.leftLargeArcRadius + ' 0 0 0 ' +
    // End of arc X //End of arc Y
    link.circularPathData.leftInnerExtent + ' ' + link.circularPathData.verticalFullExtent + ' ' + // End of arc X
    // line left to buffer point
    'L' + link.circularPathData.rightInnerExtent + ' ' + link.circularPathData.verticalFullExtent + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.rightLargeArcRadius + ' ' + link.circularPathData.rightLargeArcRadius + ' 0 0 0 ' +
    // End of arc X //End of arc Y
    link.circularPathData.rightFullExtent + ' ' + link.circularPathData.verticalRightInnerExtent + ' ' + // End of arc X
    // line down
    'L' + link.circularPathData.rightFullExtent + ' ' + (link.circularPathData.targetY - link.circularPathData.rightSmallArcRadius) + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.rightLargeArcRadius + ' ' + link.circularPathData.rightSmallArcRadius + ' 0 0 0 ' +
    // End of arc X //End of arc Y
    link.circularPathData.rightInnerExtent + ' ' + link.circularPathData.targetY + ' ' + // End of arc X
    // line to end
    'L' + link.circularPathData.targetX + ' ' + link.circularPathData.targetY;
  } else {
    // bottom path
    pathString =
    // start at the right of the source node
    'M' + link.circularPathData.sourceX + ' ' + link.circularPathData.sourceY + ' ' +
    // line right to buffer point
    'L' + link.circularPathData.leftInnerExtent + ' ' + link.circularPathData.sourceY + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.leftLargeArcRadius + ' ' + link.circularPathData.leftSmallArcRadius + ' 0 0 1 ' +
    // End of arc X //End of arc Y
    link.circularPathData.leftFullExtent + ' ' + (link.circularPathData.sourceY + link.circularPathData.leftSmallArcRadius) + ' ' + // End of arc X
    // line down to buffer point
    'L' + link.circularPathData.leftFullExtent + ' ' + link.circularPathData.verticalLeftInnerExtent + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.leftLargeArcRadius + ' ' + link.circularPathData.leftLargeArcRadius + ' 0 0 1 ' +
    // End of arc X //End of arc Y
    link.circularPathData.leftInnerExtent + ' ' + link.circularPathData.verticalFullExtent + ' ' + // End of arc X
    // line left to buffer point
    'L' + link.circularPathData.rightInnerExtent + ' ' + link.circularPathData.verticalFullExtent + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.rightLargeArcRadius + ' ' + link.circularPathData.rightLargeArcRadius + ' 0 0 1 ' +
    // End of arc X //End of arc Y
    link.circularPathData.rightFullExtent + ' ' + link.circularPathData.verticalRightInnerExtent + ' ' + // End of arc X
    // line up
    'L' + link.circularPathData.rightFullExtent + ' ' + (link.circularPathData.targetY + link.circularPathData.rightSmallArcRadius) + ' ' +
    // Arc around: Centre of arc X and  //Centre of arc Y
    'A' + link.circularPathData.rightLargeArcRadius + ' ' + link.circularPathData.rightSmallArcRadius + ' 0 0 1 ' +
    // End of arc X //End of arc Y
    link.circularPathData.rightInnerExtent + ' ' + link.circularPathData.targetY + ' ' + // End of arc X
    // line to end
    'L' + link.circularPathData.targetX + ' ' + link.circularPathData.targetY;
  }

  return pathString;
}

// sort links based on the distance between the source and tartget node columns
// if the same, then use Y position of the source node
function sortLinkColumnAscending(link1, link2) {
  if (linkColumnDistance(link1) == linkColumnDistance(link2)) {
    return link1.circularLinkType == 'bottom' ? sortLinkSourceYDescending(link1, link2) : sortLinkSourceYAscending(link1, link2);
  } else {
    return linkColumnDistance(link2) - linkColumnDistance(link1);
  }
}

// sort ascending links by their source vertical position, y0
function sortLinkSourceYAscending(link1, link2) {
  return link1.y0 - link2.y0;
}

// sort descending links by their source vertical position, y0
function sortLinkSourceYDescending(link1, link2) {
  return link2.y0 - link1.y0;
}

// sort ascending links by their target vertical position, y1
function sortLinkTargetYAscending(link1, link2) {
  return link1.y1 - link2.y1;
}

// sort descending links by their target vertical position, y1
function sortLinkTargetYDescending(link1, link2) {
  return link2.y1 - link1.y1;
}

// return the distance between the link's target and source node, in terms of the nodes' column
function linkColumnDistance(link) {
  return link.target.column - link.source.column;
}

// return the distance between the link's target and source node, in terms of the nodes' X coordinate
function linkXLength(link) {
  return link.target.x0 - link.source.x1;
}

// Return the Y coordinate on the longerLink path * which is perpendicular shorterLink's source.
// * approx, based on a straight line from target to source, when in fact the path is a bezier
function linkPerpendicularYToLinkSource(longerLink, shorterLink) {
  // get the angle for the longer link
  var angle = linkAngle(longerLink);

  // get the adjacent length to the other link's x position
  var heightFromY1ToPependicular = linkXLength(shorterLink) / Math.tan(angle);

  // add or subtract from longer link1's original y1, depending on the slope
  var yPerpendicular = incline(longerLink) == 'up' ? longerLink.y1 + heightFromY1ToPependicular : longerLink.y1 - heightFromY1ToPependicular;

  return yPerpendicular;
}

// Return the Y coordinate on the longerLink path * which is perpendicular shorterLink's source.
// * approx, based on a straight line from target to source, when in fact the path is a bezier
function linkPerpendicularYToLinkTarget(longerLink, shorterLink) {
  // get the angle for the longer link
  var angle = linkAngle(longerLink);

  // get the adjacent length to the other link's x position
  var heightFromY1ToPependicular = linkXLength(shorterLink) / Math.tan(angle);

  // add or subtract from longer link's original y1, depending on the slope
  var yPerpendicular = incline(longerLink) == 'up' ? longerLink.y1 - heightFromY1ToPependicular : longerLink.y1 + heightFromY1ToPependicular;

  return yPerpendicular;
}

// Move any nodes that overlap links which span 2+ columns
function resolveNodeLinkOverlaps(graph, y0, y1, id) {

  graph.links.forEach(function (link) {
    if (link.circular) {
      return;
    }

    if (link.target.column - link.source.column > 1) {
      var columnToTest = link.source.column + 1;
      var maxColumnToTest = link.target.column - 1;

      var i = 1;
      var numberOfColumnsToTest = maxColumnToTest - columnToTest + 1;

      for (i = 1; columnToTest <= maxColumnToTest; columnToTest++, i++) {
        graph.nodes.forEach(function (node) {
          if (node.column == columnToTest) {
            var t = i / (numberOfColumnsToTest + 1);

            // Find all the points of a cubic bezier curve in javascript
            // https://stackoverflow.com/questions/15397596/find-all-the-points-of-a-cubic-bezier-curve-in-javascript

            var B0_t = Math.pow(1 - t, 3);
            var B1_t = 3 * t * Math.pow(1 - t, 2);
            var B2_t = 3 * Math.pow(t, 2) * (1 - t);
            var B3_t = Math.pow(t, 3);

            var py_t = B0_t * link.y0 + B1_t * link.y0 + B2_t * link.y1 + B3_t * link.y1;

            var linkY0AtColumn = py_t - link.width / 2;
            var linkY1AtColumn = py_t + link.width / 2;
            var dy;

            // If top of link overlaps node, push node up
            if (linkY0AtColumn > node.y0 && linkY0AtColumn < node.y1) {

              dy = node.y1 - linkY0AtColumn + 10;
              dy = node.circularLinkType == 'bottom' ? dy : -dy;

              node = adjustNodeHeight(node, dy, y0, y1);

              // check if other nodes need to move up too
              graph.nodes.forEach(function (otherNode) {
                // don't need to check itself or nodes at different columns
                if (getNodeID(otherNode, id) == getNodeID(node, id) || otherNode.column != node.column) {
                  return;
                }
                if (nodesOverlap(node, otherNode)) {
                  adjustNodeHeight(otherNode, dy, y0, y1);
                }
              });
            } else if (linkY1AtColumn > node.y0 && linkY1AtColumn < node.y1) {
              // If bottom of link overlaps node, push node down
              dy = linkY1AtColumn - node.y0 + 10;

              node = adjustNodeHeight(node, dy, y0, y1);

              // check if other nodes need to move down too
              graph.nodes.forEach(function (otherNode) {
                // don't need to check itself or nodes at different columns
                if (getNodeID(otherNode, id) == getNodeID(node, id) || otherNode.column != node.column) {
                  return;
                }
                if (otherNode.y0 < node.y1 && otherNode.y1 > node.y1) {
                  adjustNodeHeight(otherNode, dy, y0, y1);
                }
              });
            } else if (linkY0AtColumn < node.y0 && linkY1AtColumn > node.y1) {
              // if link completely overlaps node
              dy = linkY1AtColumn - node.y0 + 10;

              node = adjustNodeHeight(node, dy, y0, y1);

              graph.nodes.forEach(function (otherNode) {
                // don't need to check itself or nodes at different columns
                if (getNodeID(otherNode, id) == getNodeID(node, id) || otherNode.column != node.column) {
                  return;
                }
                if (otherNode.y0 < node.y1 && otherNode.y1 > node.y1) {
                  adjustNodeHeight(otherNode, dy, y0, y1);
                }
              });
            }
          }
        });
      }
    }
  });
}

// check if two nodes overlap
function nodesOverlap(nodeA, nodeB) {
  // test if nodeA top partially overlaps nodeB
  if (nodeA.y0 > nodeB.y0 && nodeA.y0 < nodeB.y1) {
    return true;
  } else if (nodeA.y1 > nodeB.y0 && nodeA.y1 < nodeB.y1) {
    // test if nodeA bottom partially overlaps nodeB
    return true;
  } else if (nodeA.y0 < nodeB.y0 && nodeA.y1 > nodeB.y1) {
    // test if nodeA covers nodeB
    return true;
  } else {
    return false;
  }
}

// update a node, and its associated links, vertical positions (y0, y1)
function adjustNodeHeight(node, dy, sankeyY0, sankeyY1) {
  if (node.y0 + dy >= sankeyY0 && node.y1 + dy <= sankeyY1) {
    node.y0 = node.y0 + dy;
    node.y1 = node.y1 + dy;

    node.targetLinks.forEach(function (l) {
      l.y1 = l.y1 + dy;
    });

    node.sourceLinks.forEach(function (l) {
      l.y0 = l.y0 + dy;
    });
  }
  return node;
}

// sort and set the links' y0 for each node
function sortSourceLinks(graph, y1, id, moveNodes) {
  graph.nodes.forEach(function (node) {
    // move any nodes up which are off the bottom
    if (moveNodes && node.y + (node.y1 - node.y0) > y1) {
      node.y = node.y - (node.y + (node.y1 - node.y0) - y1);
    }

    var nodesSourceLinks = graph.links.filter(function (l) {
      return getNodeID(l.source, id) == getNodeID(node, id);
    });

    var nodeSourceLinksLength = nodesSourceLinks.length;

    // if more than 1 link then sort
    if (nodeSourceLinksLength > 1) {
      nodesSourceLinks.sort(function (link1, link2) {
        // if both are not circular...
        if (!link1.circular && !link2.circular) {
          // if the target nodes are the same column, then sort by the link's target y
          if (link1.target.column == link2.target.column) {
            return link1.y1 - link2.y1;
          } else if (!sameInclines(link1, link2)) {
            // if the links slope in different directions, then sort by the link's target y
            return link1.y1 - link2.y1;

            // if the links slope in same directions, then sort by any overlap
          } else {
            if (link1.target.column > link2.target.column) {
              var link2Adj = linkPerpendicularYToLinkTarget(link2, link1);
              return link1.y1 - link2Adj;
            }
            if (link2.target.column > link1.target.column) {
              var link1Adj = linkPerpendicularYToLinkTarget(link1, link2);
              return link1Adj - link2.y1;
            }
          }
        }

        // if only one is circular, the move top links up, or bottom links down
        if (link1.circular && !link2.circular) {
          return link1.circularLinkType == 'top' ? -1 : 1;
        } else if (link2.circular && !link1.circular) {
          return link2.circularLinkType == 'top' ? 1 : -1;
        }

        // if both links are circular...
        if (link1.circular && link2.circular) {
          // ...and they both loop the same way (both top)
          if (link1.circularLinkType === link2.circularLinkType && link1.circularLinkType == 'top') {
            // ...and they both connect to a target with same column, then sort by the target's y
            if (link1.target.column === link2.target.column) {
              return link1.target.y1 - link2.target.y1;
            } else {
              // ...and they connect to different column targets, then sort by how far back they
              return link2.target.column - link1.target.column;
            }
          } else if (link1.circularLinkType === link2.circularLinkType && link1.circularLinkType == 'bottom') {
            // ...and they both loop the same way (both bottom)
            // ...and they both connect to a target with same column, then sort by the target's y
            if (link1.target.column === link2.target.column) {
              return link2.target.y1 - link1.target.y1;
            } else {
              // ...and they connect to different column targets, then sort by how far back they
              return link1.target.column - link2.target.column;
            }
          } else {
            // ...and they loop around different ways, the move top up and bottom down
            return link1.circularLinkType == 'top' ? -1 : 1;
          }
        }
      });
    }

    // update y0 for links
    var ySourceOffset = node.y0;

    nodesSourceLinks.forEach(function (link) {
      link.y0 = ySourceOffset + link.width / 2;
      ySourceOffset = ySourceOffset + link.width;
    });

    // correct any circular bottom links so they are at the bottom of the node
    nodesSourceLinks.forEach(function (link, i) {
      if (link.circularLinkType == 'bottom') {
        var j = i + 1;
        var offsetFromBottom = 0;
        // sum the widths of any links that are below this link
        for (j; j < nodeSourceLinksLength; j++) {
          offsetFromBottom = offsetFromBottom + nodesSourceLinks[j].width;
        }
        link.y0 = node.y1 - offsetFromBottom - link.width / 2;
      }
    });
  });
}

// sort and set the links' y1 for each node
function sortTargetLinks(graph, y1, id) {
  graph.nodes.forEach(function (node) {
    var nodesTargetLinks = graph.links.filter(function (l) {
      return getNodeID(l.target, id) == getNodeID(node, id);
    });

    var nodesTargetLinksLength = nodesTargetLinks.length;

    if (nodesTargetLinksLength > 1) {
      nodesTargetLinks.sort(function (link1, link2) {
        // if both are not circular, the base on the source y position
        if (!link1.circular && !link2.circular) {
          if (link1.source.column == link2.source.column) {
            return link1.y0 - link2.y0;
          } else if (!sameInclines(link1, link2)) {
            return link1.y0 - link2.y0;
          } else {
            // get the angle of the link to the further source node (ie the smaller column)
            if (link2.source.column < link1.source.column) {
              var link2Adj = linkPerpendicularYToLinkSource(link2, link1);

              return link1.y0 - link2Adj;
            }
            if (link1.source.column < link2.source.column) {
              var link1Adj = linkPerpendicularYToLinkSource(link1, link2);

              return link1Adj - link2.y0;
            }
          }
        }

        // if only one is circular, the move top links up, or bottom links down
        if (link1.circular && !link2.circular) {
          return link1.circularLinkType == 'top' ? -1 : 1;
        } else if (link2.circular && !link1.circular) {
          return link2.circularLinkType == 'top' ? 1 : -1;
        }

        // if both links are circular...
        if (link1.circular && link2.circular) {
          // ...and they both loop the same way (both top)
          if (link1.circularLinkType === link2.circularLinkType && link1.circularLinkType == 'top') {
            // ...and they both connect to a target with same column, then sort by the target's y
            if (link1.source.column === link2.source.column) {
              return link1.source.y1 - link2.source.y1;
            } else {
              // ...and they connect to different column targets, then sort by how far back they
              return link1.source.column - link2.source.column;
            }
          } else if (link1.circularLinkType === link2.circularLinkType && link1.circularLinkType == 'bottom') {
            // ...and they both loop the same way (both bottom)
            // ...and they both connect to a target with same column, then sort by the target's y
            if (link1.source.column === link2.source.column) {
              return link1.source.y1 - link2.source.y1;
            } else {
              // ...and they connect to different column targets, then sort by how far back they
              return link2.source.column - link1.source.column;
            }
          } else {
            // ...and they loop around different ways, the move top up and bottom down
            return link1.circularLinkType == 'top' ? -1 : 1;
          }
        }
      });
    }

    // update y1 for links
    var yTargetOffset = node.y0;

    nodesTargetLinks.forEach(function (link) {
      link.y1 = yTargetOffset + link.width / 2;
      yTargetOffset = yTargetOffset + link.width;
    });

    // correct any circular bottom links so they are at the bottom of the node
    nodesTargetLinks.forEach(function (link, i) {
      if (link.circularLinkType == 'bottom') {
        var j = i + 1;
        var offsetFromBottom = 0;
        // sum the widths of any links that are below this link
        for (j; j < nodesTargetLinksLength; j++) {
          offsetFromBottom = offsetFromBottom + nodesTargetLinks[j].width;
        }
        link.y1 = node.y1 - offsetFromBottom - link.width / 2;
      }
    });
  });
}

// test if links both slope up, or both slope down
function sameInclines(link1, link2) {
  return incline(link1) == incline(link2);
}

// returns the slope of a link, from source to target
// up => slopes up from source to target
// down => slopes down from source to target
function incline(link) {
  return link.y0 - link.y1 > 0 ? 'up' : 'down';
}

// check if link is self linking, ie links a node to the same node
function selfLinking(link, id) {
  return getNodeID(link.source, id) == getNodeID(link.target, id);
}

function fillHeight(graph, y0, y1) {

  var nodes = graph.nodes;
  var links = graph.links;

  var top = false;
  var bottom = false;

  links.forEach(function (link) {
    if (link.circularLinkType == "top") {
      top = true;
    } else if (link.circularLinkType == "bottom") {
      bottom = true;
    }
  });

  if (top == false || bottom == false) {
    var minY0 = min(nodes, function (node) {
      return node.y0;
    });
    var maxY1 = max(nodes, function (node) {
      return node.y1;
    });
    var currentHeight = maxY1 - minY0;
    var chartHeight = y1 - y0;
    var ratio = chartHeight / currentHeight;

    nodes.forEach(function (node) {
      var nodeHeight = (node.y1 - node.y0) * ratio;
      node.y0 = (node.y0 - minY0) * ratio;
      node.y1 = node.y0 + nodeHeight;
    });

    links.forEach(function (link) {
      link.y0 = (link.y0 - minY0) * ratio;
      link.y1 = (link.y1 - minY0) * ratio;
      link.width = link.width * ratio;
    });
  }
}

function resolveNodesOverlap(graph, y0, py) {
  var columns = nest().key(function (d) {
    return d.column;
  }).sortKeys(ascending).entries(graph.nodes).map(function (d) {
    return d.values;
  });

  columns.forEach(function (nodes) {
    var node,
        dy,
        y = y0,
        n = nodes.length,
        i;
    // Push any overlapping nodes down.
    nodes.sort(ascendingBreadth);

    for (i = 0; i < n; ++i) {
      node = nodes[i];
      dy = y - node.y0;

      if (dy > 0) {
        node.y0 += dy;
        node.y1 += dy;
        node.targetLinks.forEach(function (l) {
          l.y1 = l.y1 + dy;
        });
        node.sourceLinks.forEach(function (l) {
          l.y0 = l.y0 + dy;
        });
      }
      y = node.y1 + py;
    }
  });
}

export { sankeyCircular, addCircularPathData, center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify };


text:
module MageRecord
  # invoice items can be parents / children of other invoice items
  # (only within the same order)
  class InvoiceItem < ActiveRecord::Base
    self.table_name = :sales_flat_invoice_item
    self.primary_key = :entity_id

    belongs_to :order_item, class_name: :OrderItem
    belongs_to :parent, class_name: :InvoiceItem, foreign_key: :parent_item_id
    belongs_to :product

    # note: add an index on the column "parent_item_id" to
    # *dramatically* speed up loading of child order items from the parent order item
    has_many :children, class_name: :InvoiceItem, foreign_key: :parent_item_id

    # call associated product's method
    def method_missing(meth, *args, &block)
      if product && product.respond_to?(meth)
        product.send(meth)
      else
        # call superclass's method_missing method
        # or risk breaking Ruby's method lookup
        super
      end
    end

    def respond_to?(meth, include_private = false)
      super || (product && product.respond_to?(meth))
    end
  end
end


text:
package ariba.util.core;

import ariba.util.i18n.I18NUtil;
import ariba.util.io.DeserializationException;
import ariba.util.io.Deserializer;
import ariba.util.io.FormattingSerializer;
import ariba.util.log.Log;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.Map;

/**
    Table file Utilities. These are helper functions for dealing with
    table files.

    @aribaapi documented
*/
public final class TableUtil
{

    /**
        prevent people from creating this class
    */
    private TableUtil ()
    {
    }

    /**
        Load a serialized Map from the given file. The format of
        the file should be that of calling a Map's toString()
        method.

        @param file the File to load the serialized Map from

        @return the Map loaded from the file
        @aribaapi documented
    */
    public static Map loadMap (File file)
    {
        return loadMap(file, true);
    }

    /**
        Load a serialized Map from the given url. The format of
        the contents should be that of calling a Map's
        toString() method.

        @param file the File to load the serialized Map from
        @param displayError if true and there are errors
        deserializing the Map, an error will be printed.

        @return the Map loaded from the url, null if the map cannot be loaded.
        @aribaapi documented
    */
    public static Map loadMap (File file, boolean displayError)
    {
        if (!file.exists()) {
            if (displayError) {
                Log.util.error(6609, file.getPath());
            }
            return null;
        }
        return loadMap(URLUtil.url(file), displayError);
    }

    /**
        Load a serialized Map from the given url. The format of
        the contents should be that of calling a Map's
        toString() method.

        @param url the URL to load the serialized Map from

        @return the Map loaded from the url
        @aribaapi documented
    */
    public static Map loadMap (URL url)
    {
        return loadMap(url, true);
    }

    /**
        Load a serialized Map from the given url. The format of
        the contents should be that of calling a Map's
        toString() method.

        @param url the URL to load the serialized Map from
        @param displayError if true and there are errors
        deserializing the Map, an error will be printed.

        @return the Map loaded from the url
        @aribaapi documented
    */
    public static Map loadMap (URL url, boolean displayError)
    {
        Object object = loadObject(url);
        if (!(object instanceof Map)) {
            if (displayError) {
                Log.util.error(2920, url, object);
            }
            return null;
        }
        return (Map)object;
    }

    /**
        Load a serialized Map from the given String. The format
        of the contents should be that of calling a Map's
        toString() method.

        @param s the String to load the serialized Map from
        @param displayError if true and there are errors
        deserializing the Map, an error will be printed.

        @return the Map loaded from the url
        @aribaapi documented
    */
    public static Map loadMap (String s, boolean displayError)
    {
        Reader r = new StringReader(s);
        Object object = null;
        try {
            object = loadObject(r);
        }
        catch (IOException e) {
            return null;
        }

        if (!(object instanceof Map)) {
            if (displayError) {
                Log.util.error(2920, s, object);
            }
            return null;
        }
        return (Map)object;
    }

    /**
        Load an object from a URL using loadObject(Reader)

        @param url the URL to load the object from

        @return the deserialized object, or null if there was
        an IOException.

        @see #loadObject(Reader)
        @aribaapi documented
    */
    public static Object loadObject (URL url)
    {
        if (!URLUtil.maybeURLExists(url)) {
            return null;
        }
        try {
            return loadObject(IOUtil.bufferedReader(url.openStream(),
                                                  I18NUtil.EncodingISO8859_1));
        }
        catch (IOException e) {
            return null;
        }
    }

    /**
        Load an object from a file using loadObject(Reader)

        @param file the path for the file to load the object from

        @return the deserialized object, or null if there was
        an IOException.

        @see #loadObject(Reader)
        @aribaapi documented
    */
    public static Object loadObject (File file)
    {
        return loadObject(file, I18NUtil.EncodingISO8859_1);
    }

    /**
        Load an object from a file using loadObject(Reader)

        @param file the path for the file to load the object from
        @param encoding the encoding used for file reader

        @return the deserialized object, or null if there was
        an IOException.

        @see #loadObject(Reader)
        @aribaapi documented
    */
    public static Object loadObject (File file, String encoding)
    {
        if (!file.exists()) {
            return null;
        }
        try {
            return loadObject(IOUtil.bufferedReader(file, encoding));
        }
        catch (IOException e) {
            return null;
        }
    }

    /**
        Load an object from a stream.  Uses the Deserializer class
        from ariba.util.io to decode the data.

        @param reader the source for the Object's data

        @return the deserialized Object.

        @exception IOException if there was an error deserializing the
        object.
        @aribaapi documented
    */
    public static Object loadObject (Reader reader) throws IOException
    {
        try {
            return new Deserializer(reader).readObject();
        }
        catch (DeserializationException e) {
            Log.util.error(2769, e);
            return null;
        }
        finally {
            reader.close();
        }
    }

    /** Writes an object to a file in safe way.
        This method is similar to {@link #writeObject(java.io.File, java.lang.Object) writeObject}
        but it actually uses the {@link FileReplacer FileReplacer} to be more robust.

        @param file the path for a file to write the object to
        @param object the Object to serialize into the file

        @return true if the object was written successfully
        false otherwise
        @aribaapi ariba
    */
    public static boolean safeWriteObject (File file, Object object)
    {
        if (! file.exists()) {
                // if the destination file doesn't exist, why bother
                // with the safer way
        	Log.util.warning(10405, file);
            return writeObject(file, object);
        }
        if (! file.canWrite()) {
                // if the file is not writable, we won't be able to make the rename
                // so don't even start.
            Log.util.warning(8418, file);
            return false;
        }
        return safeWriteObject(new FileReplacer(file), object);
    }

    private static boolean safeWriteObject (FileReplacer fileReplacer, Object object)
    {
        try {
            boolean success = false;
            OutputStream out = fileReplacer.getOutputStream();
            if (writeObject(out, object)) {
                fileReplacer.applyChanges();
                success = true;
            }
            fileReplacer.commit();
            return success;
        }
        catch (IOException e) {
            Log.util.warning(8896,
                             fileReplacer.getBaseFile(),
                             SystemUtil.stackTrace(e));
            return false;
        }
    }

    /**
        Write an object to a file.

        @param file the path for a file to write the object to
        @param object the Object to serialize into the file

        @return true if the object was written successfully
        false otherwise
        @aribaapi documented
    */
    public static boolean writeObject (File file, Object object)
    {
        OutputStream output = null;
        try {
            output = IOUtil.bufferedOutputStream(file);
            return writeObject(output, object);
        }
        catch (IOException e) {
            return false;
        }
        finally {
            if (output != null) {
                try {
                    output.close();
                }
                catch (IOException e) {
                    return false;
                }
            }
        }
    }

    /**
        Write an object to an OutputStream.

        @param outputStream the OutputStream to write the object to
        @param object the Object to serialize into the file

        @return true if the object was written successfully
        false otherwise
        @aribaapi documented
    */
    public static boolean writeObject (OutputStream outputStream,
                                       Object       object)
    {
        try {
            PrintWriter printWriter = IOUtil.printWriter(outputStream,
                                                       I18NUtil.EncodingASCII);
            boolean result = writeObject(printWriter, object);
            printWriter.flush();
            return result;
        }
        catch (IOException e) {
            return false;
        }
    }

    /**
        Write an object to a printWriter.

        @param printWriter the PrintWriter to write the object to
        @param object the Object to serialize into the file

        @return true if the object was written successfully
        false otherwise
        @aribaapi documented
    */
    public static boolean writeObject (PrintWriter printWriter, Object object)
    {
        boolean result = FormattingSerializer.writeObject(printWriter,
                                                          object);
        printWriter.print("\n");
        return result;
    }

    /**
        @aribaapi private
    */
    public static void main (String args[])
    {
        String fileName = ArrayUtil.nullOrEmptyArray(args) ?
            "config/Parameters.table" : (String)args[0];
        Assert.that(loadMap(new File(fileName)) != null,
                    "loadMap failed for %s", fileName);
    }
}


text:
var moment = require('moment');

module.exports = Date.prototype.toMysqlFormat = function() {
  return moment(arguments[0] || this).format('YYYY-MM-DDTHH:MM:SS');
};


text:
title: "Dirtbag Day 001"
author: Austin
date: 2015-07-25
categories: [Climbing, Dirtbag]
tags: [dirtbag, clmibing, tips, dirtbag tips]
toc: false
---

Prior to beginning this adventure I tried to do my homework and dig through the interwebs in search of tips found in blogs and forum posts describing other dirtbag journies.  A couple stood out to me and I'll list them here as well as some quick lessons I learned on Day 1.

### From around the web:

* Be Ruthless

> If you can't fit it in your car, you don't need it.  Storage units may be tempting but they're just added overhead expense and something to tie you to a specific location.  For clothes, I read a recommendation that served me well.  Pick five outfits (tops and bottoms), one sport-specific specialty outfit (climbing, cycling, wet-suit, etc...), a "nice" outfit or two depending on your job or if you need to dress up  for something, and some weather specific stuff (shorts if you're in a hot region, insulating layers if you're in a cold region).  You may think you'll "need something later" when you go "back to normal life", you probably won't.  Even the most modest studio apartment will seem cush after surviving on a Jetboil, mess kit, and no refrigerator.

* Get a gym membership

> This is my favorite.  No, not a climbing gym membership, but a commercial health club membership, preferably one of those pop-up 24-7 places.  This isn't to get your swole on, but simply to have access to a shower 24-7.  Even better, if you wisely choose a chain gym you'll have many cities to choose from while you're migrating around.  For a relatively modest $30 or so per month (even if it were $60) you get far more showers for your dollar than paid camping at RV parks and such.  Besides, gym memberships are commercially cleaned on the regular and if you've ever pooped and / or showered at an RV  park, then you probably prefer the woods and a dip in the river anyway.

### What I learned the first day

* Don't be fooled, you're never at home

> My firt day seemed like any other day in a lot of ways as I was running errands most of the time, then  hanging out at Barnes & Noble (read mooching AC and wifi) and then at the public library (same here).  However, there were a few little things that reminded me that this day was different in every way. 1) I woke up in a Walmart parking lot where I cooked breakfast on a backpacking stove. 2)  You start to get strange looks around the three hour mark when you set up shop with a laptop and a McD's coffee cup at Barnes & Noble and never look at a book or order coffee.  you may elect to move to the public library, but alas both of those places will eventually close for the night and you must abandon your comfy post and keep moving.

* Spending money

> I learned pretty quick that boredom is your enemy.  As a dirtbag you'll have mucho free time and that can lead to a couple detrimental things.  Spending excess money is something you'll have to resist and keep an eye on.  It'd be very easy to drift from coffee shop to restaurant to burger joint just to "have something to do" or "pass the time."  But this will cost money, money you probably don't have if you're a dirtbag and money you could otherwise spend going awesome places.

* Wasting Gas

> Just like the above you have to watch out for making unneeded trips (to the grocery store for example) or putting around town for a Sunday (or everyday) drive.  Gas will probably be your number one expense (maybe even more than food) as a dirtbag and as such you'll want to save it for the crag rather than hanging out at Starbucks or B&N just because you're bored.

* Baby wipes

> Not much needs to be said here.  It speaks volumes for itself.  Baby wipes will quickly become a much beloved friend to the padawan dirtbag.


text:
<?xml version="1.0" encoding="UTF-8"?>		<grammar>
			<name>Extracted</name>
			<meta><src>Atlantic</src><tol0>wget</tol0><tol1>ecore2bgf</tol1></meta><source>
				<author>KM3 version auto-generated using ATL by the ATLAS Group (INRIA & LINA) from the Ecore version provided within the KDM Eclipse Plugin (KDM Analytics</author>
				<author>Inc).</author>
				<file>KDM.ecore</file>
				<date>2007/05/09</date>
				<readme/>
				<link>
					<uri>http://www.emn.fr/z-info/atlanmod/index.php/Ecore</uri>
					<name>Atlantic</name>
				</link>
				<link>
					<mu>topics/grammars/metamodels/KDM/KDM.ecore</mu>
					<name>GitHub</name>
				</link>
			</source>
<extraction><ecore/></extraction>		</grammar>


text:
package org.approvaltests.reporters;

import org.approvaltests.reporters.macosx.KaleidoscopeDiffReporter;
import org.approvaltests.reporters.windows.BeyondCompareReporter;
import org.approvaltests.reporters.windows.TortoiseGitImageDiffReporter;
import org.approvaltests.reporters.windows.TortoiseImageDiffReporter;

public class ImageReporter extends FirstWorkingReporter
{
  public ImageReporter()
  {
    super(TortoiseImageDiffReporter.INSTANCE, TortoiseGitImageDiffReporter.INSTANCE,
        BeyondCompareReporter.INSTANCE, KaleidoscopeDiffReporter.INSTANCE, ImageWebReporter.INSTANCE,
        QuietReporter.INSTANCE);
  }
}