<commit_before>#!/usr/bin/env node
/*
 * jQuery Core Release Management
 */

// Debugging variables
var	debug = false,
	skipRemote = false;

var fs = require("fs"),
	child = require("child_process"),
	path = require("path"),
	archiver = require("archiver");

var releaseVersion,
	nextVersion,
	isBeta,
	pkg,
	branch,

	sizzleLoc = "bower_components/sizzle",

	scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/",
	cdnURL = "http://code.origin.jquery.com/",
	repoURL = "git@github.com:jquery/jquery.git",

	// Windows needs the .cmd version but will find the non-.cmd
	// On Windows, ensure the HOME environment variable is set
	gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt",

	devFile = "dist/jquery.js",
	minFile = "dist/jquery.min.js",
	mapFile = "dist/jquery.min.map",

	releaseFiles = {
		"jquery-VER.js": devFile,
		"jquery-VER.min.js": minFile,
		"jquery-VER.min.map": mapFile,
		"jquery.js": devFile,
		"jquery.min.js": minFile,
		"jquery.min.map": mapFile,
		"jquery-latest.js": devFile,
		"jquery-latest.min.js": minFile,
		"jquery-latest.min.map": mapFile
	},

	jQueryFilesCDN = [],

	googleFilesCDN = [
		"jquery.js", "jquery.min.js", "jquery.min.map"
	],

	msFilesCDN = [
		"jquery-VER.js", "jquery-VER.min.js", "jquery-VER.min.map"
	];

steps(
	initialize,
	checkGitStatus,
	setReleaseVersion,
	gruntBuild,
	createTag,
	makeReleaseCopies,
	copyTojQueryCDN,
	buildGoogleCDN,
	buildMicrosoftCDN,
	setNextVersion,
	pushToGithub,
	publishToNpm,
	exit
);

function initialize( next ) {

	if ( process.argv[2] === "-d" ) {
		process.argv.shift();
		debug = true;
		console.warn("=== DEBUG MODE ===" );
	}

	// First arg should be the version number being released
	var newver, oldver,
		exists = fs.existsSync || path.existsSync,
		rsemver = /^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/,
		version = ( process.argv[3] || "" ).toLowerCase().match( rsemver ) || {},
		major = version[1],
		minor = version[2],
		patch = version[3],
		xbeta = version[4];

	branch = process.argv[2];
	releaseVersion = process.argv[3];
	isBeta = !!xbeta;

	if ( !branch || !major || !minor || !patch ) {
		die( "Usage: " + process.argv[1] + " branch releaseVersion" );
	}
	if ( xbeta === "pre" ) {
		die( "Cannot release a 'pre' version!" );
	}
	if ( !exists( "package.json" ) ) {
		die( "No package.json in this directory" );
	}
	if ( !exists( sizzleLoc ) ) {
		die( "Sizzle expected to exist at " + sizzleLoc );
	}
	pkg = readJSON( "package.json" );

	console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion );
	version = pkg.version.match( rsemver );
	oldver = ( +version[1] ) * 10000 + ( +version[2] * 100 ) + ( +version[3] );
	newver = ( +major ) * 10000 + ( +minor * 100 ) + ( +patch );
	if ( newver < oldver ) {
		die( "Next version is older than current version!" );
	}

	nextVersion = major + "." + minor + "." + ( isBeta ? patch : +patch + 1 ) + "-pre";
	next();
}

function checkGitStatus( next ) {
	git( [ "status" ], function( error, stdout ) {
		var onBranch = ((stdout||"").match( /On branch (\S+)/ ) || [])[1];
		if ( onBranch !== branch ) {
			dieIfReal( "Branches don't match: Wanted " + branch + ", got " + onBranch );
		}
		if ( /Changes to be committed/i.test( stdout ) ) {
			dieIfReal( "Please commit changed files before attempting to push a release." );
		}
		if ( /Changes not staged for commit/i.test( stdout ) ) {
			dieIfReal( "Please stash files before attempting to push a release." );
		}
		next();
	});
}

function setReleaseVersion( next ) {
	updateVersion( releaseVersion );
	git( [ "commit", "-a", "-m", "Updating version to " + releaseVersion + "." ], next, debug );
}

function gruntBuild( next ) {
	// First clean the dist directory of anything we're not about to rebuild
	git( [ "clean", "-dfx", "dist/" ], function() {
		exec( gruntCmd, [], function( error, stdout, stderr ) {
			if ( error ) {
				die( error + stderr );
			}
			console.log( stdout );
			next();
		}, false );
	}, debug );
}

function makeReleaseCopies( next ) {
	Object.keys( releaseFiles ).forEach(function( key ) {
		var text,
			builtFile = releaseFiles[ key ],
			unpathedFile = key.replace( /VER/g, releaseVersion ),
			releaseFile = "dist/" + unpathedFile;

		// Beta releases don't update the jquery-latest etc. copies
		if ( !isBeta || key.indexOf( "VER" ) >= 0 ) {

			if ( /\.map$/.test( releaseFile ) ) {
				// Map files need to reference the new uncompressed name;
				// assume that all files reside in the same directory.
				// "file":"jquery.min.js","sources":["jquery.js"]
				text = fs.readFileSync( builtFile, "utf8" )
					.replace( /"file":"([^"]+)","sources":\["([^"]+)"\]/,
						"\"file\":\"" + unpathedFile.replace( /\.min\.map/, ".min.js" ) +
						"\",\"sources\":[\"" + unpathedFile.replace( /\.min\.map/, ".js" ) + "\"]" );
				fs.writeFileSync( releaseFile, text );
			} else if ( /\.min\.js$/.test( releaseFile ) ) {
				// Remove the source map comment; it causes way too many problems.
				// Keep the map file in case DevTools allow manual association.
				text = fs.readFileSync( builtFile, "utf8" )
					.replace( /\/\/# sourceMappingURL=\S+/, "" );
				fs.writeFileSync( releaseFile, text );
			} else if ( builtFile !== releaseFile ) {
				copy( builtFile, releaseFile );
			}

			jQueryFilesCDN.push( releaseFile );
		}
	});
	next();
}

function copyTojQueryCDN( next ) {
	var cmds = [];

	jQueryFilesCDN.forEach(function( name ) {
		cmds.push(function( nxt ){
			exec( "scp", [ name, scpURL ], nxt, debug || skipRemote );
		});
		cmds.push(function( nxt ){
			exec( "curl", [ cdnURL + name + "?reload" ], nxt, debug || skipRemote );
		});
	});
	cmds.push( next );

	steps.apply( this, cmds );
}

function buildGoogleCDN( next ) {
	makeArchive( "googlecdn", googleFilesCDN, next );
}

function buildMicrosoftCDN( next ) {
	makeArchive( "mscdn", msFilesCDN, next );
}

function createTag( next ) {
	steps(
		checkoutCommit,
		commitDistFiles,
		tagRelease,
		checkoutBranch,
		next
	);
}

function setNextVersion( next ) {
	updateVersion( nextVersion );
	git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion + "✓™" ], next, debug );
}

function pushToGithub( next ) {
	git( [ "push", "--tags", repoURL, branch ], next, debug || skipRemote );
}

/* Utilities
---------------------------------------------------------------------- */
function steps() {
	var cur = 0,
		st = arguments;
	(function next(){
		process.nextTick(function(){
			st[ cur++ ]( next );
		});
	})();
}

function readJSON( filename ) {
	return JSON.parse( fs.readFileSync( filename ) );
}

function replaceVersionJSON( file, version ) {
	var text = fs.readFileSync( file, "utf8" );
	text = text.replace( /("version":\s*")[^"]+/, "$1" + version );
	fs.writeFileSync( file, text );
}

function updateVersion( ver ) {
	console.log( "Updating version to " + ver );
	pkg.version = ver;
	if ( !debug ) {
		[ "package.json", "bower.json" ].forEach(function( filename ) {
			replaceVersionJSON( filename, ver );
		});
	}
}

function copy( oldFile, newFile, skip ) {
	console.log( "Copying " + oldFile + " to " + newFile );
	if ( !skip ) {
		fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) );
	}
}

function exec( cmd, args, fn, skip ) {
	if ( skip ) {
		console.log( "# " + cmd + " " + args.join(" ") );
		fn( "", "", "" );
	} else {
		console.log( cmd + " " + args.join(" ") );
		child.execFile( cmd, args, { env: process.env },
			function( err, stdout, stderr ) {
				if ( err ) {
					die( stderr || stdout || err );
				}
				fn.apply( this, arguments );
			}
		);
	}
}

function git( args, fn, skip ) {
	exec( "git", args, fn, skip );
}

/* Tag creation
---------------------------------------------------------------------- */
function checkoutCommit( next ) {
	git( [ "checkout", "HEAD^0" ], next, debug );
}

function commitDistFiles( next ) {
	// Remove scripts property from package.json
	var pkgClone = readJSON( "package.json" );
	delete pkgClone.scripts;
	fs.writeFileSync( "package.json", JSON.stringify( pkgClone, null, "\t" ) );
	fs.unlinkSync( ".gitignore" );
	// Add files to be committed
	git( [ "add", "package.json", "dist", sizzleLoc ], function() {
		// Remove unneeded files
		git( [ "rm", "-r",
			"build",
			"speed",
			"test",
			".editorconfig",
			".gitattributes",
			".gitignore",
			".jscs.json",
			".jshintignore",
			".jshintrc",
			".mailmap",
			".travis.yml",
			"Gruntfile.js",
			"README.md"
		], function() {
			git( [ "commit", "-a", "-m", releaseVersion ], next, debug );
		}, debug );
	}, debug );
}

function tagRelease( next ) {
	git( [ "tag", releaseVersion ], next, debug );
}

function checkoutBranch( next ) {
	// Reset files to previous state before leaving the commit
	git( [ "reset", "--hard", "HEAD" ], function() {
		git( [ "checkout", branch ], next, debug );
	}, debug );
}

/* Archive creation
---------------------------------------------------------------------- */
function makeArchive( cdn, files, fn ) {
	if ( isBeta ) {
		console.log( "Skipping archive creation for " + cdn + "; " + releaseVersion + " is beta" );
		process.nextTick( fn );
		return;
	}

	console.log( "Creating production archive for " + cdn );

	var archive = archiver( "zip" ),
		md5file = "dist/" + cdn + "-md5.txt",
		output = fs.createWriteStream( "dist/" + cdn + "-jquery-" + releaseVersion + ".zip" );

	archive.on( "error", function( err ) {
		throw err;
	});

	output.on( "close", fn );
	archive.pipe( output );

	files = files.map(function( item ) {
		return "dist/" + item.replace( /VER/g, releaseVersion );
	});

	exec( "md5sum", files, function( err, stdout ) {
		fs.writeFileSync( md5file, stdout );
		files.push( md5file );

		files.forEach(function( file ) {
			archive.append( fs.createReadStream( file ), { name: file } );
		});

		archive.finalize();
	}, false );
}

/* NPM
---------------------------------------------------------------------- */
function publishToNpm( next ) {
	// Only publish the master branch to NPM
	// You must be the jquery npm user for this not to fail
	// To check, run `npm whoami`
	// Log in to the jquery user with `npm adduser`
	if ( branch !== "master" ) {
		next();
		return;
	}
	git( [ "checkout", releaseVersion ], function() {
		// Only publish committed files
		git( [ "clean", "-dfx" ], function() {
			var args = [ "publish" ];
			// Tag the version as beta if necessary
			if ( isBeta ) {
				args.push( "--tag", "beta" );
			}
			exec( "npm", args, function() {
				git( [ "checkout", branch ], next, debug );
			}, debug || skipRemote );
		}, debug );
	}, debug);
}

