<commit_before>
var git = require('git');
var fs = require('fs');
var path = require('path');
var winston = require('winston');
var spawn = require('child_process').spawn;

var TEAMS = 'teams';
var DOT_GIT = '.git';
var REFS = 'refs';
var TAGS = 'tags';
var HEADS = 'heads';
var REMOTES = 'remotes';
var MASTER = 'master';

function _findPlayer() {
    var teams = fs.readdirSync(TEAMS);
    var matches;
    var re = 'team[0-9][0-9][0-9]';
    for (var i = 0; i < teams.length; i++) {
        matches = teams[i].match(re);
        if (matches && matches.length == 1) {
            return matches[0];
        }
    }
    return null;
}

function _findPathToGitRepo() {
    var teamXXX = _findPlayer();
    if (fs.existsSync('.git')) {
        return '.';
    }
    if (fs.existsSync(path.join(TEAMS,'.git'))) {
        return 'teams';
    }
    if (fs.existsSync(path.join(TEAMS, teamXXX, '.git'))) {
        return path.join(TEAMS, teamXXX);
    }
    return null;
}

function getTagsSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, TAGS));
}

function getLocalBranchesSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, HEADS));
}

function getRemotesSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, REMOTES));
}

function getRemoteBranchesSync(remote) {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, REMOTES, remote));
}

function removeSedBackkupsFromTeam(team, callback) {
    // "find ./$folderName -name '*.bak'* -delete"
    var findRemove = spawn('find', [
        path.join(TEAMS, team),
        '-name',
        "'*.bak'*",
        '-delete'
    ]);

    findRemove.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    findRemove.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    findRemove.on('close', function (code) {
        winston.verbose('findRemove exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });
}

function sedRepalceTeam(oldTeam, newTeam, callback) {
    var sedRename = spawn('find', [
        path.join(TEAMS, newTeam),
        '-name',
        '*.java',
        '-type',
        'f',
        '-exec',
        'sed',
        '-i.bak',
        "s/" + oldTeam + "/" + newTeam + "/g",
        '{}',
        '+'
    ]);

    sedRename.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    sedRename.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    sedRename.on('close', function (code) {
        winston.verbose('sedRename exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });

}

function makeNewTeam(branchOrTag, remote, callback) {
    var gitPath = _findPathToGitRepo();
    var name = branchOrTag;
    while(name.indexOf('.') > -1 || name.indexOf('/') > -1) {
        name = name.replace('.','_').replace('/','_');
    }
    name = '_team' + name;
    var teamXXX = _findPlayer();
    checkout(branchOrTag, remote, gitPath, function(success) {
        if (!success) {
            winston.error('branch not checked out');
            callback(false);
            return;
        }
        copyTeam(teamXXX, name, function(success) {
            if (!success) {
                winston.error('files not copied');
                callback(false);
                return;
            }
            sedRepalceTeam(teamXXX, name, function(success) {
                if (!success) {
                    winston.error('sed failed');
                    callback(false);
                    return;
                }
                removeSedBackkupsFromTeam(name, function(success) {
                    callback(success)
                })
            })
        });
    });
}

function copyTeam(team, newTeam, callback) {
    if (fs.existsSync(path.join(TEAMS, newTeam))) {
        callback(false);
    } else {
        fs.mkdirSync(path.join(TEAMS, newTeam));
        _copyFiles(path.join(process.cwd(), TEAMS, team), path.join(process.cwd(), TEAMS, newTeam), callback);
    }

}

function _copyFiles(folder, newFolder, callback) {
    var files = fs.readdirSync(folder);

    function temp(status) {
        if (files.length > 0 && status) {
            _copyFile(path.join(folder, files.shift()), newFolder, temp);
        } else {
            callback(status);
        }
    }
    temp(true);
}

function _copyFile(file, newFolder, callback) {
    var cp = spawn('cp', ['-R', file, newFolder]);

    cp.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    cp.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
        console.log(data.toString());
    });

    cp.on('close', function (code) {
        winston.verbose('copyFiles exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });
}

function checkoutMaster(callback) {
    checkout('master', null, _findPathToGitRepo(), callback);
}

function clearChanges(callback) {
    checkout('.', null, _findPathToGitRepo(), callback);
}

function checkout(branch, remote, gitPath, callback) {
    isClean(gitPath, function(clean) {
        if(!clean) {
            winston.error("Current working branch not clean! Please stash or commit to continue");
            callback(false);
        } else {
            _checkout(branch, remote, gitPath, callback)
        }
    })
}

function _checkout(branch, remote, gitPath, callback) {
    if(remote && remote != HEADS) {
        branch = remote + '/' + branch
    }

    var gitCheckout = spawn('git', ['checkout', branch], {cwd: gitPath});

    gitCheckout.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    gitCheckout.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    gitCheckout.on('close', function (code) {
        winston.verbose('git checkout exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });

}

/**
 * Tells you if the given directory is clean
 */
function isClean(gitPath, callback) {
    gitStatus(gitPath, function(result) {
        if (result.indexOf('modified') === -1) {
            callback(true);
        } else {
            callback(false);
        }
    })
}

function gitStatus(gitPath, callback) {
    var gitStatus = spawn('git', ['status'], {cwd: gitPath});
    var result = '';

    gitStatus.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
        result += data.toString();
    });

    gitStatus.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    gitStatus.on('close', function (code) {
        winston.verbose('gitStatus exit code ' + code);
        if (callback) {
            callback(result);
        }
    });

}

function validate(callback) {
    // we need a valid player and valid repo
    var player = _findPlayer();
    var gitPath = _findPathToGitRepo();
    if (!player) {
        throw "Couldn't find a valid team of type teamXXX";
    }
    if (gitPath === null) {
        throw "Couldn't find a valid git repo in ., teams/ or teams/" + player;
    }
    isClean(gitPath, function(status) {
        if (!status) {
            throw "Looks like there are outstanding changes, stash or commit them"
        }
        callback(status);
    });
}

module.exports = {
    validate: validate,
    checkoutMaster: checkoutMaster,
    makeNewTeam: makeNewTeam,
    getTagsSync: getTagsSync,
    getLocalBranchesSync: getLocalBranchesSync,
    getRemotesSync: getRemotesSync,
    getRemoteBranchesSync: getRemoteBranchesSync
};<commit_msg>Fixed an issue with spawning<commit_after>
var git = require('git');
var fs = require('fs');
var path = require('path');
var winston = require('winston');
var spawn = require('child_process').spawn;

var TEAMS = 'src';
var DOT_GIT = '.git';
var REFS = 'refs';
var TAGS = 'tags';
var HEADS = 'heads';
var REMOTES = 'remotes';
var MASTER = 'master';

function _findPlayer() {
    var teams = fs.readdirSync(TEAMS);
    var matches;
    var re = 'team[0-9][0-9][0-9]';
    for (var i = 0; i < teams.length; i++) {
        matches = teams[i].match(re);
        if (matches && matches.length == 1) {
            return matches[0];
        }
    }
    return null;
}

function _findPathToGitRepo() {
    var teamXXX = _findPlayer();
    if (fs.existsSync(path.join(TEAMS,'.git'))) {
        return TEAMS;
    }
    if (fs.existsSync(path.join(TEAMS, teamXXX, '.git'))) {
        return path.join(TEAMS, teamXXX);
    }
    return null;
}

function getTagsSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, TAGS));
}

function getLocalBranchesSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, HEADS));
}

function getRemotesSync() {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, REMOTES));
}

function getRemoteBranchesSync(remote) {
    var pathGit = _findPathToGitRepo();
    return fs.readdirSync(path.join(pathGit, DOT_GIT, REFS, REMOTES, remote));
}

