<commit_before>#!/usr/bin/env node

var util = require('util');
var path = require('path');
var assemble = require('..');
var commands = require('../lib/commands');
var plugins = require('../lib/plugins');
var utils = require('../lib/utils');
var errors = require('./errors');
var argv = utils.parseArgs(process.argv.slice(2));

function run(cb) {
  var cwd = process.cwd();
  var app;

  /**
   * Set the working directory
   */

  if (argv.cwd && cwd !== path.resolve(argv.cwd)) {
    process.chdir(argv.cwd);
    cwd = process.cwd();
  }

  /**
   * Log the working directory
   */

  console.log(utils.log.timestamp, 'using cwd ' + utils.formatDir(cwd));

  /**
   * Get the assemblefile.js to use
   */

  var assemblefile = path.resolve(cwd, argv.file || 'assemblefile.js');

  /**
   * Get the `assemble` instance to use
   */

  var defaults = require('../lib/generator');
  var configfile = utils.exists(assemblefile);
  if (configfile) {
    app = require(assemblefile);
  } else {
    app = defaults;
  }

  /**
   * If `app` is a function, it's an assemble "generator",
   * so we need to invoke it with an instance of assemble
   */

  if (typeof app === 'function') {
    var fn = app;
    app = assemble(argv);
    app.option(argv);
    app.use(fn);
  } else if (Object.keys(app).length === 0) {
    var msg = util.format(errors['instance'], utils.homeRelative(assemblefile));
    cb(new Error(msg));
    return;
  }

  assemble.initPlugins(app);

  /**
   * Listen for errors
   */

  app.on('error', handleError);
  app.on('build', function(event, build) {
    if (typeof event === 'string' && !build.isSilent) {
      app.log.time(event, build.key, app.log.magenta(build.time));
    }
  });
  app.on('task', function(event, task) {
    if (typeof event === 'string' && !task.isSilent) {
      app.log.time(event, task.key);
    }
  });

  /**
   * Support `--emit` for debugging
   *
   * Example:
   *   $ --emit data
   */

  if (argv.emit && typeof argv.emit === 'string') {
    app.on(argv.emit, app.log.bind(console));
  }

  /**
   * Process command line arguments
   */

  var tasks = argv._.length ? argv._ : ['default'];
  var args = app.argv(argv);
  args.tasks = tasks;

  app.set('cache.argv', args);
  app.option(args);

  /**
   * Show path to assemblefile
   */

  var fp = utils.homeRelative(assemblefile);
  app.log.path('using assemblefile ' + utils.colors.green('~/' + fp));

  /**
   * Registert `runtimes` plugin
   */

  app.use(plugins.runtimes());

  /**
   * Process command line arguments
   */

  cb(null, app);
}

/**
 * Run
 */

run(function(err, app) {
  if (err) handleError(err);
  commands(app);

  /**
   * Process command line arguments
   */

  app.cli.process(app.get('cache.argv'), function(err) {
    if (err) handleError(err);

    /**
     * Run tasks
     */

    var tasks = app.get('cache.argv.tasks');
    app.build(tasks, function(err) {
      if (err) handleError(err);
      app.log.success('finished');
    });
  });
});

/**
 * Handle CLI errors
 */

function handleError(err) {
  if (typeof err === 'string' && errors[err]) {
    console.error(errors[err]);
  } else {
    if (argv.verbose) {
      console.error(err.stack);
    } else {
      console.error(err.message);
    }
  }
  process.exit(1);
}
<commit_msg>ensure exported function is not assemble ctor<commit_after>#!/usr/bin/env node

var util = require('util');
var path = require('path');
var assemble = require('..');
var commands = require('../lib/commands');
var plugins = require('../lib/plugins');
var utils = require('../lib/utils');
var errors = require('./errors');
var argv = utils.parseArgs(process.argv.slice(2));

function run(cb) {
  var cwd = process.cwd();
  var app;

  /**
   * Set the working directory
   */

  if (argv.cwd && cwd !== path.resolve(argv.cwd)) {
    process.chdir(argv.cwd);
    cwd = process.cwd();
  }

  /**
   * Log the working directory
   */

  console.log(utils.log.timestamp, 'using cwd ' + utils.formatDir(cwd));

  /**
   * Get the assemblefile.js to use
   */

  var assemblefile = path.resolve(cwd, argv.file || 'assemblefile.js');

  /**
   * Get the `assemble` instance to use
   */

  var defaults = require('../lib/generator');
  var configfile = utils.exists(assemblefile);
  if (configfile) {
    app = require(assemblefile);
  } else {
    app = defaults;
  }

  /**
   * If `app` is a function, it's an assemble "generator",
   * so we need to invoke it with an instance of assemble
   */

  if ((app && Object.keys(app).length === 0) || (typeof app === 'function' && app.initAssemble)) {
    var msg = util.format(errors['instance'], utils.homeRelative(assemblefile));
    cb(new Error(msg));
    return;
  } else if (typeof app === 'function') {
    var fn = app;
    app = assemble(argv);
    app.option(argv);
    app.use(fn);
  }

  assemble.initPlugins(app);

  /**
   * Listen for errors
   */

  app.on('error', handleError);
  app.on('build', function(event, build) {
    if (typeof event === 'string' && !build.isSilent) {
      app.log.time(event, build.key, app.log.magenta(build.time));
    }
  });
  app.on('task', function(event, task) {
    if (typeof event === 'string' && !task.isSilent) {
      app.log.time(event, task.key);
    }
  });

  /**
   * Support `--emit` for debugging
   *
   * Example:
   *   $ --emit data
   */

  if (argv.emit && typeof argv.emit === 'string') {
    app.on(argv.emit, app.log.bind(console));
  }

  /**
   * Process command line arguments
   */

  var tasks = argv._.length ? argv._ : ['default'];
  var args = app.argv(argv);
  args.tasks = tasks;

  app.set('cache.argv', args);
  app.option(args);

  /**
   * Show path to assemblefile
   */

  var fp = utils.homeRelative(assemblefile);
  app.log.path('using assemblefile ' + utils.colors.green('~/' + fp));

  /**
   * Registert `runtimes` plugin
   */

  app.use(plugins.runtimes());

  /**
   * Process command line arguments
   */

  cb(null, app);
}

/**
 * Run
 */

run(function(err, app) {
  if (err) handleError(err);
  commands(app);

  /**
   * Process command line arguments
   */

  app.cli.process(app.get('cache.argv'), function(err) {
    if (err) handleError(err);

    /**
     * Run tasks
     */

    var tasks = app.get('cache.argv.tasks');
    app.build(tasks, function(err) {
      if (err) handleError(err);
      app.log.success('finished');
    });
  });
});

/**
 * Handle CLI errors
 */

function handleError(err) {
  if (typeof err === 'string' && errors[err]) {
    console.error(errors[err]);
  } else {
    if (argv.verbose) {
      console.error(err.stack);
    } else {
      console.error(err.message);
    }
  }
  process.exit(1);
}
<|endoftext|>


<commit_before>var watch = require('node-watch'),
	fs = require('fs'),
	path = require('path'),
	jade = require('jade'),
	express = require('express'),
	async = require('async');

	var liveReload = require('./live-reload.js'),
		fsUtil = require('./fs-util'),
		parsers = require('./parsers');

function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

var Site = function(param, callback) {
	this.directory = param.directory;
	this.url = path.join('/', this.directory);
	woods.express.use(
		path.join(this.url, 'static'),
		express.static(this.getUri('assets'))
	);
	var site = this;
	loadParsers(this, function() {
		site.build(function(err) {
			callback(err);
			site.watchDirectory();
		});
	});

	var regex = new RegExp(escapeRegExp(this.url) + '(.+)*');

	// Install the path in express:
	woods.express.get(regex, function(req, res, next) {
		var then = new Date(),
			page = site.root.get(req.params.length && req.params[0]);
		if (page) {
			res.end(page.render('html'));
			console.log('Serving ', req.url, 'took', new Date() - then);
		} else {
			next();
		}
	});
};

Site.prototype.build = function(callback) {
	this.pageCount = 0;
	// TODO: remove static routes
	this.types = {};
	this.templateLocations = {};
	var site = this;
	this.addType('default', function(err) {
		if (err)
			return callback(err);
		site.root = new Page(site, null, '', null, callback);
	});
};

// TODO: moving this to woods makes sense:
Site.prototype.watchDirectory = function() {
	var site = this,
		options = { recursive: true, followSymLinks: true };

	watch(this.getUri(), options, function(uri) {
		// Ignore hidden files:
		if((/^\./).test(path.basename(uri)))
			return;

		// TODO: if it is a jade file, just recompile the template

		// Just reload the page if only a static resource changed:
		console.log('File changed: ', path.join(site.directory, path.relative(site.getUri(), uri)));
		var ext = path.extname(uri);
		if (ext.length && !(/(md|jade)$/).test(ext)) {
			liveReload.changed();
		} else {
			var then = new Date();
			// TODO: rebuild the Page instead of the whole site
			site.build(function() {
				console.log('Rebuilt', site.pageCount, 'pages in', new Date() - then);
				liveReload.changed();
			});
		}
	});
};

Site.prototype.getUri = function(file) {
	return path.resolve(woods.directory, this.directory, file || '');
};

Site.prototype.getTemplateDirectory = function(type) {
	return this.getUri(path.join('templates', type || ''));
};

Site.prototype.addType = function(type, callback) {
	if (this.types[type])
		return callback();
	// Check for templates belonging to type and install them
	var typeTemplates = this.types[type] = {},
		templateLocations = this.templateLocations[type] = {},
		templatesDir = this.getTemplateDirectory(type);

	var compile = function(file, doneCompiling) {
		// Compile jade templates:
		if ((/jade$/).test(file)) {
			var templateName = path.basename(file, '.jade');
			var location = templateLocations[templateName] =
					path.join(templatesDir, file);
			fs.readFile(location, 'utf-8', function(err, data) {
				if (!err)
					typeTemplates[templateName] = jade.compile(data);
				return doneCompiling(err);
			});
		} else {
			return doneCompiling();
		}
	};
	fsUtil.listFiles(templatesDir, function(err, files) {
		if (err || !files)
			return callback(err);
		async.each(files, compile, callback);
	});
};

// TODO: make parsers editable
function loadParsers(site, callback) {
	var uri = site.getUri('parsers');
	fsUtil.listFiles(uri, function(err, files) {
		if (!files)
			return callback();
		files.forEach(function(file) {
			var parser = require(path.join(uri, file)),
				name = path.basename(file, '.js');
			parsers.register(name, parser);
		});
		callback();
	});
}

function removeRoute(route) {
	var routes = woods.express.routes;
	for (var i in routes.get) {
		if (routes.get[i].path + '' === route + '') {
			routes.get.splice(i, 1);
			break;
		}
	}
}

var Page = require('./Page'),
	woods = require('./woods');

module.exports = Site;
<commit_msg>Add todo.<commit_after>var watch = require('node-watch'),
	fs = require('fs'),
	path = require('path'),
	jade = require('jade'),
	express = require('express'),
	async = require('async');

	var liveReload = require('./live-reload.js'),
		fsUtil = require('./fs-util'),
		parsers = require('./parsers');

function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

var Site = function(param, callback) {
	this.directory = param.directory;
	this.url = path.join('/', this.directory);
	woods.express.use(
		path.join(this.url, 'static'),
		express.static(this.getUri('assets'))
	);
	var site = this;
	loadParsers(this, function() {
		site.build(function(err) {
			callback(err);
			site.watchDirectory();
		});
	});

	var regex = new RegExp(escapeRegExp(this.url) + '(.+)*');

	// Install the path in express:
	woods.express.get(regex, function(req, res, next) {
		var then = new Date(),
			page = site.root.get(req.params.length && req.params[0]);
		if (page) {
			res.end(page.render('html'));
			console.log('Serving ', req.url, 'took', new Date() - then);
		} else {
			next();
		}
	});
};

