<commit_before>//functionality of manticore with asynchronous behavior and dependencies for integration testing
var consuler;
var nomader = require('nomad-helper');
var core = require('./core.js');
var needle = require('needle');
var uuid = require('node-uuid');
var randomString = require('randomstring');
var exec = require('child_process').exec;
var fs = require('fs');
var ip = require('ip');
var logger = require('../lib/logger');
var AWS = require('aws-sdk');
AWS.config.update({region: process.env.AWS_REGION});
var ec2;
var nomadAddress;
var self;
var io;

module.exports = {
	init: function (address, socketIo, callback) {
		consuler = require('consul-helper')(address);
		//set the address
		nomadAddress = address + ":4646";
		logger.debug("Nomad address: " + nomadAddress);
		self = this; //keep a consistent context around
		io = socketIo;
		//set up AWS SDK. assume this EC2 instance has an IAM role so we don't need to put in extra credentials
		ec2 = new AWS.EC2();
		/*ec2.describeSecurityGroups({}, function (err, data) {
			console.log(data.SecurityGroups[16].IpPermissions);
			console.log(data.SecurityGroups[16].IpPermissionsEgress);
		});*/
		//make a security group because why not
		var params = {
			Description: "Im computer generated!",
			GroupName: "Please delete me",
			IpPermissions: {},
			IpPermissionsEgress: {}
		};
		ec2.createSecurityGroup(params, function (err, data) {
			console.log(err);
			console.log(data);
		});
		consuler.setKeyValue("manticore/filler", "Keep me here please!", function () {
			callback();
		});
	},
	startWatches: function (postUrl) {
		//set a watch for the KV store
		consuler.watchKVStore("manticore/", keysWatch);

		function keysWatch (keys) {
			//if keys is undefined, set it to an empty array
			keys = keys || [];
			keys = core.filterKeys(keys, "manticore/requests/");
			logger.debug("KV store update (after filtering)");
			logger.debug(keys);

			//set up an expectation that we want the values of <keys.length> keys.
			//send a callback function about what to do once we get all the values
			var expecting = core.expect(keys.length, function (job) {
				core.checkJobs(job, function () {//there are tasks. submit the job
					logger.debug("Core tasks exist");
					job.submitJob(nomadAddress, function (result) {
						logger.debug(result);
					});
				}, function () { //there are no tasks. delete the job
					logger.debug("No core tasks");
					self.deleteJob("core", function () {});
				});
			});
			for (let i = 0; i < keys.length; i++) {
				//go through each key and get their value. send the value to expecting
				//expecting will keep track of how many more keys are left
				consuler.getKeyValue(keys[i], function (value) {
					expecting.send(keys[i], value);
				});
			}
		}

		//set up a watch for all services
		consuler.watchServices(serviceWatch);

		function serviceWatch (services) {
			logger.debug("Services update");
			//services updated. get information about core and hmi if possible
			let cores = services.filter("core-master");
			let hmis = services.filter("hmi-master");
			logger.debug("Core services: " + cores.length);
			logger.debug("Hmi services: " + hmis.length);
			//for every core service, ensure it has a corresponding HMI
			var job = nomader.createJob("hmi");
			core.addHmisToJob(job, cores);
			//submit the job. if there are no task groups then
			//we want to remove the job completely. delete the job in that case
			core.checkJobs(job, function () {//there are tasks
				logger.debug("HMI tasks exist");
				job.submitJob(nomadAddress, function (result) {
					logger.debug(result);
				});
			}, function () { //there are no tasks
				logger.debug("No HMI tasks");
				self.deleteJob("hmi", function () {});
			});

			var pairs = core.findPairs(cores, hmis, function (userId) {
				//remove user from KV store because the HMI has no paired core which
				//indicates that the user exited the HMI page and is done with their instance
				self.deleteKey("manticore/requests/" + userId, function () {});
			});
			pairs = {
				pairs: pairs
			};
			//post all pairs at once
			logger.info(pairs);
			needle.post(postUrl, pairs, function (err, res) {
			});

			//if NGINX_OFF was not set to "true". write the file and reload nginx
			core.checkNginxFlag(function () {
				//create an nginx file and write it so that nginx notices it
				//use the pairs because that has information about what addresses to use
				//NOTE: the user that runs manticore should own this directory or it may not write to the file!
				logger.debug("Updating Nginx conf files");
				var nginxFiles = core.generateNginxFiles(pairs);
			    fs.writeFile(process.env.NGINX_MAIN_DIRECTORY+"/manticore.conf", nginxFiles[0], function (err) {
			    	if (err) {
			    		logger.error(err);
			    	}
				    //the file for TCP server blocks
				    fs.writeFile(process.env.NGINX_TCP_DIRECTORY+"/manticore.conf", nginxFiles[1], function (err) {
				    	if (err) {
			    			logger.error(err);
			    		}
				    	//done! restart nginx
				    	exec("sudo service nginx reload", function (err, stdout, stderr) {
				    		if (stdout) {
				    			logger.debug(stdout);
				    		}
				    		if (stderr) {
				    			logger.error(stderr);
				    		}
				    	});
				    });
			    });

			}, function () {//NGINX_OFF is set to true. do nothing
			});
		}
	},
	requestCore: function (userId, body) {
		//store the userId and request info in the database. wait for this app to find it
		//also generate unique strings to append to the external IP address that will
		//be given to users. NGINX will map those IPs to the correct internal IP addresses
		//of core and hmi
		//generate random letters and numbers for the user and hmi addresses
		//get all keys in the KV store and find their external address prefixes
		consuler.getKeyAll("manticore/requests/", function (results) {
			var addresses = core.getAddressesFromUserRequests(results);
			var options1 = {
				length: 12,
				charset: 'alphanumeric',
				capitalization: 'lowercase'
			}
			var options2 = {
				length: 4,
				charset: 'numeric'
			}

			var func1 = randomString.generate.bind(undefined, options1);
			const userToHmiAddress = core.getUniqueString(addresses, func1); //userAddress prefix
			const hmiToCoreAddress = core.getUniqueString(addresses, func1); //hmiAddress prefix
			//since SOME APPS have character limits (15) use a smaller random string generator for the TCP address
			var func2 = randomString.generate.bind(undefined, options2);
			const userToCoreAddress = core.getUniqueString(addresses, func2); //tcpAddress prefix
			body.userToHmiPrefix = userToHmiAddress;
			body.hmiToCorePrefix = hmiToCoreAddress;
			body.userToCorePrefix = userToCoreAddress;
			logger.debug("Store request " + userId);
			consuler.setKeyValue("manticore/requests/" + userId, JSON.stringify(body));
		});

	},
	//send back connection information in order for the client to make a websocket connection to
	//receive sdl_core logs
	requestLogs: function (userId, callback) {
		//point the user to the appropriate address
		var address = core.getWsUrl();
		//use the userId to generate a unique ID intended for the socket connection
		var connectionId = userId;
		logger.debug("Connection ID Generated:" + connectionId);
		//make sure there is an allocation for core intended for this user before
		//starting up a connection
		nomader.getAllocations("core", nomadAddress, function (res) {
			//we know which allocation to find because the TaskGroup name has the client ID
			//make sure the allocation is alive, which indicates it's the one that's running core
			var allocation = core.findAliveCoreAllocation(res.allocations, userId);
			if (allocation === null) {
				//core isn't available to stream logs
				logger.debug("Core isn't available for streaming for connection ID " + userId);
				callback(null);
			}
			else {
				//we can stream logs! return the appropriate connection details
				//pass back the address and connectionID to connect to the websocket server
				var connectionInfo = {
					url: address,
					connectionId: connectionId
				}
				logger.debug("Sending connection information to user " + userId);
				logger.debug("Address: " + connectionInfo.url);
				logger.debug("Connection ID: " + connectionInfo.connectionId);
				callback(connectionInfo);
				var taskName; //get the task name
				for (var obj in allocation.TaskStates) {
					taskName = obj;
					break;
				}
				//start streaming logs to the client once they connect using the connection details
				var custom = io.of('/' + userId);
				custom.on('connection', function (socket) {
					logger.debug("User connected! Stream core logs");
					//get the stdout logs and stream them
					nomader.streamLogs(allocation.ID, taskName, "stdout", nomadAddress, function (data) {
						//this function gets invoked whenever new data arrives from core
						socket.emit("logs", data);
					});
				});
			}

		});

	},
	deleteKey: function (key, callback) {
		consuler.delKey(key, function () {
			callback();
		});
	},
	deleteJob: function (jobName, callback) {
		nomader.deleteJob(jobName, nomadAddress, function () {
			callback();
		});
	}
}<commit_msg>Test AWS API<commit_after>//functionality of manticore with asynchronous behavior and dependencies for integration testing
var consuler;
var nomader = require('nomad-helper');
var core = require('./core.js');
var needle = require('needle');
var uuid = require('node-uuid');
var randomString = require('randomstring');
var exec = require('child_process').exec;
var fs = require('fs');
var ip = require('ip');
var logger = require('../lib/logger');
var AWS = require('aws-sdk');
AWS.config.update({region: process.env.AWS_REGION});
var ec2;
var nomadAddress;
var self;
var io;