/* Death
---------------------------------------------------------------------- */
function die( msg ) {
	console.error( "ERROR: " + msg );
	process.exit( 1 );
}

function dieIfReal( msg ) {
	if ( debug ) {
		console.log ( "DIE: " + msg );
	} else {
		die( msg );
	}
}

function exit() {
	process.exit( 0 );
}
<commit_msg>Update sizzle location in release script<commit_after>#!/usr/bin/env node
/*
 * jQuery Core Release Management
 */

// Debugging variables
var	debug = false,
	skipRemote = false;

var fs = require("fs"),
	child = require("child_process"),
	path = require("path"),
	archiver = require("archiver");

var releaseVersion,
	nextVersion,
	isBeta,
	pkg,
	branch,

	sizzleLoc = "bower_modules/sizzle",

	scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/",
	cdnURL = "http://code.origin.jquery.com/",
	repoURL = "git@github.com:jquery/jquery.git",

	// Windows needs the .cmd version but will find the non-.cmd
	// On Windows, ensure the HOME environment variable is set
	gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt",

	devFile = "dist/jquery.js",
	minFile = "dist/jquery.min.js",
	mapFile = "dist/jquery.min.map",

	releaseFiles = {
		"jquery-VER.js": devFile,
		"jquery-VER.min.js": minFile,
		"jquery-VER.min.map": mapFile,
		"jquery.js": devFile,
		"jquery.min.js": minFile,
		"jquery.min.map": mapFile,
		"jquery-latest.js": devFile,
		"jquery-latest.min.js": minFile,
		"jquery-latest.min.map": mapFile
	},

	jQueryFilesCDN = [],

	googleFilesCDN = [
		"jquery.js", "jquery.min.js", "jquery.min.map"
	],

	msFilesCDN = [
		"jquery-VER.js", "jquery-VER.min.js", "jquery-VER.min.map"
	];

steps(
	initialize,
	checkGitStatus,
	setReleaseVersion,
	gruntBuild,
	createTag,
	makeReleaseCopies,
	copyTojQueryCDN,
	buildGoogleCDN,
	buildMicrosoftCDN,
	setNextVersion,
	pushToGithub,
	publishToNpm,
	exit
);

function initialize( next ) {

	if ( process.argv[2] === "-d" ) {
		process.argv.shift();
		debug = true;
		console.warn("=== DEBUG MODE ===" );
	}

	// First arg should be the version number being released
	var newver, oldver,
		exists = fs.existsSync || path.existsSync,
		rsemver = /^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/,
		version = ( process.argv[3] || "" ).toLowerCase().match( rsemver ) || {},
		major = version[1],
		minor = version[2],
		patch = version[3],
		xbeta = version[4];

	branch = process.argv[2];
	releaseVersion = process.argv[3];
	isBeta = !!xbeta;

	if ( !branch || !major || !minor || !patch ) {
		die( "Usage: " + process.argv[1] + " branch releaseVersion" );
	}
	if ( xbeta === "pre" ) {
		die( "Cannot release a 'pre' version!" );
	}
	if ( !exists( "package.json" ) ) {
		die( "No package.json in this directory" );
	}
	if ( !exists( sizzleLoc ) ) {
		die( "Sizzle expected to exist at " + sizzleLoc );
	}
	pkg = readJSON( "package.json" );

	console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion );
	version = pkg.version.match( rsemver );
	oldver = ( +version[1] ) * 10000 + ( +version[2] * 100 ) + ( +version[3] );
	newver = ( +major ) * 10000 + ( +minor * 100 ) + ( +patch );
	if ( newver < oldver ) {
		die( "Next version is older than current version!" );
	}

	nextVersion = major + "." + minor + "." + ( isBeta ? patch : +patch + 1 ) + "-pre";
	next();
}

function checkGitStatus( next ) {
	git( [ "status" ], function( error, stdout ) {
		var onBranch = ((stdout||"").match( /On branch (\S+)/ ) || [])[1];
		if ( onBranch !== branch ) {
			dieIfReal( "Branches don't match: Wanted " + branch + ", got " + onBranch );
		}
		if ( /Changes to be committed/i.test( stdout ) ) {
			dieIfReal( "Please commit changed files before attempting to push a release." );
		}
		if ( /Changes not staged for commit/i.test( stdout ) ) {
			dieIfReal( "Please stash files before attempting to push a release." );
		}
		next();
	});
}

function setReleaseVersion( next ) {
	updateVersion( releaseVersion );
	git( [ "commit", "-a", "-m", "Updating version to " + releaseVersion + "." ], next, debug );
}

function gruntBuild( next ) {
	// First clean the dist directory of anything we're not about to rebuild
	git( [ "clean", "-dfx", "dist/" ], function() {
		exec( gruntCmd, [], function( error, stdout, stderr ) {
			if ( error ) {
				die( error + stderr );
			}
			console.log( stdout );
			next();
		}, false );
	}, debug );
}

function makeReleaseCopies( next ) {
	Object.keys( releaseFiles ).forEach(function( key ) {
		var text,
			builtFile = releaseFiles[ key ],
			unpathedFile = key.replace( /VER/g, releaseVersion ),
			releaseFile = "dist/" + unpathedFile;

		// Beta releases don't update the jquery-latest etc. copies
		if ( !isBeta || key.indexOf( "VER" ) >= 0 ) {

			if ( /\.map$/.test( releaseFile ) ) {
				// Map files need to reference the new uncompressed name;
				// assume that all files reside in the same directory.
				// "file":"jquery.min.js","sources":["jquery.js"]
				text = fs.readFileSync( builtFile, "utf8" )
					.replace( /"file":"([^"]+)","sources":\["([^"]+)"\]/,
						"\"file\":\"" + unpathedFile.replace( /\.min\.map/, ".min.js" ) +
						"\",\"sources\":[\"" + unpathedFile.replace( /\.min\.map/, ".js" ) + "\"]" );
				fs.writeFileSync( releaseFile, text );
			} else if ( /\.min\.js$/.test( releaseFile ) ) {
				// Remove the source map comment; it causes way too many problems.
				// Keep the map file in case DevTools allow manual association.
				text = fs.readFileSync( builtFile, "utf8" )
					.replace( /\/\/# sourceMappingURL=\S+/, "" );
				fs.writeFileSync( releaseFile, text );
			} else if ( builtFile !== releaseFile ) {
				copy( builtFile, releaseFile );
			}

			jQueryFilesCDN.push( releaseFile );
		}
	});
	next();
}

function copyTojQueryCDN( next ) {
	var cmds = [];

	jQueryFilesCDN.forEach(function( name ) {
		cmds.push(function( nxt ){
			exec( "scp", [ name, scpURL ], nxt, debug || skipRemote );
		});
		cmds.push(function( nxt ){
			exec( "curl", [ cdnURL + name + "?reload" ], nxt, debug || skipRemote );
		});
	});
	cmds.push( next );

	steps.apply( this, cmds );
}

function buildGoogleCDN( next ) {
	makeArchive( "googlecdn", googleFilesCDN, next );
}

function buildMicrosoftCDN( next ) {
	makeArchive( "mscdn", msFilesCDN, next );
}

function createTag( next ) {
	steps(
		checkoutCommit,
		commitDistFiles,
		tagRelease,
		checkoutBranch,
		next
	);
}

function setNextVersion( next ) {
	updateVersion( nextVersion );
	git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion + "✓™" ], next, debug );
}

function pushToGithub( next ) {
	git( [ "push", "--tags", repoURL, branch ], next, debug || skipRemote );
}

/* Utilities
---------------------------------------------------------------------- */
function steps() {
	var cur = 0,
		st = arguments;
	(function next(){
		process.nextTick(function(){
			st[ cur++ ]( next );
		});
	})();
}

function readJSON( filename ) {
	return JSON.parse( fs.readFileSync( filename ) );
}

function replaceVersionJSON( file, version ) {
	var text = fs.readFileSync( file, "utf8" );
	text = text.replace( /("version":\s*")[^"]+/, "$1" + version );
	fs.writeFileSync( file, text );
}

function updateVersion( ver ) {
	console.log( "Updating version to " + ver );
	pkg.version = ver;
	if ( !debug ) {
		[ "package.json", "bower.json" ].forEach(function( filename ) {
			replaceVersionJSON( filename, ver );
		});
	}
}

function copy( oldFile, newFile, skip ) {
	console.log( "Copying " + oldFile + " to " + newFile );
	if ( !skip ) {
		fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) );
	}
}

function exec( cmd, args, fn, skip ) {
	if ( skip ) {
		console.log( "# " + cmd + " " + args.join(" ") );
		fn( "", "", "" );
	} else {
		console.log( cmd + " " + args.join(" ") );
		child.execFile( cmd, args, { env: process.env },
			function( err, stdout, stderr ) {
				if ( err ) {
					die( stderr || stdout || err );
				}
				fn.apply( this, arguments );
			}
		);
	}
}

function git( args, fn, skip ) {
	exec( "git", args, fn, skip );
}

/* Tag creation
---------------------------------------------------------------------- */
function checkoutCommit( next ) {
	git( [ "checkout", "HEAD^0" ], next, debug );
}

function commitDistFiles( next ) {
	// Remove scripts property from package.json
	var pkgClone = readJSON( "package.json" );
	delete pkgClone.scripts;
	fs.writeFileSync( "package.json", JSON.stringify( pkgClone, null, "\t" ) );
	fs.unlinkSync( ".gitignore" );
	// Add files to be committed
	git( [ "add", "package.json", "dist", sizzleLoc ], function() {
		// Remove unneeded files
		git( [ "rm", "-r",
			"build",
			"speed",
			"test",
			".editorconfig",
			".gitattributes",
			".gitignore",
			".jscs.json",
			".jshintignore",
			".jshintrc",
			".mailmap",
			".travis.yml",
			"Gruntfile.js",
			"README.md"
		], function() {
			git( [ "commit", "-a", "-m", releaseVersion ], next, debug );
		}, debug );
	}, debug );
}

function tagRelease( next ) {
	git( [ "tag", releaseVersion ], next, debug );
}

function checkoutBranch( next ) {
	// Reset files to previous state before leaving the commit
	git( [ "reset", "--hard", "HEAD" ], function() {
		git( [ "checkout", branch ], next, debug );
	}, debug );
}

/* Archive creation
---------------------------------------------------------------------- */
function makeArchive( cdn, files, fn ) {
	if ( isBeta ) {
		console.log( "Skipping archive creation for " + cdn + "; " + releaseVersion + " is beta" );
		process.nextTick( fn );
		return;
	}

	console.log( "Creating production archive for " + cdn );

	var archive = archiver( "zip" ),
		md5file = "dist/" + cdn + "-md5.txt",
		output = fs.createWriteStream( "dist/" + cdn + "-jquery-" + releaseVersion + ".zip" );

	archive.on( "error", function( err ) {
		throw err;
	});

	output.on( "close", fn );
	archive.pipe( output );

	files = files.map(function( item ) {
		return "dist/" + item.replace( /VER/g, releaseVersion );
	});

	exec( "md5sum", files, function( err, stdout ) {
		fs.writeFileSync( md5file, stdout );
		files.push( md5file );

		files.forEach(function( file ) {
			archive.append( fs.createReadStream( file ), { name: file } );
		});

		archive.finalize();
	}, false );
}