Site.prototype.build = function(callback) {
	this.pageCount = 0;
	// TODO: remove static routes
	this.types = {};
	this.templateLocations = {};
	var site = this;
	this.addType('default', function(err) {
		if (err)
			return callback(err);
		site.root = new Page(site, null, '', null, callback);
	});
};

// TODO: moving this to woods makes sense:
Site.prototype.watchDirectory = function() {
	var site = this,
		options = { recursive: true, followSymLinks: true };
	// TODO: limit the amount of times this is called when many files are changed:
	watch(this.getUri(), options, function(uri) {
		// Ignore hidden files:
		if((/^\./).test(path.basename(uri)))
			return;

		// TODO: if it is a jade file, just recompile the template

		// Just reload the page if only a static resource changed:
		console.log('File changed: ', path.join(site.directory, path.relative(site.getUri(), uri)));
		var ext = path.extname(uri);
		if (ext.length && !(/(md|jade)$/).test(ext)) {
			liveReload.changed();
		} else {
			var then = new Date();
			// TODO: rebuild the Page instead of the whole site
			site.build(function() {
				console.log('Rebuilt', site.pageCount, 'pages in', new Date() - then);
				liveReload.changed();
			});
		}
	});
};

Site.prototype.getUri = function(file) {
	return path.resolve(woods.directory, this.directory, file || '');
};

Site.prototype.getTemplateDirectory = function(type) {
	return this.getUri(path.join('templates', type || ''));
};

Site.prototype.addType = function(type, callback) {
	if (this.types[type])
		return callback();
	// Check for templates belonging to type and install them
	var typeTemplates = this.types[type] = {},
		templateLocations = this.templateLocations[type] = {},
		templatesDir = this.getTemplateDirectory(type);

	var compile = function(file, doneCompiling) {
		// Compile jade templates:
		if ((/jade$/).test(file)) {
			var templateName = path.basename(file, '.jade');
			var location = templateLocations[templateName] =
					path.join(templatesDir, file);
			fs.readFile(location, 'utf-8', function(err, data) {
				if (!err)
					typeTemplates[templateName] = jade.compile(data);
				return doneCompiling(err);
			});
		} else {
			return doneCompiling();
		}
	};
	fsUtil.listFiles(templatesDir, function(err, files) {
		if (err || !files)
			return callback(err);
		async.each(files, compile, callback);
	});
};

// TODO: make parsers editable
function loadParsers(site, callback) {
	var uri = site.getUri('parsers');
	fsUtil.listFiles(uri, function(err, files) {
		if (!files)
			return callback();
		files.forEach(function(file) {
			var parser = require(path.join(uri, file)),
				name = path.basename(file, '.js');
			parsers.register(name, parser);
		});
		callback();
	});
}

function removeRoute(route) {
	var routes = woods.express.routes;
	for (var i in routes.get) {
		if (routes.get[i].path + '' === route + '') {
			routes.get.splice(i, 1);
			break;
		}
	}
}

var Page = require('./Page'),
	woods = require('./woods');

module.exports = Site;
<|endoftext|>


<commit_before>'use strict';

var co = require('co');
var path = require('path');
var util = require('util');
var debug = require('debug');
var mkdirp = require('mkdirp');
var expand = require('globby');
var chokidar = require('chokidar');
var assign = require('object-assign');
var Cat = require('concat-with-sourcemaps');

var Emitter = require('./emitter');
var utils = require('./utils');

// import { dirname, join, parse, sep } from "path"
// import { readFile, writeFile } from "mz/fs"
// import { log, alert, error, defer, flatten } from "./utils"
var _ = utils.debug('fly');
var clear = utils.defer(require('./rimraf'));

function Fly(options) {
	if (!(this instanceof Fly)) {
		throw new TypeError('Fly cannot be invoked without \'new\'');
	}

	// constructor defaults
	options = options || {};
	var host = options.host || {};
	var file = options.file || '.';
	var plugins = options.plugins || [];

	// ~ `super()`
	Emitter.call(this);

	// attach files & funcs into the curr instance
	assign(this, {
		file: file,
		plugins: plugins,
		root: path.dirname(file),
		alert: utils.alert,
		error: utils.error,
		defer: utils.defer,
		log: utils.log,
		host: (typeof host === 'function') ? assign(host, {default: host}) : host,
		debug: _,
		_: {
			filters: []
		},
		tasks: Object.keys(host).reduce(function (_, key) {
			return assign(_, {[key]: host[key].bind(this)});
		}, {})
	});

	plugins.forEach(function (el) {
		if (!el.plugin) {
			throw new Error('Did you forget to `npm i -D ' + el.name + '`?');
		}
		// if (plugin.default) plugin = plugin.default
		el.plugin.call(this, debug(el.name.replace('-', ':')), _('load %o', el.name));
	});

	_('chdir %o', this.root);

	process.chdir(this.root);
}

// `Fly extends emitter`...
util.inherits(Fly, Emitter);
module.exports = Fly;

/**
 * Compose a new, yeildable sequence.
 * Resets instance's glob, filters, and writer.
 *
 * @param  {String|Array} globs The glob selection
 * @return 											The current Fly instance.
 */
Fly.prototype.source = function (globs) {
	assign(this, {
		_: {
			filters: [],
			globs: flatten(globs)
		}
	});

	this._.cat = undefined;
	_('source %o', this._.globs);
	return this;
};

/**
/**
 * Add filter / transform function.
 * Create a closure bound to the current Fly instance.
 *
 * @param {String|Function} name 		The name of filter || the callback
 * @param {Function} 				cb 			the function: (cb, options) => {}
*/
Fly.prototype.filter = function (name, cb) {
	var type = typeof name;

	if (type === 'function') {
		this.filter({cb: name});
	} else if (type === 'object') {
		this._.filters.push(name);
	} else {
		if (typeof this[name] === 'function') {
			throw new RangeError(name + ' method is already defined!');
		}

		this[name] = function (options) {
			var rest = [];
			rest.push.apply(rest, arguments) && rest.shift();

			debug('fly')(`${name} %o, %o`, options, rest);

			return this.filter({
				cb: cb,
				options: options,
				rest: rest
			});
		};
	}

	return this;
};

/**
 * Watch IO events within glob selections & run tasks
 * @param  {String} globs   The glob patterns to observe
 * @param  {String} tasks   The list of tasks to run on file changes
 * @param  {Object} options The options for `Fly.proto.start`
 * @return {void}
 */
Fly.prototype.watch = function (globs, tasks, options) {
	_('watch %o', globs);

	var self = this;
	return self.emit('fly+watch').start(tasks, options).then(function () {
		chokidar.watch(flatten(globs), {ignoreInitial: true}).on('all', function () {
			self.start(tasks, options);
		});
	});
};

/**
 * Unwrap/Expand source globs as single files, then run fn.
 * @param  {Function} onResolved  The callback to run on 'success'.
 * @param  {Function} onRejected  The callback to run on 'error'.
 * @return {Promise}
 */
Fly.prototype.unwrap = function (onResolved, onRejected) {
	var self = this;

	var p = new Promise(function (resolve, reject) {
		// unwrap all globs
		return Promise.all(self._.globs.map(function (glob) {
			return expand(glob);
		})).then(function (files) {
			// then attach 'files' array to instance
			return resolve.call(self, files.reduce(function (arr, item) {
				return arr.concat(item);
			}));
		}).catch(reject);
	});

	return p.then(onResolved).catch(onRejected);
};

/**
 * Execute a single task.
 * @param  {String} task     The name of the task
 * @param  {Mixed}  value    The initial value to pass into `task`
 * @param  {Object} instance The Fly instance `task` should be bound to
 * @return {Mixed}           The task's resulting value.
 */
Fly.prototype.exec = function * (task, value, instance) {
	instance = instance || this;

	_('run %o', task);

	try {
		var start = getTime();

		this.emit('task_start', {
			task: task
		});

		value = (yield this.host[task].call(instance, value)) || value;

		this.emit('task_complete', {
			task: task,
			duration: getTime() - start
		});
	} catch (e) {
		this.emit('task_error', {
			task: task,
			error: e
		});
	}

	return value;
};

/**
 * Run a task sequence of 1 or more.
 * Each task's return value is piped into the next task of sequence.
 *
 * @param  {Array}  tasks   The list of tasks to start
 * @param  {Object} options The options to begin.
 * @return {Promise}
 */
Fly.prototype.start = function (tasks, options) {
	tasks = tasks || 'default';
	options = assign({}, {
		parallel: false,
		value: null
	}, options || {});

	_('start %o in ' + (options.parallel ? 'parallel' : 'sequence'), tasks);

	var self = this;
	var value = options.value;

	return co.call(self, function * (tasks) {
		if (options.parallel) {
			yield tasks.map(function (task) {
				return self.exec(task, value, Object.create(self));
			});
		} else {
			tasks.map(function * (task) {
				value = yield self.exec(task, value);
			});
		}
		return value;
	}, [].concat(tasks).filter(function (task) {
		return Object.keys(self.host).indexOf(task) !== -1 || !self.emit('task_not_found', {task: task});
	}));
};

/**
 * Deferred `rimraf` wrapper
 * @param  {String|Array} paths The paths to delete
 * @return {void}
 */
Fly.prototype.clear = function (paths) {
	paths = Array.isArray(paths) ? paths : [paths];

	_('clear %o', paths);

	return flatten(paths).map(function (p) {
		clear(p);
	});
};

/**
 * Concatenate active `files` to single file.
 * @param  {String} filename  The single output file
 * @return {Fly}      				The current Fly instance.
 */
Fly.prototype.concat = function (filename) {
	this._.cat = new Cat(false, filename, '\n');
	this._.cat.base = filename;
	return this;
};

/**
 * Resolve a yieldable sequence.
 * Reduces `source` with filters and invokes writer.
 *
 * @param  {Array}  dirs    The target/destination directories
 * @param  {Object} options Target options. Depth refers to path retention
 * @return {Promise}
 */
Fly.prototype.target = function (dirs, options) {
	dirs = Array.isArray(dirs) ? dirs : [dirs];
	options = assign({}, {depth: -1}, options || {});

	var self = this;
	var _cat = self._.concat;
	var _filters = self._.filters;
	var sep = path.sep;

	// @todo: utilize `unwrap` here?
	return co.call(self, function * () {
		// run thru all globs
		self._.globs.map(function * (glob) {
			var files = yield expand(glob);
			// run thru all files of each glob
			for (var i = 0, file = files[i]; i < files.length; i++) {
				// get data & stats
				var f = path.parse(file);
				var data = yield fs.readFile(file);
				var ext = f.ext;

				// pass files' data thru attached filters
				_filters.map(function * (filter) {
					// run the filter's closure fn w/data
					var res = yield Promise.resolve(filter.cb.apply(
						self, [data, assign({filename: f.base}, filter.options)].concat(filter.rest)
					));

					// once done, retrieve the final `data` & `ext` of output
					data = res.code || res.js || res.css || res.data || res || data;
					ext = res.ext || res.extension || ext;
				});

				if (_cat) {
					_cat.add(f.base, data);
				} else {
					// get common 'base' path between glob & current filepath
					var base = f.dir.split(sep).filter(function (filepath) {
						return glob.split(sep).indexOf(filepath) !== -1;
					});

					// attach file to base
					base = path.join(base, f.name + '.' + ext);

					// complete the promise & write the output
					yield resolve(dirs, {
						data: data,
						base: base,
						depth: options.depth
					});
				}
			}
		});

		if (_cat) {
			yield resolve(dirs, {
				data: _cat.content,
				base: _cat.base,
				write: fs.writeFile,
				depth: options.depth
			});
		}
	});
};