module.exports = {
	init: function (address, socketIo, callback) {
		consuler = require('consul-helper')(address);
		//set the address
		nomadAddress = address + ":4646";
		logger.debug("Nomad address: " + nomadAddress);
		self = this; //keep a consistent context around
		io = socketIo;
		//set up AWS SDK. assume this EC2 instance has an IAM role so we don't need to put in extra credentials
		ec2 = new AWS.EC2();
		/*ec2.describeSecurityGroups({}, function (err, data) {
			console.log(data.SecurityGroups[16].IpPermissions);
			console.log(data.SecurityGroups[16].IpPermissionsEgress);
		});*/
		//make a security group because why not
		var params = {
			Description: "Im computer generated!",
			GroupName: "Please delete me"
		};
		ec2.createSecurityGroup(params, function (err, data) {
			console.log(err);
			console.log(data);
		});
		consuler.setKeyValue("manticore/filler", "Keep me here please!", function () {
			callback();
		});
	},
	startWatches: function (postUrl) {
		//set a watch for the KV store
		consuler.watchKVStore("manticore/", keysWatch);

		function keysWatch (keys) {
			//if keys is undefined, set it to an empty array
			keys = keys || [];
			keys = core.filterKeys(keys, "manticore/requests/");
			logger.debug("KV store update (after filtering)");
			logger.debug(keys);

			//set up an expectation that we want the values of <keys.length> keys.
			//send a callback function about what to do once we get all the values
			var expecting = core.expect(keys.length, function (job) {
				core.checkJobs(job, function () {//there are tasks. submit the job
					logger.debug("Core tasks exist");
					job.submitJob(nomadAddress, function (result) {
						logger.debug(result);
					});
				}, function () { //there are no tasks. delete the job
					logger.debug("No core tasks");
					self.deleteJob("core", function () {});
				});
			});
			for (let i = 0; i < keys.length; i++) {
				//go through each key and get their value. send the value to expecting
				//expecting will keep track of how many more keys are left
				consuler.getKeyValue(keys[i], function (value) {
					expecting.send(keys[i], value);
				});
			}
		}

		//set up a watch for all services
		consuler.watchServices(serviceWatch);

		function serviceWatch (services) {
			logger.debug("Services update");
			//services updated. get information about core and hmi if possible
			let cores = services.filter("core-master");
			let hmis = services.filter("hmi-master");
			logger.debug("Core services: " + cores.length);
			logger.debug("Hmi services: " + hmis.length);
			//for every core service, ensure it has a corresponding HMI
			var job = nomader.createJob("hmi");
			core.addHmisToJob(job, cores);
			//submit the job. if there are no task groups then
			//we want to remove the job completely. delete the job in that case
			core.checkJobs(job, function () {//there are tasks
				logger.debug("HMI tasks exist");
				job.submitJob(nomadAddress, function (result) {
					logger.debug(result);
				});
			}, function () { //there are no tasks
				logger.debug("No HMI tasks");
				self.deleteJob("hmi", function () {});
			});

			var pairs = core.findPairs(cores, hmis, function (userId) {
				//remove user from KV store because the HMI has no paired core which
				//indicates that the user exited the HMI page and is done with their instance
				self.deleteKey("manticore/requests/" + userId, function () {});
			});
			pairs = {
				pairs: pairs
			};
			//post all pairs at once
			logger.info(pairs);
			needle.post(postUrl, pairs, function (err, res) {
			});

			//if NGINX_OFF was not set to "true". write the file and reload nginx
			core.checkNginxFlag(function () {
				//create an nginx file and write it so that nginx notices it
				//use the pairs because that has information about what addresses to use
				//NOTE: the user that runs manticore should own this directory or it may not write to the file!
				logger.debug("Updating Nginx conf files");
				var nginxFiles = core.generateNginxFiles(pairs);
			    fs.writeFile(process.env.NGINX_MAIN_DIRECTORY+"/manticore.conf", nginxFiles[0], function (err) {
			    	if (err) {
			    		logger.error(err);
			    	}
				    //the file for TCP server blocks
				    fs.writeFile(process.env.NGINX_TCP_DIRECTORY+"/manticore.conf", nginxFiles[1], function (err) {
				    	if (err) {
			    			logger.error(err);
			    		}
				    	//done! restart nginx
				    	exec("sudo service nginx reload", function (err, stdout, stderr) {
				    		if (stdout) {
				    			logger.debug(stdout);
				    		}
				    		if (stderr) {
				    			logger.error(stderr);
				    		}
				    	});
				    });
			    });

			}, function () {//NGINX_OFF is set to true. do nothing
			});
		}
	},
	requestCore: function (userId, body) {
		//store the userId and request info in the database. wait for this app to find it
		//also generate unique strings to append to the external IP address that will
		//be given to users. NGINX will map those IPs to the correct internal IP addresses
		//of core and hmi
		//generate random letters and numbers for the user and hmi addresses
		//get all keys in the KV store and find their external address prefixes
		consuler.getKeyAll("manticore/requests/", function (results) {
			var addresses = core.getAddressesFromUserRequests(results);
			var options1 = {
				length: 12,
				charset: 'alphanumeric',
				capitalization: 'lowercase'
			}
			var options2 = {
				length: 4,
				charset: 'numeric'
			}

			var func1 = randomString.generate.bind(undefined, options1);
			const userToHmiAddress = core.getUniqueString(addresses, func1); //userAddress prefix
			const hmiToCoreAddress = core.getUniqueString(addresses, func1); //hmiAddress prefix
			//since SOME APPS have character limits (15) use a smaller random string generator for the TCP address
			var func2 = randomString.generate.bind(undefined, options2);
			const userToCoreAddress = core.getUniqueString(addresses, func2); //tcpAddress prefix
			body.userToHmiPrefix = userToHmiAddress;
			body.hmiToCorePrefix = hmiToCoreAddress;
			body.userToCorePrefix = userToCoreAddress;
			logger.debug("Store request " + userId);
			consuler.setKeyValue("manticore/requests/" + userId, JSON.stringify(body));
		});

	},
	//send back connection information in order for the client to make a websocket connection to
	//receive sdl_core logs
	requestLogs: function (userId, callback) {
		//point the user to the appropriate address
		var address = core.getWsUrl();
		//use the userId to generate a unique ID intended for the socket connection
		var connectionId = userId;
		logger.debug("Connection ID Generated:" + connectionId);
		//make sure there is an allocation for core intended for this user before
		//starting up a connection
		nomader.getAllocations("core", nomadAddress, function (res) {
			//we know which allocation to find because the TaskGroup name has the client ID
			//make sure the allocation is alive, which indicates it's the one that's running core
			var allocation = core.findAliveCoreAllocation(res.allocations, userId);
			if (allocation === null) {
				//core isn't available to stream logs
				logger.debug("Core isn't available for streaming for connection ID " + userId);
				callback(null);
			}
			else {
				//we can stream logs! return the appropriate connection details
				//pass back the address and connectionID to connect to the websocket server
				var connectionInfo = {
					url: address,
					connectionId: connectionId
				}
				logger.debug("Sending connection information to user " + userId);
				logger.debug("Address: " + connectionInfo.url);
				logger.debug("Connection ID: " + connectionInfo.connectionId);
				callback(connectionInfo);
				var taskName; //get the task name
				for (var obj in allocation.TaskStates) {
					taskName = obj;
					break;
				}
				//start streaming logs to the client once they connect using the connection details
				var custom = io.of('/' + userId);
				custom.on('connection', function (socket) {
					logger.debug("User connected! Stream core logs");
					//get the stdout logs and stream them
					nomader.streamLogs(allocation.ID, taskName, "stdout", nomadAddress, function (data) {
						//this function gets invoked whenever new data arrives from core
						socket.emit("logs", data);
					});
				});
			}

		});

	},
	deleteKey: function (key, callback) {
		consuler.delKey(key, function () {
			callback();
		});
	},
	deleteJob: function (jobName, callback) {
		nomader.deleteJob(jobName, nomadAddress, function () {
			callback();
		});
	}
}<|endoftext|>


<commit_before>"use strict";

var Bluebird = require("bluebird"),
	fs = require("fs"),
	minimatch = require("minimatch"),
	path = require("path"),
	util = require("util");

var ignorePatterns = [],
	messages = {};

try {
	ignorePatterns = fs.readFileSync(".precommitignore", "utf8")
		.replace(/\r/g, "")
		.split(/\n/)
		.filter(function(v) {
			return !!v;
		});
} catch (e) {
	// empty
}

function fileExists(file) {
	try {
		fs.statSync(file);
		return true;
	} catch (e) {
		return false;
	}
}

function write(data) {
	return process.stdout.write(data);
}

function writeLine(data) {
	return process.stdout.write(data + "\n");
}

function writeError(type, file, line, message) {
	if (!messages[type]) {
		messages[type] = [];
	}
	messages[type].push({
		type : type,
		file : file,
		line : line,
		message : message
	});
}

function flushMessages() {
	Object.keys(messages)
		.forEach(function(type) {
			messages[type].forEach(function(msg) {
				writeLine(msg.type + " error: [" + msg.file + ":" + msg.line + "] " + msg.message);
			});
		});
}

function getConfig(file) {
	var config = {},
		subConfig;
	try {
		config = JSON.parse(fs.readFileSync(file, "utf8"));
		if (config.extends) {
			subConfig = JSON.parse(fs.readFileSync(config.extends, "utf8"));
			util._extend(subConfig, config);
			delete subConfig.extends;
			config = subConfig;
		}
	} catch (e) {
		// empty
	}
	return config;
}

function isIgnored(file) {
	return ignorePatterns.some(function(pattern) {
		return minimatch(file, pattern, {
			nocase : true,
			matchBase : true
		});
	});
}

function extractScripts(src) {
	var isInBlock = false,
		lines = [];

	src.replace(/\r/g, "").split("\n").forEach(function(l) {
		// we're at the end of the script tag
		if (l.indexOf("</script") > -1) {
			lines[lines.length] = "";
			isInBlock = false;
			return;
		}
		if (isInBlock) {
			lines[lines.length] = l;
		} else {
			lines[lines.length] = "";
		}
		if (l.indexOf("<script") > -1 && (l.indexOf("text/ng-template") === -1 && l.indexOf("text/html") === -1)) {
			isInBlock = true;
		}
	});
	return lines.join("\n").replace(/\{\$(\w+\.)*\w+\}/g, "{}");
}