function removeSedBackkupsFromTeam(team, callback) {
    // "find ./$folderName -name '*.bak'* -delete"
    var findRemove = spawn('find', [
        path.join(TEAMS, team),
        '-name',
        "'*.bak'*",
        '-delete'
    ]);

    findRemove.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    findRemove.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    findRemove.on('close', function (code) {
        winston.verbose('findRemove exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });
}

function sedRepalceTeam(oldTeam, newTeam, callback) {
    var sedRename = spawn('find', [
        path.join(TEAMS, newTeam),
        '-name',
        '*.java',
        '-type',
        'f',
        '-exec',
        'sed',
        '-i.bak',
        "s/" + oldTeam + "/" + newTeam + "/g",
        '{}',
        '+'
    ]);

    sedRename.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    sedRename.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    sedRename.on('close', function (code) {
        winston.verbose('sedRename exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });

}

function makeNewTeam(branchOrTag, remote, callback) {
    var gitPath = _findPathToGitRepo();
    var name = branchOrTag;
    while(name.indexOf('.') > -1 || name.indexOf('/') > -1) {
        name = name.replace('.','_').replace('/','_');
    }
    name = '_team' + name;
    var teamXXX = _findPlayer();
    checkout(branchOrTag, remote, gitPath, function(success) {
        if (!success) {
            winston.error('branch not checked out');
            callback(false);
            return;
        }
        copyTeam(teamXXX, name, function(success) {
            if (!success) {
                winston.error('files not copied');
                callback(false);
                return;
            }
            sedRepalceTeam(teamXXX, name, function(success) {
                if (!success) {
                    winston.error('sed failed');
                    callback(false);
                    return;
                }
                removeSedBackkupsFromTeam(name, function(success) {
                    callback(success)
                })
            })
        });
    });
}

function copyTeam(team, newTeam, callback) {
    if (fs.existsSync(path.join(TEAMS, newTeam))) {
        callback(false);
    } else {
        fs.mkdirSync(path.join(TEAMS, newTeam));
        _copyFiles(path.join(process.cwd(), TEAMS, team), path.join(process.cwd(), TEAMS, newTeam), callback);
    }

}

function _copyFiles(folder, newFolder, callback) {
    var files = fs.readdirSync(folder);

    function temp(status) {
        if (files.length > 0 && status) {
            _copyFile(path.join(folder, files.shift()), newFolder, temp);
        } else {
            callback(status);
        }
    }
    temp(true);
}

function _copyFile(file, newFolder, callback) {
    var cp = spawn('cp', ['-R', file, newFolder]);

    cp.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    cp.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
        console.log(data.toString());
    });

    cp.on('close', function (code) {
        winston.verbose('copyFiles exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });
}

function checkoutMaster(callback) {
    checkout('master', null, _findPathToGitRepo(), callback);
}

function clearChanges(callback) {
    checkout('.', null, _findPathToGitRepo(), callback);
}

function checkout(branch, remote, gitPath, callback) {
    isClean(gitPath, function(clean) {
        if(!clean) {
            winston.error("Current working branch not clean! Please stash or commit to continue");
            callback(false);
        } else {
            _checkout(branch, remote, gitPath, callback)
        }
    })
}

function _checkout(branch, remote, gitPath, callback) {
    if(remote && remote != HEADS) {
        branch = remote + '/' + branch
    }

    var gitCheckout = spawn('git', ['checkout', branch], {cwd: gitPath});

    gitCheckout.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
    });

    gitCheckout.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    gitCheckout.on('close', function (code) {
        winston.verbose('git checkout exit code ' + code);
        if (callback) {
            if (code === 0) {
                callback(true);
            } else {
                callback(false);
            }
        }
    });

}

/**
 * Tells you if the given directory is clean
 */
function isClean(gitPath, callback) {
    gitStatus(gitPath, function(result) {
        if (result.indexOf('modified') === -1) {
            callback(true);
        } else {
            callback(false);
        }
    })
}

function gitStatus(gitPath, callback) {
    var gitStatus = spawn('git', ['status'], {cwd: gitPath});
    var result = '';

    gitStatus.stdout.on('data', function (data) {
        winston.verbose('stdout: ' + data.toString());
        result += data.toString();
    });

    gitStatus.stderr.on('data', function (data) {
        winston.error('stderr: ' + data.toString());
    });

    gitStatus.on('close', function (code) {
        winston.verbose('gitStatus exit code ' + code);
        if (callback) {
            callback(result);
        }
    });

}

function validate(callback) {
    // we need a valid player and valid repo
    var player = _findPlayer();
    var gitPath = _findPathToGitRepo();
    if (!player) {
        throw "Couldn't find a valid team of type teamXXX";
    }
    if (gitPath === null) {
        throw "Couldn't find a valid git repo in src/ or src/" + player;
    }
    isClean(gitPath, function(status) {
        if (!status) {
            throw "Looks like there are outstanding changes, stash or commit them"
        }
        callback(status);
    });
}

module.exports = {
    validate: validate,
    checkoutMaster: checkoutMaster,
    makeNewTeam: makeNewTeam,
    getTagsSync: getTagsSync,
    getLocalBranchesSync: getLocalBranchesSync,
    getRemotesSync: getRemotesSync,
    getRemoteBranchesSync: getRemoteBranchesSync
};<|endoftext|>


<commit_before>module( "EdgesGeometry" );

var DEBUG = false;

var vertList = [
	new THREE.Vector3(0, 0, 0),
	new THREE.Vector3(1, 0, 0),
	new THREE.Vector3(1, 1, 0),
	new THREE.Vector3(0, 1, 0),
	new THREE.Vector3(1, 1, 1),
];

test( "singularity", function() {

	testEdges( vertList, [1, 1, 1], 0 );

});

test( "needle", function() {

	testEdges( vertList, [0, 0, 1], 0 );

});

test( "single triangle", function() {

	testEdges( vertList, [0, 1, 2], 3 );

});

test( "two isolated triangles", function() {

	var vertList = [
		new THREE.Vector3(0, 0, 0),
		new THREE.Vector3(1, 0, 0),
		new THREE.Vector3(1, 1, 0),
		new THREE.Vector3(0, 0, 1),
		new THREE.Vector3(1, 0, 1),
		new THREE.Vector3(1, 1, 1),
	];

	testEdges( vertList, [0, 1, 2, 3, 4, 5], 6 );

});

test( "two flat triangles", function() {

	testEdges( vertList, [0, 1, 2, 0, 2, 3], 4 );

});

test( "two flat triangles, inverted", function() {

	testEdges( vertList, [0, 1, 2, 0, 3, 2], 5 );

});

test( "two non-coplanar triangles", function() {

	testEdges( vertList, [0, 1, 2, 0, 4, 2], 5 );

});

test( "three triangles, coplanar first", function() {

	testEdges( vertList, [0, 1, 2, 0, 2, 3, 0, 4, 2], 7 );

});

test( "three triangles, coplanar last", function() {

	testEdges( vertList, [0, 1, 2, 0, 4, 2, 0, 2, 3], 6 ); // Should be 7

});

test( "tetrahedron", function() {

	testEdges( vertList, [0, 1, 2, 0, 1, 4, 0, 4, 2, 1, 2, 4], 6 );

});

//
// HELPERS
//

function testEdges ( vertList, idxList, numAfter ) {

	var geoms = createGeometries ( vertList, idxList );

	for ( var i = 0 ; i < geoms.length ; i ++ ) {

		var geom = geoms[i];

		var numBefore = idxList.length;
		equal( countEdges (geom), numBefore, "Edges before!" );

		var egeom = new THREE.EdgesGeometry( geom );

		equal( countEdges (egeom), numAfter, "Edges after!" );
		output( geom, egeom );

	}

}

function createGeometries ( vertList, idxList ) {

	var geomIB = createIndexedBufferGeometry ( vertList, idxList );
	var geom = new THREE.Geometry().fromBufferGeometry( geomIB );
	var geomB = new THREE.BufferGeometry().fromGeometry( geom );
	var geomDC = addDrawCalls( geomIB.clone() );
	return [ geom, geomB, geomIB, geomDC ];

}

function createIndexedBufferGeometry ( vertList, idxList ) {

	var geom = new THREE.BufferGeometry();

	var indexTable = [];
	var numTris = idxList.length / 3;
	var numVerts = 0;

	var indices = new Uint32Array( numTris * 3 );
	var vertices = new Float32Array( vertList.length * 3 );

	for ( var i = 0; i < numTris; i ++ ) {

		for ( var j = 0; j < 3; j ++ ) {

			var idx = idxList[ 3 * i + j ];
			if ( indexTable[ idx ] === undefined ) {

				var v = vertList[ idx ];
				vertices[ 3 * numVerts ] = v.x;
				vertices[ 3 * numVerts + 1 ] = v.y;
				vertices[ 3 * numVerts + 2 ] = v.z;

				indexTable[ idx ] = numVerts;

				numVerts ++;

			}

			indices[ 3 * i + j ] = indexTable[ idx ] ;

		}

	}

	vertices = vertices.subarray( 0, 3 * numVerts );

	geom.setIndex( new THREE.BufferAttribute( indices, 1 ) );
	geom.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );

	geom.computeFaceNormals();

	return geom;

}

function addDrawCalls ( geometry ) {

	var numTris = geometry.index.count / 3;

	var offset = 0;
	for ( var i = 0 ; i < numTris; i ++ ) {

		var start = i * 3;
		var count = 3;

		geometry.addGroup( start, count );
	}

	return geometry;

}

function countEdges ( geom ) {

	if ( geom instanceof THREE.EdgesGeometry ) {

		return geom.getAttribute( 'position' ).count / 2;

	}

	if ( geom.faces !== undefined ) {

		return geom.faces.length * 3;

	}

	var indices = geom.getAttribute( 'index' );
	if ( indices !== undefined ) {

		return indices.count;

	}

	return geom.getAttribute( 'position' ).count;

}

//
// DEBUGGING
//

var renderer;
var camera;
var scene = new THREE.Scene();
var xoffset = 0;

function output ( geom, egeom ) {

	if ( DEBUG !== true ) return;

	if ( !renderer ) initDebug();

	var mesh = new THREE.Mesh( geom, undefined );
	var edges = new THREE.LineSegments( egeom, new THREE.LineBasicMaterial( { color: 'black' } ) );

	mesh.position.setX( xoffset );
	edges.position.setX( xoffset ++ );
	scene.add(mesh);
	scene.add(edges);

	if (scene.children.length % 8 === 0) {

		xoffset += 2;

	}

}

function initDebug () {

	renderer = new THREE.WebGLRenderer({

		antialias: true

	});

	var width = 600;
	var height = 480;

	renderer.setSize(width, height);
	renderer.setClearColor( 0xCCCCCC );

	camera = new THREE.PerspectiveCamera(45, width / height, 1, 100);
	camera.position.x = 30;
	camera.position.z = 40;
	camera.lookAt(new THREE.Vector3(30, 0, 0));

	document.body.appendChild(renderer.domElement);

	var controls = new THREE.OrbitControls( camera, renderer.domElement );
	controls.target = new THREE.Vector3(30, 0, 0);

	animate();

	function animate() {

		requestAnimationFrame( animate );

		controls.update();

		renderer.render( scene, camera );

	}

}
<commit_msg>fix unit test for edgesgeometry<commit_after>module( "EdgesGeometry" );

var DEBUG = false;

var vertList = [
	new THREE.Vector3(0, 0, 0),
	new THREE.Vector3(1, 0, 0),
	new THREE.Vector3(1, 1, 0),
	new THREE.Vector3(0, 1, 0),
	new THREE.Vector3(1, 1, 1),
];

test( "singularity", function() {

	testEdges( vertList, [1, 1, 1], 0 );

});

test( "needle", function() {

	testEdges( vertList, [0, 0, 1], 0 );

});

test( "single triangle", function() {

	testEdges( vertList, [0, 1, 2], 3 );

});

test( "two isolated triangles", function() {

	var vertList = [
		new THREE.Vector3(0, 0, 0),
		new THREE.Vector3(1, 0, 0),
		new THREE.Vector3(1, 1, 0),
		new THREE.Vector3(0, 0, 1),
		new THREE.Vector3(1, 0, 1),
		new THREE.Vector3(1, 1, 1),
	];

	testEdges( vertList, [0, 1, 2, 3, 4, 5], 6 );

});

test( "two flat triangles", function() {

	testEdges( vertList, [0, 1, 2, 0, 2, 3], 4 );

});

test( "two flat triangles, inverted", function() {

	testEdges( vertList, [0, 1, 2, 0, 3, 2], 5 );

});

test( "two non-coplanar triangles", function() {

	testEdges( vertList, [0, 1, 2, 0, 4, 2], 5 );

});

test( "three triangles, coplanar first", function() {

	testEdges( vertList, [0, 1, 2, 0, 2, 3, 0, 4, 2], 7 );

});

test( "three triangles, coplanar last", function() {

	testEdges( vertList, [0, 1, 2, 0, 4, 2, 0, 2, 3], 6 ); // Should be 7

});

test( "tetrahedron", function() {

	testEdges( vertList, [0, 1, 2, 0, 1, 4, 0, 4, 2, 1, 2, 4], 6 );

});

//
// HELPERS
//

function testEdges ( vertList, idxList, numAfter ) {

	var geoms = createGeometries ( vertList, idxList );

	for ( var i = 0 ; i < geoms.length ; i ++ ) {

		var geom = geoms[i];

		var numBefore = idxList.length;
		equal( countEdges (geom), numBefore, "Edges before!" );

		var egeom = new THREE.EdgesGeometry( geom );

		equal( countEdges (egeom), numAfter, "Edges after!" );
		output( geom, egeom );

	}

}

function createGeometries ( vertList, idxList ) {

	var geomIB = createIndexedBufferGeometry ( vertList, idxList );
	var geom = new THREE.Geometry().fromBufferGeometry( geomIB );
	var geomB = new THREE.BufferGeometry().fromGeometry( geom );
	var geomDC = addDrawCalls( geomIB.clone() );
	return [ geom, geomB, geomIB, geomDC ];

}

function createIndexedBufferGeometry ( vertList, idxList ) {

	var geom = new THREE.BufferGeometry();

	var indexTable = [];
	var numTris = idxList.length / 3;
	var numVerts = 0;

	var indices = new Uint32Array( numTris * 3 );
	var vertices = new Float32Array( vertList.length * 3 );

	for ( var i = 0; i < numTris; i ++ ) {

		for ( var j = 0; j < 3; j ++ ) {

			var idx = idxList[ 3 * i + j ];
			if ( indexTable[ idx ] === undefined ) {

				var v = vertList[ idx ];
				vertices[ 3 * numVerts ] = v.x;
				vertices[ 3 * numVerts + 1 ] = v.y;
				vertices[ 3 * numVerts + 2 ] = v.z;

				indexTable[ idx ] = numVerts;

				numVerts ++;

			}

			indices[ 3 * i + j ] = indexTable[ idx ] ;

		}

	}

	vertices = vertices.subarray( 0, 3 * numVerts );

	geom.setIndex( new THREE.BufferAttribute( indices, 1 ) );
	geom.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );

	geom.computeFaceNormals();

	return geom;

}

function addDrawCalls ( geometry ) {

	var numTris = geometry.index.count / 3;

	var offset = 0;
	for ( var i = 0 ; i < numTris; i ++ ) {

		var start = i * 3;
		var count = 3;

		geometry.addGroup( start, count );
	}

	return geometry;

}

function countEdges ( geom ) {

	if ( geom instanceof THREE.EdgesGeometry ) {

		return geom.getAttribute( 'position' ).count / 2;

	}

	if ( geom.faces !== undefined ) {

		return geom.faces.length * 3;

	}

	var indices = geom.index;
	if ( indices ) {

		return indices.count;

	}

	return geom.getAttribute( 'position' ).count;

}

//
// DEBUGGING
//

var renderer;
var camera;
var scene = new THREE.Scene();
var xoffset = 0;

function output ( geom, egeom ) {

	if ( DEBUG !== true ) return;

	if ( !renderer ) initDebug();

	var mesh = new THREE.Mesh( geom, undefined );
	var edges = new THREE.LineSegments( egeom, new THREE.LineBasicMaterial( { color: 'black' } ) );

	mesh.position.setX( xoffset );
	edges.position.setX( xoffset ++ );
	scene.add(mesh);
	scene.add(edges);

	if (scene.children.length % 8 === 0) {

		xoffset += 2;

	}

}

function initDebug () {

	renderer = new THREE.WebGLRenderer({

		antialias: true

	});

	var width = 600;
	var height = 480;

	renderer.setSize(width, height);
	renderer.setClearColor( 0xCCCCCC );

	camera = new THREE.PerspectiveCamera(45, width / height, 1, 100);
	camera.position.x = 30;
	camera.position.z = 40;
	camera.lookAt(new THREE.Vector3(30, 0, 0));

	document.body.appendChild(renderer.domElement);

	var controls = new THREE.OrbitControls( camera, renderer.domElement );
	controls.target = new THREE.Vector3(30, 0, 0);

	animate();

	function animate() {

		requestAnimationFrame( animate );

		controls.update();

		renderer.render( scene, camera );

	}

}
<|endoftext|>


<commit_before>/* eslint-disable global-require */

module.exports = Characteristic => {
  const DefaultCharacteristic = require('./default-characteristic')(
    Characteristic
  );
  return {
    Amperes: require('./amperes')(DefaultCharacteristic),
  };
};
<commit_msg>fix: add missing require()s for characteristics (#117)<commit_after>/* eslint-disable global-require */

module.exports = Characteristic => {
  const DefaultCharacteristic = require('./default-characteristic')(
    Characteristic
  );
  return {
    Amperes: require('./amperes')(DefaultCharacteristic),
    KilowattHours: require('./kilowatt-hours')(DefaultCharacteristic),
    KilowattVoltAmpereHour: require('./kilowatt-volt-ampere-hour')(DefaultCharacteristic),
    VoltAmperes: require('./volt-amperes')(DefaultCharacteristic),
    Volts: require('./volts')(DefaultCharacteristic),
    Watts: require('./watts')(DefaultCharacteristic),
  };
};
<|endoftext|>


<commit_before>module.exports = handler

const fs = require('fs')
const glob = require('glob')
const _path = require('path')
const $rdf = require('rdflib')
const Negotiator = require('negotiator')
const mime = require('mime-types')

const debug = require('debug')('solid:get')
const debugGlob = require('debug')('solid:glob')
const allow = require('./allow')

const translate = require('../utils.js').translate
const error = require('../http-error')

const RDFs = require('../ldp').mimeTypesAsArray()

async function handler (req, res, next) {
  const ldp = req.app.locals.ldp
  const includeBody = req.method === 'GET'
  const negotiator = new Negotiator(req)
  const baseUri = ldp.resourceMapper.resolveUrl(req.hostname, req.path)
  const path = res.locals.path || req.path
  const requestedType = negotiator.mediaType()
  let possibleRDFType = negotiator.mediaType(RDFs)

  res.header('MS-Author-Via', 'SPARQL')

  // Set live updates
  if (ldp.live) {
    res.header('Updates-Via', ldp.resourceMapper.resolveUrl(req.hostname).replace(/^http/, 'ws'))
  }

  debug(req.originalUrl + ' on ' + req.hostname)

  const options = {
    'hostname': req.hostname,
    'path': path,
    'includeBody': includeBody,
    'possibleRDFType': possibleRDFType,
    'range': req.headers.range
  }

  let ret
  try {
    ret = await ldp.get(options)
  } catch (err) {
    // use globHandler if magic is detected
    if (err.status === 404 && glob.hasMagic(path)) {
      debug('forwarding to glob request')
      return globHandler(req, res, next)
    } else {
      debug(req.method + ' -- Error: ' + err.status + ' ' + err.message)
      return next(err)
    }
  }

  let stream
  let contentType
  let container
  let contentRange
  let chunksize

  if (ret) {
    stream = ret.stream
    contentType = ret.contentType
    container = ret.container
    contentRange = ret.contentRange
    chunksize = ret.chunksize
  }

  // Till here it must exist
  if (!includeBody) {
    debug('HEAD only')
    res.setHeader('Content-Type', ret.contentType)
    return res.status(200).send('OK')
  }

  // Handle dataBrowser
  if (requestedType && requestedType.includes('text/html')) {
    const { path: filename } = await ldp.resourceMapper.mapUrlToFile({ url: options })
    let mimeTypeByExt = mime.lookup(_path.basename(filename))
    let isHtmlResource = mimeTypeByExt && mimeTypeByExt.includes('html')
    let useDataBrowser = ldp.dataBrowserPath && (
      container ||
      RDFs.includes(contentType) && !isHtmlResource && !ldp.suppressDataBrowser)

    if (useDataBrowser) {
      res.set('Content-Type', 'text/html')
      const defaultDataBrowser = _path.join(__dirname, '../../static/databrowser.html')
      const dataBrowserPath = ldp.dataBrowserPath === 'default' ? defaultDataBrowser : ldp.dataBrowserPath
      debug('   sending data browser file: ' + dataBrowserPath)
      res.sendFile(dataBrowserPath)
      return
    } else if (stream) {
      res.setHeader('Content-Type', contentType)
      return stream.pipe(res)
    }
  }

  // If request accepts the content-type we found
  if (stream && negotiator.mediaType([contentType])) {
    res.setHeader('Content-Type', contentType)
    if (contentRange) {
      const headers = { 'Content-Range': contentRange, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize }
      res.writeHead(206, headers)
      return stream.pipe(res)
    } else {
      return stream.pipe(res)
    }
  }

  // If it is not in our RDFs we can't even translate,
  // Sorry, we can't help
  if (!possibleRDFType) {
    return next(error(406, 'Cannot serve requested type: ' + contentType))
  }

  try {
    // Translate from the contentType found to the possibleRDFType desired
    const data = await translate(stream, baseUri, contentType, possibleRDFType)
    debug(req.originalUrl + ' translating ' + contentType + ' -> ' + possibleRDFType)
    res.setHeader('Content-Type', possibleRDFType)
    res.send(data)
    return next()
  } catch (err) {
    debug('error translating: ' + req.originalUrl + ' ' + contentType + ' -> ' + possibleRDFType + ' -- ' + 500 + ' ' + err.message)
    return next(error(500, 'Error translating between RDF formats'))
  }
}

async function globHandler (req, res, next) {
  const ldp = req.app.locals.ldp
  // TODO: This is a hack, that does not check if the target file exists, as this is quite complex with globbing.
  // TODO: Proper support for this is not implemented, as globbing support might be removed in the future.
  const requestUri = await ldp.resourceMapper.resolveUrl(req.hostname, req.path)

  const globOptions = {
    noext: true,
    nobrace: true,
    nodir: true
  }

  const filename = ldp.resourceMapper.getFullPath(req)
  glob(filename, globOptions, function (err, matches) {
    if (err || matches.length === 0) {
      debugGlob('No files matching the pattern')
      return next(error(404, 'No files matching glob pattern'))
    }

    // Matches found
    const globGraph = $rdf.graph()

    debugGlob('found matches ' + matches)
    Promise.all(matches.map(match => new Promise(async (resolve, reject) => {
      const urlData = await ldp.resourceMapper.mapFileToUrl({ path: match, hostname: req.hostname })
      fs.readFile(match, {encoding: 'utf8'}, function (err, fileData) {
        if (err) {
          debugGlob('error ' + err)
          return resolve()
        }
        // Files should be Turtle
        if (urlData.contentType !== 'text/turtle') {
          return resolve()
        }
        // The agent should have Read access to the file
        hasReadPermissions(match, req, res, function (allowed) {
          if (allowed) {
            try {
              $rdf.parse(fileData, globGraph, urlData.url, 'text/turtle')
            } catch (parseErr) {
              debugGlob(`error parsing ${match}: ${parseErr}`)
            }
          }
          return resolve()
        })
      })
    })))
    .then(() => {
      const data = $rdf.serialize(undefined, globGraph, requestUri, 'text/turtle')
      // TODO this should be added as a middleware in the routes
      res.setHeader('Content-Type', 'text/turtle')
      debugGlob('returning turtle')

      res.send(data)
      return next()
    })
  })
}

// TODO: get rid of this ugly hack that uses the Allow handler to check read permissions
function hasReadPermissions (file, req, res, callback) {
  const ldp = req.app.locals.ldp

  if (!ldp.webid) {
    return callback(true)
  }

  const root = ldp.resourceMapper.getBasePath(req.hostname)
  const relativePath = '/' + _path.relative(root, file)
  res.locals.path = relativePath
  allow('Read')(req, res, err => callback(!err))
}
<commit_msg>Reverting some previous changes<commit_after>module.exports = handler

const fs = require('fs')
const glob = require('glob')
const _path = require('path')
const $rdf = require('rdflib')
const Negotiator = require('negotiator')
const mime = require('mime-types')

const debug = require('debug')('solid:get')
const debugGlob = require('debug')('solid:glob')
const allow = require('./allow')

const translate = require('../utils.js').translate
const error = require('../http-error')

const RDFs = require('../ldp').mimeTypesAsArray()

async function handler (req, res, next) {
  const ldp = req.app.locals.ldp
  const includeBody = req.method === 'GET'
  const negotiator = new Negotiator(req)
  const baseUri = ldp.resourceMapper.resolveUrl(req.hostname, req.path)
  const path = res.locals.path || req.path
  const requestedType = negotiator.mediaType()
  let possibleRDFType = negotiator.mediaType(RDFs)

  res.header('MS-Author-Via', 'SPARQL')

  // Set live updates
  if (ldp.live) {
    res.header('Updates-Via', ldp.resourceMapper.resolveUrl(req.hostname).replace(/^http/, 'ws'))
  }

  debug(req.originalUrl + ' on ' + req.hostname)

  const options = {
    'hostname': req.hostname,
    'path': path,
    'includeBody': includeBody,
    'possibleRDFType': possibleRDFType,
    'range': req.headers.range
  }

  let ret
  try {
    ret = await ldp.get(options)
  } catch (err) {
    // use globHandler if magic is detected
    if (err.status === 404 && glob.hasMagic(path)) {
      debug('forwarding to glob request')
      return globHandler(req, res, next)
    } else {
      debug(req.method + ' -- Error: ' + err.status + ' ' + err.message)
      return next(err)
    }
  }

  let stream
  let contentType
  let container
  let contentRange
  let chunksize

  if (ret) {
    stream = ret.stream
    contentType = ret.contentType
    container = ret.container
    contentRange = ret.contentRange
    chunksize = ret.chunksize
  }

  // Till here it must exist
  if (!includeBody) {
    debug('HEAD only')
    res.setHeader('Content-Type', ret.contentType)
    return res.status(200).send('OK')
  }

  // Handle dataBrowser
  if (requestedType && requestedType.includes('text/html')) {
    const { path: filename } = await ldp.resourceMapper.mapUrlToFile({ url: options })
    let mimeTypeByExt = mime.lookup(_path.basename(filename))
    let isHtmlResource = mimeTypeByExt && mimeTypeByExt.includes('html')
    let useDataBrowser = ldp.dataBrowserPath && (
      container ||
      RDFs.includes(contentType) && !isHtmlResource && !ldp.suppressDataBrowser)

    if (useDataBrowser) {
      res.set('Content-Type', 'text/html')
      const defaultDataBrowser = _path.join(__dirname, '../../static/databrowser.html')
      const dataBrowserPath = ldp.dataBrowserPath === 'default' ? defaultDataBrowser : ldp.dataBrowserPath
      debug('   sending data browser file: ' + dataBrowserPath)
      res.sendFile(dataBrowserPath)
      return
    } else if (stream) {
      res.setHeader('Content-Type', contentType)
      return stream.pipe(res)
    }
  }

  // If request accepts the content-type we found
  if (stream && negotiator.mediaType([contentType])) {
    res.setHeader('Content-Type', contentType)
    if (contentRange) {
      const headers = { 'Content-Range': contentRange, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize }
      res.writeHead(206, headers)
      return stream.pipe(res)
    } else {
      return stream.pipe(res)
    }
  }

  // If it is not in our RDFs we can't even translate,
  // Sorry, we can't help
  if (!possibleRDFType) {
    return next(error(406, 'Cannot serve requested type: ' + contentType))
  }

  try {
    // Translate from the contentType found to the possibleRDFType desired
    const data = await translate(stream, baseUri, contentType, possibleRDFType)
    debug(req.originalUrl + ' translating ' + contentType + ' -> ' + possibleRDFType)
    res.setHeader('Content-Type', possibleRDFType)
    res.send(data)
    return next()
  } catch (err) {
    debug('error translating: ' + req.originalUrl + ' ' + contentType + ' -> ' + possibleRDFType + ' -- ' + 500 + ' ' + err.message)
    return next(error(500, 'Error translating between RDF formats'))
  }
}

async function globHandler (req, res, next) {
  const ldp = req.app.locals.ldp
  // TODO: This is a hack, that does not check if the target file exists, as this is quite complex with globbing.
  // TODO: Proper support for this is not implemented, as globbing support might be removed in the future.
  const filename = ldp.resourceMapper.getFullPath(req)
  const requestUri = (await ldp.resourceMapper.mapFileToUrl({ path: filename, hostname: req.hostname })).url

  const globOptions = {
    noext: true,
    nobrace: true,
    nodir: true
  }

  glob(filename, globOptions, function (err, matches) {
    if (err || matches.length === 0) {
      debugGlob('No files matching the pattern')
      return next(error(404, 'No files matching glob pattern'))
    }

    // Matches found
    const globGraph = $rdf.graph()

    debugGlob('found matches ' + matches)
    Promise.all(matches.map(match => new Promise(async (resolve, reject) => {
      const urlData = await ldp.resourceMapper.mapFileToUrl({ path: match, hostname: req.hostname })
      fs.readFile(match, {encoding: 'utf8'}, function (err, fileData) {
        if (err) {
          debugGlob('error ' + err)
          return resolve()
        }
        // Files should be Turtle
        if (urlData.contentType !== 'text/turtle') {
          return resolve()
        }
        // The agent should have Read access to the file
        hasReadPermissions(match, req, res, function (allowed) {
          if (allowed) {
            try {
              $rdf.parse(fileData, globGraph, urlData.url, 'text/turtle')
            } catch (parseErr) {
              debugGlob(`error parsing ${match}: ${parseErr}`)
            }
          }
          return resolve()
        })
      })
    })))
    .then(() => {
      const data = $rdf.serialize(undefined, globGraph, requestUri, 'text/turtle')
      // TODO this should be added as a middleware in the routes
      res.setHeader('Content-Type', 'text/turtle')
      debugGlob('returning turtle')

      res.send(data)
      return next()
    })
  })
}

// TODO: get rid of this ugly hack that uses the Allow handler to check read permissions
function hasReadPermissions (file, req, res, callback) {
  const ldp = req.app.locals.ldp

  if (!ldp.webid) {
    return callback(true)
  }

  const root = ldp.resourceMapper.getBasePath(req.hostname)
  const relativePath = '/' + _path.relative(root, file)
  res.locals.path = relativePath
  allow('Read')(req, res, err => callback(!err))
}
<|endoftext|>


<commit_before>// Exports an Express middleware factory.
//
// Example:
//
//   const healthchecks = require('healthchecks');
//   const CHECKS_FILE = './checks';
//
//   server.use('/_healthchecks', healthchecks(CHECKS_FILE));
//
// If you want to change the check timeout, use named argument:
//
//   const options = {
//     filename: CHECKS_FILE,
//     timeout:  '5s'     // 5 seconds, can also pass duration in milliseconds
//   };
//   server.use('/_healthchecks', healthchecks(options);

const _           = require('lodash');
const assert      = require('assert');
const Promise     = require('bluebird');
const debug       = require('debug')('healthchecks');
const File        = require('fs');
const Handlebars  = require('handlebars');
const ms          = require('ms');
const request     = require('request');
const URL         = require('url');

// Default timeout for checks; a slow server is a failed server.
const DEFAULT_TIMEOUT = '3s';

// Read the checks file and returns a check function (see checkFunction).
function readChecks(filename, timeout) {
  const checks = File.readFileSync(filename, 'utf-8')
    .split(/[\n\r]+/)                 // Split into lines
    .map(function(line) {             // Ignore leading/trailing spaces
      return line.trim();
    })
    .filter(function(line) {          // Ignore empty lines
      return line.length;
    })
    .filter(function(line) {          // Ignore comments
      return line[0] !== '#';
    })
    .filter(function(line) {          // Ignore name = value pairs
      return !/^\w+=/.test(line);
    })
    .map(function(line) {             // Split line to URL + expected value
      const match = line.match(/^(\S+)\s*(.*)/);
      debug('Added check', match[1], match[2]);
      return {
        url:      match[1],
        expected: match[2]
      };
    })
    .map(function(check) {            // Valid URLs only
      // URLs may be relative to the server, so contain an absolute path
      const url = URL.parse(check.url);
      assert(url.pathname && url.pathname[0] === '/', 'Check URL must have absolute pathname');
      assert(!url.protocol || /^https?:$/.test(url.protocol), 'Check URL may only use HTTP/S protocol');
      return check;
    })
    .reduce(function(checks, check) {
      const url = check.url;
      checks[url] = checks[url] || [];
      if (check.expected)
        checks[url].push(check.expected);
      return checks;
    }, {});

  // Returns a check function that will use these checks / settings
  const context = {
    checks:   checks,
    timeout:  timeout
  };
  return checkFunction.bind(context);
}

// Represents a check outcome with the properties url, reason, etc.
function Outcome(url, expected, error, response, body, elapsed) {
  this.url      = url;
  this.elapsed  = elapsed;
  if (error) {

    if (error.code === 'ETIMEDOUT') {
      this.reason   = 'timeout';
      this.timeout  = true;
    } else {
      this.reason   = 'error';
      this.error    = error;
    }

  } else {

    this.statusCode = response.statusCode;
    this.body       = body;
    if (response.statusCode < 200 || response.statusCode >= 400) {
      this.reason   = 'statusCode';
    } else {

      const allMatching = _.all(expected, function(text) {
        return body.indexOf(text) >= 0;
      });
      if (!allMatching)
        this.reason = 'body';

    }
  }
}

// Easy way to log check outcome, shows the URL and the reason check failed
Outcome.prototype.toString = function() {
  switch (this.reason) {
    case 'error': {
      return this.url + ' => ' + this.error.message;
    }
    case 'statusCode': {
      return this.url + ' => ' + this.statusCode;
    }
    case undefined: {
      return this.url;
    }
    default: {
      return this.url + ' => ' + this.reason;
    }
  }
};

// The check function will run all checks in parallel, and resolve to an object
// with the properties:
// passed  - A list of all check URLs that passed
// failed  - A list of all check URLs that failed
function checkFunction(baseURL, requestID) {
  const checks  = this.checks;
  const timeout = this.timeout;

  // Each check resolves into an outcome object
  const allChecks = _.map(checks, function(expected, checkURL) {
    return new Promise(function(resolve) {
      // Checks have relative URLs, resolve them to absolute URLs
      const absoluteURL = URL.resolve(baseURL, checkURL);
      const headers     = {};
      if (requestID)
        headers['X-Request-Id'] = requestID;
      const params  = {
        uri:      absoluteURL,
        headers:  headers,
        timeout:  timeout
      };
      const start = Date.now();
      request(params, function(error, response, body) {

        const elapsed  = Date.now() - start;
        const outcome  = new Outcome(absoluteURL, expected, error, response, body, elapsed);
        resolve(outcome);

        switch (outcome.reason) {
          case 'error': {
            debug('Server responded with error ' + error.message, absoluteURL);
            break;
          }
          case 'timeout': {
            debug('Server response timeout', absoluteURL);
            break;
          }
          case 'statusCode': {
            debug('Server responded with status code ' + response.statusCode, absoluteURL);
            break;
          }
          case 'body': {
            debug('Server response did not contain expected text', absoluteURL);
            break;
          }
        }
      });
    });
  });

  // Run all checks in parallel
  const allOutcomes = Promise.all(allChecks);

  // Reduce into an object with the passed and failed lists of URLs
  const passedAndFailed = allOutcomes
    .then(function(outcomes) {
      return {
        passed: _.reject(outcomes, 'reason'),
        failed: _.filter(outcomes, 'reason')
      };
    });

  // Returns the promise
  return passedAndFailed;
}

// Call this function to configure and return the middleware.
module.exports = function healthchecks(options) {
  assert(options, 'Missing options');

  // Pass filename as first argument or named option
  const filename    = (typeof(options) === 'string') ? options : options.filename;
  assert(filename, 'Missing checks filename');

  // Pass timeout as named option, or use default
  const timeoutArg  = (typeof(options) !== 'string' && options.timeout) || DEFAULT_TIMEOUT;
  // If timeout argument is a string (e.g. "3d"), convert to milliseconds
  const timeout     = (typeof(timeoutArg) === 'string') ? ms(timeoutArg) : +timeoutArg;

  const onFailed    = options.onFailed || function() {};

  // Read all checks form the file and returns a checking function
  const runChecks = readChecks(filename, timeout);

  // Load Handlebars template for rendering results
  const template  = File.readFileSync(__dirname + '/index.hbs', 'utf-8');
  Handlebars.registerHelper('ms', ms);
  const render    = Handlebars.compile(template);

  // Return the Express middleware
  return function(request, response) {
    debug('Health checks: running');

    // The base URL where this middleware is mounted on.  We do this
    // dynamically, so sending healthchecks request to HTTP vs HTTPS, or
    // different domain, may result in running different checks.
    const mounted = URL.format({
      protocol: request.protocol,
      host:     request.headers.host,
      port:     request.port
    });

    const requestID = request.headers['x-request-id'];

    // Run all checks
    runChecks(mounted, requestID)
      .then(function(outcomes) {
        debug('Health checks: ' + outcomes.passed.length + ' passed and ' + outcomes.failed.length + ' failed');

        // Respond with 200 only if all checks passed
        // Respond with 500 if any check fail
        // Respond with 404 if there are no checks to run
        const statusCode  =
          outcomes.failed.length ? 500 :
          outcomes.passed.length ? 200 : 404;
        // Render template
        const html        = render({
          passed: _.sortBy(outcomes.passed, 'url'),
          failed: _.sortBy(outcomes.failed, 'url')
        });
        response.status(statusCode).send(html).end();

        if (outcomes.failed.length)
          onFailed(outcomes.failed);
      });
  };

};
<commit_msg>CHANGED support Node response, no need to use Express<commit_after>// Exports an Express middleware factory.
//
// Example:
//
//   const healthchecks = require('healthchecks');
//   const CHECKS_FILE = './checks';
//
//   server.use('/_healthchecks', healthchecks(CHECKS_FILE));
//
// If you want to change the check timeout, use named argument:
//
//   const options = {
//     filename: CHECKS_FILE,
//     timeout:  '5s'     // 5 seconds, can also pass duration in milliseconds
//   };
//   server.use('/_healthchecks', healthchecks(options);

const _           = require('lodash');
const assert      = require('assert');
const Promise     = require('bluebird');
const debug       = require('debug')('healthchecks');
const File        = require('fs');
const Handlebars  = require('handlebars');
const ms          = require('ms');
const request     = require('request');
const URL         = require('url');

// Default timeout for checks; a slow server is a failed server.
const DEFAULT_TIMEOUT = '3s';

// Read the checks file and returns a check function (see checkFunction).
function readChecks(filename, timeout) {
  const checks = File.readFileSync(filename, 'utf-8')
    .split(/[\n\r]+/)                 // Split into lines
    .map(function(line) {             // Ignore leading/trailing spaces
      return line.trim();
    })
    .filter(function(line) {          // Ignore empty lines
      return line.length;
    })
    .filter(function(line) {          // Ignore comments
      return line[0] !== '#';
    })
    .filter(function(line) {          // Ignore name = value pairs
      return !/^\w+=/.test(line);
    })
    .map(function(line) {             // Split line to URL + expected value
      const match = line.match(/^(\S+)\s*(.*)/);
      debug('Added check', match[1], match[2]);
      return {
        url:      match[1],
        expected: match[2]
      };
    })
    .map(function(check) {            // Valid URLs only
      // URLs may be relative to the server, so contain an absolute path
      const url = URL.parse(check.url);
      assert(url.pathname && url.pathname[0] === '/', 'Check URL must have absolute pathname');
      assert(!url.protocol || /^https?:$/.test(url.protocol), 'Check URL may only use HTTP/S protocol');
      return check;
    })
    .reduce(function(checks, check) {
      const url = check.url;
      checks[url] = checks[url] || [];
      if (check.expected)
        checks[url].push(check.expected);
      return checks;
    }, {});

  // Returns a check function that will use these checks / settings
  const context = {
    checks:   checks,
    timeout:  timeout
  };
  return checkFunction.bind(context);
}

// Represents a check outcome with the properties url, reason, etc.
function Outcome(url, expected, error, response, body, elapsed) {
  this.url      = url;
  this.elapsed  = elapsed;
  if (error) {

    if (error.code === 'ETIMEDOUT') {
      this.reason   = 'timeout';
      this.timeout  = true;
    } else {
      this.reason   = 'error';
      this.error    = error;
    }

  } else {

    this.statusCode = response.statusCode;
    this.body       = body;
    if (response.statusCode < 200 || response.statusCode >= 400) {
      this.reason   = 'statusCode';
    } else {

      const allMatching = _.all(expected, function(text) {
        return body.indexOf(text) >= 0;
      });
      if (!allMatching)
        this.reason = 'body';

    }
  }
}

// Easy way to log check outcome, shows the URL and the reason check failed
Outcome.prototype.toString = function() {
  switch (this.reason) {
    case 'error': {
      return this.url + ' => ' + this.error.message;
    }
    case 'statusCode': {
      return this.url + ' => ' + this.statusCode;
    }
    case undefined: {
      return this.url;
    }
    default: {
      return this.url + ' => ' + this.reason;
    }
  }
};

// The check function will run all checks in parallel, and resolve to an object
// with the properties:
// passed  - A list of all check URLs that passed
// failed  - A list of all check URLs that failed
function checkFunction(baseURL, requestID) {
  const checks  = this.checks;
  const timeout = this.timeout;

  // Each check resolves into an outcome object
  const allChecks = _.map(checks, function(expected, checkURL) {
    return new Promise(function(resolve) {
      // Checks have relative URLs, resolve them to absolute URLs
      const absoluteURL = URL.resolve(baseURL, checkURL);
      const headers     = {};
      if (requestID)
        headers['X-Request-Id'] = requestID;
      const params  = {
        uri:      absoluteURL,
        headers:  headers,
        timeout:  timeout
      };
      const start = Date.now();
      request(params, function(error, response, body) {

        const elapsed  = Date.now() - start;
        const outcome  = new Outcome(absoluteURL, expected, error, response, body, elapsed);
        resolve(outcome);

        switch (outcome.reason) {
          case 'error': {
            debug('Server responded with error ' + error.message, absoluteURL);
            break;
          }
          case 'timeout': {
            debug('Server response timeout', absoluteURL);
            break;
          }
          case 'statusCode': {
            debug('Server responded with status code ' + response.statusCode, absoluteURL);
            break;
          }
          case 'body': {
            debug('Server response did not contain expected text', absoluteURL);
            break;
          }
        }
      });
    });
  });

  // Run all checks in parallel
  const allOutcomes = Promise.all(allChecks);

  // Reduce into an object with the passed and failed lists of URLs
  const passedAndFailed = allOutcomes
    .then(function(outcomes) {
      return {
        passed: _.reject(outcomes, 'reason'),
        failed: _.filter(outcomes, 'reason')
      };
    });

  // Returns the promise
  return passedAndFailed;
}

// Call this function to configure and return the middleware.
module.exports = function healthchecks(options) {
  assert(options, 'Missing options');

  // Pass filename as first argument or named option
  const filename    = (typeof(options) === 'string') ? options : options.filename;
  assert(filename, 'Missing checks filename');

  // Pass timeout as named option, or use default
  const timeoutArg  = (typeof(options) !== 'string' && options.timeout) || DEFAULT_TIMEOUT;
  // If timeout argument is a string (e.g. "3d"), convert to milliseconds
  const timeout     = (typeof(timeoutArg) === 'string') ? ms(timeoutArg) : +timeoutArg;

  const onFailed    = options.onFailed || function() {};

  // Read all checks form the file and returns a checking function
  const runChecks = readChecks(filename, timeout);

  // Load Handlebars template for rendering results
  const template  = File.readFileSync(__dirname + '/index.hbs', 'utf-8');
  Handlebars.registerHelper('ms', ms);
  const render    = Handlebars.compile(template);

  // Return the Express middleware
  return function(request, response) {
    debug('Health checks: running');

    // The base URL where this middleware is mounted on.  We do this
    // dynamically, so sending healthchecks request to HTTP vs HTTPS, or
    // different domain, may result in running different checks.
    const mounted = URL.format({
      protocol: request.protocol,
      host:     request.headers.host,
      port:     request.port
    });

    const requestID = request.headers['x-request-id'];

    // Run all checks
    runChecks(mounted, requestID)
      .then(function(outcomes) {
        debug('Health checks: ' + outcomes.passed.length + ' passed and ' + outcomes.failed.length + ' failed');

        // Respond with 200 only if all checks passed
        // Respond with 500 if any check fail
        // Respond with 404 if there are no checks to run
        const statusCode  =
          outcomes.failed.length ? 500 :
          outcomes.passed.length ? 200 : 404;
        // Render template
        const html        = render({
          passed: _.sortBy(outcomes.passed, 'url'),
          failed: _.sortBy(outcomes.failed, 'url')
        });
        response.writeHeader(statusCode);
        response.write(html);
        response.end();

        if (outcomes.failed.length)
          onFailed(outcomes.failed);
      });
  };

};
<|endoftext|>


<commit_before>(function() {
  "use strict";

  var fs = require("fs");

  function getBufferFromFile(fileName, done) {
    console.log("Reading :" + fileName);

    fs.exists(fileName, function(exists) {
      if (exists) {
        fs.stat(fileName, function(error, stats) {
          if (error) {
            return done(error);
          }

          fs.open(fileName, "r", function(error, fd) {
            if (error) {
              return done(error);
            }
            var buffer = new Buffer(stats.size);

            fs.read(fd, buffer, 0, buffer.length, null, function(error, bytesRead, buffer) {
              fs.close(fd);
              return done(null, buffer, bytesRead);
            });
          });
        });
      } else {
        return done(new Error("File does not exist", indexFile));
      }
    });
  }

  // http://bocoup.com/weblog/getting-bitwise-with-javascript/
  function numToBinaryArray(num) {
    var res = [];
    var index, bitMask;

    for (bitMask = 0x80000000, index = 0; index < 32; bitMask >>>= 1, index++) {
      res[31 - index] = ((bitMask & num) ? 1 : 0);
    }

    // console.log("" + num + " -> binary:"+res);
    return res;
  }

  function bufferReader(buffer, bytesRead) {
    var _buffer = buffer;
    var _delta = 0;
    var _mark = 0;
    var _bytesRead = bytesRead;

    return {
      readUInt32BE: function() {
        var result = _buffer.readUInt32BE(_delta);
        _delta += 4;
        return result;
      },

      readUInt16BE: function() {
        var result = _buffer.readUInt16BE(_delta);
        _delta += 2;
        return result;
      },

      readString: function() {
        var result = "";
        var state = 0;
        var len = 0;

        while (state !== 99) {
          var b = _buffer.readInt8(_delta);
          _delta++;
          len++;
          console.log("@@ (" + String.fromCharCode(b) + "),(" + b + "), at len=" + len + ",_delta:" + _delta);
          if (state === 0) {
            if (b === 0x00) {
              state = 1;
            } else {
              result = result + String.fromCharCode(b);
            }
          } else if (state === 1) {
            if (_delta % 8 === 0) {
              console.log("@@ delta:" + _delta);
              // var b = _buffer.readInt8(_delta + 1);
              // console.log("@@ next was:("+String.fromCharCode(b)+"),("+b+")");
              // var b = _buffer.readInt8(_delta + 2);
              // console.log("@@ next2 was:("+String.fromCharCode(b)+"),("+b+")");

              state = 99;
            } else {
              if (b !== 0x00) {
                throw new Error("bad string padding:" + b + ", with len:" + len);
              }
            }
          }
        }
        return result;
      },

      slice: function(length) {
        var result = _buffer.slice(_delta, _delta + length);
        _delta += length;
        return result;
      },

      setMark: function() {
        _mark = _delta;
      },

      getMark: function() {
        return _delta - _mark;
      },

      offset: function() {
        return _delta;
      }
    }
  }

  //
  // http://schacon.github.io/gitbook/7_the_git_index.html
  //
  // https://github.com/git/git/blob/master/Documentation/technical/index-format.txt
  // https://code.google.com/p/git-core/source/browse/Documentation/technical/index-format.txt?spec=svne44b6df90cfd6ccbf35c3d147ff5a0e4e22fb17a&r=e44b6df90cfd6ccbf35c3d147ff5a0e4e22fb17a
  //
  // https://github.com/chrisdickinson/git-packidx-parser/blob/master/index.js
  // https://github.com/sbp/gin/blob/master/gin
  //
  // http://stackoverflow.com/questions/4084921/what-does-the-git-index-contain-exactly
  //
  function parseIndex(fileName, done) {
    getBufferFromFile(fileName, function(error, buffer, bytesRead) {
      if (error) {
        return done(error);
      }

      var info = {};

      // prepare Buffer reader
      var br = bufferReader(buffer, bytesRead);

      // check for the 'DIRC' signature
      if (br.readUInt32BE() !== 0x44495243) {
        return done(new Error("Invalid signature:" + Number(buffer.readUInt32BE(0)).toString(16)));
      }

      info.version = br.readUInt32BE();

      info.numberOfIndexEntries = br.readUInt32BE();

      info.entries = [];

      for (var i = 0; i < info.numberOfIndexEntries; i++) {
        var entry = {};
        info.entries.push(entry);

        // we mark the beginning of the record
        // in order to allow padding computation
        br.setMark();
        entry.index = i;
        var ctimeSeconds = br.readUInt32BE();
        var ctimeNanoSeconds = br.readUInt32BE();
        var mtimeSeconds = br.readUInt32BE();
        var mtimeNanoSeconds = br.readUInt32BE();
        var dev = br.readUInt32BE();
        var ino = br.readUInt32BE();
        entry.mode = Number(br.readUInt32BE()).toString(8);
        entry.uid = br.readUInt32BE();
        var gid = br.readUInt32BE();
        entry.size = br.readUInt32BE();
        entry.sha1 = br.slice(20).toString('hex');

        entry.flags = br.readUInt16BE();
        var bits = numToBinaryArray(entry.flags);

        entry.assume_valid = (bits[15] == 1);
        entry.extended_flag = (bits[14] == 1);
        entry.stage = ((bits[13] * 8) + bits[12]);
        entry.nameLen = entry.flags & 0x00000FFF

        // TODO:
        // test if extended and version 3

        if (entry.nameLen < 0xFFF) {
          entry.pathName = br.slice(entry.nameLen).toString();
        } else {
          // TODO
        }

        var entryLen = br.getMark();
        var padlen = (8 - (entryLen % 8)) || 8;
        br.slice(padlen);
      }

      console.log("--");

      return done(null, info);
    });
  }

  parseIndex(".git/index", function(err, info) {
    if (err) {
      console.log("ERR:", err);
    } else {
      console.log(info);
    }
  });
}());
<commit_msg>add buffer check (nul)<commit_after>(function() {
  "use strict";

  var fs = require("fs");

  function getBufferFromFile(fileName, done) {
    console.log("Reading :" + fileName);

    fs.exists(fileName, function(exists) {
      if (exists) {
        fs.stat(fileName, function(error, stats) {
          if (error) {
            return done(error);
          }

          fs.open(fileName, "r", function(error, fd) {
            if (error) {
              return done(error);
            }
            var buffer = new Buffer(stats.size);

            fs.read(fd, buffer, 0, buffer.length, null, function(error, bytesRead, buffer) {
              fs.close(fd);
              return done(null, buffer, bytesRead);
            });
          });
        });
      } else {
        return done(new Error("File does not exist", indexFile));
      }
    });
  }

  function checkNul(buffer) {
    for(var i = 0; i < buffer.length; i++) {
      if (buffer[i] !== 0) {
        throw new Error("buffer nul check failed!");
      }
    }
  }

  // http://bocoup.com/weblog/getting-bitwise-with-javascript/
  function numToBinaryArray(num) {
    var res = [];
    var index, bitMask;

    for (bitMask = 0x80000000, index = 0; index < 32; bitMask >>>= 1, index++) {
      res[31 - index] = ((bitMask & num) ? 1 : 0);
    }

    // console.log("" + num + " -> binary:"+res);
    return res;
  }

  function bufferReader(buffer, bytesRead) {
    var _buffer = buffer;
    var _delta = 0;
    var _mark = 0;
    var _bytesRead = bytesRead;

    return {
      readUInt32BE: function() {
        var result = _buffer.readUInt32BE(_delta);
        _delta += 4;
        return result;
      },

      readUInt16BE: function() {
        var result = _buffer.readUInt16BE(_delta);
        _delta += 2;
        return result;
      },

      readString: function() {
        var result = "";
        var state = 0;
        var len = 0;

        while (state !== 99) {
          var b = _buffer.readInt8(_delta);
          _delta++;
          len++;
          console.log("@@ (" + String.fromCharCode(b) + "),(" + b + "), at len=" + len + ",_delta:" + _delta);
          if (state === 0) {
            if (b === 0x00) {
              state = 1;
            } else {
              result = result + String.fromCharCode(b);
            }
          } else if (state === 1) {
            if (_delta % 8 === 0) {
              console.log("@@ delta:" + _delta);
              // var b = _buffer.readInt8(_delta + 1);
              // console.log("@@ next was:("+String.fromCharCode(b)+"),("+b+")");
              // var b = _buffer.readInt8(_delta + 2);
              // console.log("@@ next2 was:("+String.fromCharCode(b)+"),("+b+")");

              state = 99;
            } else {
              if (b !== 0x00) {
                throw new Error("bad string padding:" + b + ", with len:" + len);
              }
            }
          }
        }
        return result;
      },

      slice: function(length) {
        var result = _buffer.slice(_delta, _delta + length);
        _delta += length;
        return result;
      },

      setMark: function() {
        _mark = _delta;
      },

      getMark: function() {
        return _delta - _mark;
      },

      offset: function() {
        return _delta;
      }
    }
  }

  //
  // http://schacon.github.io/gitbook/7_the_git_index.html
  //
  // https://github.com/git/git/blob/master/Documentation/technical/index-format.txt
  // https://code.google.com/p/git-core/source/browse/Documentation/technical/index-format.txt?spec=svne44b6df90cfd6ccbf35c3d147ff5a0e4e22fb17a&r=e44b6df90cfd6ccbf35c3d147ff5a0e4e22fb17a
  //
  // https://github.com/chrisdickinson/git-packidx-parser/blob/master/index.js
  // https://github.com/sbp/gin/blob/master/gin
  //
  // http://stackoverflow.com/questions/4084921/what-does-the-git-index-contain-exactly
  //
  function parseIndex(fileName, done) {
    getBufferFromFile(fileName, function(error, buffer, bytesRead) {
      if (error) {
        return done(error);
      }

      var info = {};

      // prepare Buffer reader
      var br = bufferReader(buffer, bytesRead);

      // check for the 'DIRC' signature
      if (br.readUInt32BE() !== 0x44495243) {
        return done(new Error("Invalid signature:" + Number(buffer.readUInt32BE(0)).toString(16)));
      }

      info.version = br.readUInt32BE();

      info.numberOfIndexEntries = br.readUInt32BE();

      info.entries = [];

      for (var i = 0; i < info.numberOfIndexEntries; i++) {
        var entry = {};
        info.entries.push(entry);

        // we mark the beginning of the record
        // in order to allow padding computation
        br.setMark();
        entry.index = i;
        var ctimeSeconds = br.readUInt32BE();
        var ctimeNanoSeconds = br.readUInt32BE();
        var mtimeSeconds = br.readUInt32BE();
        var mtimeNanoSeconds = br.readUInt32BE();
        var dev = br.readUInt32BE();
        var ino = br.readUInt32BE();
        entry.mode = Number(br.readUInt32BE()).toString(8);
        entry.uid = br.readUInt32BE();
        var gid = br.readUInt32BE();
        entry.size = br.readUInt32BE();
        entry.sha1 = br.slice(20).toString('hex');

        entry.flags = br.readUInt16BE();
        var bits = numToBinaryArray(entry.flags);

        entry.assume_valid = (bits[15] == 1);
        entry.extended_flag = (bits[14] == 1);
        entry.stage = ((bits[13] * 8) + bits[12]);
        entry.nameLen = entry.flags & 0x00000FFF

        // TODO:
        // test if extended and version 3

        if (entry.nameLen < 0xFFF) {
          entry.pathName = br.slice(entry.nameLen).toString();
        } else {
          // TODO
        }

        var entryLen = br.getMark();
        var padlen = (8 - (entryLen % 8)) || 8;
        var nul = br.slice(padlen);
        checkNul(nul);
      }

      console.log("--");

      return done(null, info);
    });
  }

  parseIndex(".git/index", function(err, info) {
    if (err) {
      console.log("ERR:", err);
    } else {
      console.log(info);
    }
  });
}());
<|endoftext|>


<commit_before>export default function() {
  this.namespace = 'https://staging-api.osf.io/v2';
  // if using localhost rather than staging, uncomment the following line
  //this.namespace = 'https://localhost:8000/v2';

  this.get('/submission-evals');
  this.get('/submission-evals/:id');
  this.post('/submission-evals', (db, request) => {
    return db.db.submissionEvals.insert(JSON.parse(request.requestBody));
  });

  this.post('/conferences');
  this.get('/conferences');
  this.get('/conferences/:id');
  this.patch('/conferences/:id');

  this.get('/nodes/:id/files/:id');
  this.post('/nodes/:id/files', (db, request) => {
    let attrs = request.requestBody;
    return db.db.files.insert(attrs);
  });

  this.get('/reviewers');
  this.get('/reviewers/:id');

  this.get('/reviewslists');
  this.get('/reviewslists/:id');

  this.passthrough('https://staging-api.osf.io/v2/users/me/');
  this.passthrough('http://localhost:8000/v2/users/me/');

  this.passthrough('https://staging-api.osf.io/v2/nodes');
  this.passthrough('http://localhost:8000/v2/nodes');

  this.passthrough('https://staging-api.osf.io/v2/nodes/**');
  this.passthrough('https://localhost:8000/v2/nodes/**');

  // These comments are here to help you get started. Feel free to delete them.

  /*
    Config (with defaults).

    Note: these only affect routes defined *after* them!
  */
  // this.urlPrefix = '';    // make this `http://localhost:8080`, for example, if your API is on a different server
  // this.namespace = '';    // make this `api`, for example, if your API is namespaced
  // this.timing = 400;      // delay for each request, automatically set to 0 during testing

  /*
    Route shorthand cheatsheet
  */
  /*
    GET shorthands

    // Collections
    this.get('/contacts');
    this.get('/contacts', 'users');
    this.get('/contacts', ['contacts', 'addresses']);

    // Single objects
    this.get('/contacts/:id');
    this.get('/contacts/:id', 'user');
    this.get('/contacts/:id', ['contact', 'addresses']);
  */

  /*
    POST shorthands

    this.post('/contacts');
    this.post('/contacts', 'user'); // specify the type of resource to be created
  */

  /*
    PUT shorthands

    this.put('/contacts/:id');
    this.put('/contacts/:id', 'user'); // specify the type of resource to be updated
  */

  /*
    DELETE shorthands

    this.del('/contacts/:id');
    this.del('/contacts/:id', 'user'); // specify the type of resource to be deleted

    // Single object + related resources. Make sure parent resource is first.
    this.del('/contacts/:id', ['contact', 'addresses']);
  */

  /*
    Function fallback. Manipulate data in the db via

      - db.{collection}
      - db.{collection}.find(id)
      - db.{collection}.where(query)
      - db.{collection}.update(target, attrs)
      - db.{collection}.remove(target)

    // Example: return a single object with related models
    this.get('/contacts/:id', function(db, request) {
      var contactId = +request.params.id;

      return {
        contact: db.contacts.find(contactId),
        addresses: db.addresses.where({contact_id: contactId})
      };
    });

  */
}

/*
You can optionally export a config that is only loaded during tests
export function testConfig() {

}
*/
<commit_msg>mirage/config<commit_after>export default function() {
  this.namespace = 'https://staging-api.osf.io/v2';
  // if using localhost rather than staging, uncomment the following line
  this.namespace = 'https://localhost:8000/v2';

  this.get('/submission-evals');
  this.get('/submission-evals/:id');
  this.post('/submission-evals', (db, request) => {
    return db.db.submissionEvals.insert(JSON.parse(request.requestBody));
  });

  this.post('/conferences');
  this.get('/conferences');
  this.get('/conferences/:id');
  this.patch('/conferences/:id');

  this.get('/nodes/:id/files/:id');
  this.post('/nodes/:id/files', (db, request) => {
    let attrs = request.requestBody;
    return db.db.files.insert(attrs);
  });

  this.get('/reviewers');
  this.get('/reviewers/:id');

  this.get('/reviewslists');
  this.get('/reviewslists/:id');

  this.passthrough('https://staging-api.osf.io/v2/users/me/');
  this.passthrough('http://localhost:8000/v2/users/me/');

  this.passthrough('https://staging-api.osf.io/v2/nodes');
  this.passthrough('http://localhost:8000/v2/nodes');

  this.passthrough('https://staging-api.osf.io/v2/nodes/**');
  this.passthrough('https://localhost:8000/v2/nodes/**');

  // These comments are here to help you get started. Feel free to delete them.

  /*
    Config (with defaults).

    Note: these only affect routes defined *after* them!
  */
  // this.urlPrefix = '';    // make this `http://localhost:8080`, for example, if your API is on a different server
  // this.namespace = '';    // make this `api`, for example, if your API is namespaced
  // this.timing = 400;      // delay for each request, automatically set to 0 during testing

  /*
    Route shorthand cheatsheet
  */
  /*
    GET shorthands

    // Collections
    this.get('/contacts');
    this.get('/contacts', 'users');
    this.get('/contacts', ['contacts', 'addresses']);

    // Single objects
    this.get('/contacts/:id');
    this.get('/contacts/:id', 'user');
    this.get('/contacts/:id', ['contact', 'addresses']);
  */

  /*
    POST shorthands

    this.post('/contacts');
    this.post('/contacts', 'user'); // specify the type of resource to be created
  */

  /*
    PUT shorthands

    this.put('/contacts/:id');
    this.put('/contacts/:id', 'user'); // specify the type of resource to be updated
  */

  /*
    DELETE shorthands

    this.del('/contacts/:id');
    this.del('/contacts/:id', 'user'); // specify the type of resource to be deleted

    // Single object + related resources. Make sure parent resource is first.
    this.del('/contacts/:id', ['contact', 'addresses']);
  */

  /*
    Function fallback. Manipulate data in the db via

      - db.{collection}
      - db.{collection}.find(id)
      - db.{collection}.where(query)
      - db.{collection}.update(target, attrs)
      - db.{collection}.remove(target)

    // Example: return a single object with related models
    this.get('/contacts/:id', function(db, request) {
      var contactId = +request.params.id;

      return {
        contact: db.contacts.find(contactId),
        addresses: db.addresses.where({contact_id: contactId})
      };
    });

  */
}

/*
You can optionally export a config that is only loaded during tests
export function testConfig() {

}
*/
<|endoftext|>


<commit_before>define(function () {
  function showStatImg(o, source, target) {
    var subst = {}
    subst["{SOURCE}"] = source
    subst["{TARGET}"] = target
    return showStat(o, subst)
  }

  return function (config, el, router, d) {
    var unknown = !(d.source.node)
    var h2 = document.createElement("h2")
    var a1 = document.createElement("a")
    if (!unknown) {
      a1.href = "#"
      a1.onclick = router.node(d.source.node)
    }
    a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname
    h2.appendChild(a1)
    h2.appendChild(document.createTextNode(" → "))
    var a2 = document.createElement("a")
    a2.href = "#"
    a2.onclick = router.node(d.target.node)
    a2.textContent = d.target.node.nodeinfo.hostname
    h2.appendChild(a2)
    el.appendChild(h2)

    var attributes = document.createElement("table")
    attributes.classList.add("attributes")

    attributeEntry(attributes, "TQ", showTq(d))
    attributeEntry(attributes, "Entfernung", showDistance(d))
    attributeEntry(attributes, "Typ", d.type)
    var hw1 = unknown ? null : dictGet(d.source.node.nodeinfo, ["hardware", "model"])
    var hw2 = dictGet(d.target.node.nodeinfo, ["hardware", "model"])
    attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt"))
    el.appendChild(attributes)

    if (config.linkInfos) {
      var source = d.source.node_id
      var target = d.target.node_id
      config.linkInfos.forEach( function (linkInfo) {
        var h4 = document.createElement("h4")
        h4.textContent = linkInfo.name
        el.appendChild(h4)
        el.appendChild(showStatImg(linkInfo, source, target))
      })
    }
  }
})
<commit_msg>infobox/link: linkinfos {SOURCE_NAME} and {TARGET_NAME} support (#82)<commit_after>define(function () {
  function showStatImg(o, d) {
    var subst = {}
    subst["{SOURCE}"] = d.source.node_id
	subst["{SOURCE_NAME}"] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname : "unknown"
    subst["{TARGET}"] = d.target.node_id
	subst["{TARGET_NAME}"] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname : "unknown"
    return showStat(o, subst)
  }

  return function (config, el, router, d) {
    var unknown = !(d.source.node)
    var h2 = document.createElement("h2")
    var a1 = document.createElement("a")
    if (!unknown) {
      a1.href = "#"
      a1.onclick = router.node(d.source.node)
    }
    a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname
    h2.appendChild(a1)
    h2.appendChild(document.createTextNode(" → "))
    var a2 = document.createElement("a")
    a2.href = "#"
    a2.onclick = router.node(d.target.node)
    a2.textContent = d.target.node.nodeinfo.hostname
    h2.appendChild(a2)
    el.appendChild(h2)

    var attributes = document.createElement("table")
    attributes.classList.add("attributes")

    attributeEntry(attributes, "TQ", showTq(d))
    attributeEntry(attributes, "Entfernung", showDistance(d))
    attributeEntry(attributes, "Typ", d.type)
    var hw1 = unknown ? null : dictGet(d.source.node.nodeinfo, ["hardware", "model"])
    var hw2 = dictGet(d.target.node.nodeinfo, ["hardware", "model"])
    attributeEntry(attributes, "Hardware", (hw1 != null ? hw1 : "unbekannt") + " – " + (hw2 != null ? hw2 : "unbekannt"))
    el.appendChild(attributes)

    if (config.linkInfos)
      config.linkInfos.forEach( function (linkInfo) {
        var h4 = document.createElement("h4")
        h4.textContent = linkInfo.name
        el.appendChild(h4)
        el.appendChild(showStatImg(linkInfo, d))
      })
  }
})
<|endoftext|>


<commit_before>'use strict';

var inspectUtils = {};

/**
 * Checks whether `a` is an instance of `b`
 *
 * @private
 * @method geInstanceOf
 *
 * @param {object} a Instance
 * @param {object} b Prototype
 *
 * @returns {boolean} Returns true is a is an instance of b
 */
inspectUtils.isInstanceOf = function isInstanceOf(a, b) {
    return a instanceof b;
};

inspectUtils.isObject = function isObject(obj) {
    return (typeof obj === 'object' && obj !== null && !Array.isArray(obj));
};

inspectUtils.isArray = function isObject(obj) {
    return (typeof obj === 'object' && obj !== null && Array.isArray(obj));
};

inspectUtils.isNull = function isObject(obj) {
    return obj === null;
};

inspectUtils.isUndefined = function isObject(obj) {
    return obj === undefined;
};

/**
 * Gets the type of `a`
 *
 * @method getTypeOf
 * @param  {any}  a  Input value
 */
inspectUtils.getTypeOf = function(a, realType) {
    var type = typeof(a);

    if (type === 'object') {
        if (Array.isArray(a)) {
            return 'array';
        }

        if (a === null) {
            return 'null';
        }

        if (a instanceof RegExp) {
            return 'regexp';
        }

        return 'object';
    }

    if (type === 'function') {
        if (Object.getPrototypeOf(a) === Object.getPrototypeOf(function* () { yield;})) {
            return 'generator';
        }

        var match = /class|function/.exec(a.toString());
        if (match[0] === 'class') {
            return 'class';
        }

        return 'function';
    }

    if (type === 'number') {
        if (isNaN(a)) {
            return 'NaN';
        }
    }

    return type;
};

inspectUtils.isPromise = function(a) {
    if (typeof a === 'object' && a !== null) {
        if (typeof a.then === 'function' && typeof a.catch === 'function') {
            return true;
        }
    }

    return false;
};

inspectUtils.isEmpty = function(a) {
    var type = this.getTypeOf(a);

    if (type === 'string' && a === '') {
        return true;
    }

    if (type === 'array' && a.length === 0) {
        return true;
    }

    if (type === 'object' && Object.keys(a).length === 0) {
        return true;
    }

    return false;
};

inspectUtils.hasKeys = function(a, keys) {
    var objKeys = Object.keys(a);
    return keys.every(function(k) {
       return objKeys.indexOf(k) !== -1;
    });
};

inspectUtils.hasAnyKeys = function(a, keys) {
    var objKeys = Object.keys(a);
    return keys.some(function(k) {
       return objKeys.indexOf(k) !== -1;
    });
};

inspectUtils.hasValues = function(a, values) {
    return values.every(function(left) {
        left = this.makeComparable(left);
        return a.some(function(right) {
            right = this.makeComparable(right);
            return left === right;
        }, this);
    }, this);
};

inspectUtils.hasAnyValues = function(a, values) {
    return values.some(function(left) {
        left = this.makeComparable(left);
        return a.some(function(right) {
            right = this.makeComparable(right);
            return left === right;
        }, this);
    }, this);
};

inspectUtils.hasSubset = function(a, b) {
    var index;
    for (var i = 0, len = a.length; i < len; i++) {
        if (this.compareValues(a[i], b[0])) {
            index = i;
            break;
        }
    }

    if (index === undefined) {
        return false;
    }

    for (i = 0, len = b.length; i < len; i++) {
        if (this.makeComparable(a[index + i]) !== this.makeComparable(b[i])) {
            return false;
        }
    }

    return true;
};

inspectUtils.isAny = function(a, types) {
    var type = this.getTypeOf(a);

    if (types === 'any') {
        return true;
    }

    if (typeof types === 'string') {
        types = types.split(',').map(function(t) {
            return t.replace(/^\s+|\s+$/g, '');
        });
    }

    types.forEach(function(t) {
        if (t === 'obj-types') {
            types.push('object', 'array', 'regexp', 'function', 'generator', 'class');
        }
        else if (t === 'func-types') {
            types.push('function', 'generator');
        }
        else if (t === 'data-types') {
            types.push('object', 'array');
        }
    });

    if (types.indexOf(type) !== -1) {
        return true;
    }

    if (type === 'object' && this.isPromise(a)) {
        return true;
    }

    if (type === 'boolean') {
        if (a && types.indexOf('true') !== -1) {
            return true;
        }

        if (!a && types.indexOf('false') !== -1) {
            return true;
        }
    }

    return false;
};

inspectUtils.hasProps = function(a, b) {
    for (var key in b) {
        var subRes;

        if (a === undefined && b !== undefined) {
            return false;
        }

        var typeLeft = this.getTypeOf(a);
        var typeRight = this.getTypeOf(b);

        if (typeLeft !== typeRight) {
            return false;
        }

        if (b.hasOwnProperty(key)) {
            var prop = b[key];
            if (!(key in a)) {
                return false;
            }

            if (this.isObject(prop)) {
                subRes = this.hasProps(a[key], prop);
                if (subRes === false) {
                    return false;
                }

                continue;
            }

            if (this.isArray(prop)) {
                var len = prop.length;
                for (var i = 0; i < len; i++) {
                    var itemA = a[i];
                    var itemB = b[i];

                    if (itemA === undefined && itemB !== undefined) {
                        return false;
                    }

                    typeLeft = this.getTypeOf(itemA);
                    typeRight = this.getTypeOf(itemB);

                    if (typeLeft !== typeRight) {
                        return false;
                    }

                    if (this.isObject(itemB)) {
                        subRes = this.hasProps(itemA, itemB);
                        if (subRes === false) {
                            return false;
                        }

                        continue;
                    }

                    if (itemA !== itemB) {
                        return false;
                    }

                    return this.compareValues(itemA, itemB);
                }
                if (subRes === false) {
                    return false;
                }

                continue;
            }

            if (a[key] !== prop) {
                return false;
            }
        }
    }

    return true;
};

inspectUtils.hasDeepKey = function(a, key) {
    key = key.split('.');
    for (var i = 0, len = key.length; i < len; i++) {
        a = a[key[i]];
        if (!a) {
            return false;
        }
    }

    return true;
};

inspectUtils.hasDeepProp = function(a, key, val) {
    var obj = this.undotify(a, key);
    if (obj) {
        return this.compareValues(obj, val);
    }
    else {
        return false;
    }
};

inspectUtils.compareValues = function(a, b) {
    var typeA = this.getTypeOf(a);
    var typeB = this.getTypeOf(b);

    if (typeA !== typeB) {
        return false;
    }

    if (typeA === 'regexp') {
        return a.toString() === b.toString();
    }

    if (typeof a === 'object') {
        return this.compareObjects(a, b);
    }

    return a === b;
};

inspectUtils.compareArrays = function(a, b) {
    var len = Math.max(a.length, b.length);
    for (var i = 0; i < len; i++) {
        var itemA = a[i];
        var itemB = b[i];

        return this.compareValues(itemA, itemB);
    }

    return true;
};

inspectUtils.compareObjects = function(a, b) {
    if (a === b) {
        return true;
    }

    var typeA = this.getTypeOf(a);
    var typeB = this.getTypeOf(b);

    if (typeA !== typeB) {
        return false;
    }

    if (typeof a === 'function' ||
        a instanceof RegExp ||
        a instanceof Date) {
        return a.toString() === b.toString();
    }

    var keys = Object.keys(a).concat(Object.keys(b)).filter(function(val, index, arr) {
        return arr.indexOf(val) === index;
    });

    for (var i = 0, len = keys.length; i < len; i++) {
        var prop = keys[i];
        if (!(prop in b)) {
            return false;
        }

        if (!this.compareValues(a[prop], b[prop])) {
            return false;
        }
    }

    return true;
};

inspectUtils.undotify = function(obj, path) {
    if (path) {
        path = path.split('.');
        for (var i = 0, len = path.length; i < len; i++) {
            obj = obj[path[i]];
            if (!obj) {
                return;
            }
        }
    }

    return obj;
};

inspectUtils.makeComparable = function(val) {
    var type = this.getTypeOf(val);

    if (type === 'regexp') {
        return val.toString();
    }

    if (typeof val === 'object') {
        return JSON.stringify(val);
    }

    return val;
};

inspectUtils.clone = function(obj) {
    return JSON.parse(JSON.stringify(obj));
};

module.exports = inspectUtils;
<commit_msg>Changes<commit_after>'use strict';

var inspectUtils = {};

/**
 * Checks whether `a` is an instance of `b`
 *
 * @private
 * @method geInstanceOf
 *
 * @param {object} a Instance
 * @param {object} b Prototype
 *
 * @returns {boolean} Returns true is a is an instance of b
 */
inspectUtils.isInstanceOf = function isInstanceOf(a, b) {
    return a instanceof b;
};

inspectUtils.isObject = function isObject(obj) {
    return (typeof obj === 'object' && obj !== null && !Array.isArray(obj));
};

inspectUtils.isArray = function isObject(obj) {
    return (typeof obj === 'object' && obj !== null && Array.isArray(obj));
};

inspectUtils.isNull = function isObject(obj) {
    return obj === null;
};

inspectUtils.isUndefined = function isObject(obj) {
    return obj === undefined;
};

/**
 * Gets the type of `a`
 *
 * @method getTypeOf
 * @param  {any}  a  Input value
 */
inspectUtils.getTypeOf = function(a, realType) {
    var type = typeof(a);

    if (type === 'object') {
        if (Array.isArray(a)) {
            return 'array';
        }

        if (a === null) {
            return 'null';
        }

        if (a instanceof RegExp) {
            return 'regexp';
        }

        return 'object';
    }

    if (type === 'function') {
        if (Object.getPrototypeOf(a) === Object.getPrototypeOf(function* () { yield;})) {
            return 'generator';
        }

        var match = /class|function/.exec(a.toString());
        if (match[0] === 'class') {
            return 'class';
        }

        return 'function';
    }

    if (type === 'number') {
        if (isNaN(a)) {
            return 'NaN';
        }
    }

    return type;
};

inspectUtils.isPromise = function(a) {
    if (typeof a === 'function' || (typeof a === 'object' && a !== null)) {
        if (typeof a.then === 'function' && typeof a.catch === 'function') {
            return true;
        }
    }

    return false;
};

inspectUtils.isEmpty = function(a) {
    var type = this.getTypeOf(a);

    if (type === 'string' && a === '') {
        return true;
    }

    if (type === 'array' && a.length === 0) {
        return true;
    }

    if (type === 'object' && Object.keys(a).length === 0) {
        return true;
    }

    return false;
};

inspectUtils.hasKeys = function(a, keys) {
    var objKeys = Object.keys(a);
    return keys.every(function(k) {
       return objKeys.indexOf(k) !== -1;
    });
};

inspectUtils.hasAnyKeys = function(a, keys) {
    var objKeys = Object.keys(a);
    return keys.some(function(k) {
       return objKeys.indexOf(k) !== -1;
    });
};

inspectUtils.hasValues = function(a, values) {
    return values.every(function(left) {
        left = this.makeComparable(left);
        return a.some(function(right) {
            right = this.makeComparable(right);
            return left === right;
        }, this);
    }, this);
};

inspectUtils.hasAnyValues = function(a, values) {
    return values.some(function(left) {
        left = this.makeComparable(left);
        return a.some(function(right) {
            right = this.makeComparable(right);
            return left === right;
        }, this);
    }, this);
};

inspectUtils.hasSubset = function(a, b) {
    var index;
    for (var i = 0, len = a.length; i < len; i++) {
        if (this.compareValues(a[i], b[0])) {
            index = i;
            break;
        }
    }

    if (index === undefined) {
        return false;
    }

    for (i = 0, len = b.length; i < len; i++) {
        if (this.makeComparable(a[index + i]) !== this.makeComparable(b[i])) {
            return false;
        }
    }

    return true;
};

inspectUtils.isAny = function(a, types) {
    var type = this.getTypeOf(a);

    if (types === 'any') {
        return true;
    }

    if (typeof types === 'string') {
        types = types.split(',').map(function(t) {
            return t.replace(/^\s+|\s+$/g, '');
        });
    }

    types.forEach(function(t) {
        if (t === 'obj-types') {
            types.push('object', 'array', 'regexp', 'function', 'generator', 'class');
        }
        else if (t === 'func-types') {
            types.push('function', 'generator');
        }
        else if (t === 'data-types') {
            types.push('object', 'array');
        }
    });

    if (types.indexOf(type) !== -1) {
        return true;
    }

    if (type === 'object' && this.isPromise(a)) {
        return true;
    }

    if (type === 'boolean') {
        if (a && types.indexOf('true') !== -1) {
            return true;
        }

        if (!a && types.indexOf('false') !== -1) {
            return true;
        }
    }

    return false;
};

inspectUtils.hasProps = function(a, b) {
    for (var key in b) {
        var subRes;

        if (a === undefined && b !== undefined) {
            return false;
        }

        var typeLeft = this.getTypeOf(a);
        var typeRight = this.getTypeOf(b);

        if (typeLeft !== typeRight) {
            return false;
        }

        if (b.hasOwnProperty(key)) {
            var prop = b[key];
            if (!(key in a)) {
                return false;
            }

            if (this.isObject(prop)) {
                subRes = this.hasProps(a[key], prop);
                if (subRes === false) {
                    return false;
                }

                continue;
            }

            if (this.isArray(prop)) {
                var len = prop.length;
                for (var i = 0; i < len; i++) {
                    var itemA = a[i];
                    var itemB = b[i];

                    if (itemA === undefined && itemB !== undefined) {
                        return false;
                    }

                    typeLeft = this.getTypeOf(itemA);
                    typeRight = this.getTypeOf(itemB);

                    if (typeLeft !== typeRight) {
                        return false;
                    }

                    if (this.isObject(itemB)) {
                        subRes = this.hasProps(itemA, itemB);
                        if (subRes === false) {
                            return false;
                        }

                        continue;
                    }

                    if (itemA !== itemB) {
                        return false;
                    }

                    return this.compareValues(itemA, itemB);
                }
                if (subRes === false) {
                    return false;
                }

                continue;
            }

            if (a[key] !== prop) {
                return false;
            }
        }
    }

    return true;
};

inspectUtils.hasDeepKey = function(a, key) {
    key = key.split('.');
    for (var i = 0, len = key.length; i < len; i++) {
        a = a[key[i]];
        if (!a) {
            return false;
        }
    }

    return true;
};

inspectUtils.hasDeepProp = function(a, key, val) {
    var obj = this.undotify(a, key);
    if (obj) {
        return this.compareValues(obj, val);
    }
    else {
        return false;
    }
};

inspectUtils.compareValues = function(a, b) {
    var typeA = this.getTypeOf(a);
    var typeB = this.getTypeOf(b);

    if (typeA !== typeB) {
        return false;
    }

    if (typeA === 'regexp') {
        return a.toString() === b.toString();
    }

    if (typeof a === 'object') {
        return this.compareObjects(a, b);
    }

    return a === b;
};

inspectUtils.compareArrays = function(a, b) {
    var len = Math.max(a.length, b.length);
    for (var i = 0; i < len; i++) {
        var itemA = a[i];
        var itemB = b[i];

        return this.compareValues(itemA, itemB);
    }

    return true;
};

inspectUtils.compareObjects = function(a, b) {
    if (a === b) {
        return true;
    }

    var typeA = this.getTypeOf(a);
    var typeB = this.getTypeOf(b);

    if (typeA !== typeB) {
        return false;
    }

    if (typeof a === 'function' ||
        a instanceof RegExp ||
        a instanceof Date) {
        return a.toString() === b.toString();
    }

    var keys = Object.keys(a).concat(Object.keys(b)).filter(function(val, index, arr) {
        return arr.indexOf(val) === index;
    });

    for (var i = 0, len = keys.length; i < len; i++) {
        var prop = keys[i];
        if (!(prop in b)) {
            return false;
        }

        if (!this.compareValues(a[prop], b[prop])) {
            return false;
        }
    }

    return true;
};

inspectUtils.undotify = function(obj, path) {
    if (path) {
        path = path.split('.');
        for (var i = 0, len = path.length; i < len; i++) {
            obj = obj[path[i]];
            if (!obj) {
                return;
            }
        }
    }

    return obj;
};

inspectUtils.makeComparable = function(val) {
    var type = this.getTypeOf(val);

    if (type === 'regexp') {
        return val.toString();
    }

    if (typeof val === 'object') {
        return JSON.stringify(val);
    }

    return val;
};

inspectUtils.clone = function(obj) {
    return JSON.parse(JSON.stringify(obj));
};

module.exports = inspectUtils;
<|endoftext|>