/** Write utility to help concat and target.
	@param {String}   dirs  parent directory
	@param {String}   base  directory/file
	@param {Mixed}    data
	@param {Integer}  depth number of parent directories to keep
	@param {Function} write promisified writer function
*/
function* resolve (dirs, { base, data, depth, write = writeFile }) {
	if (depth > -1) {
		base = dirpaths(base, depth);
	}

	for (let dir of flatten(dirs)) {
		const file = join(dir, base)
		mkdirp.sync(dirname(file))
		yield write(file, data)
	}
}

/**
 * Shorten a directory string to # of parent dirs
 * @param  {String}  	full    The original full path
 * @param  {Integer}  depth   The number of levels to retain
 * @return {String}
 */
function dirpaths (full, depth) {
	var arr = full.split(sep);
	var len = arr.length;
	return (depth == 0) ? arr[len - 1] : (depth >= len) ? full : arr.slice(len - 1 - depth).join(sep);
}

/**
 * Get the current timestamp
 * @return {Integer}
 */
function getTime() {
	return (new Date()).getTime();
}
<commit_msg>declare 'fs' utility, move 'sep' to global<commit_after>'use strict';

var co = require('co');
var fs = require('fs');
var path = require('path');
var util = require('util');
var debug = require('debug');
var mkdirp = require('mkdirp');
var expand = require('globby');
var chokidar = require('chokidar');
var assign = require('object-assign');
var Cat = require('concat-with-sourcemaps');

var Emitter = require('./emitter');

var sep = path.sep;
var _ = utils.debug('fly');
var clear = utils.defer(require('./rimraf'));

// import { dirname, join, parse, sep } from "path"
// import { readFile, writeFile } from "mz/fs"
// import { log, alert, error, defer, flatten } from "./utils"

function Fly(options) {
	if (!(this instanceof Fly)) {
		throw new TypeError('Fly cannot be invoked without \'new\'');
	}

	// constructor defaults
	options = options || {};
	var host = options.host || {};
	var file = options.file || '.';
	var plugins = options.plugins || [];

	// ~ `super()`
	Emitter.call(this);

	// attach files & funcs into the curr instance
	assign(this, {
		file: file,
		plugins: plugins,
		root: path.dirname(file),
		alert: utils.alert,
		error: utils.error,
		defer: utils.defer,
		log: utils.log,
		host: (typeof host === 'function') ? assign(host, {default: host}) : host,
		debug: _,
		_: {
			filters: []
		},
		tasks: Object.keys(host).reduce(function (_, key) {
			return assign(_, {[key]: host[key].bind(this)});
		}, {})
	});

	plugins.forEach(function (el) {
		if (!el.plugin) {
			throw new Error('Did you forget to `npm i -D ' + el.name + '`?');
		}
		// if (plugin.default) plugin = plugin.default
		el.plugin.call(this, debug(el.name.replace('-', ':')), _('load %o', el.name));
	});

	_('chdir %o', this.root);

	process.chdir(this.root);
}

// `Fly extends emitter`...
util.inherits(Fly, Emitter);
module.exports = Fly;

/**
 * Compose a new, yeildable sequence.
 * Resets instance's glob, filters, and writer.
 *
 * @param  {String|Array} globs The glob selection
 * @return 											The current Fly instance.
 */
Fly.prototype.source = function (globs) {
	assign(this, {
		_: {
			filters: [],
			globs: flatten(globs)
		}
	});

	this._.cat = undefined;
	_('source %o', this._.globs);
	return this;
};

/**
/**
 * Add filter / transform function.
 * Create a closure bound to the current Fly instance.
 *
 * @param {String|Function} name 		The name of filter || the callback
 * @param {Function} 				cb 			the function: (cb, options) => {}
*/
Fly.prototype.filter = function (name, cb) {
	var type = typeof name;

	if (type === 'function') {
		this.filter({cb: name});
	} else if (type === 'object') {
		this._.filters.push(name);
	} else {
		if (typeof this[name] === 'function') {
			throw new RangeError(name + ' method is already defined!');
		}

		this[name] = function (options) {
			var rest = [];
			rest.push.apply(rest, arguments) && rest.shift();

			debug('fly')(`${name} %o, %o`, options, rest);

			return this.filter({
				cb: cb,
				options: options,
				rest: rest
			});
		};
	}

	return this;
};

/**
 * Watch IO events within glob selections & run tasks
 * @param  {String} globs   The glob patterns to observe
 * @param  {String} tasks   The list of tasks to run on file changes
 * @param  {Object} options The options for `Fly.proto.start`
 * @return {void}
 */
Fly.prototype.watch = function (globs, tasks, options) {
	_('watch %o', globs);

	var self = this;
	return self.emit('fly+watch').start(tasks, options).then(function () {
		chokidar.watch(flatten(globs), {ignoreInitial: true}).on('all', function () {
			self.start(tasks, options);
		});
	});
};

/**
 * Unwrap/Expand source globs as single files, then run fn.
 * @param  {Function} onResolved  The callback to run on 'success'.
 * @param  {Function} onRejected  The callback to run on 'error'.
 * @return {Promise}
 */
Fly.prototype.unwrap = function (onResolved, onRejected) {
	var self = this;

	var p = new Promise(function (resolve, reject) {
		// unwrap all globs
		return Promise.all(self._.globs.map(function (glob) {
			return expand(glob);
		})).then(function (files) {
			// then attach 'files' array to instance
			return resolve.call(self, files.reduce(function (arr, item) {
				return arr.concat(item);
			}));
		}).catch(reject);
	});

	return p.then(onResolved).catch(onRejected);
};

/**
 * Execute a single task.
 * @param  {String} task     The name of the task
 * @param  {Mixed}  value    The initial value to pass into `task`
 * @param  {Object} instance The Fly instance `task` should be bound to
 * @return {Mixed}           The task's resulting value.
 */
Fly.prototype.exec = function * (task, value, instance) {
	instance = instance || this;

	_('run %o', task);

	try {
		var start = getTime();

		this.emit('task_start', {
			task: task
		});

		value = (yield this.host[task].call(instance, value)) || value;

		this.emit('task_complete', {
			task: task,
			duration: getTime() - start
		});
	} catch (e) {
		this.emit('task_error', {
			task: task,
			error: e
		});
	}

	return value;
};

/**
 * Run a task sequence of 1 or more.
 * Each task's return value is piped into the next task of sequence.
 *
 * @param  {Array}  tasks   The list of tasks to start
 * @param  {Object} options The options to begin.
 * @return {Promise}
 */
Fly.prototype.start = function (tasks, options) {
	tasks = tasks || 'default';
	options = assign({}, {
		parallel: false,
		value: null
	}, options || {});

	_('start %o in ' + (options.parallel ? 'parallel' : 'sequence'), tasks);

	var self = this;
	var value = options.value;

	return co.call(self, function * (tasks) {
		if (options.parallel) {
			yield tasks.map(function (task) {
				return self.exec(task, value, Object.create(self));
			});
		} else {
			tasks.map(function * (task) {
				value = yield self.exec(task, value);
			});
		}
		return value;
	}, [].concat(tasks).filter(function (task) {
		return Object.keys(self.host).indexOf(task) !== -1 || !self.emit('task_not_found', {task: task});
	}));
};

/**
 * Deferred `rimraf` wrapper
 * @param  {String|Array} paths The paths to delete
 * @return {void}
 */
Fly.prototype.clear = function (paths) {
	paths = Array.isArray(paths) ? paths : [paths];

	_('clear %o', paths);

	return flatten(paths).map(function (p) {
		clear(p);
	});
};

/**
 * Concatenate active `files` to single file.
 * @param  {String} filename  The single output file
 * @return {Fly}      				The current Fly instance.
 */
Fly.prototype.concat = function (filename) {
	this._.cat = new Cat(false, filename, '\n');
	this._.cat.base = filename;
	return this;
};

/**
 * Resolve a yieldable sequence.
 * Reduces `source` with filters and invokes writer.
 *
 * @param  {Array}  dirs    The target/destination directories
 * @param  {Object} options Target options. Depth refers to path retention
 * @return {Promise}
 */
Fly.prototype.target = function (dirs, options) {
	dirs = Array.isArray(dirs) ? dirs : [dirs];
	options = assign({}, {depth: -1}, options || {});

	var self = this;
	var _cat = self._.concat;
	var _filters = self._.filters;

	// @todo: utilize `unwrap` here?
	return co.call(self, function * () {
		// run thru all globs
		self._.globs.map(function * (glob) {
			var files = yield expand(glob);
			// run thru all files of each glob
			for (var i = 0, file = files[i]; i < files.length; i++) {
				// get data & stats
				var f = path.parse(file);
				var data = yield fs.readFile(file);
				var ext = f.ext;

				// pass files' data thru attached filters
				_filters.map(function * (filter) {
					// run the filter's closure fn w/data
					var res = yield Promise.resolve(filter.cb.apply(
						self, [data, assign({filename: f.base}, filter.options)].concat(filter.rest)
					));

					// once done, retrieve the final `data` & `ext` of output
					data = res.code || res.js || res.css || res.data || res || data;
					ext = res.ext || res.extension || ext;
				});

				if (_cat) {
					_cat.add(f.base, data);
				} else {
					// get common 'base' path between glob & current filepath
					var base = f.dir.split(sep).filter(function (filepath) {
						return glob.split(sep).indexOf(filepath) !== -1;
					});

					// attach file to base
					base = path.join(base, f.name + '.' + ext);

					// complete the promise & write the output
					yield resolve(dirs, {
						data: data,
						base: base,
						depth: options.depth
					});
				}
			}
		});

		if (_cat) {
			yield resolve(dirs, {
				data: _cat.content,
				base: _cat.base,
				write: fs.writeFile,
				depth: options.depth
			});
		}
	});
};

/** Write utility to help concat and target.
	@param {String}   dirs  parent directory
	@param {String}   base  directory/file
	@param {Mixed}    data
	@param {Integer}  depth number of parent directories to keep
	@param {Function} write promisified writer function
*/
function* resolve (dirs, { base, data, depth, write = writeFile }) {
	if (depth > -1) {
		base = dirpaths(base, depth);
	}

	for (let dir of flatten(dirs)) {
		const file = join(dir, base)
		mkdirp.sync(dirname(file))
		yield write(file, data)
	}
}

/**
 * Shorten a directory string to # of parent dirs
 * @param  {String}  	full    The original full path
 * @param  {Integer}  depth   The number of levels to retain
 * @return {String}
 */
function dirpaths (full, depth) {
	var arr = full.split(sep);
	var len = arr.length;
	return (depth == 0) ? arr[len - 1] : (depth >= len) ? full : arr.slice(len - 1 - depth).join(sep);
}

/**
 * Get the current timestamp
 * @return {Integer}
 */
function getTime() {
	return (new Date()).getTime();
}
<|endoftext|>


<commit_before>// Bitmap patch reversed from Abyss
// All credit to Blade3575

var bm1 = scan('client.exe', '80 BF 88 00 00 00 00 57 74 0D');

if (debug) {
    send(bm1);
}

patch(bm1.add(8), 0x90);
patch(bm1.add(9), 0x90);