/* NPM
---------------------------------------------------------------------- */
function publishToNpm( next ) {
	// Only publish the master branch to NPM
	// You must be the jquery npm user for this not to fail
	// To check, run `npm whoami`
	// Log in to the jquery user with `npm adduser`
	if ( branch !== "master" ) {
		next();
		return;
	}
	git( [ "checkout", releaseVersion ], function() {
		// Only publish committed files
		git( [ "clean", "-dfx" ], function() {
			var args = [ "publish" ];
			// Tag the version as beta if necessary
			if ( isBeta ) {
				args.push( "--tag", "beta" );
			}
			exec( "npm", args, function() {
				git( [ "checkout", branch ], next, debug );
			}, debug || skipRemote );
		}, debug );
	}, debug);
}

/* Death
---------------------------------------------------------------------- */
function die( msg ) {
	console.error( "ERROR: " + msg );
	process.exit( 1 );
}

function dieIfReal( msg ) {
	if ( debug ) {
		console.log ( "DIE: " + msg );
	} else {
		die( msg );
	}
}

function exit() {
	process.exit( 0 );
}
<|endoftext|>


<commit_before>var _=require('underscore'),
URLUtils=require('./URLUtils'),
s3db=require('./s3db'),
Q=require('q'),
crypto=require('crypto');

exports=module.exports=init;

function init(s3,uri,endpoint_prefix)
{
	if(!s3 || !uri) throw new Error('init@ObjectDB@s3db: s3 and uri parameters cannot be empty');
	this.s3=s3;
	var info=URLUtils.parse_s3_uri(uri);
	if(!info) throw new Error('init@ObjectDB@s3db: Invalid S3 URI: '+uri);
	if(!endpoint_prefix) s3.setBucket(info['bucket']);
	else s3.setBucket(info['bucket']+'.'+endpoint_prefix);
	this.prefix=URLUtils.remove_leading_slash(URLUtils.add_ending_slash(info['path']));
	this.path=URLUtils.add_ending_slash(info['path']);

	this.next_marker='';
	this.is_truncated=false;
	this.limit=0;
	this.delimiter='';
}

init.prototype.default_limit=1000;
init.prototype.default_delimiter='/';

init.prototype.reset=function(){
	this.next_marker='';
	this.is_truncated=false;
	this.limit=0;
	this.delimiter='';
};

init.prototype.get=function(ok_func,error_func,limit,marker){
	try{

		var params={};

		var delimiter=(this.is_truncated && this.delimiter)?this.delimiter:this.default_delimiter;
		if(delimiter) params['delimiter']=delimiter;

		if(this.prefix) params['prefix']=this.prefix;

		if(!limit) limit=(this.is_truncated && this.limit) ? this.limit : this.default_limit;

		params['max-keys']=limit;

		if(!marker && this.is_truncated && this.next_marker) marker=this.next_marker;
		if(marker) params['marker']=marker;

		if(_.isEmpty(params)) params=null;

		this.s3.get('/',params,'xml',_.bind(function(error,response){
			try{
				if(error) throw error;
				this.is_truncated=response['IsTruncated']=='true'?true:false;
				this.next_marker=(response['NextMarker'] && typeof(response['NextMarker'])=='string')?response['NextMarker']:'';
				this.limit=(response['MaxKeys'] && typeof(response['MaxKeys'])=='string')?response['MaxKeys']:0;
				this.delimiter=(response['Delimiter'] && typeof(response['Delimiter'])=='string')?response['Delimiter']:'';
				var prefix=(response['Prefix'] && typeof(response['Prefix'])=='string')?response['Prefix']:'';

				var data=[];
				var key;

				if(response['Contents'] && response['Contents']['length'])
				{
					for(var i=0;i<response['Contents']['length'];i++)
					{
						if(!response['Contents'][i] || !response['Contents'][i]['Key'] || typeof(response['Contents'][i]['Key'])!='string') continue;
						key=response['Contents'][i]['Key'];
						if(!prefix) data.push(key);
						else data.push(key.substr(prefix.length));
					}
				}else if(response['Contents'] && response['Contents']['Key'] && typeof(response['Contents']['Key'])=='string'){
					key=response['Contents']['Key'];
					if(!prefix) data.push(key);
					else data.push(key.substr(prefix.length));
				}
				if(ok_func && _.isFunction(ok_func)) ok_func(data,this.is_truncated,this.next_marker,this.limit,this.delimiter);
			}catch(e){
				if(error_func && _.isFunction(error_func)) error_func(e);
			}
		},this));
	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}

};