function extractStyles(src) {
	var isInBlock = false,
		lines = [];

	src.replace(/\r/g, "").split("\n").forEach(function(l) {
		// we're at the end of the style tag
		if (l.indexOf("</style") > -1) {
			lines[lines.length] = "";
			isInBlock = false;
			return;
		}
		if (isInBlock) {
			lines[lines.length] = l;
		} else {
			lines[lines.length] = "";
		}
		if (l.indexOf("<style") > -1) {
			isInBlock = true;
		}
	});
	return lines.join("\n").replace(/\{\$(\w+\.)*\w+\}/g, "{}");
}

function read() {
	// filename, src
	return Bluebird.resolve({
		filename : process.argv[2],
		src : fs.readFileSync(process.argv[3], "utf8")
	});
}

function done(code) {
	setTimeout(function() {
		process.exit(code || 0);
	}, 4);
}

function loadFileTypePlugin(extension) {
	return require(
		path.join(
			process.cwd(),
			".git-hooks/pre-commit-plugins/filetypes/file-" + extension
		)
	);
}

function loadFileCheckerPlugins() {
	var checkers = {};
	fs.readdirSync(path.join(process.cwd(), ".git-hooks/pre-commit-plugins/plugins"))
		.forEach(function(file) {
			var check = file.replace(/\.js$/, "");
			if (!(/\.js$/).test(file)) {
				return;
			}
			checkers[check] = require(path.join(process.cwd(), ".git-hooks/pre-commit-plugins/plugins", file));
		});
	return checkers;
}

module.exports = {
	fileExists : fileExists,
	write : write,
	writeLine : writeLine,
	writeError : writeError,
	flushMessages : flushMessages,
	getConfig : getConfig,
	isIgnored : isIgnored,
	extractScripts : extractScripts,
	extractStyles : extractStyles,
	read : read,
	done : done,
	loadFileTypePlugin : loadFileTypePlugin,
	loadFileCheckerPlugins : loadFileCheckerPlugins
};
<commit_msg>Don't crash when no plugins<commit_after>"use strict";

var Bluebird = require("bluebird"),
	fs = require("fs"),
	minimatch = require("minimatch"),
	path = require("path"),
	util = require("util");

var ignorePatterns = [],
	messages = {};

try {
	ignorePatterns = fs.readFileSync(".precommitignore", "utf8")
		.replace(/\r/g, "")
		.split(/\n/)
		.filter(function(v) {
			return !!v;
		});
} catch (e) {
	// empty
}

function fileExists(file) {
	try {
		fs.statSync(file);
		return true;
	} catch (e) {
		return false;
	}
}

function write(data) {
	return process.stdout.write(data);
}

function writeLine(data) {
	return process.stdout.write(data + "\n");
}

function writeError(type, file, line, message) {
	if (!messages[type]) {
		messages[type] = [];
	}
	messages[type].push({
		type : type,
		file : file,
		line : line,
		message : message
	});
}

function flushMessages() {
	Object.keys(messages)
		.forEach(function(type) {
			messages[type].forEach(function(msg) {
				writeLine(msg.type + " error: [" + msg.file + ":" + msg.line + "] " + msg.message);
			});
		});
}

function getConfig(file) {
	var config = {},
		subConfig;
	try {
		config = JSON.parse(fs.readFileSync(file, "utf8"));
		if (config.extends) {
			subConfig = JSON.parse(fs.readFileSync(config.extends, "utf8"));
			util._extend(subConfig, config);
			delete subConfig.extends;
			config = subConfig;
		}
	} catch (e) {
		// empty
	}
	return config;
}

function isIgnored(file) {
	return ignorePatterns.some(function(pattern) {
		return minimatch(file, pattern, {
			nocase : true,
			matchBase : true
		});
	});
}

function extractScripts(src) {
	var isInBlock = false,
		lines = [];

	src.replace(/\r/g, "").split("\n").forEach(function(l) {
		// we're at the end of the script tag
		if (l.indexOf("</script") > -1) {
			lines[lines.length] = "";
			isInBlock = false;
			return;
		}
		if (isInBlock) {
			lines[lines.length] = l;
		} else {
			lines[lines.length] = "";
		}
		if (l.indexOf("<script") > -1 && (l.indexOf("text/ng-template") === -1 && l.indexOf("text/html") === -1)) {
			isInBlock = true;
		}
	});
	return lines.join("\n").replace(/\{\$(\w+\.)*\w+\}/g, "{}");
}

function extractStyles(src) {
	var isInBlock = false,
		lines = [];

	src.replace(/\r/g, "").split("\n").forEach(function(l) {
		// we're at the end of the style tag
		if (l.indexOf("</style") > -1) {
			lines[lines.length] = "";
			isInBlock = false;
			return;
		}
		if (isInBlock) {
			lines[lines.length] = l;
		} else {
			lines[lines.length] = "";
		}
		if (l.indexOf("<style") > -1) {
			isInBlock = true;
		}
	});
	return lines.join("\n").replace(/\{\$(\w+\.)*\w+\}/g, "{}");
}

function read() {
	// filename, src
	return Bluebird.resolve({
		filename : process.argv[2],
		src : fs.readFileSync(process.argv[3], "utf8")
	});
}

function done(code) {
	setTimeout(function() {
		process.exit(code || 0);
	}, 4);
}

function loadFileTypePlugin(extension) {
	return require(
		path.join(
			process.cwd(),
			".git-hooks/pre-commit-plugins/filetypes/file-" + extension
		)
	);
}

function loadFileCheckerPlugins() {
	var checkers = {};
	try {
		fs.readdirSync(path.join(process.cwd(), ".git-hooks/pre-commit-plugins/plugins"))
			.forEach(function(file) {
				var check = file.replace(/\.js$/, "");
				if (!(/\.js$/).test(file)) {
					return;
				}
				checkers[check] = require(path.join(process.cwd(), ".git-hooks/pre-commit-plugins/plugins", file));
			});
	} catch (e) {
		// empty
	}
	return checkers;
}

module.exports = {
	fileExists : fileExists,
	write : write,
	writeLine : writeLine,
	writeError : writeError,
	flushMessages : flushMessages,
	getConfig : getConfig,
	isIgnored : isIgnored,
	extractScripts : extractScripts,
	extractStyles : extractStyles,
	read : read,
	done : done,
	loadFileTypePlugin : loadFileTypePlugin,
	loadFileCheckerPlugins : loadFileCheckerPlugins
};
<|endoftext|>


<commit_before>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {rethrowAsync, user} from '../../log';

export const PARSER_IGNORE_FLAG = '`';

/** Rudamentary parser to handle nested Url replacement. */
export class Expander {

  /**
   * Link this instance of parser to the calling UrlReplacment
   * @param {!../variable-source.VariableSource|null} variableSource the keywords to replace
   */
  constructor(variableSource) {
    this.variableSource_ = variableSource;
  }

  /**
   * take the template url and return a promise of its evaluated value
   * @param {string} url url to be substituted
   * @param {!Object<string, *>=} opt_bindings additional one-off bindings
   * @param {!Object<string, boolean>=} opt_whiteList Optional white list of names
   *     that can be substituted.
   * @return {!Promise<string>}
   */
  expand(url, opt_bindings, opt_whiteList) {
    if (!url.length) {
      return Promise.resolve(url);
    }
    const expr = this.variableSource_
        .getExpr(opt_bindings, /*opt_ignoreArgs */ true);

    const matches = this.findMatches_(url, expr);
    // if no keywords move on
    if (!matches.length) {
      return Promise.resolve(url);
    }
    return this.parseUrlRecursively_(url, matches, opt_bindings);
  }

  /**
   * Structures the regex matching into the desired format
   * @param {string} url url to be substituted
   * @param {RegExp} expression regex containing all keywords
   * @return {Array<Object<string, string|number>>} array of objects representing
   *  matching keywords
   */
  findMatches_(url, expression) {
    const matches = [];
    url.replace(expression, (match, name, startPosition) => {
      const length = match.length;
      const stopPosition = length + startPosition - 1;
      const info = {
        start: startPosition,
        stop: stopPosition,
        name,
        length,
      };
      matches.push(info);
    });
    return matches;
  }