var bm2 = scan('client.exe', '80 BE 88 00 00 00 00 74 ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 F8 01 75');

if (debug) {
    send(bm2);
}

patch(bm2.add(22), 0xEB);
<commit_msg>Update BitmapFont.js<commit_after>// Bitmap patch reversed from Abyss
// All credit to Blade3575

var bm1 = scan('client.exe', '80 BF 88 00 00 00 00 57 74 0D');
var bm2 = scan('client.exe', '80 BE 88 00 00 00 00 74 ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 F8 01 75');

if (debug) {
    send(bm1);
    send(bm2);
}

if (bm1 == NULL || bm2 == NULL)
	send('Failed to apply patch.');
else
{
	patch(bm1.add(8), 0x90);
	patch(bm1.add(9), 0x90);

	patch(bm2.add(22), 0xEB);
}
<|endoftext|>


<commit_before>'use strict';

const Slack = require('slack-client');
const JiraApi = require('jira').JiraApi;
const async = require('async');
const _ = require('lodash');
const moment = require('moment');

const JIRA_REGEX = /\b([A-Z]{2,8}-[0-9]{1,8})\b/g;

function Bot(config) {
  this.config = config;
  this.issueTimes = {};
  this.projectKeys = [];
}

module.exports = Bot;

// istanbul ignore next
Bot.prototype.init = function(callback) {
  this.jira = new JiraApi(
    'https',
    this.config.jira.host,
    this.config.jira.port,
    this.config.jira.user,
    this.config.jira.password,
    'latest'
  );
  this.slack = new Slack(this.config.slack.token, true, true);
  this._setupSlackHandlers();
  this.jira.listProjects((err, projects) => {
    if (err) {
      return callback(err);
    }
    this.projectKeys = projects.map(project => {
      return project.key;
    });
    this.slack.login();
    return callback();
  });
};

// istanbul ignore next
Bot.prototype._setupSlackHandlers = function() {
  this.slack.on('open', () => {
    console.log('Bot connected to Slack');
  });

  this.slack.on('message', message => {
    this._handleMessage(message, this._handleError);
  });

  this.slack.on('error', this._handleError);
};

Bot.prototype._handleMessage = function(message, callback) {
  // Skip messages posted by the bot!
  if (message.user === this.slack.self.id) {
    return callback();
  }
  // Skip messages in rooms that we've been told to ignore
  if (_.contains(this.config.channelsToIgnore, message.channel)) {
    return callback();
  }
  // Skip messages sent by other bots
  const user = this.slack.getUserByID(message.user);
  if (!user || user.is_bot) {
    return callback();
  }
  if (!message.text) {
    return callback();
  }
  const ids = _.uniq(message.text.match(this._jiraRegex()));
  const channel = this.slack.getChannelGroupOrDMByID(message.channel);
  async.eachSeries(ids, (id, next) => {
    if (!this._shouldPostIssue(message.channel, id)) {
      return next();
    }
    this.jira.findIssue(id, (err, issue) => {
      if (err) {
        return next();
      }
      // istanbul ignore next
      if (!issue) {
        return next();
      }
      channel.postMessage(this._messageFromIssue(id, issue));
      this._markIssuePosted(message.channel, id);
      next();
    });
  },
  callback);
};

Bot.prototype._shouldPostIssue = function(channelId, jiraId) {
  if (!this.issueTimes[channelId]) {
    return true;
  }
  if (!this.issueTimes[channelId][jiraId]) {
    return true;
  }
  const timeSince = new Date() - this.issueTimes[channelId][jiraId];
  return timeSince >= 30 * 60 * 1000;
};

Bot.prototype._markIssuePosted = function(channelId, jiraId) {
  if (!this.issueTimes[channelId]) {
    this.issueTimes[channelId] = {};
  }
  this.issueTimes[channelId][jiraId] = new Date();
};

Bot.prototype._makeJiraLink = function(id) {
  return `${this.config.jira.urlRoot}${id}`;
};

Bot.prototype._jiraRegex = function() {
  if (this.projectKeys && this.projectKeys.length) {
    const keyString = this.projectKeys.join('|');
    return new RegExp(`\\b((${keyString})-[0-9]{1,8})\\b`, 'gi');
  }
  return JIRA_REGEX;
};

// istanbul ignore next
Bot.prototype._handleError = function(err) {
  if (!err) {
    return;
  }
  console.error(err);
};

Bot.prototype._formatDate = function(date) {
  if (!date) {
    return null;
  }
  return moment(date).format('YYYY-MM-DD HH:mm');
};

Bot.prototype._messageFromIssue = function(id, issue) {
  return {
    text: `<${this._makeJiraLink(id)}|*${id}*: ${issue.fields.summary}>`,
    as_user: true,
    attachments: [
      {
        fallback: '',
        fields: [
          {
            title: 'Type',
            value: _.get(issue, 'fields.issuetype.name', 'Unknown'),
            short: true
          },
          {
            title: 'Priority',
            value: _.get(issue, 'fields.priority.name', 'Unknown'),
            short: true
          },
          {
            title: 'Status',
            value: _.get(issue, 'fields.status.name', 'Unknotwn'),
            short: true
          },
          {
            title: 'Assignee',
            value: _.get(issue, 'fields.assignee.displayName', 'None'),
            short: true
          },
          {
            title: 'Created',
            value: this._formatDate(_.get(issue, 'fields.created', null)),
            short: true
          },
          {
            title: 'Updated',
            value: this._formatDate(_.get(issue, 'fields.updated', null)),
            short: true
          }
        ]
      }
    ]
  };
};
<commit_msg>Provide the fallback text for IRC users<commit_after>'use strict';

const Slack = require('slack-client');
const JiraApi = require('jira').JiraApi;
const async = require('async');
const _ = require('lodash');
const moment = require('moment');

const JIRA_REGEX = /\b([A-Z]{2,8}-[0-9]{1,8})\b/g;

function Bot(config) {
  this.config = config;
  this.issueTimes = {};
  this.projectKeys = [];
}

module.exports = Bot;

// istanbul ignore next
Bot.prototype.init = function(callback) {
  this.jira = new JiraApi(
    'https',
    this.config.jira.host,
    this.config.jira.port,
    this.config.jira.user,
    this.config.jira.password,
    'latest'
  );
  this.slack = new Slack(this.config.slack.token, true, true);
  this._setupSlackHandlers();
  this.jira.listProjects((err, projects) => {
    if (err) {
      return callback(err);
    }
    this.projectKeys = projects.map(project => {
      return project.key;
    });
    this.slack.login();
    return callback();
  });
};

// istanbul ignore next
Bot.prototype._setupSlackHandlers = function() {
  this.slack.on('open', () => {
    console.log('Bot connected to Slack');
  });

  this.slack.on('message', message => {
    this._handleMessage(message, this._handleError);
  });

  this.slack.on('error', this._handleError);
};

Bot.prototype._handleMessage = function(message, callback) {
  // Skip messages posted by the bot!
  if (message.user === this.slack.self.id) {
    return callback();
  }
  // Skip messages in rooms that we've been told to ignore
  if (_.contains(this.config.channelsToIgnore, message.channel)) {
    return callback();
  }
  // Skip messages sent by other bots
  const user = this.slack.getUserByID(message.user);
  if (!user || user.is_bot) {
    return callback();
  }
  if (!message.text) {
    return callback();
  }
  const ids = _.uniq(message.text.match(this._jiraRegex()));
  const channel = this.slack.getChannelGroupOrDMByID(message.channel);
  async.eachSeries(ids, (id, next) => {
    if (!this._shouldPostIssue(message.channel, id)) {
      return next();
    }
    this.jira.findIssue(id, (err, issue) => {
      if (err) {
        return next();
      }
      // istanbul ignore next
      if (!issue) {
        return next();
      }
      channel.postMessage(this._messageFromIssue(id, issue));
      this._markIssuePosted(message.channel, id);
      next();
    });
  },
  callback);
};

Bot.prototype._shouldPostIssue = function(channelId, jiraId) {
  if (!this.issueTimes[channelId]) {
    return true;
  }
  if (!this.issueTimes[channelId][jiraId]) {
    return true;
  }
  const timeSince = new Date() - this.issueTimes[channelId][jiraId];
  return timeSince >= 30 * 60 * 1000;
};

Bot.prototype._markIssuePosted = function(channelId, jiraId) {
  if (!this.issueTimes[channelId]) {
    this.issueTimes[channelId] = {};
  }
  this.issueTimes[channelId][jiraId] = new Date();
};

Bot.prototype._makeJiraLink = function(id) {
  return `${this.config.jira.urlRoot}${id}`;
};

Bot.prototype._jiraRegex = function() {
  if (this.projectKeys && this.projectKeys.length) {
    const keyString = this.projectKeys.join('|');
    return new RegExp(`\\b((${keyString})-[0-9]{1,8})\\b`, 'gi');
  }
  return JIRA_REGEX;
};

// istanbul ignore next
Bot.prototype._handleError = function(err) {
  if (!err) {
    return;
  }
  console.error(err);
};

Bot.prototype._formatDate = function(date) {
  if (!date) {
    return null;
  }
  return moment(date).format('YYYY-MM-DD HH:mm');
};