init.prototype.put=function(key,ok_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		var data=new Buffer('1','utf-8');

		var promises=_.map(keys,function(k){
			var deferred = Q.defer();

			this.s3.putBuffer(this.path+k,data,'private',{
				'Content-Type':'application/json'
			},function(error,response){
				if(error) deferred.reject(error);
				deferred.resolve();
			});
			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(ok_func && _.isFunction(ok_func)) ok_func();
		},function(e){
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.del=function(key,ok_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		var tasks=[];
		if(keys.length<=this.default_limit) tasks.push(keys);
		else {
			for(var i=0;i<keys.length-this.default_limit;i+=this.default_limit)
				tasks.push(keys.slice(i,i+this.default_limit));
		}

		var promises=_.map(tasks,function(k_arr){
			var deferred = Q.defer();

			var req='<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>true</Quiet>';

			for(var i=0;i<k_arr.length;i++)
				req+='<Object><Key>'+_.escape(this.prefix+k_arr[i])+'</Key></Object>';

			req+='</Delete>';

			req=new Buffer(req,'utf-8');

			var hash=crypto.createHash('md5');
			hash.update(req);
			var md5=hash.digest('base64');

			this.s3.post('/?delete',{
				'Content-MD5':md5,
				'Content-Length':req.length
			},req,function(error,response){
				if(error) deferred.reject(error);
				deferred.resolve();
			});

			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(ok_func && _.isFunction(ok_func)) ok_func();
		},function(e){
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.del_all=function(ok_func,error_func){
	try{
		var get_list_func=_.bind(function(){
			this.get(_.bind(function(data){
				if(!data.length) {
					if(this.is_truncated) get_list_func();
					return;
				}
				this.del(data,_.bind(function(){
					if(this.is_truncated) get_list_func();
				},this),function(e){
					if(error_func && _.isFunction(error_func)) error_func(e);
				});
			},this),function(e){
				if(error_func && _.isFunction(error_func)) error_func(e);
			});
		},this);

		get_list_func();
	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.on_list=function(key,yes_func,no_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		key=null;

		var promises=_.map(keys,function(k){
			var deferred = Q.defer();

			this.s3.head(this.path+k,function(error,response){
				if(error) {
					error.key=k;
					deferred.reject(error);
				}
				deferred.resolve();
			});

			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(yes_func && _.isFunction(yes_func)) yes_func();
		},function(e){
			if(e['code'] && e['code']=='404') {
				if(no_func && _.isFunction(no_func)) no_func(e.key,e);
			}
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

<commit_msg>promise should not be resolved after rejected<commit_after>var _=require('underscore'),
URLUtils=require('./URLUtils'),
s3db=require('./s3db'),
Q=require('q'),
crypto=require('crypto');

exports=module.exports=init;

function init(s3,uri,endpoint_prefix)
{
	if(!s3 || !uri) throw new Error('init@ObjectDB@s3db: s3 and uri parameters cannot be empty');
	this.s3=s3;
	var info=URLUtils.parse_s3_uri(uri);
	if(!info) throw new Error('init@ObjectDB@s3db: Invalid S3 URI: '+uri);
	if(!endpoint_prefix) s3.setBucket(info['bucket']);
	else s3.setBucket(info['bucket']+'.'+endpoint_prefix);
	this.prefix=URLUtils.remove_leading_slash(URLUtils.add_ending_slash(info['path']));
	this.path=URLUtils.add_ending_slash(info['path']);

	this.next_marker='';
	this.is_truncated=false;
	this.limit=0;
	this.delimiter='';
}

init.prototype.default_limit=1000;
init.prototype.default_delimiter='/';

init.prototype.reset=function(){
	this.next_marker='';
	this.is_truncated=false;
	this.limit=0;
	this.delimiter='';
};

init.prototype.get=function(ok_func,error_func,limit,marker){
	try{

		var params={};

		var delimiter=(this.is_truncated && this.delimiter)?this.delimiter:this.default_delimiter;
		if(delimiter) params['delimiter']=delimiter;

		if(this.prefix) params['prefix']=this.prefix;

		if(!limit) limit=(this.is_truncated && this.limit) ? this.limit : this.default_limit;

		params['max-keys']=limit;

		if(!marker && this.is_truncated && this.next_marker) marker=this.next_marker;
		if(marker) params['marker']=marker;

		if(_.isEmpty(params)) params=null;

		this.s3.get('/',params,'xml',_.bind(function(error,response){
			try{
				if(error) throw error;
				this.is_truncated=response['IsTruncated']=='true'?true:false;
				this.next_marker=(response['NextMarker'] && typeof(response['NextMarker'])=='string')?response['NextMarker']:'';
				this.limit=(response['MaxKeys'] && typeof(response['MaxKeys'])=='string')?response['MaxKeys']:0;
				this.delimiter=(response['Delimiter'] && typeof(response['Delimiter'])=='string')?response['Delimiter']:'';
				var prefix=(response['Prefix'] && typeof(response['Prefix'])=='string')?response['Prefix']:'';

				var data=[];
				var key;

				if(response['Contents'] && response['Contents']['length'])
				{
					for(var i=0;i<response['Contents']['length'];i++)
					{
						if(!response['Contents'][i] || !response['Contents'][i]['Key'] || typeof(response['Contents'][i]['Key'])!='string') continue;
						key=response['Contents'][i]['Key'];
						if(!prefix) data.push(key);
						else data.push(key.substr(prefix.length));
					}
				}else if(response['Contents'] && response['Contents']['Key'] && typeof(response['Contents']['Key'])=='string'){
					key=response['Contents']['Key'];
					if(!prefix) data.push(key);
					else data.push(key.substr(prefix.length));
				}
				if(ok_func && _.isFunction(ok_func)) ok_func(data,this.is_truncated,this.next_marker,this.limit,this.delimiter);
			}catch(e){
				if(error_func && _.isFunction(error_func)) error_func(e);
			}
		},this));
	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}

};

init.prototype.put=function(key,ok_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		var data=new Buffer('1','utf-8');

		var promises=_.map(keys,function(k){
			var deferred = Q.defer();

			this.s3.putBuffer(this.path+k,data,'private',{
				'Content-Type':'application/json'
			},function(error,response){
				if(error) deferred.reject(error);
				else deferred.resolve();
			});
			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(ok_func && _.isFunction(ok_func)) ok_func();
		},function(e){
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.del=function(key,ok_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		var tasks=[];
		if(keys.length<=this.default_limit) tasks.push(keys);
		else {
			for(var i=0;i<keys.length-this.default_limit;i+=this.default_limit)
				tasks.push(keys.slice(i,i+this.default_limit));
		}

		var promises=_.map(tasks,function(k_arr){
			var deferred = Q.defer();

			var req='<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>true</Quiet>';

			for(var i=0;i<k_arr.length;i++)
				req+='<Object><Key>'+_.escape(this.prefix+k_arr[i])+'</Key></Object>';

			req+='</Delete>';

			req=new Buffer(req,'utf-8');

			var hash=crypto.createHash('md5');
			hash.update(req);
			var md5=hash.digest('base64');

			this.s3.post('/?delete',{
				'Content-MD5':md5,
				'Content-Length':req.length
			},req,function(error,response){
				if(error) deferred.reject(error);
				else deferred.resolve();
			});

			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(ok_func && _.isFunction(ok_func)) ok_func();
		},function(e){
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.del_all=function(ok_func,error_func){
	try{
		var get_list_func=_.bind(function(){
			this.get(_.bind(function(data){
				if(!data.length) {
					if(this.is_truncated) get_list_func();
					return;
				}
				this.del(data,_.bind(function(){
					if(this.is_truncated) get_list_func();
				},this),function(e){
					if(error_func && _.isFunction(error_func)) error_func(e);
				});
			},this),function(e){
				if(error_func && _.isFunction(error_func)) error_func(e);
			});
		},this);

		get_list_func();
	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

init.prototype.on_list=function(key,yes_func,no_func,error_func){
	try{
		if(!key) throw new Error('Empty Key');
		var keys;
		if(_.isArray(key)) {
			if(!key.length) throw new Error('Empty Key Array');
			keys=key;
		}else if(_.isString(key)) {
			keys=[key];
		}else throw new Error('Unknow `key` parameter type');

		key=null;

		var promises=_.map(keys,function(k){
			var deferred = Q.defer();

			this.s3.head(this.path+k,function(error,response){
				if(error) {
					error.key=k;
					deferred.reject(error);
				}else deferred.resolve();
			});

			return deferred.promise;
		},this);

		Q.all(promises).then(function(){
			if(yes_func && _.isFunction(yes_func)) yes_func();
		},function(e){
			if(e['code'] && e['code']=='404') {
				if(no_func && _.isFunction(no_func)) no_func(e.key,e);
			}
			if(error_func && _.isFunction(error_func)) error_func(e);
		});

	}catch(e){
		if(error_func && _.isFunction(error_func)) error_func(e);
	}
};

<|endoftext|>


<commit_before>'use strict';
var React = require('react');
var _ = require('underscore');
var moment = require('moment');
var globals = require('../../globals');
var RestMixin = require('../../rest').RestMixin;
var parseClinvar = require('../../../libs/parse-resources').parseClinvar;
var LocalStorageMixin = require('react-localstorage');
var SO_terms = require('./mapping/SO_term.json');

var external_url_map = globals.external_url_map;

// Display the curator data of the curation data
var CurationInterpretationBasicInfo = module.exports.CurationInterpretationBasicInfo = React.createClass({
    mixins: [RestMixin, LocalStorageMixin],

    propTypes: {
        data: React.PropTypes.object, // ClinVar data payload
        shouldFetchData: React.PropTypes.bool
    },

    getInitialState: function() {
        return {
            clinvar_id: null, // ClinVar ID
            car_id: null, // ClinGen Allele Registry ID
            dbSNP_id: null,
            nucleotide_change: [],
            molecular_consequence: [],
            protein_change: [],
            ensembl_transcripts: [],
            sequence_location: [],
            primary_transcript: {},
            hgvs_GRCh37: null,
            hgvs_GRCh38: null,
            gene_symbol: null,
            uniprot_id: null,
            shouldFetchData: false
        };
    },

    componentWillReceiveProps: function(nextProps) {
        this.setState({shouldFetchData: nextProps.shouldFetchData});
        if (this.state.shouldFetchData === true) {
            this.fetchRefseqData();
            this.fetchEnsemblData();
        }
    },

    // Retrieve the variant data from NCBI REST API
    fetchRefseqData: function() {
        //var refseq_data = {};
        var variant = this.props.data;
        var url = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=clinvar&rettype=variation&id=';
        if (variant) {
            var clinVarId = (variant.clinvarVariantId) ? variant.clinvarVariantId : 'Unknown';
            this.setState({
                clinvar_id: clinVarId,
                car_id: variant.carId,
                dbSNP_id: variant.dbSNPIds[0],
                hgvs_GRCh37: variant.hgvsNames.gRCh37,
                hgvs_GRCh37: variant.hgvsNames.gRCh37,
                hgvs_GRCh37: variant.hgvsNames.gRCh37,
                hgvs_GRCh38: variant.hgvsNames.gRCh38,
            });
            this.getRestDataXml(url + clinVarId).then(xml => {
                // Passing 'true' option to invoke 'mixin' function
                // To extract more ClinVar data for 'basic info' tab
                var d = parseClinvar(xml, true);
                this.setState({
                    nucleotide_change: d.RefSeqTranscripts.NucleotideChangeList,
                    protein_change: d.RefSeqTranscripts.ProteinChangeList,
                    molecular_consequence: d.RefSeqTranscripts.MolecularConsequenceList,
                    sequence_location: d.allele.SequenceLocation,
                    gene_symbol: d.gene.symbol
                });
                this.getUniprotId(this.state.gene_symbol);
                this.getPrimaryTranscript(d.clinvarVariantTitle, this.state.nucleotide_change, this.state.protein_change, this.state.molecular_consequence);
            }).catch(function(e) {
                console.log('RefSeq Fetch Error=: %o', e);
            });
        }
    },

    // Create primary transcript object
    // Called in the "fetchRefseqData" method after various states are set
    getPrimaryTranscript: function(str, nucleotide_change, protein_change, molecular_consequence) {
        var transcript = {}, SO_id_term = '';
        var result = nucleotide_change.find((n) => str.indexOf(n.AccessionVersion) > -1);
        if (result && molecular_consequence.length) {
            var item = molecular_consequence.find((x) => x.HGVS === result.HGVS);
            // 'SO_terms' is defined via requiring external mapping file
            var entry = SO_terms.find((v) => v.SO_id === item.SOid);
            SO_id_term = entry.SO_term + ' ' + entry.SO_id;
            // FIXME: temporarily use protein_change[0] due to lack of mapping
            // associated with nucleotide transcript in ClinVar data
            transcript = {
                "nucleotide": result.HGVS,
                "protein": protein_change[0].HGVS,
                "molecular": SO_id_term
            };
        }
        this.setState({primary_transcript: transcript});
    },

    // Retrieve variant data from Ensembl REST API
    fetchEnsemblData: function() {
        var variant = this.props.data;
        if (variant) {
            var rsid = (variant.dbSNPIds) ? variant.dbSNPIds[0] : 'Unknown';
            this.getRestData('http://rest.ensembl.org/vep/human/id/' + rsid + '?content-type=application/json&hgvs=1&protein=1&xref_refseq=1&domains=1').then(response => {
                this.setState({ensembl_transcripts: response[0].transcript_consequences});
            }).catch(function(e) {
                console.log('Ensembl Fetch Error=: %o', e);
            });
        }
    },

    // Use Ensembl consequence_terms to find matching SO_id and SO_term pair
    // Then concatenate all pairs into string
    handleSOTerms: function(array) {
        var newArray = [],
            SO_id_term,
            newStr = '';
        for (let value of array.values()) {
            // 'SO_terms' is defined via requiring external mapping file
            var entry = SO_terms.find((v) => v.SO_term === value);
            SO_id_term = entry.SO_term + ' ' + entry.SO_id;
            newArray.push(SO_id_term);
        }
        for (let [key, value] of newArray.entries()) {
            if (key === 0) {
                newStr += value;
            }
            if (key > 0) {
                newStr += ', ' + value;
            }
        }
        return newStr;
    },

    // Find gene_id from Ensembl REST API response
    // Used to construct LinkOut URL to Ensembl Browser
    getGeneId: function(array) {
        var gene_id = '';
        if (array.length && array[0].gene_id) {
            gene_id = array[0].gene_id;
        }
        return gene_id;
    },

    // Find Uniprot id given the gene_symbol from ClinVar
    // Called in the "fetchRefseqData" method after gene_symbol state is set
    // Used to construct LinkOut URL to Uniprot
    getUniprotId: function(gene_symbol) {
        if (gene_symbol) {
            this.getRestData('http://rest.genenames.org/fetch/symbol/' + gene_symbol).then(result => {
                this.setState({uniprot_id: result.response.docs[0].uniprot_ids[0]});
            }).catch(function(e) {
                console.log('HGNC Fetch Error=: %o', e);
            });
        }
    },

    // Construct LinkOut URLs to UCSC Viewer
    // For both GRCh38/hg38 and GRCh37/hg19
    ucscViewerURL: function(array, db, assembly) {
        var url = '';
        array.forEach(v => {
            if (v.Assembly === assembly) {
                url = 'https://genome.ucsc.edu/cgi-bin/hgTracks?db=' + db + '&position=Chr' + v.Chr + '%3A' + v.start + '-' + v.stop;
            }
        });
        return url;
    },

    // Construct LinkOut URLs to NCBI Variation Viewer
    // For both GRCh38 and GRCh37
    variationViewerURL: function(array, gene_symbol, assembly) {
        var url = '';
        array.forEach(v => {
            if (v.Assembly === assembly) {
                url = 'http://www.ncbi.nlm.nih.gov/variation/view/?chr=' + v.Chr + '&q=' + gene_symbol + '&assm=' + v.AssemblyAccessionVersion + '&from=' + v.start + '&to=' + v.stop;
            }
        });
        return url;
    },

    render: function() {
        var clinvar_id = this.state.clinvar_id;
        var car_id = this.state.car_id;
        var dbSNP_id = this.state.dbSNP_id;
        var nucleotide_change = this.state.nucleotide_change;
        var molecular_consequence = this.state.molecular_consequence;
        var protein_change = this.state.protein_change;
        var ensembl_data = this.state.ensembl_transcripts;
        var sequence_location = this.state.sequence_location;
        var gene_symbol = this.state.gene_symbol;
        var uniprot_id = this.state.uniprot_id;
        var GRCh37 = this.state.hgvs_GRCh37;
        var GRCh38 = this.state.hgvs_GRCh38;
        var primary_transcript = this.state.primary_transcript;
        var self = this;

        return (

IDs

                            {(clinvar_id) ?
ClinVar Variation ID: {clinvar_id}
 : null}
                            {(car_id) ?
ClinGen Allele ID: {car_id}
 : null}
                            {(dbSNP_id) ?
dbSNP ID: {dbSNP_id}
 : null}

                    {(GRCh37 || GRCh38) ?

Genomic

                            {(GRCh38) ?
{GRCh38 + ' (GRCh38)'}
 : null}
                            {(GRCh37) ?
{GRCh37 + ' (GRCh37)'}
 : null}

                    : null}

Primary Transcript

                                Nucleotide Change
                                Protein Change
                                Molecular Consequence

                                    {(primary_transcript) ? primary_transcript.nucleotide : '--'}

                                    {(primary_transcript) ? primary_transcript.protein : '--'}

                                    {(primary_transcript) ? primary_transcript.molecular : '--'}

All Transcripts

                                Nucleotide Change
                                Protein Change
                                Molecular Consequence

                            {ensembl_data.map(function(item, i) {
                                return (

                                        {item.hgvsc}
                                        {(item.hgvsp) ? item.hgvsp : '--'}

                                            {(item.consequence_terms) ? self.handleSOTerms(item.consequence_terms) : '--'}

                                );
                            })}

LinkOut to external resources

Variation Viewer [GRCh38 - GRCh37]

Ensembl Browser [GRCh38]

UCSC [GRCh38/hg38 - GRCh37/hg19]

UniProtKB

        );
    }
});
<commit_msg>Replaced instances of one-letter variables with descriptive names and added more comments<commit_after>'use strict';
var React = require('react');
var _ = require('underscore');
var moment = require('moment');
var globals = require('../../globals');
var RestMixin = require('../../rest').RestMixin;
var parseClinvar = require('../../../libs/parse-resources').parseClinvar;
var LocalStorageMixin = require('react-localstorage');
var SO_terms = require('./mapping/SO_term.json');

var external_url_map = globals.external_url_map;

// Display the curator data of the curation data
var CurationInterpretationBasicInfo = module.exports.CurationInterpretationBasicInfo = React.createClass({
    mixins: [RestMixin, LocalStorageMixin],

    propTypes: {
        data: React.PropTypes.object, // ClinVar data payload
        shouldFetchData: React.PropTypes.bool
    },

    getInitialState: function() {
        return {
            clinvar_id: null, // ClinVar ID
            car_id: null, // ClinGen Allele Registry ID
            dbSNP_id: null,
            nucleotide_change: [],
            molecular_consequence: [],
            protein_change: [],
            ensembl_transcripts: [],
            sequence_location: [],
            primary_transcript: {},
            hgvs_GRCh37: null,
            hgvs_GRCh38: null,
            gene_symbol: null,
            uniprot_id: null,
            shouldFetchData: false
        };
    },

    componentWillReceiveProps: function(nextProps) {
        this.setState({shouldFetchData: nextProps.shouldFetchData});
        if (this.state.shouldFetchData === true) {
            this.fetchRefseqData();
            this.fetchEnsemblData();
        }
    },

    // Retrieve the variant data from NCBI REST API
    fetchRefseqData: function() {
        //var refseq_data = {};
        var variant = this.props.data;
        var url = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=clinvar&rettype=variation&id=';
        if (variant) {
            var clinVarId = (variant.clinvarVariantId) ? variant.clinvarVariantId : 'Unknown';
            this.setState({
                clinvar_id: clinVarId,
                car_id: variant.carId,
                dbSNP_id: variant.dbSNPIds[0],
                hgvs_GRCh37: variant.hgvsNames.gRCh37,
                hgvs_GRCh38: variant.hgvsNames.gRCh38,
            });
            // Get ClinVar data via the parseClinvar method defined in parse-resources.js
            this.getRestDataXml(url + clinVarId).then(xml => {
                // Passing 'true' option to invoke 'mixin' function
                // To extract more ClinVar data for 'Basic Information' tab
                var variantData = parseClinvar(xml, true);
                this.setState({
                    nucleotide_change: variantData.RefSeqTranscripts.NucleotideChangeList,
                    protein_change: variantData.RefSeqTranscripts.ProteinChangeList,
                    molecular_consequence: variantData.RefSeqTranscripts.MolecularConsequenceList,
                    sequence_location: variantData.allele.SequenceLocation,
                    gene_symbol: variantData.gene.symbol
                });
                // Calling method to get uniprot id for LinkOut link
                this.getUniprotId(this.state.gene_symbol);
                // Calling method to identify nucleotide change, protein change and molecular consequence
                // Used for UI display in the Primary Transcript table
                this.getPrimaryTranscript(variantData.clinvarVariantTitle, this.state.nucleotide_change, this.state.protein_change, this.state.molecular_consequence);
            }).catch(function(e) {
                console.log('RefSeq Fetch Error=: %o', e);
            });
        }
    },

    // Create primary transcript object
    // Called in the "fetchRefseqData" method after various states are set
    getPrimaryTranscript: function(str, nucleotide_change, protein_change, molecular_consequence) {
        var transcript = {}, SO_id_term = '';
        var result = nucleotide_change.find((n) => str.indexOf(n.AccessionVersion) > -1);
        if (result && molecular_consequence.length) {
            var item = molecular_consequence.find((x) => x.HGVS === result.HGVS);
            // 'SO_terms' is defined via requiring external mapping file
            var found = SO_terms.find((entry) => entry.SO_id === item.SOid);
            SO_id_term = found.SO_term + ' ' + found.SO_id;
            // FIXME: temporarily use protein_change[0] due to lack of mapping
            // associated with nucleotide transcript in ClinVar data
            transcript = {
                "nucleotide": result.HGVS,
                "protein": protein_change[0].HGVS,
                "molecular": SO_id_term
            };
        }
        this.setState({primary_transcript: transcript});
    },

    // Retrieve variant data from Ensembl REST API
    fetchEnsemblData: function() {
        var variant = this.props.data;
        if (variant) {
            var rsid = (variant.dbSNPIds) ? variant.dbSNPIds[0] : 'Unknown';
            this.getRestData('http://rest.ensembl.org/vep/human/id/' + rsid + '?content-type=application/json&hgvs=1&protein=1&xref_refseq=1&domains=1').then(response => {
                this.setState({ensembl_transcripts: response[0].transcript_consequences});
            }).catch(function(e) {
                console.log('Ensembl Fetch Error=: %o', e);
            });
        }
    },

    // Use Ensembl consequence_terms to find matching SO_id and SO_term pair
    // Then concatenate all pairs into string
    handleSOTerms: function(array) {
        var newArray = [],
            SO_id_term,
            newStr = '';
        for (let value of array.values()) {
            // 'SO_terms' is defined via requiring external mapping file
            var found = SO_terms.find((entry) => entry.SO_term === value);
            SO_id_term = found.SO_term + ' ' + found.SO_id;
            newArray.push(SO_id_term);
        }
        // Concatenate SO terms with comma delimiter
        for (let [key, value] of newArray.entries()) {
            if (key === 0) {
                newStr += value;
            }
            if (key > 0) {
                newStr += ', ' + value;
            }
        }
        return newStr;
    },

    // Find gene_id from Ensembl REST API response
    // Used to construct LinkOut URL to Ensembl Browser
    getGeneId: function(array) {
        var gene_id = '';
        if (array.length && array[0].gene_id) {
            gene_id = array[0].gene_id;
        }
        return gene_id;
    },

    // Find Uniprot id given the gene_symbol from ClinVar
    // Called in the "fetchRefseqData" method after gene_symbol state is set
    // Used to construct LinkOut URL to Uniprot
    getUniprotId: function(gene_symbol) {
        if (gene_symbol) {
            this.getRestData('http://rest.genenames.org/fetch/symbol/' + gene_symbol).then(result => {
                this.setState({uniprot_id: result.response.docs[0].uniprot_ids[0]});
            }).catch(function(e) {
                console.log('HGNC Fetch Error=: %o', e);
            });
        }
    },

    // Construct LinkOut URLs to UCSC Viewer
    // For both GRCh38/hg38 and GRCh37/hg19
    ucscViewerURL: function(array, db, assembly) {
        var url = '';
        array.forEach(SequenceLocationObj => {
            if (SequenceLocationObj.Assembly === assembly) {
                url = 'https://genome.ucsc.edu/cgi-bin/hgTracks?db=' + db + '&position=Chr' + SequenceLocationObj.Chr + '%3A' + SequenceLocationObj.start + '-' + SequenceLocationObj.stop;
            }
        });
        return url;
    },

    // Construct LinkOut URLs to NCBI Variation Viewer
    // For both GRCh38 and GRCh37
    variationViewerURL: function(array, gene_symbol, assembly) {
        var url = '';
        array.forEach(SequenceLocationObj => {
            if (SequenceLocationObj.Assembly === assembly) {
                url = 'http://www.ncbi.nlm.nih.gov/variation/view/?chr=' + SequenceLocationObj.Chr + '&q=' + gene_symbol + '&assm=' + SequenceLocationObj.AssemblyAccessionVersion + '&from=' + SequenceLocationObj.start + '&to=' + SequenceLocationObj.stop;
            }
        });
        return url;
    },

    render: function() {
        var clinvar_id = this.state.clinvar_id;
        var car_id = this.state.car_id;
        var dbSNP_id = this.state.dbSNP_id;
        var nucleotide_change = this.state.nucleotide_change;
        var molecular_consequence = this.state.molecular_consequence;
        var protein_change = this.state.protein_change;
        var ensembl_data = this.state.ensembl_transcripts;
        var sequence_location = this.state.sequence_location;
        var gene_symbol = this.state.gene_symbol;
        var uniprot_id = this.state.uniprot_id;
        var GRCh37 = this.state.hgvs_GRCh37;
        var GRCh38 = this.state.hgvs_GRCh38;
        var primary_transcript = this.state.primary_transcript;
        var self = this;

        return (

IDs

                            {(clinvar_id) ?
ClinVar Variation ID: {clinvar_id}
 : null}
                            {(car_id) ?
ClinGen Allele ID: {car_id}
 : null}
                            {(dbSNP_id) ?
dbSNP ID: {dbSNP_id}
 : null}

                    {(GRCh37 || GRCh38) ?

Genomic

                            {(GRCh38) ?
{GRCh38 + ' (GRCh38)'}
 : null}
                            {(GRCh37) ?
{GRCh37 + ' (GRCh37)'}
 : null}

                    : null}

Primary Transcript

                                Nucleotide Change
                                Protein Change
                                Molecular Consequence

                                    {(primary_transcript) ? primary_transcript.nucleotide : '--'}

                                    {(primary_transcript) ? primary_transcript.protein : '--'}

                                    {(primary_transcript) ? primary_transcript.molecular : '--'}

All Transcripts

                                Nucleotide Change
                                Protein Change
                                Molecular Consequence

                            {ensembl_data.map(function(item, i) {
                                return (

                                        {item.hgvsc}
                                        {(item.hgvsp) ? item.hgvsp : '--'}

                                            {(item.consequence_terms) ? self.handleSOTerms(item.consequence_terms) : '--'}

                                );
                            })}

LinkOut to external resources

Variation Viewer [GRCh38 - GRCh37]

Ensembl Browser [GRCh38]

UCSC [GRCh38/hg38 - GRCh37/hg19]

UniProtKB

        );
    }
});
<|endoftext|>


<commit_before>$(function() {
    function NavigationViewModel(parameters) {
        var self = this;

        self.loginState = parameters[0];
        self.appearance = parameters[1];
        self.settings = parameters[2];
        self.usersettings = parameters[3];

        self.systemActions = self.settings.system_actions;

        self.appearanceClasses = ko.computed(function() {
            var classes = self.appearance.color();
            if (self.appearance.colorTransparent()) {
                classes += " transparent";
            }
            return classes;
        });

        self.triggerAction = function(action) {
            var callback = function() {
                $.ajax({
                    url: API_BASEURL + "system",
                    type: "POST",
                    dataType: "json",
                    data: "action=" + action.action,
                    success: function() {
                        new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"});
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        var error = "
" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: action.name}) + "
";
                        error += pnotifyAdditionalInfo("
" + jqXHR.responseText + "
");
                        new PNotify({title: gettext("Error"), text: error, type: "error", hide: false});
                    }
                })
            };
            if (action.confirm) {
                showConfirmationDialog(action.confirm, function (e) {
                    callback();
                });
            } else {
                callback();
            }
        }
    }

    OCTOPRINT_VIEWMODELS.push([
        NavigationViewModel,
        ["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel"],
        "#navbar"
    ]);
});<commit_msg>System commands with ignore set to true also ignore http errors<commit_after>$(function() {
    function NavigationViewModel(parameters) {
        var self = this;

        self.loginState = parameters[0];
        self.appearance = parameters[1];
        self.settings = parameters[2];
        self.usersettings = parameters[3];

        self.systemActions = self.settings.system_actions;

        self.appearanceClasses = ko.computed(function() {
            var classes = self.appearance.color();
            if (self.appearance.colorTransparent()) {
                classes += " transparent";
            }
            return classes;
        });

        self.triggerAction = function(action) {
            var callback = function() {
                $.ajax({
                    url: API_BASEURL + "system",
                    type: "POST",
                    dataType: "json",
                    data: "action=" + action.action,
                    success: function() {
                        new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"});
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        if (!action.hasOwnProperty("ignore") || !action.ignore) {
                            var error = "
" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: action.name}) + "
";
                            error += pnotifyAdditionalInfo("
" + jqXHR.responseText + "
");
                            new PNotify({title: gettext("Error"), text: error, type: "error", hide: false});
                        }
                    }
                })
            };
            if (action.confirm) {
                showConfirmationDialog(action.confirm, function (e) {
                    callback();
                });
            } else {
                callback();
            }
        }
    }

    OCTOPRINT_VIEWMODELS.push([
        NavigationViewModel,
        ["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel"],
        "#navbar"
    ]);
});
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @author       Felipe Alfonso <@bitnenfer>
 * @author       Matthew Groves <@doormat>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Generate shader source to test maximum ifs.
 *
 * @private
 * @ignore
 * @param {number} maxIfs - The number of if statements to generate
 */
function GenerateSrc (maxIfs)
{
    var src = '';

    for (var i = 0; i < maxIfs; ++i)
    {
        if (i > 0)
        {
            src += '\nelse ';
        }

        if (i < maxIfs - 1)
        {
            src += 'if(test == ' + i + '.0){}';
        }
    }

    return src;
}

/**
 * @namespace Phaser.Renderer.WebGL.Utils
 * @since 3.0.0
 */
module.exports = {

    /**
     * Packs four floats on a range from 0.0 to 1.0 into a single Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintFromFloats
     * @since 3.0.0
     *
     * @param {number} r - Red component in a range from 0.0 to 1.0
     * @param {number} g - Green component in a range from 0.0 to 1.0
     * @param {number} b - Blue component in a range from 0.0 to 1.0
     * @param {number} a - Alpha component in a range from 0.0 to 1.0
     *
     * @return {number} The packed RGBA values as a Uint32.
     */
    getTintFromFloats: function (r, g, b, a)
    {
        var ur = ((r * 255) | 0) & 0xff;
        var ug = ((g * 255) | 0) & 0xff;
        var ub = ((b * 255) | 0) & 0xff;
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | (ur << 16) | (ug << 8) | ub) >>> 0;
    },

    /**
     * Packs a Uint24, representing RGB components, with a Float32, representing
     * the alpha component, with a range between 0.0 and 1.0 and return a Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlpha
     * @since 3.0.0
     *
     * @param {number} rgb - Uint24 representing RGB components
     * @param {number} a - Float32 representing Alpha component
     *
     * @return {number} Packed RGBA as Uint32
     */
    getTintAppendFloatAlpha: function (rgb, a)
    {
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | rgb) >>> 0;
    },

    /**
     * Packs a Uint24, representing RGB components, with a Float32, representing
     * the alpha component, with a range between 0.0 and 1.0 and return a
     * swizzled Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlphaAndSwap
     * @since 3.0.0
     *
     * @param {number} rgb - Uint24 representing RGB components
     * @param {number} a - Float32 representing Alpha component
     *
     * @return {number} Packed RGBA as Uint32
     */
    getTintAppendFloatAlphaAndSwap: function (rgb, a)
    {
        var ur = ((rgb >> 16) | 0) & 0xff;
        var ug = ((rgb >> 8) | 0) & 0xff;
        var ub = (rgb | 0) & 0xff;
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | (ub << 16) | (ug << 8) | ur) >>> 0;
    },

    /**
     * Unpacks a Uint24 RGB into an array of floats of ranges of 0.0 and 1.0
     *
     * @function Phaser.Renderer.WebGL.Utils.getFloatsFromUintRGB
     * @since 3.0.0
     *
     * @param {number} rgb - RGB packed as a Uint24
     *
     * @return {array} Array of floats representing each component as a float
     */
    getFloatsFromUintRGB: function (rgb)
    {
        var ur = ((rgb >> 16) | 0) & 0xff;
        var ug = ((rgb >> 8) | 0) & 0xff;
        var ub = (rgb | 0) & 0xff;

        return [ ur / 255, ug / 255, ub / 255 ];
    },

    /**
     * Check to see how many texture units the GPU supports, based on the given config value.
     * Then tests this against the maximum number of iterations GLSL can support.
     *
     * @function Phaser.Renderer.WebGL.Utils.checkShaderMax
     * @since 3.50.0
     *
     * @param {WebGLRenderingContext} gl - The WebGLContext used to create the shaders.
     * @param {number} maxTextures - The Game Config maxTextures value.
     *
     * @return {number} The number of texture units that is supported by this browser and GPU.
     */
    checkShaderMax: function (gl, maxTextures)
    {
        if (!maxTextures || maxTextures === -1)
        {
            maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
        }

        var shader = gl.createShader(gl.FRAGMENT_SHADER);

        var fragTemplate = [
            'precision mediump float;',
            'void main(void){',
            'float test = 0.1;',
            '%forloop%',
            'gl_FragColor = vec4(0.0);',
            '}'
        ].join('\n');

        // eslint-disable-next-line no-constant-condition
        while (true)
        {
            var fragmentSrc = fragTemplate.replace(/%forloop%/gi, GenerateSrc(maxTextures));

            gl.shaderSource(shader, fragmentSrc);
            gl.compileShader(shader);

            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
            {
                maxTextures = (maxTextures / 2) | 0;
            }
            else
            {
                // valid!
                break;
            }
        }

        return maxTextures;
    },

    /**
     * Checks the given Fragment Shader Source for `%count%` and `%forloop%` declarations and
     * replaces those with GLSL code for setting `texture = texture2D(uMainSampler[i], outTexCoord)`.
     *
     * @function Phaser.Renderer.WebGL.Utils.parseFragmentShaderMaxTextures
     * @since 3.50.0
     *
     * @param {string} fragmentShaderSource - The Fragment Shader source code to operate on.
     * @param {number} maxTextures - The number of maxTextures value.
     *
     * @return {string} The modified Fragment Shader source.
     */
    parseFragmentShaderMaxTextures: function (fragmentShaderSource, maxTextures)
    {
        var src = '';

        for (var i = 0; i < maxTextures; i++)
        {
            if (i > 0)
            {
                src += '\n\telse ';
            }

            if (i < maxTextures - 1)
            {
                src += 'if (outTexId < ' + i + '.5)';
            }

            src += '\n\t{';
            src += '\n\t\ttexture = texture2D(uMainSampler[' + i + '], outTexCoord);';
            src += '\n\t}';
        }

        fragmentShaderSource = fragmentShaderSource.replace(/%count%/gi, maxTextures.toString());

        return fragmentShaderSource.replace(/%forloop%/gi, src);
    }
};
<commit_msg>Don't `.replace` non-strings.<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @author       Felipe Alfonso <@bitnenfer>
 * @author       Matthew Groves <@doormat>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

/**
 * Generate shader source to test maximum ifs.
 *
 * @private
 * @ignore
 * @param {number} maxIfs - The number of if statements to generate
 */
function GenerateSrc (maxIfs)
{
    var src = '';

    for (var i = 0; i < maxIfs; ++i)
    {
        if (i > 0)
        {
            src += '\nelse ';
        }

        if (i < maxIfs - 1)
        {
            src += 'if(test == ' + i + '.0){}';
        }
    }

    return src;
}

/**
 * @namespace Phaser.Renderer.WebGL.Utils
 * @since 3.0.0
 */
module.exports = {

    /**
     * Packs four floats on a range from 0.0 to 1.0 into a single Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintFromFloats
     * @since 3.0.0
     *
     * @param {number} r - Red component in a range from 0.0 to 1.0
     * @param {number} g - Green component in a range from 0.0 to 1.0
     * @param {number} b - Blue component in a range from 0.0 to 1.0
     * @param {number} a - Alpha component in a range from 0.0 to 1.0
     *
     * @return {number} The packed RGBA values as a Uint32.
     */
    getTintFromFloats: function (r, g, b, a)
    {
        var ur = ((r * 255) | 0) & 0xff;
        var ug = ((g * 255) | 0) & 0xff;
        var ub = ((b * 255) | 0) & 0xff;
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | (ur << 16) | (ug << 8) | ub) >>> 0;
    },

    /**
     * Packs a Uint24, representing RGB components, with a Float32, representing
     * the alpha component, with a range between 0.0 and 1.0 and return a Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlpha
     * @since 3.0.0
     *
     * @param {number} rgb - Uint24 representing RGB components
     * @param {number} a - Float32 representing Alpha component
     *
     * @return {number} Packed RGBA as Uint32
     */
    getTintAppendFloatAlpha: function (rgb, a)
    {
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | rgb) >>> 0;
    },

    /**
     * Packs a Uint24, representing RGB components, with a Float32, representing
     * the alpha component, with a range between 0.0 and 1.0 and return a
     * swizzled Uint32
     *
     * @function Phaser.Renderer.WebGL.Utils.getTintAppendFloatAlphaAndSwap
     * @since 3.0.0
     *
     * @param {number} rgb - Uint24 representing RGB components
     * @param {number} a - Float32 representing Alpha component
     *
     * @return {number} Packed RGBA as Uint32
     */
    getTintAppendFloatAlphaAndSwap: function (rgb, a)
    {
        var ur = ((rgb >> 16) | 0) & 0xff;
        var ug = ((rgb >> 8) | 0) & 0xff;
        var ub = (rgb | 0) & 0xff;
        var ua = ((a * 255) | 0) & 0xff;

        return ((ua << 24) | (ub << 16) | (ug << 8) | ur) >>> 0;
    },

    /**
     * Unpacks a Uint24 RGB into an array of floats of ranges of 0.0 and 1.0
     *
     * @function Phaser.Renderer.WebGL.Utils.getFloatsFromUintRGB
     * @since 3.0.0
     *
     * @param {number} rgb - RGB packed as a Uint24
     *
     * @return {array} Array of floats representing each component as a float
     */
    getFloatsFromUintRGB: function (rgb)
    {
        var ur = ((rgb >> 16) | 0) & 0xff;
        var ug = ((rgb >> 8) | 0) & 0xff;
        var ub = (rgb | 0) & 0xff;

        return [ ur / 255, ug / 255, ub / 255 ];
    },

    /**
     * Check to see how many texture units the GPU supports, based on the given config value.
     * Then tests this against the maximum number of iterations GLSL can support.
     *
     * @function Phaser.Renderer.WebGL.Utils.checkShaderMax
     * @since 3.50.0
     *
     * @param {WebGLRenderingContext} gl - The WebGLContext used to create the shaders.
     * @param {number} maxTextures - The Game Config maxTextures value.
     *
     * @return {number} The number of texture units that is supported by this browser and GPU.
     */
    checkShaderMax: function (gl, maxTextures)
    {
        if (!maxTextures || maxTextures === -1)
        {
            maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
        }

        var shader = gl.createShader(gl.FRAGMENT_SHADER);

        var fragTemplate = [
            'precision mediump float;',
            'void main(void){',
            'float test = 0.1;',
            '%forloop%',
            'gl_FragColor = vec4(0.0);',
            '}'
        ].join('\n');

        // eslint-disable-next-line no-constant-condition
        while (true)
        {
            var fragmentSrc = fragTemplate.replace(/%forloop%/gi, GenerateSrc(maxTextures));

            gl.shaderSource(shader, fragmentSrc);
            gl.compileShader(shader);

            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
            {
                maxTextures = (maxTextures / 2) | 0;
            }
            else
            {
                // valid!
                break;
            }
        }

        return maxTextures;
    },

    /**
     * Checks the given Fragment Shader Source for `%count%` and `%forloop%` declarations and
     * replaces those with GLSL code for setting `texture = texture2D(uMainSampler[i], outTexCoord)`.
     *
     * @function Phaser.Renderer.WebGL.Utils.parseFragmentShaderMaxTextures
     * @since 3.50.0
     *
     * @param {string} fragmentShaderSource - The Fragment Shader source code to operate on.
     * @param {number} maxTextures - The number of maxTextures value.
     *
     * @return {string} The modified Fragment Shader source.
     */
    parseFragmentShaderMaxTextures: function (fragmentShaderSource, maxTextures)
    {
        if (!fragmentShaderSource)
        {
            return '';
        }

        var src = '';

        for (var i = 0; i < maxTextures; i++)
        {
            if (i > 0)
            {
                src += '\n\telse ';
            }

            if (i < maxTextures - 1)
            {
                src += 'if (outTexId < ' + i + '.5)';
            }

            src += '\n\t{';
            src += '\n\t\ttexture = texture2D(uMainSampler[' + i + '], outTexCoord);';
            src += '\n\t}';
        }

        fragmentShaderSource = fragmentShaderSource.replace(/%count%/gi, maxTextures.toString());

        return fragmentShaderSource.replace(/%forloop%/gi, src);
    }
};
<|endoftext|>


<commit_before>const CopyWebpackPlugin = require('copy-webpack-plugin')
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin')
const HtmlInsertTagWebpackPlugin = require('html-insert-tag-webpack-plugin')
const path = require('path')
const plugins = require('./webpack.plugins')
const webpack = require('webpack')
const rules = require('./webpack.rules')

rules.push({
  test: /\.css$/,
  use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
})

module.exports = {
  module: {
    rules,
  },
  output: { chunkFilename: 'main_window/[name].chunk.js', publicPath: '/' },
  plugins: [
    ...plugins,
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(
        process.env.NODE_ENV ?? 'development'
      ),
      'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN),
      'process.type': '"renderer"',
    }),
    new HtmlInsertTagWebpackPlugin([
      {
        tagName: 'base',
        inject: {
          tagName: 'head',
          location: 'after',
        },
        attributes: {
          href: 'stencila://rse',
        },
      },
    ]),
    new CspHtmlWebpackPlugin(
      {
        'base-uri': "'self' stencila://rse",
        'default-src': 'stencila://rse',
        'frame-src': 'http://127.0.0.1:9000',
        'script-src': ["'self'"],
        'img-src': ["'self'", 'data:', 'local:'],
        'style-src': [
          "'self'",
          "'unsafe-inline'",
          'https://unpkg.com/',
          'https://fonts.googleapis.com/',
        ],
        'connect-src': "'self'",
        'font-src': [
          "'self'",
          'https://fonts.gstatic.com/',
          'https://unpkg.com/',
        ],
      },
      {
        hashEnabled: {
          'script-src': true,
          'style-src': true,
        },
        nonceEnabled: {
          'script-src': true,
          'style-src': false,
        },
      }
    ),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, 'www', 'build'),
          to: 'build',
        },
        {
          from: path.resolve(__dirname, 'www', 'assets'),
          to: 'assets',
        },
        {
          from: path.resolve(__dirname, 'www', 'manifest.json'),
          to: '.',
        },
      ],
    }),
  ],
  resolve: {
    mainFields: ['browser', 'module', 'main'],
    extensions: ['.js', '.mjs', '.ts', '.css'],
  },
}
<commit_msg>fix(Preview): Broaden range of document preview server ports<commit_after>const CopyWebpackPlugin = require('copy-webpack-plugin')
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin')
const HtmlInsertTagWebpackPlugin = require('html-insert-tag-webpack-plugin')
const path = require('path')
const plugins = require('./webpack.plugins')
const webpack = require('webpack')
const rules = require('./webpack.rules')

rules.push({
  test: /\.css$/,
  use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
})

module.exports = {
  module: {
    rules,
  },
  output: { chunkFilename: 'main_window/[name].chunk.js', publicPath: '/' },
  plugins: [
    ...plugins,
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(
        process.env.NODE_ENV ?? 'development'
      ),
      'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN),
      'process.type': '"renderer"',
    }),
    new HtmlInsertTagWebpackPlugin([
      {
        tagName: 'base',
        inject: {
          tagName: 'head',
          location: 'after',
        },
        attributes: {
          href: 'stencila://rse',
        },
      },
    ]),
    new CspHtmlWebpackPlugin(
      {
        'base-uri': "'self' stencila://rse",
        'default-src': 'stencila://rse',
        'frame-src': 'http://127.0.0.1:*',
        'script-src': ["'self'"],
        'img-src': ["'self'", 'data:', 'local:'],
        'style-src': [
          "'self'",
          "'unsafe-inline'",
          'https://unpkg.com/',
          'https://fonts.googleapis.com/',
        ],
        'connect-src': "'self'",
        'font-src': [
          "'self'",
          'https://fonts.gstatic.com/',
          'https://unpkg.com/',
        ],
      },
      {
        hashEnabled: {
          'script-src': true,
          'style-src': true,
        },
        nonceEnabled: {
          'script-src': true,
          'style-src': false,
        },
      }
    ),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, 'www', 'build'),
          to: 'build',
        },
        {
          from: path.resolve(__dirname, 'www', 'assets'),
          to: 'assets',
        },
        {
          from: path.resolve(__dirname, 'www', 'manifest.json'),
          to: '.',
        },
      ],
    }),
  ],
  resolve: {
    mainFields: ['browser', 'module', 'main'],
    extensions: ['.js', '.mjs', '.ts', '.css'],
  },
}
<|endoftext|>


<commit_before>// --- Modules --- //

const moduleLoader = require( './support/moduleLoader' )

const utility = moduleLoader( 'utility' )

const Server  = require( './class/Server' ).Server
const App     = require( './class/App' ).App
const GUI     = require( './class/GUI' ).GUI
const Storage = require( './class/Storage' ).Storage

// --- Functions --- //

const debug = message => {
  return utility.debug( 'magenta', 'yacona', message )
}

// --- Store : Declare private member and method --- //

const store = new WeakMap()

// --- Yacona Class --- //

class Yacona {

  constructor( options ){
    options = options || {}

    const server = new Server( {
      port: options.port
    } )

    let socketFunctions = {}

    const io = require( 'socket.io' )( server.getServer() )

    // --- Store --- //

    store.set( this, {
      server         : server,
      chdir          : options.chdir || process.cwd(),
      prefix         : options.prefix || null,
      io             : io,
      modules        : {},
      clientModules  : {},
      apps           : {},
      socketFunctions: {},
      listeners      : {},
      connected      : {},
      on             : {}, // connected
      gui            : new GUI( this.prefix ),
      storage        : new Storage( {
        prefix   : this.prefix,
        directory: this.chdir
      } )
    } )

    const self = store.get( this )
    debug( 'Prefix : ' + self.prefix )
    debug( 'Working directory : ' + self.chdir )
    debug( 'Port : ' + self.server.getPort() )
  }

  getPrefix(){
    return store.get( this ).prefix
  }

  getChdir(){
    return store.get( this ).chdir
  }

  getApps(){
    return store.get( this ).apps
  }

  // --- Support Modules --- //

  addModule( name, place ){
    if( name === undefined || place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )
    self.modules[name] = place
    return true
  }

  removeModule( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    delete self.modules[name]
    return true
  }

  loadModule( name ){
    const self = store.get( this )
    if( name === undefined || self.modules[name] === undefined )
      return moduleLoader( name )
    return require( self.modules[name] )
  }

  // --- Support Client Modules --- //

  addClientModule( name, place ){
    if( name === undefined || place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )

    self.clientModules[name] = place
    self.server.get( '/modules/' + name
                   , ( _, response ) => response.sendFile( self.clientModules[name] ) )
    return true
  }

  removeClientModule( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    delete self.clientModules[name]
    self.server.removeGet( '/modules/' + name )
    return true
  }

  // --- Socket --- //

  addWebSocket( name, callback ){
    console.log( name, callback )
    if( name === undefined || callback === undefined )
      return false

    const self = store.get( this )

    self.io.of( name ).on( 'connection', callback )

    debug( 'Add socket namespace : ' + name )
    self.socketFunctions[name] = callback

    return true
  }

  removeWebSocket( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    const io = self.io

    const namespace = self.io.of( name )
    const connected = Object.keys( namespace.connected )
    connected.forEach( socketId => {
      namespace.connected[socketId].disconnect()
    } )

    namespace.removeAllListeners()
    delete self.io.nsps[name]

    debug( 'Remove socket namespace : ' + name )
    delete self.socketFunctions[name]
    return true
  }

  // --- Documents --- //

  saveDocument( filePath, content ){
    const self = store.get( this )
    return self.storage.saveDocument( filePath, content )
  }

  loadDocument( filePath ){
    const self = store.get( this )
    return self.storage.loadDocument( filePath )
  }

  saveAppData( filePath, content ){
    const self = store.get( this )
    return self.storage.saveAppData( filePath, content )
  }

  loadAppData( filePath ){
    const self = store.get( this )
    return self.storage.loadAppData( filePath )
  }

  // --- Express --- //

  use( ...args ){
    const self = store.get( this )
    return self.server.use.apply( self.server, args )
  }

  get( ...args ){
    const self = store.get( this )
    return self.server.get.apply( self.server, args )
  }

  post( ...args ){
    const self = store.get( this )
    return self.server.post.apply( self.server, args )
  }

  put( ...args ){
    const self = store.get( this )
    return self.server.put.apply( self.server, args )
  }

  delete( ...args ){
    const self = store.get( this )
    return self.server.delete.apply( self.server, args )
  }

  removeGet( route ){
    const self = store.get( this )
    return self.server.removeGet( route )
  }

  removePost( route ){
    const self = store.get( this )
    return self.server.removePost( route )
  }

  removePut( route ){
    const self = store.get( this )
    return self.server.removePut( route )
  }

  removeDelete( route ){
    const self = store.get( this )
    return self.server.removeDelete( route )
  }

  getPort(){
    return store.get( this ).server.getPort()
  }

  getUrl(){
    return '127.0.0.1:' + String( this.getPort() )
  }

  // --- App --- //

  attachApp( place ){
    if( place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )

    let app  = new App( this, place )
    let name = app.getName()

    if( self.apps[name] !== undefined ){
      app = undefined
      return false
    }

    self.apps[name] = app

    return app
  }

  detachApp( appName ){
    const self = store.get( this )
    let app

    if( typeof appName === 'string' )
      app = self.apps[appName]
    else if( typeof appName === 'object' && appName instanceof App )
      app = appName // App Instance Object

    appName = app.getName()

    app.close()

    delete self.apps[appName]

    return true
  }

  // --- Other Instance --- //

  c(){
    return store.get( this ).connected
  }

  connect( yacona ){
    if( yacona === undefined || yacona instanceof Yacona === false )
      return false

    const self = store.get( this )
    const name = yacona.getPrefix()

    if( self.connected[name] !== undefined )
      return false

    self.connected[name] = yacona
    yacona.connect( this )

    debug( 'Connected to ' + yacona.getPrefix() )

    return true
  }

  disconnect( yacona ){
    if( yacona === undefined || yacona instanceof Yacona === false )
      return false

    const self = store.get( this )
    const name = yacona.getPrefix()

    if( self.connected[name] === undefined )
      return false

    delete self.connected[name]
    yacona.disconnect( this )

    debug( 'Disconnected to ' + yacona.getPrefix() )

    return true
  }

  broadcast( name, data ){
    if( name === undefined )
      return false

    const self = store.get( this )

    for( let target in self.connected ){
      this.emit( target, name, data )
    }

    return true
  }

  emit( target, name, data ){
    if( typeof target !== 'string' )
      return false

    const self = store.get( this )

    if( self.connected[target] === undefined )
      return false

    self.connected[target].on( {
      signature: this.getPrefix(),
      name     : name,
      data     : data
    } )

    return true
  }

  // on( name, callback )
  // on( data )
  on( name, callback ){
    const self = store.get( this )

    if( typeof name === 'string' ){
      self.on[name] = callback
      return true
    }

    if( callback !== undefined || typeof name !== 'object' ){
      return false
    }

    let message = name

    if( message.signature === undefined || message.name === undefined ){
      return false
    }

    let fn = self.on[message.name]

    if( fn === undefined ){
      return false
    }

    fn( message.signature, message.data )

    return true
  }

  // --- Electron --- //

  createWindow( options ){
    return store.get( this ).gui.createWindow( options )
  }

  // appId => String
  // appId => Object ( Instance of BrowserWindow )
  destroyWindow( appId ){
    return store.get( this ).gui.destroyWindow( appId )
  }

  // --- On, Emit --- //

  addListener( name, callback ){
    const self = store.get( this )
    if( self.listeners[name] === undefined ){
      self.listeners[name] = callback
      return true
    }
    return false
  }

  // args : Array
  callListener( name, ...args ){
    const self = store.get( this )
    if( self.listeners[name] !== undefined ){
      return utility.status( undefined, self.listeners[name].apply( self.listeners[name], args ) )
    }
    return utility.status( false, undefined )
  }

  removeListener( name ){
    const self = store.get( this )
    if( self.listeners[name] !== undefined ){
      delete self.listeners[name]
      return true
    }
    return false
  }

  // --- Static --- //

  static loadModule( name ){
    return moduleLoader( name )
  }

}

module.exports.Yacona = Yacona
<commit_msg>Remove method called c<commit_after>// --- Modules --- //

const moduleLoader = require( './support/moduleLoader' )

const utility = moduleLoader( 'utility' )

const Server  = require( './class/Server' ).Server
const App     = require( './class/App' ).App
const GUI     = require( './class/GUI' ).GUI
const Storage = require( './class/Storage' ).Storage

// --- Functions --- //

const debug = message => {
  return utility.debug( 'magenta', 'yacona', message )
}

// --- Store : Declare private member and method --- //

const store = new WeakMap()

// --- Yacona Class --- //

class Yacona {

  constructor( options ){
    options = options || {}

    const server = new Server( {
      port: options.port
    } )

    let socketFunctions = {}

    const io = require( 'socket.io' )( server.getServer() )

    // --- Store --- //

    store.set( this, {
      server         : server,
      chdir          : options.chdir || process.cwd(),
      prefix         : options.prefix || null,
      io             : io,
      modules        : {},
      clientModules  : {},
      apps           : {},
      socketFunctions: {},
      listeners      : {},
      connected      : {},
      on             : {}, // connected
      gui            : new GUI( this.prefix ),
      storage        : new Storage( {
        prefix   : this.prefix,
        directory: this.chdir
      } )
    } )

    const self = store.get( this )
    debug( 'Prefix : ' + self.prefix )
    debug( 'Working directory : ' + self.chdir )
    debug( 'Port : ' + self.server.getPort() )
  }

  getPrefix(){
    return store.get( this ).prefix
  }

  getChdir(){
    return store.get( this ).chdir
  }

  getApps(){
    return store.get( this ).apps
  }

  // --- Support Modules --- //

  addModule( name, place ){
    if( name === undefined || place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )
    self.modules[name] = place
    return true
  }

  removeModule( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    delete self.modules[name]
    return true
  }

  loadModule( name ){
    const self = store.get( this )
    if( name === undefined || self.modules[name] === undefined )
      return moduleLoader( name )
    return require( self.modules[name] )
  }

  // --- Support Client Modules --- //

  addClientModule( name, place ){
    if( name === undefined || place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )

    self.clientModules[name] = place
    self.server.get( '/modules/' + name
                   , ( _, response ) => response.sendFile( self.clientModules[name] ) )
    return true
  }

  removeClientModule( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    delete self.clientModules[name]
    self.server.removeGet( '/modules/' + name )
    return true
  }

  // --- Socket --- //

  addWebSocket( name, callback ){
    console.log( name, callback )
    if( name === undefined || callback === undefined )
      return false

    const self = store.get( this )

    self.io.of( name ).on( 'connection', callback )

    debug( 'Add socket namespace : ' + name )
    self.socketFunctions[name] = callback

    return true
  }

  removeWebSocket( name ){
    if( name === undefined )
      return false

    const self = store.get( this )

    const io = self.io

    const namespace = self.io.of( name )
    const connected = Object.keys( namespace.connected )
    connected.forEach( socketId => {
      namespace.connected[socketId].disconnect()
    } )

    namespace.removeAllListeners()
    delete self.io.nsps[name]

    debug( 'Remove socket namespace : ' + name )
    delete self.socketFunctions[name]
    return true
  }

  // --- Documents --- //

  saveDocument( filePath, content ){
    const self = store.get( this )
    return self.storage.saveDocument( filePath, content )
  }

  loadDocument( filePath ){
    const self = store.get( this )
    return self.storage.loadDocument( filePath )
  }

  saveAppData( filePath, content ){
    const self = store.get( this )
    return self.storage.saveAppData( filePath, content )
  }

  loadAppData( filePath ){
    const self = store.get( this )
    return self.storage.loadAppData( filePath )
  }

  // --- Express --- //

  use( ...args ){
    const self = store.get( this )
    return self.server.use.apply( self.server, args )
  }

  get( ...args ){
    const self = store.get( this )
    return self.server.get.apply( self.server, args )
  }

  post( ...args ){
    const self = store.get( this )
    return self.server.post.apply( self.server, args )
  }

  put( ...args ){
    const self = store.get( this )
    return self.server.put.apply( self.server, args )
  }

  delete( ...args ){
    const self = store.get( this )
    return self.server.delete.apply( self.server, args )
  }

  removeGet( route ){
    const self = store.get( this )
    return self.server.removeGet( route )
  }

  removePost( route ){
    const self = store.get( this )
    return self.server.removePost( route )
  }

  removePut( route ){
    const self = store.get( this )
    return self.server.removePut( route )
  }

  removeDelete( route ){
    const self = store.get( this )
    return self.server.removeDelete( route )
  }

  getPort(){
    return store.get( this ).server.getPort()
  }

  getUrl(){
    return '127.0.0.1:' + String( this.getPort() )
  }

  // --- App --- //

  attachApp( place ){
    if( place === undefined )
      return false

    const self = store.get( this )

    if( place[0] !== '/' )
      place = utility.absPath( self.chdir, place )

    let app  = new App( this, place )
    let name = app.getName()

    if( self.apps[name] !== undefined ){
      app = undefined
      return false
    }

    self.apps[name] = app

    return app
  }

  detachApp( appName ){
    const self = store.get( this )
    let app

    if( typeof appName === 'string' )
      app = self.apps[appName]
    else if( typeof appName === 'object' && appName instanceof App )
      app = appName // App Instance Object

    appName = app.getName()

    app.close()

    delete self.apps[appName]

    return true
  }

  // --- Other Instance --- //

  connect( yacona ){
    if( yacona === undefined || yacona instanceof Yacona === false )
      return false

    const self = store.get( this )
    const name = yacona.getPrefix()

    if( self.connected[name] !== undefined )
      return false

    self.connected[name] = yacona
    yacona.connect( this )

    debug( 'Connected to ' + yacona.getPrefix() )

    return true
  }

  disconnect( yacona ){
    if( yacona === undefined || yacona instanceof Yacona === false )
      return false

    const self = store.get( this )
    const name = yacona.getPrefix()

    if( self.connected[name] === undefined )
      return false

    delete self.connected[name]
    yacona.disconnect( this )

    debug( 'Disconnected to ' + yacona.getPrefix() )

    return true
  }

  broadcast( name, data ){
    if( name === undefined )
      return false

    const self = store.get( this )

    for( let target in self.connected ){
      this.emit( target, name, data )
    }

    return true
  }

  emit( target, name, data ){
    if( typeof target !== 'string' )
      return false

    const self = store.get( this )

    if( self.connected[target] === undefined )
      return false

    self.connected[target].on( {
      signature: this.getPrefix(),
      name     : name,
      data     : data
    } )

    return true
  }

  // on( name, callback )
  // on( data )
  on( name, callback ){
    const self = store.get( this )

    if( typeof name === 'string' ){
      self.on[name] = callback
      return true
    }

    if( callback !== undefined || typeof name !== 'object' ){
      return false
    }

    let message = name

    if( message.signature === undefined || message.name === undefined ){
      return false
    }

    let fn = self.on[message.name]

    if( fn === undefined ){
      return false
    }

    fn( message.signature, message.data )

    return true
  }

  // --- Electron --- //

  createWindow( options ){
    return store.get( this ).gui.createWindow( options )
  }

  // appId => String
  // appId => Object ( Instance of BrowserWindow )
  destroyWindow( appId ){
    return store.get( this ).gui.destroyWindow( appId )
  }

  // --- On, Emit --- //

  addListener( name, callback ){
    const self = store.get( this )
    if( self.listeners[name] === undefined ){
      self.listeners[name] = callback
      return true
    }
    return false
  }

  // args : Array
  callListener( name, ...args ){
    const self = store.get( this )
    if( self.listeners[name] !== undefined ){
      return utility.status( undefined, self.listeners[name].apply( self.listeners[name], args ) )
    }
    return utility.status( false, undefined )
  }

  removeListener( name ){
    const self = store.get( this )
    if( self.listeners[name] !== undefined ){
      delete self.listeners[name]
      return true
    }
    return false
  }

  // --- Static --- //

  static loadModule( name ){
    return moduleLoader( name )
  }

}

module.exports.Yacona = Yacona
<|endoftext|>