  /**
   * @param {string} url
   * @param {!Array<Object<string, string|number>>} matches array of objects representing
   *  matching keywords
   * @param {!Object<string, *>=} opt_bindings additional one-off bindings
   * @return {!Promise<string>}
   */
  parseUrlRecursively_(url, matches, opt_bindings) {
    const stack = [];
    let urlIndex = 0;
    let matchIndex = 0;
    let match = matches[matchIndex];
    let numOfPendingCalls = 0;
    let ignoringChars = false;
    let nextArgShouldBeRaw = false;

    const evaluateNextLevel = () => {
      let builder = '';
      const results = [];

      while (urlIndex < url.length && matchIndex <= matches.length) {
        if (match && urlIndex === match.start) {
          let binding;
          // find out where this keyword is coming from
          if (opt_bindings && opt_bindings.hasOwnProperty(match.name)) {
            // the optional bindings
            binding = opt_bindings[match.name];
          } else {
            // or the global source
            binding = this.variableSource_.get(match.name);
            binding = binding.async || binding.sync;
          }

          urlIndex = match.stop + 1;
          match = matches[++matchIndex];

          if (url[urlIndex] === '(') {
            // if we hit a left parenthesis we still need to get args
            urlIndex++;
            numOfPendingCalls++;
            stack.push(binding);
            if (builder.length) {
              results.push(builder);
            }
            results.push(evaluateNextLevel());
          } else {
            if (builder.length) {
              results.push(builder);
            }
            results.push(this.evaluateBinding_(binding));
          }

          builder = '';
        }

        else if (url[urlIndex] === PARSER_IGNORE_FLAG) {
          if (!ignoringChars) {
            ignoringChars = true;
            nextArgShouldBeRaw = true;
            user().assert(builder.trim() === '',
                `The substring "${builder}" was lost during url-replacement. ` +
                'Please ensure the url syntax is correct');
            builder = '';
          } else {
            ignoringChars = false;
          }
          urlIndex++;
        }

        else if (numOfPendingCalls && url[urlIndex] === ',' && !ignoringChars) {
          if (builder.length) {
            const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
            results.push(nextArg);
            nextArgShouldBeRaw = false;
          }
          // support existing two comma format
          // eg CLIENT_ID(__ga,,ga-url)
          if (url[urlIndex + 1] === ',') {
            results.push(''); // TODO(ccordry): may want this to be undefined at some point
            urlIndex++;
          }
          builder = '';
          urlIndex++;
        }

        else if (url[urlIndex] === ')' && !ignoringChars) {
          urlIndex++;
          numOfPendingCalls--;
          const binding = stack.pop();
          const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
          results.push(nextArg);
          nextArgShouldBeRaw = false;
          const value = this.evaluateBinding_(binding, results);
          return value;
        }

        else {
          builder += url[urlIndex];
          urlIndex++;
        }

        //capture trailing characters
        if (urlIndex === url.length && builder.length) {
          results.push(builder);
        }
      }
      return Promise.all(results)
          .then(promiseArray => promiseArray.join(''))
          .catch(e => {
            rethrowAsync(e);
            return '';
          });
    };

    return evaluateNextLevel();
  }