Bot.prototype._messageFromIssue = function(id, issue) {
  const attachment = {
    fallback: '',
    fields: [
      {
        title: 'Type',
        value: _.get(issue, 'fields.issuetype.name', 'Unknown'),
        short: true
      },
      {
        title: 'Priority',
        value: _.get(issue, 'fields.priority.name', 'Unknown'),
        short: true
      },
      {
        title: 'Status',
        value: _.get(issue, 'fields.status.name', 'Unknotwn'),
        short: true
      },
      {
        title: 'Assignee',
        value: _.get(issue, 'fields.assignee.displayName', 'None'),
        short: true
      },
      {
        title: 'Created',
        value: this._formatDate(_.get(issue, 'fields.created', null)),
        short: true
      },
      {
        title: 'Updated',
        value: this._formatDate(_.get(issue, 'fields.updated', null)),
        short: true
      }
    ]
  };
  attachment.fallback = attachment.fields.map(field => {
    return [field.title, field.value].join(': ');
  }).join(', ');

  return {
    text: `<${this._makeJiraLink(id)}|*${id}*: ${issue.fields.summary}>`,
    as_user: true,
    attachments: [ attachment ]
  };
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var program = require('commander')
  , utils = require('utilities')
  , path = require('path')
  , geddy = require('geddy')
  , _ = require('underscore')
  , request = require('request')
  , envoy = require('envoy')
  , kitten = require('kitten')
  , fs = require('fs');

program
  .option('create <name>', 'create a new directory (<name>) and generate a new Scotch site in it.')
  .option('serve [port]', 'start the server, defaults to 80', 80)
  .option('generate', 'generate a static html site')
  .option('import [folder]', 'import markdown files from folder')
  .option('deploy', 'deploys a generated site')
  .option('upgrade', 'upgrades a site\'s database')
  .parse(process.argv);

var Controller = function () {

  this.create = function (name) {
    console.log('Created a new site in directory: ' + program.create);
    utils.file.cpR(path.join(__dirname, '..'), name, {silent: true});
    utils.file.rmRf(path.join(name, '.git'), {silent: true});
    utils.file.rmRf(path.join(name, '.gitignore'), {silent: true});
  };

  this.serve = function (port) {
    port = port || 80;
    console.log('Serving on port ' + port);
    console.log(process.cwd())
    geddy.start({
      'geddy-root': process.cwd()
    , port: port
    });
  };

  this.generate = function () {
    console.log('generated static site in ./static');
    utils.file.cpR(path.join(process.cwd(), 'public'), 'static', {silent: true});
    geddy.start(
    {
      'geddy-root': process.cwd()
    , 'port': 8080
    });
    geddy.model.Post.all({isPublished: true}, {sort: {createdAt: 'asc'}}, function (err, posts) {
      if (err) return console.log(err);
      var slugs = _.pluck(posts, 'slug')
        , done = _.after(slugs.length, function () {
            request('http://localhost:8080/')
            .on('end', function () {
              console.log('done');
              process.exit();
            })
            .pipe(fs.createWriteStream(path.join('static', 'index.html')))
          });
      for (var i in slugs) {
        (function (slug, i) {
          request('http://localhost:8080/'+slug)
                  .on('end', done)
                  .pipe(fs.createWriteStream(path.join('static', slug+'.html')))
        })(slugs[i], i);
      }
    });
  };

  this['import'] = function (folder) {
    var chain = []
      , asyncChain
      , createPost = function (params, cb) {
          var post = geddy.model.Post.create(params);

          if(post.isValid()) {
            post.save(cb);
          }
          else {
            cb(post.errors);
          }
        };

    kitten.load(folder, function (err, posts) {
      if(err) {
        console.error('failed to import: ' + err);
        return;
      }

      geddy.start(
      {
        'geddy-root': process.cwd()
      , 'port': 8080
      });

      _.each(posts, function (post) {
        var params = {
          title: post.title
        , markdown: post.content
        , isPublished: post.published
        , publishedAt: post.date
        , callback: null
        };

        if(post.layout === 'post') {
          chain.push({
            func: createPost
          , args: [params]
          });
        }
        else {
          console.log('ignoring the page ' + post.name + ', set `layout: post` to import');
        }
      });

      asyncChain = new utils.async.AsyncChain(chain);

      asyncChain.last = function () {
        console.log('imported ' + chain.length + ' posts');
        process.exit(0);
      }

      asyncChain.run();
    });
  };

  /*
  * As of right now, this will just copy the createdAt field over to
  * the publishedAt field
  */
  this.upgrade = function () {

    console.log('upgrading database to latest version');

    var upgradePost = function (post, cb) {
          post.publishedAt = post.createdAt;

          post.save(cb);
        }
      , chain = []
      , asyncChain;

    geddy.start(
    {
      'geddy-root': process.cwd()
    , 'port': 8080
    });

    geddy.model.Post.all(function (err, posts) {
      _.each(posts, function (post) {
        chain.push({
          func: upgradePost
        , args: [post]
        , callback: null
        });
      });

      asyncChain = new utils.async.AsyncChain(chain);

      asyncChain.last = function () {
        console.log('upgraded ' + posts.length + ' posts');

        process.exit(0);
      };

      asyncChain.run();
    });
  };

  this.deploy = function () {
    var deployOpts
      , staticSiteDir = path.join(process.cwd(),'static')
      , deployOptsFile = path.join(process.cwd(),'config','deployment')
      , now = (new Date).getTime()
      , elapsed;

    //Check if static site has been generated
    if(!fs.existsSync(staticSiteDir)) {
      console.error('no static site detected');
      console.error('generate a static site with `scotch generate`');
      process.exit(1);
    }

    try {
      deployOpts = require(deployOptsFile);
    }
    catch (e) {
      console.error('could not load deployment settings');
      console.error('see: https://github.com/Techwraith/scotch#deployment');
      process.exit(1);
    }

    if(!deployOpts) {
      return;
    }

    deployOpts = _.clone(deployOpts);

    deployOpts.destination = deployOpts.destination || 'memory';
    deployOpts.opts = deployOpts.opts || {};

    console.log('deploying static site using ' + deployOpts.destination);

    envoy.deployFolder(staticSiteDir, deployOpts.destination, deployOpts.opts, function (err, log) {
      if(err) {
        console.error('failed to deploy: '+err);
        process.exit(1);
      }
      else {
        elapsed = (new Date).getTime() - now;

        elapsed = Math.round(elapsed/100)/10;

        console.log('deployed in ' + log.length + ' operations (' + elapsed + ' sec)');
        process.exit(0);
      }
    });
  };
}
var actions = new Controller();

if (program.create) return actions.create(program.create);
if (program.generate) return actions.generate();
if (program.deploy) return actions.deploy();
if (program.upgrade) return actions.upgrade();
if (program['import']) return actions['import'](program['import']);
if (program.serve) return actions.serve(program.serve);
<commit_msg>Remove whitespace<commit_after>#!/usr/bin/env node

var program = require('commander')
  , utils = require('utilities')
  , path = require('path')
  , geddy = require('geddy')
  , _ = require('underscore')
  , request = require('request')
  , envoy = require('envoy')
  , kitten = require('kitten')
  , fs = require('fs');

program
  .option('create <name>', 'create a new directory (<name>) and generate a new Scotch site in it.')
  .option('serve [port]', 'start the server, defaults to 80', 80)
  .option('generate', 'generate a static html site')
  .option('import [folder]', 'import markdown files from folder')
  .option('deploy', 'deploys a generated site')
  .option('upgrade', 'upgrades a site\'s database')
  .parse(process.argv);

var Controller = function () {

  this.create = function (name) {
    console.log('Created a new site in directory: ' + program.create);
    utils.file.cpR(path.join(__dirname, '..'), name, {silent: true});
    utils.file.rmRf(path.join(name, '.git'), {silent: true});
    utils.file.rmRf(path.join(name, '.gitignore'), {silent: true});
  };

  this.serve = function (port) {
    port = port || 80;
    console.log('Serving on port ' + port);
    console.log(process.cwd())
    geddy.start({
      'geddy-root': process.cwd()
    , port: port
    });
  };

  this.generate = function () {
    console.log('generated static site in ./static');
    utils.file.cpR(path.join(process.cwd(), 'public'), 'static', {silent: true});
    geddy.start(
    {
      'geddy-root': process.cwd()
    , 'port': 8080
    });
    geddy.model.Post.all({isPublished: true}, {sort: {createdAt: 'asc'}}, function (err, posts) {
      if (err) return console.log(err);
      var slugs = _.pluck(posts, 'slug')
        , done = _.after(slugs.length, function () {
            request('http://localhost:8080/')
            .on('end', function () {
              console.log('done');
              process.exit();
            })
            .pipe(fs.createWriteStream(path.join('static', 'index.html')))
          });
      for (var i in slugs) {
        (function (slug, i) {
          request('http://localhost:8080/'+slug)
                  .on('end', done)
                  .pipe(fs.createWriteStream(path.join('static', slug+'.html')))
        })(slugs[i], i);
      }
    });
  };

  this['import'] = function (folder) {
    var chain = []
      , asyncChain
      , createPost = function (params, cb) {
          var post = geddy.model.Post.create(params);

          if(post.isValid()) {
            post.save(cb);
          }
          else {
            cb(post.errors);
          }
        };

    kitten.load(folder, function (err, posts) {
      if(err) {
        console.error('failed to import: ' + err);
        return;
      }

      geddy.start(
      {
        'geddy-root': process.cwd()
      , 'port': 8080
      });

      _.each(posts, function (post) {
        var params = {
          title: post.title
        , markdown: post.content
        , isPublished: post.published
        , publishedAt: post.date
        , callback: null
        };

        if(post.layout === 'post') {
          chain.push({
            func: createPost
          , args: [params]
          });
        }
        else {
          console.log('ignoring the page ' + post.name + ', set `layout: post` to import');
        }
      });

      asyncChain = new utils.async.AsyncChain(chain);

      asyncChain.last = function () {
        console.log('imported ' + chain.length + ' posts');
        process.exit(0);
      }

      asyncChain.run();
    });
  };

  /*
  * As of right now, this will just copy the createdAt field over to
  * the publishedAt field
  */
  this.upgrade = function () {

    console.log('upgrading database to latest version');

    var upgradePost = function (post, cb) {
          post.publishedAt = post.createdAt;

          post.save(cb);
        }
      , chain = []
      , asyncChain;

    geddy.start(
    {
      'geddy-root': process.cwd()
    , 'port': 8080
    });

    geddy.model.Post.all(function (err, posts) {
      _.each(posts, function (post) {
        chain.push({
          func: upgradePost
        , args: [post]
        , callback: null
        });
      });

      asyncChain = new utils.async.AsyncChain(chain);

      asyncChain.last = function () {
        console.log('upgraded ' + posts.length + ' posts');

        process.exit(0);
      };

      asyncChain.run();
    });
  };

  this.deploy = function () {
    var deployOpts
      , staticSiteDir = path.join(process.cwd(),'static')
      , deployOptsFile = path.join(process.cwd(),'config','deployment')
      , now = (new Date).getTime()
      , elapsed;

    //Check if static site has been generated
    if(!fs.existsSync(staticSiteDir)) {
      console.error('no static site detected');
      console.error('generate a static site with `scotch generate`');
      process.exit(1);
    }

    try {
      deployOpts = require(deployOptsFile);
    }
    catch (e) {
      console.error('could not load deployment settings');
      console.error('see: https://github.com/Techwraith/scotch#deployment');
      process.exit(1);
    }

    if(!deployOpts) {
      return;
    }

    deployOpts = _.clone(deployOpts);

    deployOpts.destination = deployOpts.destination || 'memory';
    deployOpts.opts = deployOpts.opts || {};

    console.log('deploying static site using ' + deployOpts.destination);

    envoy.deployFolder(staticSiteDir, deployOpts.destination, deployOpts.opts, function (err, log) {
      if(err) {
        console.error('failed to deploy: '+err);
        process.exit(1);
      }
      else {
        elapsed = (new Date).getTime() - now;

        elapsed = Math.round(elapsed/100)/10;

        console.log('deployed in ' + log.length + ' operations (' + elapsed + ' sec)');
        process.exit(0);
      }
    });
  };
}
var actions = new Controller();

if (program.create) return actions.create(program.create);
if (program.generate) return actions.generate();
if (program.deploy) return actions.deploy();
if (program.upgrade) return actions.upgrade();
if (program['import']) return actions['import'](program['import']);
if (program.serve) return actions.serve(program.serve);
<|endoftext|>


<commit_before>'use strict';

angular.module('bbc.alert', [])
    /**
     * @ngdoc object
     * @name bbc.alert.$bbcAlert
     * @requires $log
     * @requires $timeout
     *
     * @description
     * Service for angular-ui alert handling.
     *
     */
    .factory('$bbcAlert', function ($log, $timeout) {
        var pub = {};

        // timeout for show alert box.
        pub.timeout = 5000;

        // logLevel for $log
        pub.logLevel = 'info';

        // show or hide alert message box
        pub.visible = false;

        // private for timeout cancel
        var promise = null;

        // private close helper
        var close = function () {
            pub.visible = false;
        };

        // private log helper
        var log = function (type, msg) {

            var level = 0;

            if (pub.logLevel === 'info') {
                level = 4;
            }
            if (pub.logLevel === 'success') {
                level = 3;
            }
            if (pub.logLevel === 'warning') {
                level = 2;
            }
            if (pub.logLevel === 'danger') {
                level = 1;
            }

            if (type === 'info' && level >= 4) {
                $log.info(type + ': ' + msg);
            }
            if (type === 'success' && level >= 3) {
                $log.info(type + ': ' + msg);
            }
            if (type === 'warning' && level >= 2) {
                $log.warn(type + ': ' + msg);
            }
            if (type === 'danger' && level >= 1) {
                $log.error(type + ': ' + msg);
            }
        };

        // private show helper
        var show = function (type, msg) {
            pub.type = type;
            pub.msg = msg;
            pub.visible = true;

            // log in console
            log(type, msg);

            // timeout for close alert
            if (pub.timeout > 0) {
                if (promise) {
                    $timeout.cancel(promise);
                }
                promise = $timeout(function () {
                    close();
                }, pub.timeout);
            }
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#close
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Closes the alert message.
         *
         */
        pub.close = function () {
            close();
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#info
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows an info alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.info = function (message) {
            show('info', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#success
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a success alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.success = function (message) {
            show('success', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#warning
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a warning alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.warning = function (message) {
            show('warning', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#danger
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a danger alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.danger = function (message) {
            show('danger', message);
        };

        return pub;
    })
    /**
     * @ngdoc directive
     * @name bbc.alert.directive:bbcAlert
     * @restrict E
     *
     * @description
     * Markup for alert.
     *
     * @example
     <example module="ngView">
     <file name="index.html">

             <bbc-alert service="bbcAlert" on-show="showAlert()"></bbc-alert>
             <button class='btn btn-default' ng-click="showAlert()">Show Info-Alert</button>

     </file>
     <file name="scripts.js">
        angular.module('ngView', ['ui.bootstrap', 'bbc.alert']).controller('AlertCtrl', function ($scope, $bbcAlert) {
            $scope.bbcAlert = $bbcAlert;
            $scope.showAlert = function() {
                $scope.bbcAlert.info('Info message from controller');
            };
         });
     </file>
     </example>
     */
    .directive('bbcAlert', function () {
        return {
            restrict: 'E',
            replace: true,
            template: '
' +
                '<alert class="ng-cloak" type="service.type" close="service.close()">{{ service.msg }}</alert>' +
                '
',
            scope: {
                service: '='
            }
        };
    });

<commit_msg>chore(doc): add all alert types to sample<commit_after>'use strict';

angular.module('bbc.alert', [])
    /**
     * @ngdoc object
     * @name bbc.alert.$bbcAlert
     * @requires $log
     * @requires $timeout
     *
     * @description
     * Service for angular-ui alert handling.
     *
     */
    .factory('$bbcAlert', function ($log, $timeout) {
        var pub = {};

        // timeout for show alert box.
        pub.timeout = 5000;

        // logLevel for $log
        pub.logLevel = 'info';

        // show or hide alert message box
        pub.visible = false;

        // private for timeout cancel
        var promise = null;

        // private close helper
        var close = function () {
            pub.visible = false;
        };

        // private log helper
        var log = function (type, msg) {

            var level = 0;

            if (pub.logLevel === 'info') {
                level = 4;
            }
            if (pub.logLevel === 'success') {
                level = 3;
            }
            if (pub.logLevel === 'warning') {
                level = 2;
            }
            if (pub.logLevel === 'danger') {
                level = 1;
            }

            if (type === 'info' && level >= 4) {
                $log.info(type + ': ' + msg);
            }
            if (type === 'success' && level >= 3) {
                $log.info(type + ': ' + msg);
            }
            if (type === 'warning' && level >= 2) {
                $log.warn(type + ': ' + msg);
            }
            if (type === 'danger' && level >= 1) {
                $log.error(type + ': ' + msg);
            }
        };

        // private show helper
        var show = function (type, msg) {
            pub.type = type;
            pub.msg = msg;
            pub.visible = true;

            // log in console
            log(type, msg);

            // timeout for close alert
            if (pub.timeout > 0) {
                if (promise) {
                    $timeout.cancel(promise);
                }
                promise = $timeout(function () {
                    close();
                }, pub.timeout);
            }
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#close
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Closes the alert message.
         *
         */
        pub.close = function () {
            close();
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#info
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows an info alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.info = function (message) {
            show('info', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#success
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a success alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.success = function (message) {
            show('success', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#warning
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a warning alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.warning = function (message) {
            show('warning', message);
        };

        /**
         * @ngdoc method
         * @name bbc.alert.$bbcAlert#danger
         * @methodOf bbc.alert.$bbcAlert
         *
         * @description
         * Shows a danger alert message.
         *
         * @param {string} message The message to be displayed.
         */
        pub.danger = function (message) {
            show('danger', message);
        };

        return pub;
    })
    /**
     * @ngdoc directive
     * @name bbc.alert.directive:bbcAlert
     * @restrict E
     *
     * @description
     * Markup for alert.
     *
     * @example
     <example module="ngView">
     <file name="index.html">

             <bbc-alert service="bbcAlert" on-show="showAlert()"></bbc-alert>
             <button class='btn btn-default' ng-click="showAlert('info')">Info-Alert</button>
             <button class='btn btn-default' ng-click="showAlert('success')">Success-Alert</button>
             <button class='btn btn-default' ng-click="showAlert('warning')">Warning-Alert</button>
             <button class='btn btn-default' ng-click="showAlert('danger')">Danger-Alert</button>

     </file>
     <file name="scripts.js">
        angular.module('ngView', ['ui.bootstrap', 'bbc.alert']).controller('AlertCtrl', function ($scope, $bbcAlert) {
            $scope.bbcAlert = $bbcAlert;
            $scope.showAlert = function(type) {
                $scope.bbcAlert[type]('Info message from controller');
            };
         });
     </file>
     </example>
     */
    .directive('bbcAlert', function () {
        return {
            restrict: 'E',
            replace: true,
            template: '
' +
                '<alert class="ng-cloak" type="service.type" close="service.close()">{{ service.msg }}</alert>' +
                '
',
            scope: {
                service: '='
            }
        };
    });

<|endoftext|>


<commit_before>/*jslint node: true */
/*jshint -W069 */
'use strict';

var CmdLineOpts = require('commander');
var MongoClient = require('mongodb').MongoClient;
var LineByLineReader = require('line-by-line');
var assert = require('assert');
var config = require('./config.json');
var VariantRecord = require('./VariantRecord.js');
var logger = require('./winstonLog');

/*
 * Setup Commandline options, auto generates help
 */
CmdLineOpts
    .version('0.0.1')
    .usage('[options] -i <file> -n studyname')
    .option('-i, --input [file]', 'VCF file to be processed')
    .option('-n, --studyname [text]', 'Study Name, for importing')
    .parse(process.argv);
var ts1 = process.hrtime();

//Make sure are variables are set
if (!CmdLineOpts.input) {
    console.log("\nMissing Input VCF file.");
    CmdLineOpts.outputHelp();
    process.exit(27); // Exit Code 27: IC68342 = Missing Input Parameters
}

if (!CmdLineOpts.studyname) {
    console.log("\nMissing Study Name.");
    CmdLineOpts.outputHelp();
    process.exit(27);
}

//Get study ID
var study_id = CmdLineOpts.studyname;
var Header = [];
//var sampleNames = [];

// Use connect method to connect to the Server
var url = 'mongodb://' + config.db.host + ':' + config.db.port + '/' + config.db.name;
MongoClient.connect(url, function (err, db) {
    assert.equal(null, err);
    readMyFileLineByLine(db, CmdLineOpts.input, function () {
        // Time reporting - callback
        var ts2 = process.hrtime(ts1);
        console.log('\n Total Time: %j s %j ms', ts2[0], (ts2[1] / 1000000));
        db.close();
    });
});

/*###############################################################
 # Define functions
 ################################################################*/

var readMyFileLineByLine  = function(db, filepath, callback) {
    var lr = new LineByLineReader(filepath);
    lr.on('error', function (err) {
        console.error(err);
    }).on('end', function () {
        console.log("Line reading finished");
        callback();
    }).on('line', function (line) {
        // 'line' contains the current line without the trailing newline character.
        // skip lines here to avoid unnecessary callbacks
        if (!line.match(/^##/)) {
            if (line.match(/^#CHROM/)) {
                //Get sample index positions
                Header = line.split('\t');
                //sampleNames = Header.slice(9,Header.length); // no need for a loop.
            } else {
                processLines(line, db);
                //console.log("Line ---- " + line);
            }
        }
    });
}

//Process line
var processLines = function (line, db) {
    VariantRecord.parseVCFline(line, Header, function(myVar){
        // file line is parsed into an object, now do database work
        findVariant(myVar, db, function(ret) {
            findSamples(myVar, db, function(samps) {
               // updateVariant(myVar, ret, db, function() {

               // });
            });
        });
    });

   /* var res = parseInputLine(line);
    if (res !== undefined) {    ///this is problem
        prepFormat(res, db);
    }*/
};

var findVariant = function(varObj, db, callback) {
    var collection = db.collection(config.names.variant);
    // Find this variant
    collection.findOne(varObj.variant, function(err, found) {
        assert.equal(err, null);
        callback(found);
    });
};

var findSamples = function(varObj, db, callback){
    var collection = db.collection(config.names.sample);

    collection.find( {"study_id" : study_id, "sample_id" : { $in : varObj.sampleNames } } ).toArray(function (err, result) {
        assert.equal(err, null);
        callback(result);
    });

}

var updateVariant = function(varObj, retVariant, db, callback){
    var collection = db.collection(config.names.variant);

    if (retVariant === null) {
        varObj.needsAnnotation = true;
        collection.insert(varObj, function (err, result) {
            assert.equal(err, null);
            //console.log('Inserted '+ result);

            ///   logger.info('log to file');

        });
    }

};

//Async Code
var findDocument = function (OBJ, setQuery1, setQuery2, db) {
    // Get the documents collection
    var collection = db.collection('variants');

    // Insert some documents
    collection.findOne(
        {"chr": OBJ.chr, "pos": OBJ.pos, "ref": OBJ.ref, "alt": OBJ.alt},
        function (err, result) {
            assert.equal(err, null);
            console.log("result = " + JSON.stringify(result) + " typeof " + typeof result);
            if (result === null) {
                //console.log('Need to insert new record');
                OBJ.needsAnnotation = true;
                collection.insert(OBJ, function (err, result) {
                    assert.equal(err, null);
                    //console.log('Inserted '+ result);
                });
            }
            else {
                for (var j = 0; j < OBJ.samples.length; j++) {
                    //See if that sample already exists
                    var sampleExists = false;
                    for (var i = 0; i < result.samples.length; i++) {
                        if (result.samples[i].sample == OBJ.samples[j].sample) {
                            //console.log('Sample '+ OBJ.samples[j].sample+' already exists at position '+ i);
                            // Replace the samples[j] field
                            collection.updateOne(
                                {
                                    "chr": OBJ.chr,
                                    "pos": OBJ.pos,
                                    "ref": OBJ.ref,
                                    "alt": OBJ.alt,
                                    "samples.sample_id": OBJ.samples[j].sample_id,
                                    "samples.study_id": OBJ.samples[j].study_id
                                },
                                {"$set": setQuery2},
                                function (err2, results3) {
                                    //console.log('Situation3 = '+results3);
                                });
                            sampleExists = true;
                        }
                        ;
                    }//End i
                    // If you've gone through all of I and sampleExists is still false, push into array
                    if (sampleExists === false) {
                        //push sample data into the array
                        //console.log('I need to push this sample into the array')
                        collection.updateOne(
                            {"chr": OBJ.chr, "pos": OBJ.pos, "ref": OBJ.ref, "alt": OBJ.alt},
                            {"$push": {samples: setQuery1}},
                            function (err2, results4) {
                                // console.log('Situation4 = '+results4);
                            });
                    }
                }//End j
            }//End else
            //db.close();
        }
    )
};

// Prepare format for query
function prepFormat(res, db) {
    if (typeof res !== 'undefined') {
        var _id = res.shift();
        var PIECE1 = [];
        var PIECE2 = [];
        //var res = [];
        _id = _id._id;
        //console.log('res='+JSON.stringify(res));
        for (var j = 0; j < res.length; j++) {
            //console.log('sample='+res[j]['sample']);
            var line = {};
            line['chr'] = _id.chr;
            line['pos'] = Number(_id.pos);
            line['ref'] = _id.ref;
            line['alt'] = _id.alt;
            var SAMPLE = res[j]['sample_id'];
            var STUDY = res[j]['study_id'];

            // Now create set string for remaining variables
            delete res[j].study_id;
            delete res[j].sample_id;
            delete res[j]._id;
            //Get genotype count (GTC)
            var GTC = getGTC(res[j]['GT'])

            var setQuery1 = {'samples.$.GTC':GTC};
            var setQuery2 = {'GTC':GTC};
            for (var key in res[j]) {
                var attrName1 = key;
                var attrName2 = key;
                var attrValue1 = res[j][key];
                var attrValue2 = res[j][key];
                attrName1 = 'samples.$.' + attrName1;
                setQuery1[attrName1] = attrValue1;
                attrName2 = attrName2;
                setQuery2[attrName2] = attrValue2;
            }
            //Add in GenotTypeCount
            setQuery2['study_id'] = String(STUDY);
            setQuery2['sample_id'] = String(SAMPLE);
            //console.log('Q1: '+JSON.stringify(setQuery1));
            //console.log('Q2: '+JSON.stringify(setQuery2));
            PIECE2.push(setQuery2);
            PIECE1.push(setQuery1);
        } //End J
        line.samples = PIECE2;
        findDocument(line, PIECE1, PIECE2, db);
    } //End typeof
}

function parseInputLine(line) {
    var Variant = {};
        var Row = line.split('\t');
        var FORMAT = Row[8].split(':');
        var pos = Row[1];
        if (Row[4].match(',')) {
            console.log('I cannot handle multiple alleles');
            console.log(line);
        }
        else {
            var _id = {chr: Row[0], pos: Number(pos), ref: Row[3], alt: Row[4]};
            var lineArray = [{_id: _id}];
            for (var k = 9; k < Row.length; k++) {
                var sample_id = Header[k];
                var formatdata = {study_id: study_id, _id: _id};
                formatdata['sample_id'] = sample_id;
                //formatdata.sample = sample_id;
                if (!Row[k].match(/\.\/\./)) {
                    for (var j = 0; j < FORMAT.length; j++) {
                        //Create an array to store objects of SampleID and SampleFormat
                        var sampleFormat = Row[k].split(':');
                        var result = getValue(sampleFormat[j]);
                        //Set key-value pairs in formatdata
                        formatdata[FORMAT[j]] = result;
                    }//End format parsing
                } //End sample-level parsing
                //Only keep the samples with data
                if (typeof formatdata.GT !== 'undefined') {
                    lineArray.push(formatdata);
                }
            } // End All Samples
            //Insert my array into the complete object
            console.log(lineArray);
            return lineArray;
        }
}//end function

//Get number of alt genotypes
function getGTC(GT) {
    GT=JSON.stringify(GT)
    GT=GT.replace(/[\/\|\.0\"]/gi, '')
    return GT.length
}

function getValue(variable) {
    // for each value, convert to a number if it is one.
    var a = variable.split(',');
    //console.log("figuring out what to do with "+a);
    var result = '';
    if (a.length > 1) {
        result = numberOrStringMulti(a);
    }
    else {
        result = numberOrStringSingle(a);
    }
    return result;
}

function numberOrStringMulti(variable) {
    var result = variable.map(function (x) {
        if (isNaN(Number(x))) {
            if (x !== '.') {
                return String(x);
            }
        }
        else {
            return Number(x);
        }
    });
    return result;
}
function numberOrStringSingle(x) {
    var result = '';
    if (isNaN(Number(x))) {
        if (x !== '.') {
            result = String(x);
        }
    }
    else {
        result = Number(x);
    }
    return result;
}<commit_msg>get sample information once, need to force blocking code for samples info to finish first<commit_after>/*jslint node: true */
/*jshint -W069 */
'use strict';

var CmdLineOpts = require('commander');
var MongoClient = require('mongodb').MongoClient;
var LineByLineReader = require('line-by-line');
var assert = require('assert');
var config = require('./config.json');
var VariantRecord = require('./VariantRecord.js');
//var logger = require('./winstonLog');

/*
 * Setup Commandline options, auto generates help
 */
CmdLineOpts
    .version('0.0.1')
    .usage('[options] -i <file> -n studyname')
    .option('-i, --input [file]', 'VCF file to be processed')
    .option('-n, --studyname [text]', 'Study Name, for importing')
    .parse(process.argv);
var ts1 = process.hrtime();

//Make sure are variables are set
if (!CmdLineOpts.input) {
    console.log("\nMissing Input VCF file.");
    CmdLineOpts.outputHelp();
    process.exit(27); // Exit Code 27: IC68342 = Missing Input Parameters
}

if (!CmdLineOpts.studyname) {
    console.log("\nMissing Study Name.");
    CmdLineOpts.outputHelp();
    process.exit(27);
}

//Get study ID
var study_id = CmdLineOpts.studyname;
var Header = [];
var sampleDbIds = [];

// Use connect method to connect to the Server
var url = 'mongodb://' + config.db.host + ':' + config.db.port + '/' + config.db.name;
MongoClient.connect(url, function (err, db) {
    assert.equal(null, err);
    readMyFileLineByLine(db, CmdLineOpts.input, function () {
        // Time reporting - callback
        var ts2 = process.hrtime(ts1);
        console.log('\n Total Time: %j s %j ms', ts2[0], (ts2[1] / 1000000));
        db.close();
    });
});

/*###############################################################
 # Define functions
 ################################################################*/

var readMyFileLineByLine  = function(db, filepath, callback) {
    var lr = new LineByLineReader(filepath);
    lr.on('error', function (err) {
        console.error(err);
    }).on('end', function () {
        console.log("Line reading finished");
        callback();
    }).on('line', function (line) {
        // 'line' contains the current line without the trailing newline character.
        // skip lines here to avoid unnecessary callbacks
        if (!line.match(/^##/)) {
            if (line.match(/^#CHROM/)) {
                //Get sample index positions
                Header = line.split('\t');
                findSamples(db, function(samps) {
                    sampleDbIds = samps;
                });

                setTimeout(function(){console.log("Chom Line timmer block")}, 6000);// this is hack

            } else {
                // NEED TO BLOCK UNTIL SAMPLES HAVE BEEN RESOLVED!!! - don't want async for #chom line...

                processLines(line, db);
                console.log("Line ---- " + line);
            }
        }
    });
};

// One database transaction for getting samples back...if all aren't already registered...accept none!
var findSamples = function(db, callback){
    var sampleNames = Header.slice(9,Header.length); // no need for a loop.
    var collection = db.collection(config.names.sample);

    console.log({"study_id" : study_id, "sample_id" : { $in : sampleNames } });

    collection.find( {"study_id" : study_id, "sample_id" : { $in : sampleNames } } ).toArray(function (err, result) {
        assert.equal(err, [], "No Sample(s) in this study. Need to register all samples to '" + study_id + "' first."); // returns empty, if study wrong, or no samples exist

        console.log(result);

        callback(result);
    });
};

//Process line
var processLines = function (line, db) {
    VariantRecord.parseVCFline(line, Header, function(myVar){
        // file line is parsed into an object, now do database work
        findVariant(myVar, db, function(ret) {
               // console.log("find samps", myVar);
               /* updateVariant(myVar, ret, samps, db, function() {

                });*/
            //});
        });
    });

   /* var res = parseInputLine(line);
    if (res !== undefined) {    ///this is problem
        prepFormat(res, db);
    }*/
};

var findVariant = function(varObj, db, callback) {
    var collection = db.collection(config.names.variant);
    // Find this variant
    collection.findOne(varObj.variant, function(err, found) {
       // assert.equal(err, null);
        callback(found);
    });
};

var updateVariant = function(varObj, retVariant, retSamples, db, callback){
    var collection = db.collection(config.names.variant);

    if (retVariant === null) {
        varObj.variant.needsAnnotation = true;

        collection.insert(varObj, function (err, result) {
            assert.equal(err, null);
            console.log('Inserted '+ result);

            ///   logger.info('log to file');

        });
    }

};

//Async Code
var findDocument = function (OBJ, setQuery1, setQuery2, db) {
    // Get the documents collection
    var collection = db.collection('variants');

    // Insert some documents
    collection.findOne(
        {"chr": OBJ.chr, "pos": OBJ.pos, "ref": OBJ.ref, "alt": OBJ.alt},
        function (err, result) {
            assert.equal(err, null);
            console.log("result = " + JSON.stringify(result) + " typeof " + typeof result);
            if (result === null) {
                //console.log('Need to insert new record');
                OBJ.needsAnnotation = true;
                collection.insert(OBJ, function (err, result) {
                    assert.equal(err, null);
                    //console.log('Inserted '+ result);
                });
            }
            else {
                for (var j = 0; j < OBJ.samples.length; j++) {
                    //See if that sample already exists
                    var sampleExists = false;
                    for (var i = 0; i < result.samples.length; i++) {
                        if (result.samples[i].sample == OBJ.samples[j].sample) {
                            //console.log('Sample '+ OBJ.samples[j].sample+' already exists at position '+ i);
                            // Replace the samples[j] field
                            collection.updateOne(
                                {
                                    "chr": OBJ.chr,
                                    "pos": OBJ.pos,
                                    "ref": OBJ.ref,
                                    "alt": OBJ.alt,
                                    "samples.sample_id": OBJ.samples[j].sample_id,
                                    "samples.study_id": OBJ.samples[j].study_id
                                },
                                {"$set": setQuery2},
                                function (err2, results3) {
                                    //console.log('Situation3 = '+results3);
                                });
                            sampleExists = true;
                        }
                        ;
                    }//End i
                    // If you've gone through all of I and sampleExists is still false, push into array
                    if (sampleExists === false) {
                        //push sample data into the array
                        //console.log('I need to push this sample into the array')
                        collection.updateOne(
                            {"chr": OBJ.chr, "pos": OBJ.pos, "ref": OBJ.ref, "alt": OBJ.alt},
                            {"$push": {samples: setQuery1}},
                            function (err2, results4) {
                                // console.log('Situation4 = '+results4);
                            });
                    }
                }//End j
            }//End else
            //db.close();
        }
    )
};

// Prepare format for query
function prepFormat(res, db) {
    if (typeof res !== 'undefined') {
        var _id = res.shift();
        var PIECE1 = [];
        var PIECE2 = [];
        //var res = [];
        _id = _id._id;
        //console.log('res='+JSON.stringify(res));
        for (var j = 0; j < res.length; j++) {
            //console.log('sample='+res[j]['sample']);
            var line = {};
            line['chr'] = _id.chr;
            line['pos'] = Number(_id.pos);
            line['ref'] = _id.ref;
            line['alt'] = _id.alt;
            var SAMPLE = res[j]['sample_id'];
            var STUDY = res[j]['study_id'];

            // Now create set string for remaining variables
            delete res[j].study_id;
            delete res[j].sample_id;
            delete res[j]._id;
            //Get genotype count (GTC)
            var GTC = getGTC(res[j]['GT'])

            var setQuery1 = {'samples.$.GTC':GTC};
            var setQuery2 = {'GTC':GTC};
            for (var key in res[j]) {
                var attrName1 = key;
                var attrName2 = key;
                var attrValue1 = res[j][key];
                var attrValue2 = res[j][key];
                attrName1 = 'samples.$.' + attrName1;
                setQuery1[attrName1] = attrValue1;
                attrName2 = attrName2;
                setQuery2[attrName2] = attrValue2;
            }
            //Add in GenotTypeCount
            setQuery2['study_id'] = String(STUDY);
            setQuery2['sample_id'] = String(SAMPLE);
            //console.log('Q1: '+JSON.stringify(setQuery1));
            //console.log('Q2: '+JSON.stringify(setQuery2));
            PIECE2.push(setQuery2);
            PIECE1.push(setQuery1);
        } //End J
        line.samples = PIECE2;
        findDocument(line, PIECE1, PIECE2, db);
    } //End typeof
}

function parseInputLine(line) {
    var Variant = {};
        var Row = line.split('\t');
        var FORMAT = Row[8].split(':');
        var pos = Row[1];
        if (Row[4].match(',')) {
            console.log('I cannot handle multiple alleles');
            console.log(line);
        }
        else {
            var _id = {chr: Row[0], pos: Number(pos), ref: Row[3], alt: Row[4]};
            var lineArray = [{_id: _id}];
            for (var k = 9; k < Row.length; k++) {
                var sample_id = Header[k];
                var formatdata = {study_id: study_id, _id: _id};
                formatdata['sample_id'] = sample_id;
                //formatdata.sample = sample_id;
                if (!Row[k].match(/\.\/\./)) {
                    for (var j = 0; j < FORMAT.length; j++) {
                        //Create an array to store objects of SampleID and SampleFormat
                        var sampleFormat = Row[k].split(':');
                        var result = getValue(sampleFormat[j]);
                        //Set key-value pairs in formatdata
                        formatdata[FORMAT[j]] = result;
                    }//End format parsing
                } //End sample-level parsing
                //Only keep the samples with data
                if (typeof formatdata.GT !== 'undefined') {
                    lineArray.push(formatdata);
                }
            } // End All Samples
            //Insert my array into the complete object
            console.log(lineArray);
            return lineArray;
        }
}//end function

//Get number of alt genotypes
function getGTC(GT) {
    GT=JSON.stringify(GT)
    GT=GT.replace(/[\/\|\.0\"]/gi, '')
    return GT.length
}

function getValue(variable) {
    // for each value, convert to a number if it is one.
    var a = variable.split(',');
    //console.log("figuring out what to do with "+a);
    var result = '';
    if (a.length > 1) {
        result = numberOrStringMulti(a);
    }
    else {
        result = numberOrStringSingle(a);
    }
    return result;
}

function numberOrStringMulti(variable) {
    var result = variable.map(function (x) {
        if (isNaN(Number(x))) {
            if (x !== '.') {
                return String(x);
            }
        }
        else {
            return Number(x);
        }
    });
    return result;
}
function numberOrStringSingle(x) {
    var result = '';
    if (isNaN(Number(x))) {
        if (x !== '.') {
            result = String(x);
        }
    }
    else {
        result = Number(x);
    }
    return result;
}<|endoftext|>


<commit_before>const Promise = require('bluebird')
const fs = require('fs')
const path = require('path')

const readDirAsync = Promise.promisify(fs.readdir)

const log = console.log.bind(console)
const defaultLogger = {
  debug: log,
  verbose: log,
  info: log,
  warn: console.warn.bind(console),
  error: console.error.bind(console)
}

const UP = 'up'
const DOWN = 'down'

function adbm ({ db, adapter, metadata = '_adbm', directory = 'migrations', logger = defaultLogger }) {
  if (!db) {
    throw new Error('You must pass a connected database driver instance to adbm()')
  }

  validateAdapter(adapter)

  return async ({ direction = UP, exclude = [ ] } = { }) => {
    logger.verbose('○ Initializing database migrations, direction is %s.', direction)

    await adapter.init({ db, metadata, directory, logger })

    const migrateUp = direction === UP
    const completed = await adapter.getCompletedMigrationIds({ db, metadata, logger })

    let migrations = await getMigrationObjects({ directory, logger, exclude: exclude.concat(migrateUp ? completed : [ ]) })

    // Only keep objects for already completed migrations when migrating down
    if (!migrateUp) {
      migrations = migrations.filter(({ id }) => completed.includes(id))
    }

    if (migrations.length === 0) {
      logger.info('⚡ No pending database migrations.')

      return [ ]
    }

    logger.debug('○ Will attempt to perform %s migrations in total.', migrations.length)

    const ops = await performMigrations({ migrations, direction, db, metadata, logger, registerSuccess: migrateUp ? adapter.registerMigration : adapter.unregisterMigration })

    logger.info('%s the following database migrations:\n%s', migrateUp ? 'Applied' : 'Reverted', ops.map(({ id, duration }) => `- ${id}: ${duration} sec`).join('\n'))

    return ops
  }
}

function validateAdapter (adapter) {
  const requiredFunctions = [ 'init', 'getCompletedMigrationIds', 'registerMigration', 'unregisterMigration' ]

  const missingFunctions = requiredFunctions.reduce((missing, func) => {
    if (typeof adapter[func] !== 'function') {
      return missing.concat([ func ])
    }

    return missing
  }, [ ])

  if (typeof adapter !== 'object' || missingFunctions.length > 0) {
    throw new Error('Adapters must be an object implementing all of the following functions: %s', requiredFunctions.join(', '))
  }
}

function isValidMigrationObject (obj) {
  return typeof obj === 'object' && typeof obj[UP] === 'function' && typeof obj[DOWN] === 'function'
}

async function getMigrationObjects ({ directory, exclude = [ ], verify = isValidMigrationObject, logger = defaultLogger }) {
  const fullPath = path.resolve(directory)
  const files = await readDirAsync(fullPath)

  const ids = files
    .filter((file) => file.endsWith('.js'))
    .map((file) => file.slice(0, -3))

  logger.debug('○ Directory %s contains %s valid migration files.', fullPath, ids.length)

  return ids
    .filter((id) => !exclude.includes(id))
    .map((id) => {
      const file = `${fullPath}/${id}.js`

      try {
        const obj = require(file)

        if (!verify(obj)) {
          throw new Error(`Not a valid migration file (must export "${UP}" and "${DOWN}" functions).`)
        }

        return Object.assign({ }, obj, { id })
      } catch (e) {
        logger.error('❌ Failed to include migration file %s: %s', file, e.message)

        return false
      }
    })
    .filter((obj) => obj !== false)
}

async function performMigrations ({ migrations, direction, db, metadata, registerSuccess, logger = defaultLogger }) {
  const migrateUp = direction === UP
  const arrow = migrateUp ? '↗' : '↘'
  const action = migrateUp ? 'Applying' : 'Reverting'

  return Promise.mapSeries(migrations, async ({ [direction]: fn, id }) => {
    logger.debug('%s %s migration "%s"', arrow, action, id)

    const then = new Date()

    await fn(db, logger)

    const now = new Date()
    const duration = ((now - then) / 1000).toFixed(3)

    logger.debug('✔ Migration %s successful, took %s sec.', id, duration)

    await registerSuccess({ id, db, metadata, logger })

    return { id, duration }
  })
}

module.exports = {
  UP,
  DOWN,
  defaultLogger,
  adbm,
  isValidMigrationObject,
  getMigrationObjects,
  performMigrations,
  validateAdapter
}
<commit_msg>add optional dbName param<commit_after>const Promise = require('bluebird')
const fs = require('fs')
const path = require('path')

const readDirAsync = Promise.promisify(fs.readdir)

const log = console.log.bind(console)
const defaultLogger = {
  debug: log,
  verbose: log,
  info: log,
  warn: console.warn.bind(console),
  error: console.error.bind(console)
}

const UP = 'up'
const DOWN = 'down'

function adbm ({ db, dbName, adapter, metadata = '_adbm', directory = 'migrations', logger = defaultLogger }) {
  if (!db) {
    throw new Error('You must pass a connected database driver instance to adbm()')
  }

  validateAdapter(adapter)

  return async ({ direction = UP, exclude = [ ] } = { }) => {
    logger.verbose('○ Initializing database migrations, direction is %s.', direction)

    await adapter.init({ db, dbName, metadata, directory, logger })

    const migrateUp = direction === UP
    const completed = await adapter.getCompletedMigrationIds({ db, metadata, logger })

    let migrations = await getMigrationObjects({ directory, logger, exclude: exclude.concat(migrateUp ? completed : [ ]) })

    // Only keep objects for already completed migrations when migrating down
    if (!migrateUp) {
      migrations = migrations.filter(({ id }) => completed.includes(id))
    }

    if (migrations.length === 0) {
      logger.info('⚡ No pending database migrations.')

      return [ ]
    }

    logger.debug('○ Will attempt to perform %s migrations in total.', migrations.length)

    const ops = await performMigrations({ migrations, direction, db, metadata, logger, registerSuccess: migrateUp ? adapter.registerMigration : adapter.unregisterMigration })

    logger.info('%s the following database migrations:\n%s', migrateUp ? 'Applied' : 'Reverted', ops.map(({ id, duration }) => `- ${id}: ${duration} sec`).join('\n'))

    return ops
  }
}

function validateAdapter (adapter) {
  const requiredFunctions = [ 'init', 'getCompletedMigrationIds', 'registerMigration', 'unregisterMigration' ]

  const missingFunctions = requiredFunctions.reduce((missing, func) => {
    if (typeof adapter[func] !== 'function') {
      return missing.concat([ func ])
    }

    return missing
  }, [ ])

  if (typeof adapter !== 'object' || missingFunctions.length > 0) {
    throw new Error('Adapters must be an object implementing all of the following functions: %s', requiredFunctions.join(', '))
  }
}

function isValidMigrationObject (obj) {
  return typeof obj === 'object' && typeof obj[UP] === 'function' && typeof obj[DOWN] === 'function'
}

async function getMigrationObjects ({ directory, exclude = [ ], verify = isValidMigrationObject, logger = defaultLogger }) {
  const fullPath = path.resolve(directory)
  const files = await readDirAsync(fullPath)

  const ids = files
    .filter((file) => file.endsWith('.js'))
    .map((file) => file.slice(0, -3))

  logger.debug('○ Directory %s contains %s valid migration files.', fullPath, ids.length)

  return ids
    .filter((id) => !exclude.includes(id))
    .map((id) => {
      const file = `${fullPath}/${id}.js`

      try {
        const obj = require(file)

        if (!verify(obj)) {
          throw new Error(`Not a valid migration file (must export "${UP}" and "${DOWN}" functions).`)
        }

        return Object.assign({ }, obj, { id })
      } catch (e) {
        logger.error('❌ Failed to include migration file %s: %s', file, e.message)

        return false
      }
    })
    .filter((obj) => obj !== false)
}

async function performMigrations ({ migrations, direction, db, metadata, registerSuccess, logger = defaultLogger }) {
  const migrateUp = direction === UP
  const arrow = migrateUp ? '↗' : '↘'
  const action = migrateUp ? 'Applying' : 'Reverting'

  return Promise.mapSeries(migrations, async ({ [direction]: fn, id }) => {
    logger.debug('%s %s migration "%s"', arrow, action, id)

    const then = new Date()

    await fn(db, logger)

    const now = new Date()
    const duration = ((now - then) / 1000).toFixed(3)

    logger.debug('✔ Migration %s successful, took %s sec.', id, duration)

    await registerSuccess({ id, db, metadata, logger })

    return { id, duration }
  })
}

module.exports = {
  UP,
  DOWN,
  defaultLogger,
  adbm,
  isValidMigrationObject,
  getMigrationObjects,
  performMigrations,
  validateAdapter
}
<|endoftext|>