  /**
   * resolves binding to value to be substituted
   * @param {*} binding container for sync/async resolutions
   * @param {?Array=} opt_args arguments to be passed if binding is function
   * @return {!Promise<string>} resolved value
   */
  evaluateBinding_(binding, opt_args) {
    let value;
    try {
      if (typeof binding === 'function') {
        if (opt_args) {
          value = Promise.all(opt_args)
              .then(args => binding.apply(null, args));
        } else {
          value = Promise.resolve(binding.apply(null, opt_args));
        }
      } else {
        value = Promise.resolve(binding);
      }
      return value.then(val => val == null ? '' : encodeURIComponent(val))
          .catch(e => {
            rethrowAsync(e);
            return '';
          });

    } catch (e) {
      // Report error, but do not disrupt URL replacement. This will
      // interpolate as the empty string.
      rethrowAsync(e);
      return Promise.resolve('');
    }
  }
}
<commit_msg>Use tryResolve in URL Expander (#15140)<commit_after>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {rethrowAsync, user} from '../../log';
import {tryResolve} from '../../promise';

export const PARSER_IGNORE_FLAG = '`';

/** Rudamentary parser to handle nested Url replacement. */
export class Expander {

  /**
   * Link this instance of parser to the calling UrlReplacment
   * @param {!../variable-source.VariableSource|null} variableSource the keywords to replace
   */
  constructor(variableSource) {
    this.variableSource_ = variableSource;
  }

  /**
   * take the template url and return a promise of its evaluated value
   * @param {string} url url to be substituted
   * @param {!Object<string, *>=} opt_bindings additional one-off bindings
   * @param {!Object<string, boolean>=} opt_whiteList Optional white list of names
   *     that can be substituted.
   * @return {!Promise<string>}
   */
  expand(url, opt_bindings, opt_whiteList) {
    if (!url.length) {
      return Promise.resolve(url);
    }
    const expr = this.variableSource_
        .getExpr(opt_bindings, /*opt_ignoreArgs */ true);

    const matches = this.findMatches_(url, expr);
    // if no keywords move on
    if (!matches.length) {
      return Promise.resolve(url);
    }
    return this.parseUrlRecursively_(url, matches, opt_bindings);
  }

  /**
   * Structures the regex matching into the desired format
   * @param {string} url url to be substituted
   * @param {RegExp} expression regex containing all keywords
   * @return {Array<Object<string, string|number>>} array of objects representing
   *  matching keywords
   */
  findMatches_(url, expression) {
    const matches = [];
    url.replace(expression, (match, name, startPosition) => {
      const length = match.length;
      const stopPosition = length + startPosition - 1;
      const info = {
        start: startPosition,
        stop: stopPosition,
        name,
        length,
      };
      matches.push(info);
    });
    return matches;
  }

  /**
   * @param {string} url
   * @param {!Array<Object<string, string|number>>} matches array of objects representing
   *  matching keywords
   * @param {!Object<string, *>=} opt_bindings additional one-off bindings
   * @return {!Promise<string>}
   */
  parseUrlRecursively_(url, matches, opt_bindings) {
    const stack = [];
    let urlIndex = 0;
    let matchIndex = 0;
    let match = matches[matchIndex];
    let numOfPendingCalls = 0;
    let ignoringChars = false;
    let nextArgShouldBeRaw = false;

    const evaluateNextLevel = () => {
      let builder = '';
      const results = [];

      while (urlIndex < url.length && matchIndex <= matches.length) {
        if (match && urlIndex === match.start) {
          let binding;
          // find out where this keyword is coming from
          if (opt_bindings && opt_bindings.hasOwnProperty(match.name)) {
            // the optional bindings
            binding = opt_bindings[match.name];
          } else {
            // or the global source
            binding = this.variableSource_.get(match.name);
            binding = binding.async || binding.sync;
          }

          urlIndex = match.stop + 1;
          match = matches[++matchIndex];

          if (url[urlIndex] === '(') {
            // if we hit a left parenthesis we still need to get args
            urlIndex++;
            numOfPendingCalls++;
            stack.push(binding);
            if (builder.length) {
              results.push(builder);
            }
            results.push(evaluateNextLevel());
          } else {
            if (builder.length) {
              results.push(builder);
            }
            results.push(this.evaluateBinding_(binding));
          }

          builder = '';
        }

        else if (url[urlIndex] === PARSER_IGNORE_FLAG) {
          if (!ignoringChars) {
            ignoringChars = true;
            nextArgShouldBeRaw = true;
            user().assert(builder.trim() === '',
                `The substring "${builder}" was lost during url-replacement. ` +
                'Please ensure the url syntax is correct');
            builder = '';
          } else {
            ignoringChars = false;
          }
          urlIndex++;
        }

        else if (numOfPendingCalls && url[urlIndex] === ',' && !ignoringChars) {
          if (builder.length) {
            const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
            results.push(nextArg);
            nextArgShouldBeRaw = false;
          }
          // support existing two comma format
          // eg CLIENT_ID(__ga,,ga-url)
          if (url[urlIndex + 1] === ',') {
            results.push(''); // TODO(ccordry): may want this to be undefined at some point
            urlIndex++;
          }
          builder = '';
          urlIndex++;
        }

        else if (url[urlIndex] === ')' && !ignoringChars) {
          urlIndex++;
          numOfPendingCalls--;
          const binding = stack.pop();
          const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
          results.push(nextArg);
          nextArgShouldBeRaw = false;
          const value = this.evaluateBinding_(binding, results);
          return value;
        }

        else {
          builder += url[urlIndex];
          urlIndex++;
        }

        //capture trailing characters
        if (urlIndex === url.length && builder.length) {
          results.push(builder);
        }
      }
      return Promise.all(results)
          .then(promiseArray => promiseArray.join(''))
          .catch(e => {
            rethrowAsync(e);
            return '';
          });
    };

    return evaluateNextLevel();
  }

  /**
   * resolves binding to value to be substituted
   * @param {*} binding container for sync/async resolutions
   * @param {?Array=} opt_args arguments to be passed if binding is function
   * @return {!Promise<string>} resolved value
   */
  evaluateBinding_(binding, opt_args) {
    let value;
    try {
      if (typeof binding === 'function') {
        if (opt_args) {
          value = Promise.all(opt_args)
              .then(args => binding.apply(null, args));
        } else {
          value = tryResolve(binding);
        }
      } else {
        value = Promise.resolve(binding);
      }
      return value.then(val => val == null ? '' : encodeURIComponent(val))
          .catch(e => {
            rethrowAsync(e);
            return '';
          });

    } catch (e) {
      // Report error, but do not disrupt URL replacement. This will
      // interpolate as the empty string.
      rethrowAsync(e);
      return Promise.resolve('');
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Imports data into Postgres DB for further analysis.
 */

// Packages
var path = require('path');
var fs = require('fs');
var events = require('events');
var pg = require('pg');
var celeri = require('celeri');

// Config
var connection = 'postgres://postgres:@localhost/mn_marriage';
var imports = {};

// Make the tables
function makeTables(done) {
  var client = new pg.Client(connection);
  var loading = celeri.loading('Creating and resetting Marriage table: ');

  var query = " \
    DROP TABLE marriages; CREATE TABLE IF NOT EXISTS marriages ( \
      id SERIAL, \
      county VARCHAR(128), \
      groom_last_before VARCHAR(256), \
      groom_first_before VARCHAR(256), \
      groom_middle_before VARCHAR(256), \
      bride_last_before VARCHAR(256), \
      bride_first_before VARCHAR(256), \
      bride_middle_before VARCHAR(256), \
      groom_last_after VARCHAR(256), \
      groom_first_after VARCHAR(256), \
      groom_middle_after VARCHAR(256), \
      bride_last_after VARCHAR(256), \
      bride_first_after VARCHAR(256), \
      bride_middle_after VARCHAR(256), \
      certificate_date DATE, \
      application_date DATE, \
      file_date DATE, \
      external_id VARCHAR(512), \
      notes TEXT, \
      CONSTRAINT marriages_primary_key PRIMARY KEY (id) \
    )";

  client.connect(function(err) {
    if (err) {
      loading.done('Error.', false);
      return console.error('Could not connect to postgres.', err);
    }
    client.query(query, function(err, result) {
      if (err) {
        loading.done('Error.', false);
        return console.error('Error running table query.', err);
      }

      loading.done('Done.', true);
      client.end();
      done();
    });
  });
}

// Imports

/**
 * Hennepin imports.  The following was sent with data
 *
 * G (System) (this column can be ignored)
 * Groom Last Before
 * Groom First Before
 * Groom Middle Before
 * Bride Last Before
 * Bride First Before
 * Bride Middle Before
 * Groom Last After
 * Groom First After
 * Groom Middle After
 * Bride Last After
 * Bride First After
 * Bride Middle After
 * Certificate Date
 * Application Date
 * File Date
 * Internal Use (three columns)
 *
 * There should be 829147 rows in the file.
 */
imports.hennepin = function(done) {
  var client = new pg.Client(connection);
  var file = path.join(__dirname, '../data/orig-hennepin-18500101-20111115.txt');
  var stream;
  var columnsWidths = [1, 39, 15, 15, 39, 15, 15, 39, 15, 15, 39, 15, 15, 10, 10, 10, 33, 1, 26];
  var readCount = 0;
  var writeCount = 0;
  var multiQuery = '';

  // Mark progress
  celeri.progress('Reading Hennepin file: ', 0);

  // DB connect
  client.connect(function(err) {
    if (err) {
      fileLoading.done('Error.', false);
      return console.error('Could not connect to postgres.', err);
    }

    // Start reading in the data
    stream = lineifyStream(fs.createReadStream(file));
    stream.on('line', function(line) {
      var fields = [];
      var c = 0;
      var width;
      var query;

      // Fixed width file.  Each line should be 369 characters wide
      // and each field is variable fixed width.  :(
      if (line.length != 367) {
        console.log('Line length is off (' + line.length + '): ' + line);
        return;
      }

      columnsWidths.forEach(function(w) {
        fields.push(line.substring(c, c + w).trim());
        c = c + w;
      });

      // Muck up array so that it easier to write query
      fields.shift();
      fields[16] = fields[16] + '||' + fields[17];
      fields.pop();
      fields = fields.map(function(f) {
        return "'" + f.replace("'", "''") + "'";
      });
      fields[12] = "to_date(" + fields[12] + ", 'MM/DD/YYYY')";
      fields[13] = "to_date(" + fields[13] + ", 'MM/DD/YYYY')";
      fields[14] = "to_date(" + fields[14] + ", 'MM/DD/YYYY')";

      query = "INSERT INTO marriages (county, groom_last_before, groom_first_before, groom_middle_before, bride_last_before, bride_first_before, bride_middle_before, groom_last_after, groom_first_after, groom_middle_after, bride_last_after, bride_first_after, bride_middle_after, certificate_date, application_date, file_date, external_id, notes) VALUES ('hennepin', " + fields.join(', ') + ")";

      // We only want to do a bulk insert every so often
      multiQuery += query + '; ';
      readCount++;

      if (readCount % 100 === 0) {
        // Mark progress
        celeri.progress('Reading Hennepin file: ', (readCount / 829100 * 100).toFixed(2));

        (function(readCount) {
          client.query(multiQuery, function(err, result) {
            if (err) {
              // Try again.  For some reason things fail out and give
              // syntax error even those there are none, occasionally.
              client.query(multiQuery, function(err, result) {
                if (err) {
                  console.error('Error inserting data with query: ' + multiQuery, err);
                }
              });
            }
            writeCount = readCount;
          });
          multiQuery = '';
        })(readCount);
      }
    });

    stream.on('end', function() {
      var interval;
      var pastWriteCount = 0;
      celeri.progress('Reading Hennepin file: ', 100);
      celeri.progress('Writing Hennepin data to DB: ', (writeCount / readCount * 100).toFixed(2));

      // More than likely the output into the DB will take much
      // longer than the file reading, so we just pool to see
      // when its done as there does not seem to be
      if (writeCount != readCount) {
        interval = setInterval(function() {
          if (writeCount >= readCount || writeCount === pastWriteCount) {
            // Need to write out the last query
            client.query(multiQuery, function(err, result) {
              if (err) {
                return console.error('Error inserting data with query: ' + multiQuery, err);
              }

              celeri.progress('Writing Hennepin data to DB: ', 100);
              done();
              client.end();
            });
            clearInterval(interval);
          }

          pastWriteCount = writeCount;
          celeri.progress('Writing Hennepin data to DB: ', (writeCount / readCount * 100).toFixed(2));
        }, 1000);
      }
    });
  });
};

// Make read streams handle by line
function lineifyStream(stream) {
  stream.lineBuffer = '';
  //stream.liner = new events.EventEmitter();

  stream.on('data', function(chunk) {
    var lines, l;
    chunk = stream.lineBuffer + chunk.toString();
    lines = chunk.split(/\r\n|\r|\n/g);

    // Just add to buffer
    if (lines.length === 1) {
      stream.lineBuffer += lines[0];
    }
    else {
      for (l = 0; l < lines.length - 1; l ++) {
        if (lines[l] !== '' && lines[l].length != 0) {
          stream.emit('line', lines[l]);
        }
      };

      // Make the last line the new buffer
      stream.lineBuffer = lines[lines.length - 1];
    }
  });
  stream.on('end', function() {
    // Output the last of the buffer
    stream.emit('line', stream.lineBuffer);
  });

  return stream;
}

// Run app
makeTables(function() {
  imports.hennepin(function() {
    console.log('Done.');
  });
});<commit_msg>Handling suffixes.<commit_after>/**
 * Imports data into Postgres DB for further analysis.
 */

// Packages
var path = require('path');
var fs = require('fs');
var events = require('events');
var pg = require('pg');
var celeri = require('celeri');

// Config
var connection = 'postgres://postgres:@localhost/mn_marriage';
var imports = {};

// Make the tables
function makeTables(done) {
  var client = new pg.Client(connection);
  var loading = celeri.loading('Creating and resetting Marriage table: ');

  var query = " \
    DROP TABLE marriages; CREATE TABLE IF NOT EXISTS marriages ( \
      id SERIAL, \
      county VARCHAR(128), \
      groom_last_before VARCHAR(256), \
      groom_first_before VARCHAR(256), \
      groom_middle_before VARCHAR(256), \
      groom_suffix_before VARCHAR(256), \
      bride_last_before VARCHAR(256), \
      bride_first_before VARCHAR(256), \
      bride_middle_before VARCHAR(256), \
      groom_last_after VARCHAR(256), \
      groom_first_after VARCHAR(256), \
      groom_middle_after VARCHAR(256), \
      groom_suffix_after VARCHAR(256), \
      bride_last_after VARCHAR(256), \
      bride_first_after VARCHAR(256), \
      bride_middle_after VARCHAR(256), \
      certificate_date DATE, \
      application_date DATE, \
      file_date DATE, \
      external_id VARCHAR(512), \
      notes TEXT, \
      CONSTRAINT marriages_primary_key PRIMARY KEY (id) \
    )";

  client.connect(function(err) {
    if (err) {
      loading.done('Error.', false);
      return console.error('Could not connect to postgres.', err);
    }
    client.query(query, function(err, result) {
      if (err) {
        loading.done('Error.', false);
        return console.error('Error running table query.', err);
      }

      loading.done('Done.', true);
      client.end();
      done();
    });
  });
}

// Imports

/**
 * Hennepin imports.  The following was sent with data
 *
 * G (System) (this column can be ignored)
 * Groom Last Before
 * Groom First Before
 * Groom Middle Before
 * Bride Last Before
 * Bride First Before
 * Bride Middle Before
 * Groom Last After
 * Groom First After
 * Groom Middle After
 * Bride Last After
 * Bride First After
 * Bride Middle After
 * Certificate Date
 * Application Date
 * File Date
 * Internal Use (three columns)
 *
 * There should be 829147 rows in the file.
 */
imports.hennepin = function(done) {
  var client = new pg.Client(connection);
  var file = path.join(__dirname, '../data/orig-hennepin-18500101-20111115.txt');
  var stream;
  var columnsWidths = [1, 39, 15, 15, 39, 15, 15, 39, 15, 15, 39, 15, 15, 10, 10, 10, 33, 1, 26];
  var readCount = 0;
  var writeCount = 0;
  var multiQuery = '';

  // Mark progress
  celeri.progress('Reading Hennepin file: ', 0);

  // DB connect
  client.connect(function(err) {
    if (err) {
      fileLoading.done('Error.', false);
      return console.error('Could not connect to postgres.', err);
    }

    // Start reading in the data
    stream = lineifyStream(fs.createReadStream(file));
    stream.on('line', function(line) {
      var fields = [];
      var c = 0;
      var query, parts;

      // Fixed width file.  Each line should be 369 characters wide
      // and each field is variable fixed width.  :(
      if (line.length != 367) {
        console.log('Line length is off (' + line.length + '): ' + line);
        return;
      }

      columnsWidths.forEach(function(w) {
        fields.push(line.substring(c, c + w).trim());
        c = c + w;
      });

      // Muck up array so that it easier to write query
      fields.shift();
      fields[16] = fields[16] + '||' + fields[17];
      fields.pop();

      // Suffixes :(
      [0, 6].forEach(function(f) {
        parts = fields[f].split(' ');
        if (parts.length > 1 && ['JR', 'SR', 'II', 'III'].indexOf(parts[parts.length - 1]) >= 0) {
          fields.push(parts[parts.length - 1]);
          parts.pop();
          fields[f] = parts.join(' ');
        }
        else {
          fields.push('');
        }
      });

      // Format array for query
      fields = fields.map(function(f) {
        return "'" + f.replace("'", "''") + "'";
      });
      fields[12] = "to_date(" + fields[12] + ", 'MM/DD/YYYY')";
      fields[13] = "to_date(" + fields[13] + ", 'MM/DD/YYYY')";
      fields[14] = "to_date(" + fields[14] + ", 'MM/DD/YYYY')";

      // Great array
      query = "INSERT INTO marriages (county, \
        groom_last_before, groom_first_before, groom_middle_before, \
        bride_last_before, bride_first_before, bride_middle_before, \
        groom_last_after, groom_first_after, groom_middle_after, \
        bride_last_after, bride_first_after, bride_middle_after, \
        certificate_date, application_date, file_date, \
        external_id, notes, groom_suffix_before, groom_suffix_after \
        ) VALUES ('hennepin', " + fields.join(', ') + ")";

      // We only want to do a bulk insert every so often
      multiQuery += query + '; ';
      readCount++;

      if (readCount % 100 === 0) {
        // Mark progress
        celeri.progress('Reading Hennepin file: ', (readCount / 829100 * 100).toFixed(2));

        (function(readCount) {
          client.query(multiQuery, function(err, result) {
            if (err) {
              // Try again.  For some reason things fail out and give
              // syntax error even those there are none, occasionally.
              client.query(multiQuery, function(err, result) {
                if (err) {
                  console.error('Error inserting data with query: ' + multiQuery, err);
                }
              });
            }
            writeCount = readCount;
          });
          multiQuery = '';
        })(readCount);
      }
    });

    stream.on('end', function() {
      var interval;
      var pastWriteCount = 0;
      celeri.progress('Reading Hennepin file: ', 100);
      celeri.progress('Writing Hennepin data to DB: ', (writeCount / readCount * 100).toFixed(2));

      // More than likely the output into the DB will take much
      // longer than the file reading, so we just pool to see
      // when its done as there does not seem to be
      if (writeCount != readCount) {
        interval = setInterval(function() {
          if (writeCount >= readCount || writeCount === pastWriteCount) {
            // Need to write out the last query
            client.query(multiQuery, function(err, result) {
              if (err) {
                return console.error('Error inserting data with query: ' + multiQuery, err);
              }

              celeri.progress('Writing Hennepin data to DB: ', 100);
              done();
              client.end();
            });
            clearInterval(interval);
          }

          pastWriteCount = writeCount;
          celeri.progress('Writing Hennepin data to DB: ', (writeCount / readCount * 100).toFixed(2));
        }, 1000);
      }
    });
  });
};

// Make read streams handle by line
function lineifyStream(stream) {
  stream.lineBuffer = '';
  //stream.liner = new events.EventEmitter();

  stream.on('data', function(chunk) {
    var lines, l;
    chunk = stream.lineBuffer + chunk.toString();
    lines = chunk.split(/\r\n|\r|\n/g);

    // Just add to buffer
    if (lines.length === 1) {
      stream.lineBuffer += lines[0];
    }
    else {
      for (l = 0; l < lines.length - 1; l ++) {
        if (lines[l] !== '' && lines[l].length != 0) {
          stream.emit('line', lines[l]);
        }
      };

      // Make the last line the new buffer
      stream.lineBuffer = lines[lines.length - 1];
    }
  });
  stream.on('end', function() {
    // Output the last of the buffer
    stream.emit('line', stream.lineBuffer);
  });

  return stream;
}

// Run app
makeTables(function() {
  imports.hennepin(function() {
    console.log('Done.');
  });
});<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

var p = console.log;
var assert = require('assert-plus');
var sprintf = require('extsprintf').sprintf;
var util = require('util'),
    format = util.format;
var vasync = require('vasync');

var common = require('../common');
var errors = require('../errors');

var Procedure = require('./procedure').Procedure;

function DownloadImages(options) {
    assert.arrayOfObject(options.images, 'options.images');
    this.images = options.images;
}
util.inherits(DownloadImages, Procedure);

DownloadImages.prototype.summarize = function diSummarize() {
    var size = this.images.map(function (img) {
        return (img.files.length ? img.files[0].size : 0);
    }).reduce(function (prev, curr) {
        return prev + curr;
    });
    var imageInfos = this.images.map(function (img) {
        return format('image %s\n    (%s@%s)', img.uuid, img.name, img.version);
    });
    return sprintf('download %d image%s (%d MiB):\n%s',
        this.images.length,
        (this.images.length === 1 ? '' : 's'),
        size / 1024 / 1024,
        common.indent(imageInfos.join('\n')));
};

/**
 * The 'source' URL (IMGAPI endpoint) can optionally be passed in. It defaults
 * to 'updates.joyent.com?channel=<current-channel>'.
 */
DownloadImages.prototype.execute = function diExecute(options, cb) {
    assert.object(options, 'options');
    assert.object(options.sdcadm, 'options.sdcadm');
    assert.object(options.log, 'options.log');
    assert.optionalString(options.source, 'options.source');
    assert.func(options.progress, 'options.progress');
    assert.func(cb, 'cb');
    var self = this;
    var sdcadm = options.sdcadm;
    var progress = options.progress;

    var source = options.source;
    if (!source) {
        source = sdcadm.config.updatesServerUrl;
        if (sdcadm.updates.channel) {
            source += '?channel=' + sdcadm.updates.channel;
        }
    }

    var q = vasync.queuev({
        concurrency: 4,
        worker: function importUpdateImage(image, next) {
            function deleteImage(_, nextStep) {
                if (image.state !== 'unactivated') {
                    return nextStep();
                }

                progress('Removing unactivated image %s\n(%s@%s)', image.uuid,
                    image.name, image.version);

                sdcadm.imgapi.deleteImage(image.uuid, function (err) {
                    if (err) {
                        progress('Error removing unactivated image %s\n(%s@%s)',
                                    image.uuid, image.name, image.version);

                        var e = new errors.SDCClientError(err, 'imgapi');
                        e.image = image.uuid;
                        sdcadm.log.error({err: e}, 'Error removing image');
                        nextStep(e);
                    } else {
                        nextStep();
                    }
                });
            }

            function getImage(_, nextStep) {
                progress('Downloading image %s\n    (%s@%s)',
                    image.uuid, image.name, image.version);
                sdcadm.imgapi.adminImportRemoteImageAndWait(
                    image.uuid,
                    source,
                    {
                        // TODO: Once IMGAPI-408 is sufficient deployed, then
                        // drop this `skipOwnerCheck`.
                        skipOwnerCheck: true,
                        // Retry image import 5 times by default:
                        retries: 5
                    },
                    function (err, img, res) {
                        if (err) {
                            progress('Error importing image %s\n(%s@%s)',
                                image.uuid, image.name, image.version);
                            var e = new errors.SDCClientError(err, 'imgapi');
                            e.image = image.uuid;
                            nextStep(e);
                        } else {
                            progress('Imported image %s\n    (%s@%s)',
                                image.uuid, image.name, image.version);
                            nextStep();
                        }
                    });
            }

            vasync.pipeline({funcs: [deleteImage, getImage]}, next);
        }
    });

    // TODO: For now we just collect import errors and return them. We
    //       should do better with retries (either here or in the imgapi
    //       client).
    var errs = [];
    function onTaskComplete(err) {
        if (err) {
            errs.push(err);
        }
    }

    q.on('end', function done() {
        var er = (errs.length === 1) ? errs[0] :
            new errors.MultiError(errs);

        // Check if the problem is that external nics are missing.
        if (errs.length) {
            var remoteSourceErr = errs.some(function (e) {
                return (e && e.we_cause &&
                    e.we_cause.name === 'RemoteSourceError');
            });

            if (remoteSourceErr) {
                options.sdcadm.checkMissingExternalNics({
                    progress: options.progress
                }, function (err, res) {
                    if (err) {
                        return cb(errs);
                    }

                    var doimgapi = res.doimgapi;
                    if (doimgapi) {
                        p('');
                        var msg = 'There is an error trying to download ' +
                            'images because the imgapi zone has no ' +
                            'external NIC.\nPlease run:\n\n' +
                            '   sdcadm post-setup common-external-nics\n' +
                            '\nand try again.\n';
                        p(msg);
                    }
                    // we need to return the error anyway:
                    return cb(er);
                });
            } else {
                cb(er);
            }
        } else {
            cb();
        }
    });

    for (var i = 0; i < self.images.length; i++) {
        q.push(self.images[i], onTaskComplete);
    }
    q.close();
};

//---- exports

module.exports = {
    DownloadImages: DownloadImages
};
// vim: set softtabstop=4 shiftwidth=4:
<commit_msg>TOOLS-1634 'sdcadm up' parallel import of images can break when multiple images share a new origin image Reviewed by: Trent Mick <trentm@gmail.com> Approved by: Trent Mick <trentm@gmail.com><commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2017, Joyent, Inc.
 */

var p = console.log;
var assert = require('assert-plus');
var sprintf = require('extsprintf').sprintf;
var util = require('util'),
    format = util.format;
var vasync = require('vasync');

var common = require('../common');
var errors = require('../errors');

var Procedure = require('./procedure').Procedure;

function DownloadImages(options) {
    assert.arrayOfObject(options.images, 'options.images');
    this.images = options.images;
}
util.inherits(DownloadImages, Procedure);

DownloadImages.prototype.summarize = function diSummarize() {
    var size = this.images.map(function (img) {
        return (img.files.length ? img.files[0].size : 0);
    }).reduce(function (prev, curr) {
        return prev + curr;
    });
    var imageInfos = this.images.map(function (img) {
        return format('image %s\n    (%s@%s)', img.uuid, img.name, img.version);
    });
    return sprintf('download %d image%s (%d MiB):\n%s',
        this.images.length,
        (this.images.length === 1 ? '' : 's'),
        size / 1024 / 1024,
        common.indent(imageInfos.join('\n')));
};

/**
 * The 'source' URL (IMGAPI endpoint) can optionally be passed in. It defaults
 * to 'updates.joyent.com?channel=<current-channel>'.
 */
DownloadImages.prototype.execute = function diExecute(options, cb) {
    assert.object(options, 'options');
    assert.object(options.sdcadm, 'options.sdcadm');
    assert.object(options.log, 'options.log');
    assert.optionalString(options.source, 'options.source');
    assert.func(options.progress, 'options.progress');
    assert.func(cb, 'cb');
    var self = this;
    var sdcadm = options.sdcadm;
    var progress = options.progress;

    var source = options.source;
    if (!source) {
        source = sdcadm.config.updatesServerUrl;
        if (sdcadm.updates.channel) {
            source += '?channel=' + sdcadm.updates.channel;
        }
    }

    /*
     * Keep track of errors during parallel image imports
     */
    var errs = [];

    /*
     * Given an array containing an array of images, this function will
     * recursively call itself until we get the origins for all the images,
     * storing these in arrays of the form:
     * [..., [Arr of origins of level 2], [Arr of origins of level 1], [imgs]]
     *
     * The callback will be called with `f(err, collectionsOfImages)`
     */
    function getAncestorsForImages(colsToRetrieve, callback) {
        var currCol = colsToRetrieve[0];
        var newCol = [];
        vasync.forEachParallel({
            inputs: currCol,
            func: function checkImgOrigin(img, nextImg) {
                if (!img.origin) {
                    nextImg();
                    return;
                }

                /*
                 * If we find that the image origin has already been queued for
                 * download, we need to move it up on the download queue, since
                 * we want it downloaded before the image we're evaluating now.
                 */
                var found = false;
                colsToRetrieve.forEach(function (aCol) {
                    var pos;
                    for (pos = 0; pos < aCol.length; pos += 1) {
                        if (aCol[pos].uuid === img.origin) {
                            newCol.push(aCol[pos]);
                            delete (aCol[pos]);
                            found = true;
                        }
                    }
                });
                if (found) {
                    nextImg();
                    return;
                }

                var orig = img.origin;
                sdcadm.imgapi.getImage(orig, function (err, local) {
                    if (!err) {
                        /*
                         * Origin already imported but unactivated.
                         */
                        if (local.state === 'unactivated') {
                            newCol.push(local);
                        }
                        nextImg();
                        return;
                    } else if (err) {
                        if (err.body.code !== 'ResourceNotFound') {
                            nextImg(new errors.SDCClientError(err, 'imgapi'));
                            return;
                        } else {
                            /*
                             * We need to fetch origin details from remote
                             * (origin not imported).
                             */
                            sdcadm.updates.getImage(orig, function (er, rem) {
                                if (er) {
                                    nextImg(new errors.SDCClientError(er,
                                        'updates'));
                                    return;
                                }
                                newCol.push(rem);
                                nextImg();
                            });
                        }
                    }
                });
            }
        }, function paraCb(paraErr) {
            if (paraErr) {
                callback(paraErr);
                return;
            }
            if (newCol.length) {
                var uuids = [];
                newCol = newCol.filter(function (elm) {
                    var isNew = (uuids.indexOf(elm.uuid) === -1);
                    if (isNew) {
                        uuids.push(elm.uuid);
                    }
                    return isNew;
                });
                colsToRetrieve.unshift(newCol);
                getAncestorsForImages(colsToRetrieve, callback);
            } else {
                callback(null, colsToRetrieve);
            }
        });
    }

    function importCollectionOfImages(collection, nextCollection) {
        var q = vasync.queuev({
            concurrency: 4,
            worker: function importUpdateImage(image, next) {
                /*
                 * Need to be verified here b/c there sdcadm parts other than
                 * procedures index calling DownloadImages.
                 */
                function checkIfImageIsUnactivated(_, nextStep) {
                    if (image.state === 'unactivated') {
                        nextStep();
                        return;
                    }
                    sdcadm.imgapi.getImage(image.uuid, function (err, local) {
                        if (err && err.body.code === 'ResourceNotFound') {
                            nextStep();
                        } else if (err) {
                            nextStep(new errors.SDCClientError(err, 'imgapi'));
                        } else {
                            if (local.state === 'unactivated') {
                                // Let DownloadImages know that it has to
                                // remove the image first:
                                image.state = 'unactivated';
                            }
                            nextStep();
                        }
                    });
                }

                function deleteImage(_, nextStep) {
                    if (image.state !== 'unactivated') {
                        return nextStep();
                    }

                    progress('Removing unactivated image %s\n(%s@%s)',
                        image.uuid, image.name, image.version);

                    sdcadm.imgapi.deleteImage(image.uuid, function (err) {
                        if (err) {
                            progress(
                                'Error removing unactivated image %s\n(%s@%s)',
                                image.uuid, image.name, image.version);

                            var e = new errors.SDCClientError(err, 'imgapi');
                            e.image = image.uuid;
                            sdcadm.log.error({err: e}, 'Error removing image');
                            nextStep(e);
                        } else {
                            nextStep();
                        }
                    });
                }

                function getImage(_, nextStep) {
                    progress('Downloading image %s\n    (%s@%s)',
                        image.uuid, image.name, image.version);
                    sdcadm.imgapi.adminImportRemoteImageAndWait(
                        image.uuid,
                        source,
                        {
                            // TODO: Once IMGAPI-408 is sufficient deployed,
                            // then drop this `skipOwnerCheck`.
                            skipOwnerCheck: true,
                            // Retry image import 5 times by default:
                            retries: 5
                        },
                        function (err, img, res) {
                            if (err) {
                                progress('Error importing image %s\n(%s@%s)',
                                    image.uuid, image.name, image.version);
                                var e = new errors.SDCClientError(err,
                                    'imgapi');
                                e.image = image.uuid;
                                nextStep(e);
                            } else {
                                progress('Imported image %s\n    (%s@%s)',
                                    image.uuid, image.name, image.version);
                                nextStep();
                            }
                        });
                }

                vasync.pipeline({funcs: [
                    checkIfImageIsUnactivated,
                    deleteImage,
                    getImage
                ]}, next);
            }
        });

        function onTaskComplete(err) {
            if (err) {
                errs.push(err);
            }
        }

        q.on('end', function done() {
            nextCollection();
        });

        q.push(collection, onTaskComplete);
        q.close();
    }

    /*
     * TOOLS-1634: We need to make sure that all the origins for
     * all our images are imported and active in local IMGAPI.
     * Additionally, we cannot try to import origins and the images
     * created from those origins in parallel, so we need to import
     * the different level of images ancestors sequentially.
     *
     * We'll use an array of arrays, prepending collections to this array as
     * we go deeper in image's origins. Every origin not already on the local
     * IMGAPI or with a state of 'unactivated' will be imported. Once we have
     * a collection of 'sibiling' origins, we'll normalize that collection
     * (remove duplicates) and prepend to `collectionsToRetrieve`:
     */
    var collectionsToRetrieve = [];
    /*
     * We'll begin with the service images we want to retrieve first,
     * then we'll continue with successive origins.
     */
    collectionsToRetrieve.unshift(self.images);

    getAncestorsForImages(collectionsToRetrieve, function (err, collections) {
        if (err) {
            cb(err);
            return;
        }

        vasync.forEachPipeline({
            inputs: collections,
            func: importCollectionOfImages
        }, function pipeCb(pipeErr) {
            if (pipeErr) {
                cb(pipeErr);
                return;
            }
            var er = (errs.length === 1) ? errs[0] :
                new errors.MultiError(errs);

            // Check if the problem is that external nics are missing.
            if (errs.length) {
                var remoteSourceErr = errs.some(function (e) {
                    return (e && e.we_cause &&
                        e.we_cause.name === 'RemoteSourceError');
                });

                if (remoteSourceErr) {
                    sdcadm.checkMissingExternalNics({
                        progress: progress
                    }, function (nicsErr, res) {
                        if (nicsErr) {
                            return cb(errs);
                        }

                        var doimgapi = res.doimgapi;
                        if (doimgapi) {
                            p('');
                            var msg = 'There is an error trying to download ' +
                                'images because the imgapi zone has no ' +
                                'external NIC.\nPlease run:\n\n' +
                                '   sdcadm post-setup common-external-nics\n' +
                                '\nand try again.\n';
                            p(msg);
                        }
                        // we need to return the error anyway:
                        cb(er);
                        return;
                    });
                } else {
                    cb(er);
                }
            } else {
                cb();
            }
        });
    });
};

//---- exports

module.exports = {
    DownloadImages: DownloadImages
};
// vim: set softtabstop=4 shiftwidth=4:
<|endoftext|>


<commit_before>$(document).ready(function(){
  var color_arr = ['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
  'lime', 'maroon', 'navy', 'olive', 'orange', 'purple', 'red',
  'silver', 'teal', 'white', 'yellow'];
  var chat_text = "Here is some text";
  var text_arr = chat_text.split('');
  console.log(text_arr);
  $("#play").on('click', function(){

    var color_changer = function(index){
      var hue = Math.floor(Math.random() * 360);
      var pastel = 'hsl(' + hue + ', 100%, 87.5%)';
      document.body.style.backgroundColor = pastel;
    }

    var i = 0, l = text_arr.length;
      (function iterator() {
      console.log(text_arr[i]);
        color_changer(i);

      if(++i<text_arr.length) {
          setTimeout(iterator, 1000);
      }
    })();

  });

});<commit_msg>Add play all functionality<commit_after>$(document).ready(function(){

  // var chat_text = "Here is some text";
  // var text_arr = chat_text.split('');

  $("#play").on('click', function(){
    var message_text = $('.message.row').children('p').text();
    var message_arr = message_text.split('');
    console.log(message_arr);

    var color_changer = function(index){
      var hue = Math.floor(Math.random() * 360);
      var pastel = 'hsl(' + hue + ', 100%, 87.5%)';
      document.body.style.backgroundColor = pastel;
    }

    var i = 0, l = message_arr.length;
      (function iterator() {
      console.log(message_arr[i]);
        color_changer(i);
        $('#letter-view').text(message_arr[i]);

      if(++i<message_arr.length) {
          setTimeout(iterator, 1000);
      }
    })();

  });

});<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Basic model for a push button, including over/down/enabled properties and the derived property "interactionState".
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var DownUpListener = require( 'SCENERY/input/DownUpListener' );
  var Property = require( 'AXON/Property' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );

  /**
   * @param {Object} options
   * @constructor
   */
  function ButtonModel( options ) {
    var buttonModel = this;

    options = _.extend( {
      fireOnDown: false,
      listener: null
    }, options );

    PropertySet.call( this, {
      over: false,
      down: false,
      enabled: true
    } );

    this.listeners = []
    if ( options.listener !== null ) {
      this.listeners.push( options.listener );
    }

    //Create the "interactionState" which is often used to determine how to render the button
    this.addDerivedProperty( 'interactionState', ['over', 'down', 'enabled'], function( over, down, enabled ) {
      //idle, over, pressed, disabled
      return !enabled ? 'disabled' :
             over && !down ? 'over' :
             over && down ? 'pressed' :
             'idle';
    } );

    //If button was pressed and "fire on down" was set, fire the listeners
    this.property( 'down' ).onValue( true, function() {
      if ( options.fireOnDown ) {
        buttonModel.fire();
      }
    } );

    //If button was released and "fire on down" was not set, fire the listeners
    this.property( 'down' ).onValue( false, function() {
      if ( !options.fireOnDown && buttonModel.over ) {
        buttonModel.fire();
      }
    } );
  }

  return inherit( PropertySet, ButtonModel, {
    // Adds a listener. If already a listener, this is a no-op.
    addListener: function( listener ) {
      if ( this.listeners.indexOf( listener ) === -1 ) {
        this.listeners.push( listener );
      }
    },

    // Remove a listener. If not a listener, this is a no-op.
    removeListener: function( listener ) {
      var i = this.listeners.indexOf( listener );
      if ( i !== -1 ) {
        this.listeners.splice( i, 1 );
      }
    },

    // Fires all listeners.  Should not be called outside of this file with
    // the possible exception of hooking up for accessibility.
    fire: function() {
      var copy = this.listeners.slice( 0 );
      copy.forEach( function( listener ) {
        listener();
      } );
    }
  } );
} );<commit_msg>updated comments<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Basic model for a push button, including over/down/enabled properties and the derived property "interactionState".
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var DownUpListener = require( 'SCENERY/input/DownUpListener' );
  var Property = require( 'AXON/Property' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );

  /**
   * @param {Object} options
   * @constructor
   */
  function ButtonModel( options ) {
    var buttonModel = this;

    options = _.extend( {
      fireOnDown: false,
      listener: null
    }, options );

    PropertySet.call( this, {
      over: false,
      down: false,
      enabled: true
    } );

    this.listeners = []
    if ( options.listener !== null ) {
      this.listeners.push( options.listener );
    }

    //Create the "interactionState" which is often used to determine how to render the button
    this.addDerivedProperty( 'interactionState', ['over', 'down', 'enabled'], function( over, down, enabled ) {
      return !enabled ? 'disabled' :
             over && !down ? 'over' :
             over && down ? 'pressed' :
             'idle';
    } );

    //If button was pressed and "fire on down" was set, fire the listeners
    this.property( 'down' ).onValue( true, function() {
      if ( options.fireOnDown ) {
        buttonModel.fire();
      }
    } );

    //If button was released and "fire on down" was not set, fire the listeners
    this.property( 'down' ).onValue( false, function() {
      if ( !options.fireOnDown && buttonModel.over ) {
        buttonModel.fire();
      }
    } );
  }

  return inherit( PropertySet, ButtonModel, {
    // Adds a listener. If already a listener, this is a no-op.
    addListener: function( listener ) {
      if ( this.listeners.indexOf( listener ) === -1 ) {
        this.listeners.push( listener );
      }
    },

    // Remove a listener. If not a listener, this is a no-op.
    removeListener: function( listener ) {
      var i = this.listeners.indexOf( listener );
      if ( i !== -1 ) {
        this.listeners.splice( i, 1 );
      }
    },

    // Fires all listeners.  Should not be called outside of this file with
    // the possible exception of hooking up for accessibility.
    fire: function() {
      var copy = this.listeners.slice( 0 );
      copy.forEach( function( listener ) {
        listener();
      } );
    }
  } );
} );<|endoftext|>


<commit_before>angular.module("leaflet-directive").factory('leafletLegendHelpers', function () {
	var _updateLegend = function(div, legendData, type, url) {
		div.innerHTML = '';
		if(legendData.error) {
			div.innerHTML += '
' + legendData.error.message + '
';
		} else {
			if (type === 'arcgis') {
				for (var i = 0; i < legendData.layers.length; i++) {
					var layer = legendData.layers[i];
					div.innerHTML += '
' + layer.layerName + '
';
					for(var j = 0; j < layer.legend.length; j++) {
						var leg = layer.legend[j];
						div.innerHTML +=
							'

' +
							'
' + leg.label + '
';
					}
				}
			}
			else if (type === 'image') {
				div.innerHTML = '';
			}
		}
	};

	var _getOnAddLegend = function(legendData, legendClass, type, url) {
		return function(/*map*/) {
			var div = L.DomUtil.create('div', legendClass);

			if (!L.Browser.touch) {
				L.DomEvent.disableClickPropagation(div);
				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
			} else {
				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
			}
			_updateLegend(div, legendData, type, url);
			return div;
		};
	};

	var _getOnAddArrayLegend = function(legend, legendClass) {
		return function(/*map*/) {
			var div = L.DomUtil.create('div', legendClass);
            for (var i = 0; i < legend.colors.length; i++) {
                div.innerHTML +=
                    '

' +
                    '
' + legend.labels[i] + '
';
            }
            if (!L.Browser.touch) {
				L.DomEvent.disableClickPropagation(div);
				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
			} else {
				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
			}
            return div;
		};
	};

	return {
		getOnAddLegend: _getOnAddLegend,
		getOnAddArrayLegend: _getOnAddArrayLegend,
		updateLegend: _updateLegend,
	};
});
<commit_msg>Added support for titles on array legends<commit_after>angular.module("leaflet-directive").factory('leafletLegendHelpers', function () {
	var _updateLegend = function(div, legendData, type, url) {
		div.innerHTML = '';
		if(legendData.error) {
			div.innerHTML += '
' + legendData.error.message + '
';
		} else {
			if (type === 'arcgis') {
				for (var i = 0; i < legendData.layers.length; i++) {
					var layer = legendData.layers[i];
					div.innerHTML += '
' + layer.layerName + '
';
					for(var j = 0; j < layer.legend.length; j++) {
						var leg = layer.legend[j];
						div.innerHTML +=
							'

' +
							'
' + leg.label + '
';
					}
				}
			}
			else if (type === 'image') {
				div.innerHTML = '';
			}
		}
	};

	var _getOnAddLegend = function(legendData, legendClass, type, url) {
		return function(/*map*/) {
			var div = L.DomUtil.create('div', legendClass);

			if (!L.Browser.touch) {
				L.DomEvent.disableClickPropagation(div);
				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
			} else {
				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
			}
			_updateLegend(div, legendData, type, url);
			return div;
		};
	};

	var _getOnAddArrayLegend = function(legend, legendClass) {
		return function(/*map*/) {
			var div = L.DomUtil.create('div', legendClass);
            if(legend.title)
              div.innerHTML += ''+legend.title+'';
            if(legend.titleHTML)
              div.innerHTML += legend.titleHTML;
            for (var i = 0; i < legend.colors.length; i++) {
                div.innerHTML +=
                    '

' +
                    '
' + legend.labels[i] + '
';
            }
            if (!L.Browser.touch) {
				L.DomEvent.disableClickPropagation(div);
				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
			} else {
				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
			}
            return div;
		};
	};

	return {
		getOnAddLegend: _getOnAddLegend,
		getOnAddArrayLegend: _getOnAddArrayLegend,
		updateLegend: _updateLegend,
	};
});
<|endoftext|>


<commit_before>var Ebay = require('ebay')

var ebay = new Ebay({
  app_id: 'Galvaniz-8de6-4bc1-a262-d7d776da1555'
})

//  make request to Ebay Finding API
var params = {
  'OPERATION-NAME': 'findItemsByKeywords'
, 'keywords': 'shoes'
}

ebay.get('finding', params, function (err, data) {
  if(err) throw err

  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["title"][0]));
  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["galleryURL"][0]));
  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["sellingStatus"][0]["currentPrice"][0]["__value__"]));
})
<commit_msg>added itemURL<commit_after>var Ebay = require('ebay')

var ebay = new Ebay({
  app_id: 'Galvaniz-8de6-4bc1-a262-d7d776da1555'
})

//  make request to Ebay Finding API
var params = {
  'OPERATION-NAME': 'findItemsByKeywords'
, 'keywords': 'star wars'
}

ebay.get('finding', params, function (err, data) {
  if(err) throw err

  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["galleryURL"][0]));
  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["title"][0]));
  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["sellingStatus"][0]["currentPrice"][0]["__value__"]));
  console.log(JSON.stringify(data["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"][0]["viewItemURL"][0]));
})
<|endoftext|>