<commit_before>var http = require('http');
var root = require('root');
var flat = require('flat-file-db');
var fs = require('fs');
var rimraf = require('rimraf');
var path = require('path');
var tar = require('tar-fs');
var select = require('select-keys');
var xtend = require('xtend');
var zlib = require('zlib');
var url = require('url');
var pump = require('pump');
var os = require('os');
var thunky = require('thunky');
var once = require('once');
var proc = require('child_process');
var protocol = require('../lib/protocol');
var subscriptions = require('../lib/subscriptions');
var pkg = require('../package.json');

var noop = function() {};

var HANDSHAKE =
	'HTTP/1.1 101 Swiching Protocols\r\n'+
	'Upgrade: hms-protocol\r\n'+
	'Connection: Upgrade\r\n\r\n';

var log = function(tag) {
	tag = tag ? '[term] ['+tag+']' : '[term]';
	console.log.apply(null, arguments);
};

var shuffle = function(list) {
	return list.sort(function() {
		return Math.random() < 0.5;
	});
};

module.exports = function(opts) {
	var server = root();
	var db = flat.sync(opts.db || 'terminal.db');
	var subs = subscriptions();
	var docks = [];

	var ondock = function(protocol, host) {
		protocol.id = host;

		protocol.on('close', function() {
			docks.splice(docks.indexOf(protocol), 1);
			log(null, 'connection to dock ('+host+') dropped');
		});

		protocol.on('stdout', function(id, origin, data) {
			subs.publish('stdout', id, origin, data);
		});

		protocol.on('stderr', function(id, origin, data) {
			subs.publish('stderr', id, origin, data);
		});

		protocol.on('spawn', function(id, origin, pid) {
			subs.publish('spawn', id, origin, pid);
		});

		protocol.on('exit', function(id, origin, code) {
			subs.publish('exit', id, origin, code);
		});

		docks.push(protocol);
		log(null, 'connection to dock ('+host+') established');

		subs.subscriptions().forEach(function(key) {
			protocol.subscribe(key);
		});
	};

	var clean = opts.dock ? noop : function(dir) {
		rimraf(dir, noop);
	};

	var parseDocks = function(d) {
		if (Array.isArray(d)) return d;
		if (typeof d === 'string') return [d];
		if (typeof d !== 'number') return null;

		var ids = docks.map(function(dock) {
			return dock.id;
		});

		return shuffle(ids).slice(0, d);
	};

	var forEach = function(list, fn, cb) {
		cb = once(cb || noop);

		var result = [];
		var missing = list.length;
		var onresponse = function(err, val) {
			if (err) return cb(err);

			if (val && !Buffer.isBuffer(val)) {
				if (Array.isArray(val)) result.push.apply(result, val);
				else result.push(val);
			}

			if (--missing) return;
			cb(null, result);
		};

		if (!missing) return cb(null, result);
		list.forEach(function(dock) {
			fn(dock, onresponse);
		});
	};

	subs.on('subscribe', function(id, protocol, count) {
		if (count > 1) return;
		log(id, 'subscribing to service events and logs');
		forEach(docks, function(dock, next) {
			dock.subscribe(id, next);
		});
	});

	subs.on('unsubscribe', function(id, protocol, count) {
		if (count) return;
		log(id, 'unsubscribing to service events and logs');
		forEach(docks, function(dock, next) {
			dock.unsubscribe(id, next);
		});
	});

	var save = function(id, opts, cb) {
		var service = xtend(db.get(id) || {id:id}, select(opts, ['start', 'build', 'docks', 'revision', 'env']));
		if (service.docks) service.docks = parseDocks(service.docks);
		db.put(id, service, cb);
	};

	var onstatuschange = function(id, status, cb) {
		if (!db.has(id)) return cb(new Error('Service not found'));

		var service = db.get(id);
		var upd = {start:service.start, build:service.build, env:service.env, docks:service.docks};

		service.stopped = status === 'stop';
		db.put(id, service, function(err) {
			if (err) return cb(err);
			log(id, 'sending', status, 'to docks');
			forEach(docks, function(dock, next) {
				dock.update(id, upd, function(err) {
					if (err) return next(err);
					dock[status](id, next);
				});
			}, cb);
		});
	};

	var onclient = function(protocol) {
		protocol.on('add', function(id, opts, cb) {
			if (db.has(id)) return cb(new Error('Service already exist'));
			if (!/^[a-zA-Z0-9\-\.]+$/.test(id)) return cb(new Error('Service name should be alphanumericish'));
			log(id, 'adding new service');
			save(id, opts, cb);
		});

		protocol.on('update', function(id, opts, cb) {
			if (!db.has(id)) return cb(new Error('Service not found'));
			log(id, 'updating service');
			save(id, opts, cb);
		});

		protocol.on('remove', function(id, cb) {
			log(id, 'removing service');
			forEach(docks, function(dock, next) {
				dock.remove(id, next);
			}, function(err) {
				if (err) return cb(err);
				db.del(id, cb);
			});
		});

		protocol.on('get', function(id, cb) {
			if (!db.has(id)) return cb(new Error('Service not found'));
			cb(null, db.get(id));
		});

		protocol.on('list', function(cb) {
			var list = db.keys().map(function(key) {
				return db.get(key);
			});

			cb(null, list);
		});

		protocol.on('sync', function(id, service, cb) {
			if (!service) service = db.get(id);
			if (!service) return cb(new Error('Service not found'));
			log(id, 'syncing build to docks');

			var selected = docks.filter(function(dock) {
				return service.docks && service.docks.indexOf(dock.id) > -1;
			});

			var unselected = docks.filter(function(dock) {
				return !service.docks && service.docks.indexOf(dock.id) === -1;
			});

			var purge = function(err) {
				if (err) return cb(err);
				forEach(unselected, function(dock, next) {
					dock.remove(id, next);
				}, cb);
			};

			save(id, service, function(err) {
				if (err) return cb(err);
				forEach(selected, function(dock, next) {
					dock.sync(id, service, next);
				}, purge);
			});
		});

		protocol.on('restart', function(id, cb) {
			onstatuschange(id, 'restart', cb);
		});

		protocol.on('start', function(id, cb) {
			onstatuschange(id, 'start', cb);
		});

		protocol.on('stop', function(id, cb) {
			onstatuschange(id, 'stop', cb);
		});

		protocol.on('ps', function(cb) {
			forEach(docks, function(dock, next) {
				dock.ps(next);
			}, cb);
		});

		var unsubscribe = function(id, cb) {
			if (typeof cb !== 'function') cb = noop;
			var subs = subscriptions[id] = subscriptions[id] || [];
			var i = subs.indexOf(protocol);
			if (i === -1) return cb();

			log(id, 'client unsubscribing');
			if (subs.length === 1) delete subscriptions[id];
			else subs.splice(i, 1);
			cb();
		};

		protocol.on('subscribe', function(id, cb) {
			if (!db.has(id) && id !== '*') return cb(new Error('Service not found'));
			subs.subscribe(id, protocol);
			cb();
		});

		protocol.once('subscribe', function() {
			protocol.on('close', function() {
				subs.clear(protocol);
			});
		});

		protocol.on('unsubscribe', function(id, cb) {
			subs.unsubscribe(id, protocol);
			cb();
		});
	};

	var cache = {};

	server.put('/{id}', function(req, res) {
		var id = req.params.id;
		var deployed = new Date().toISOString();
		var cwd = path.join('builds', id+'@'+deployed);

		var onerror = function(status, message) {
			log(id, 'build failed');
			rimraf(cwd, function() {
				res.statusCode = status;
				res.addTrailers({'X-Status': status});
				res.end(message);
			});
		};

		var ondone = function(status) {
			var service = db.get(id);
			var old = service.cwd;

			service.cwd = cwd;
			service.deployed = deployed;
			service.revision = req.query.revision;

			db.put(id, service, function(err) {
				if (err) return onerror(500);
				log(id, 'build succeded');
				if (old) clean(old);
				delete cache[id];
				res.statusCode = status;
				res.addTrailers({'X-Status': 200});
				res.end();
			});
		};

		log(id, 'receiving tarball');
		res.setHeader('Trailer', 'X-Status');
		pump(req, zlib.createGunzip(), tar.extract(cwd), function(err) {
			if (err) return onerror(500, err.message);

			var service = db.get(id);

			if (!service) return onerror(404, 'Service not found');
			if (!service.build) return ondone(204);

			var build = proc.spawn('/bin/sh', ['-c', service.build, path.join(cwd, 'build.sh'), id], {
				cwd:cwd,
				env:xtend(process.env, service.env)
			});

			build.stdout.pipe(res, {end:false});
			build.stderr.pipe(res, {end:false});

			build.on('error', function(err) {
				onerror(500);
			});

			build.on('close', function(code) {
				if (code) return onerror(500);
				if (!db.has(id)) return onerror(404);
				ondone(200);
			});
		});
	});

	server.get('/{id}', function(req, res) {
		var id = req.params.id;
		var service = db.get(id);

		if (!service) return res.error(404, 'Service not found');
		if (!service.cwd) return res.error(404, 'No builds found');

		if (!cache[id]) {
			log(id, 'writing tarball to cache');
			cache[id] = thunky(function(cb) {
				var tmp = path.join(os.tmpDir(), 'hms-'+id+'.tgz');
				pump(tar.pack(service.cwd), zlib.createGzip(), fs.createWriteStream(tmp), function(err) {
					if (err) return cb(err);
					cb(null, tmp);
				});
			});
		}

		log(id, 'sending tarball');
		cache[id](function(err, tmp) {
			if (err) return res.error(err);
			pump(fs.createReadStream(tmp), res);
		});
	});

	server.get('/', function(req, res) {
		res.end('hms-terminal '+pkg.version+'\n');
	});

	server.on('connect', function(req, socket, data) {
		var p = protocol(socket, data);
		socket.write(HANDSHAKE);
		if (req.url === '/dock') ondock(p, req.headers.origin || 'unknown');
		else onclient(p);
	});

	var port = opts.port || 10002;
	server.listen(port, function() {
		log(null, 'listening on', port);
		if (opts.dock) require('./dock')({port:port+1, remote:'127.0.0.1:'+port, id:opts.id});
	});
};<commit_msg>fixed inline dock regression<commit_after>var http = require('http');
var root = require('root');
var flat = require('flat-file-db');
var fs = require('fs');
var rimraf = require('rimraf');
var path = require('path');
var tar = require('tar-fs');
var select = require('select-keys');
var xtend = require('xtend');
var zlib = require('zlib');
var url = require('url');
var pump = require('pump');
var os = require('os');
var thunky = require('thunky');
var once = require('once');
var proc = require('child_process');
var protocol = require('../lib/protocol');
var subscriptions = require('../lib/subscriptions');
var pkg = require('../package.json');

var noop = function() {};

var HANDSHAKE =
	'HTTP/1.1 101 Swiching Protocols\r\n'+
	'Upgrade: hms-protocol\r\n'+
	'Connection: Upgrade\r\n\r\n';

var log = function(tag) {
	tag = tag ? '[term] ['+tag+']' : '[term]';
	console.log.apply(null, arguments);
};

var shuffle = function(list) {
	return list.sort(function() {
		return Math.random() < 0.5;
	});
};

module.exports = function(opts) {
	var server = root();
	var db = flat.sync(opts.db || 'terminal.db');
	var subs = subscriptions();
	var docks = [];

	var ondock = function(protocol, host) {
		protocol.id = host;

		protocol.on('close', function() {
			docks.splice(docks.indexOf(protocol), 1);
			log(null, 'connection to dock ('+host+') dropped');
		});

		protocol.on('stdout', function(id, origin, data) {
			subs.publish('stdout', id, origin, data);
		});

		protocol.on('stderr', function(id, origin, data) {
			subs.publish('stderr', id, origin, data);
		});

		protocol.on('spawn', function(id, origin, pid) {
			subs.publish('spawn', id, origin, pid);
		});

		protocol.on('exit', function(id, origin, code) {
			subs.publish('exit', id, origin, code);
		});

		docks.push(protocol);
		log(null, 'connection to dock ('+host+') established');

		subs.subscriptions().forEach(function(key) {
			protocol.subscribe(key);
		});
	};

	var clean = opts.dock ? noop : function(dir) {
		rimraf(dir, noop);
	};

	var parseDocks = function(d) {
		if (Array.isArray(d)) return d;
		if (typeof d === 'string') return [d];
		if (typeof d !== 'number') return null;

		var ids = docks.map(function(dock) {
			return dock.id;
		});

		return shuffle(ids).slice(0, d);
	};

	var forEach = function(list, fn, cb) {
		cb = once(cb || noop);

		var result = [];
		var missing = list.length;
		var onresponse = function(err, val) {
			if (err) return cb(err);

			if (val && !Buffer.isBuffer(val)) {
				if (Array.isArray(val)) result.push.apply(result, val);
				else result.push(val);
			}

			if (--missing) return;
			cb(null, result);
		};

		if (!missing) return cb(null, result);
		list.forEach(function(dock) {
			fn(dock, onresponse);
		});
	};

	subs.on('subscribe', function(id, protocol, count) {
		if (count > 1) return;
		log(id, 'subscribing to service events and logs');
		forEach(docks, function(dock, next) {
			dock.subscribe(id, next);
		});
	});

	subs.on('unsubscribe', function(id, protocol, count) {
		if (count) return;
		log(id, 'unsubscribing to service events and logs');
		forEach(docks, function(dock, next) {
			dock.unsubscribe(id, next);
		});
	});

	var save = function(id, opts, cb) {
		var service = xtend(db.get(id) || {id:id}, select(opts, ['start', 'build', 'docks', 'revision', 'env']));
		if (service.docks) service.docks = parseDocks(service.docks);
		db.put(id, service, cb);
	};

	var onstatuschange = function(id, status, cb) {
		if (!db.has(id)) return cb(new Error('Service not found'));

		var service = db.get(id);
		var upd = {start:service.start, build:service.build, env:service.env, docks:service.docks};

		service.stopped = status === 'stop';
		db.put(id, service, function(err) {
			if (err) return cb(err);
			log(id, 'sending', status, 'to docks');
			forEach(docks, function(dock, next) {
				dock.update(id, upd, function(err) {
					if (err) return next(err);
					dock[status](id, next);
				});
			}, cb);
		});
	};

	var onclient = function(protocol) {
		protocol.on('add', function(id, opts, cb) {
			if (db.has(id)) return cb(new Error('Service already exist'));
			if (!/^[a-zA-Z0-9\-\.]+$/.test(id)) return cb(new Error('Service name should be alphanumericish'));
			log(id, 'adding new service');
			save(id, opts, cb);
		});

		protocol.on('update', function(id, opts, cb) {
			if (!db.has(id)) return cb(new Error('Service not found'));
			log(id, 'updating service');
			save(id, opts, cb);
		});

		protocol.on('remove', function(id, cb) {
			log(id, 'removing service');
			forEach(docks, function(dock, next) {
				dock.remove(id, next);
			}, function(err) {
				if (err) return cb(err);
				db.del(id, cb);
			});
		});

		protocol.on('get', function(id, cb) {
			if (!db.has(id)) return cb(new Error('Service not found'));
			cb(null, db.get(id));
		});

		protocol.on('list', function(cb) {
			var list = db.keys().map(function(key) {
				return db.get(key);
			});

			cb(null, list);
		});

		protocol.on('sync', function(id, service, cb) {
			if (!service) service = db.get(id);
			if (!service) return cb(new Error('Service not found'));
			log(id, 'syncing build to docks');

			var selected = docks.filter(function(dock) {
				return service.docks && service.docks.indexOf(dock.id) > -1;
			});

			var unselected = docks.filter(function(dock) {
				return !service.docks && service.docks.indexOf(dock.id) === -1;
			});

			var purge = function(err) {
				if (err) return cb(err);
				forEach(unselected, function(dock, next) {
					dock.remove(id, next);
				}, cb);
			};

			save(id, service, function(err) {
				if (err) return cb(err);
				forEach(selected, function(dock, next) {
					dock.sync(id, service, next);
				}, purge);
			});
		});

		protocol.on('restart', function(id, cb) {
			onstatuschange(id, 'restart', cb);
		});

		protocol.on('start', function(id, cb) {
			onstatuschange(id, 'start', cb);
		});

		protocol.on('stop', function(id, cb) {
			onstatuschange(id, 'stop', cb);
		});

		protocol.on('ps', function(cb) {
			forEach(docks, function(dock, next) {
				dock.ps(next);
			}, cb);
		});

		var unsubscribe = function(id, cb) {
			if (typeof cb !== 'function') cb = noop;
			var subs = subscriptions[id] = subscriptions[id] || [];
			var i = subs.indexOf(protocol);
			if (i === -1) return cb();

			log(id, 'client unsubscribing');
			if (subs.length === 1) delete subscriptions[id];
			else subs.splice(i, 1);
			cb();
		};

		protocol.on('subscribe', function(id, cb) {
			if (!db.has(id) && id !== '*') return cb(new Error('Service not found'));
			subs.subscribe(id, protocol);
			cb();
		});

		protocol.once('subscribe', function() {
			protocol.on('close', function() {
				subs.clear(protocol);
			});
		});

		protocol.on('unsubscribe', function(id, cb) {
			subs.unsubscribe(id, protocol);
			cb();
		});
	};

	var cache = {};

	server.put('/{id}', function(req, res) {
		var id = req.params.id;
		var deployed = new Date().toISOString();
		var cwd = path.join('builds', id+'@'+deployed);

		var onerror = function(status, message) {
			log(id, 'build failed');
			rimraf(cwd, function() {
				res.statusCode = status;
				res.addTrailers({'X-Status': status});
				res.end(message);
			});
		};

		var ondone = function(status) {
			var service = db.get(id);
			var old = service.cwd;

			service.cwd = cwd;
			service.deployed = deployed;
			service.revision = req.query.revision;

			db.put(id, service, function(err) {
				if (err) return onerror(500);
				log(id, 'build succeded');
				if (old) clean(old);
				delete cache[id];
				res.statusCode = status;
				res.addTrailers({'X-Status': 200});
				res.end();
			});
		};

		log(id, 'receiving tarball');
		res.setHeader('Trailer', 'X-Status');
		pump(req, zlib.createGunzip(), tar.extract(cwd), function(err) {
			if (err) return onerror(500, err.message);

			var service = db.get(id);

			if (!service) return onerror(404, 'Service not found');
			if (!service.build) return ondone(204);

			var build = proc.spawn('/bin/sh', ['-c', service.build, path.join(cwd, 'build.sh'), id], {
				cwd:cwd,
				env:xtend(process.env, service.env)
			});

			build.stdout.pipe(res, {end:false});
			build.stderr.pipe(res, {end:false});

			build.on('error', function(err) {
				onerror(500);
			});

			build.on('close', function(code) {
				if (code) return onerror(500);
				if (!db.has(id)) return onerror(404);
				ondone(200);
			});
		});
	});

	server.get('/{id}', function(req, res) {
		var id = req.params.id;
		var service = db.get(id);

		if (!service) return res.error(404, 'Service not found');
		if (!service.cwd) return res.error(404, 'No builds found');

		if (!cache[id]) {
			log(id, 'writing tarball to cache');
			cache[id] = thunky(function(cb) {
				var tmp = path.join(os.tmpDir(), 'hms-'+id+'.tgz');
				pump(tar.pack(service.cwd), zlib.createGzip(), fs.createWriteStream(tmp), function(err) {
					if (err) return cb(err);
					cb(null, tmp);
				});
			});
		}

		log(id, 'sending tarball');
		cache[id](function(err, tmp) {
			if (err) return res.error(err);
			pump(fs.createReadStream(tmp), res);
		});
	});

	server.get('/', function(req, res) {
		res.end('hms-terminal '+pkg.version+'\n');
	});

	server.on('connect', function(req, socket, data) {
		var p = protocol(socket, data);
		socket.write(HANDSHAKE);
		if (req.url === '/dock') ondock(p, req.headers.origin || 'unknown');
		else onclient(p);
	});

	var port = opts.port || 10002;
	server.listen(port, function() {
		log(null, 'listening on', port);
		if (opts.dock) require('./dock')(remote, {port:port+1, remote:'127.0.0.1:'+port, id:opts.id});
	});
};<|endoftext|>


<commit_before>
import {pointerType, resolveIncompleteArrayType} from './type';
import {PointerValue, ArrayValue, RecordValue, zeroAtType} from './value';
import {readValue} from './memory';

export const finalizeVarDecl = function (core, type, init) {
  if (init && type.kind === 'array') {
    /* Resolve array dimensions using the initialization list. */
    const dims = arraySize(init);
    type = resolveIncompleteArrayType(type, dims);
  }
  return {type, init: buildInitValue(core, type, init)};
};

function arraySize (init) {
  const result = [];
  while (Array.isArray(init)) {
    result.push(init.length);
    init = init[0];
  }
  return result;
}

function buildInitValue (core, type, init) {
  if (type.kind === 'array') {
    return init && buildArrayInitValue(core, type, init);
  }
  if (type.kind === 'record') {
    return init && buildRecordInitValue(core, type, init);
  }
  return init || zeroAtType(type);
}

function buildArrayInitValue (core, type, init) {
  const elements = [];
  const elemCount = type.count.toInteger();
  if (Array.isArray(init)) {
    for (let i = 0; i < elemCount; i += 1) {
      elements.push(buildInitValue(core, type.elem, init && init[i]));
    }
  } else if (init instanceof PointerValue) {
    /* Initialization from pointer value (string literal) */
    const refType = pointerType(type.elem);
    const ref = new PointerValue(refType, init.address);
    for (let i = 0; i < elemCount; i += 1) {
      elements.push(readValue(core, ref));
      ref.address += type.elem.size;
    }
  } else {
    console.warn("unsupported array init", init);
  }
  return new ArrayValue(type, elements);
}

function buildRecordInitValue (core, type, init) {
  const {fields, fieldMap} = type;
  const props = {};
  const fieldCount = fields.length;
  for (let fieldPos = 0; fieldPos < fieldCount; fieldPos += 1) {
    const fieldInit = init[fieldPos];
    if (fieldInit) {
      const name = fields[fieldPos];
      const {type: fieldType} = fieldMap[name];
      props[name] = buildInitValue(core, fieldType, fieldInit);
    }
  }
  return new RecordValue(type, props);
}
<commit_msg>limit array initialization from string literal to literal's length<commit_after>
import {pointerType, resolveIncompleteArrayType} from './type';
import {PointerValue, ArrayValue, RecordValue, zeroAtType} from './value';
import {readValue} from './memory';

export const finalizeVarDecl = function (core, type, init) {
  if (init && type.kind === 'array') {
    /* Resolve array dimensions using the initialization list. */
    const dims = arraySize(init);
    type = resolveIncompleteArrayType(type, dims);
  }
  return {type, init: buildInitValue(core, type, init)};
};

function arraySize (init) {
  const result = [];
  while (Array.isArray(init)) {
    result.push(init.length);
    init = init[0];
  }
  return result;
}

function buildInitValue (core, type, init) {
  if (type.kind === 'array') {
    return init && buildArrayInitValue(core, type, init);
  }
  if (type.kind === 'record') {
    return init && buildRecordInitValue(core, type, init);
  }
  return init || zeroAtType(type);
}

function buildArrayInitValue (core, type, init) {
  const elements = [];
  const elemCount = type.count.toInteger();
  if (Array.isArray(init)) {
    for (let i = 0; i < elemCount; i += 1) {
      elements.push(buildInitValue(core, type.elem, init && init[i]));
    }
  } else if (init instanceof PointerValue) {
    /* Initialization from pointer value (string literal) */
    const refType = pointerType(type.elem);
    const ref = new PointerValue(refType, init.address);
    /* init is a PointerValue with a definite-sized array type */
    const count = Math.min(elemCount, init.type.size);
    for (let i = 0; i < count; i += 1) {
      elements.push(readValue(core, ref));
      ref.address += type.elem.size;
    }
  } else {
    console.warn("unsupported array init", init);
  }
  return new ArrayValue(type, elements);
}

function buildRecordInitValue (core, type, init) {
  const {fields, fieldMap} = type;
  const props = {};
  const fieldCount = fields.length;
  for (let fieldPos = 0; fieldPos < fieldCount; fieldPos += 1) {
    const fieldInit = init[fieldPos];
    if (fieldInit) {
      const name = fields[fieldPos];
      const {type: fieldType} = fieldMap[name];
      props[name] = buildInitValue(core, fieldType, fieldInit);
    }
  }
  return new RecordValue(type, props);
}
<|endoftext|>


<commit_before>import { isString, isUndefined, isArray } from './util'
import { vnode } from './vnode'

function isVnode(vNode) {
  return vNode instanceof vnode
}

function sameVnode(vnode1, vnode2) {
  let id1 = vnode1.attributes ? vnode1.attributes.id : undefined
  let id2 = vnode2.attributes ? vnode2.attributes.id : undefined
  let classList1 = vnode1.attributes ? vnode1.attributes.class : undefined
  let classList2 = vnode2.attributes ? vnode2.attributes.class : undefined
  return vnode1.nodeName === vnode2.nodeName
    && vnode1.key === vnode2.key
    && id1 === id2
    && classList1 === classList2
}

function createElm(vnode) {
  let nodeName = vnode.nodeName,
    attrs = vnode.attributes,
    vCh = vnode.children,
    text = vnode.text,
    vChild, child, elm, i
  elm = document.createElement(nodeName)
  setAttributes(elm, attrs)
  if(text){
    elm.appendChild(document.createTextNode(text))
  }
  for (i = 0; i < vCh.length; ++i) {
    vChild = vCh[i]
    if(vChild){
      child = createElm(vChild)
      elm.appendChild(child)
    }
  }
  vnode.elm = elm
  return elm
}

function emptyVnode(elm) {
  let nodeName = elm.tagName.toLowerCase()
  return new vnode(nodeName, {}, [], undefined, elm);
}

export function diff(oldVnode, newVnode) {
  console.log(oldVnode, newVnode)
  // const insertVnodeQueue = []
  let parent
  let elm
  //如果第一个参数不是vnode
  if (!isVnode(oldVnode)) {
    oldVnode = emptyVnode(oldVnode)
  }
  if (sameVnode(oldVnode, newVnode)) {
    patchVnode(oldVnode, newVnode)
  } else {
    elm = oldVnode.elm
    parent = elm.parentNode
    createElm(newVnode)
    if (parent) {
      parent.replaceChild(newVnode.elm, oldVnode.elm)
    }
  }
  return newVnode
}

function patchVnode(oldVnode, newVnode) {
  //todo
  let elm = oldVnode.elm
  if (!newVnode.text) {
    newVnode.elm = elm
    let oldProps = oldVnode.attributes,
      newProps = newVnode.attributes,
      oldCh = oldVnode.children,
      newCh = newVnode.children
    if (oldProps !== newProps) {
      diffProps(elm, oldVnode, newVnode)
    }
    if (oldCh !== newCh) {
      diffChildren(elm, oldVnode.children, newVnode.children)
    }
  } else if (oldVnode.text !== newVnode.text) {
    elm.textContent = newVnode.text
  }
}

function diffProps(elm, oldVnode, newVnode) {
  let key, old, cur,
    oldAttrs = oldVnode.attributes,
    newAttrs = newVnode.attributes

  if (!oldAttrs && !newAttrs) return
  oldAttrs = oldAttrs || {}
  newAttrs = newAttrs || {}

  //新增属性、更新属性
  for (key in newAttrs) {
    cur = newAttrs[key]
    if (oldAttrs[key] !== cur) {
      //todo 布尔属性，比如checked, selected
      elm.setAttribute(key, cur)
    }
  }
  //删除已被删除的属性
  for (key in oldAttrs) {
    if (isUndefined(newAttrs[key])) {
      elm.removeAttribute(key)
    }
  }
}
function diffChildren(parentElm, oldCh, newCh) {
  let oldStartIdx = 0,
    oldEndIdx = oldCh.length - 1,
    oldStartVnode = oldCh[0],
    oldEndVnode = oldCh[oldEndIdx],
    newStartIdx = 0,
    newEndIdx = newCh.length - 1,
    newStartVnode = newCh[0],
    newEndVnode = newCh[newEndIdx],
    oldKeyToIdx, idxInOld, elmToMove, before
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    if (isUndefined(oldStartVnode)) {
      oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
    } else if (isUndefined(oldEndVnode)) {
      oldEndVnode = oldCh[--oldEndIdx];
    } else if (sameVnode(oldStartVnode, newStartVnode)) {
      patchVnode(oldStartVnode, newStartVnode);
      oldStartVnode = oldCh[++oldStartIdx];
      newStartVnode = newCh[++newStartIdx];
    } else if (sameVnode(oldEndVnode, newEndVnode)) {
      patchVnode(oldEndVnode, newEndVnode);
      oldEndVnode = oldCh[--oldEndIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
      patchVnode(oldStartVnode, newEndVnode);
      parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
      oldStartVnode = oldCh[++oldStartIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
      patchVnode(oldEndVnode, newStartVnode);
      parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);
      oldEndVnode = oldCh[--oldEndIdx];
      newStartVnode = newCh[++newStartIdx];
    } else {
      if (isUndefined(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
      idxInOld = oldKeyToIdx[newStartVnode.key];
      if (isUndefined(idxInOld)) { // New element
        parentElm.insertBefore(createElm(newStartVnode), oldStartVnode.elm);
        newStartVnode = newCh[++newStartIdx];
      } else {
        elmToMove = oldCh[idxInOld];
        patchVnode(elmToMove, newStartVnode);
        oldCh[idxInOld] = undefined;
        parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
        newStartVnode = newCh[++newStartIdx];
      }
    }
  }
  if (oldStartIdx > oldEndIdx) {
    before = isUndefined(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
    addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx);
  } else if (newStartIdx > newEndIdx) {
    removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
  }

}

function setAttributes(elm, attrs) {
  let p
  for (p in attrs) {
    elm.setAttribute(p, attrs[p])
  }
}

function createKeyToOldIdx(children, beginIdx, endIdx) {
  var i, map = {}, key;
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key;
    if (key) map[key] = i;
  }
  return map;
}

function addVnodes(parentElm, before, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    parentElm.insertBefore(createElm(vnodes[startIdx]), before);
  }
}

function removeVnodes(parentElm, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    var ch = vnodes[startIdx];
    if (ch) {
      parentElm.removeChild(ch.elm);
    }
  }
}<commit_msg>remove log info<commit_after>import { isString, isUndefined, isArray } from './util'
import { vnode } from './vnode'

function isVnode(vNode) {
  return vNode instanceof vnode
}

function sameVnode(vnode1, vnode2) {
  let id1 = vnode1.attributes ? vnode1.attributes.id : undefined
  let id2 = vnode2.attributes ? vnode2.attributes.id : undefined
  let classList1 = vnode1.attributes ? vnode1.attributes.class : undefined
  let classList2 = vnode2.attributes ? vnode2.attributes.class : undefined
  return vnode1.nodeName === vnode2.nodeName
    && vnode1.key === vnode2.key
    && id1 === id2
    && classList1 === classList2
}

function createElm(vnode) {
  let nodeName = vnode.nodeName,
    attrs = vnode.attributes,
    vCh = vnode.children,
    text = vnode.text,
    vChild, child, elm, i
  elm = document.createElement(nodeName)
  setAttributes(elm, attrs)
  if(text){
    elm.appendChild(document.createTextNode(text))
  }
  for (i = 0; i < vCh.length; ++i) {
    vChild = vCh[i]
    if(vChild){
      child = createElm(vChild)
      elm.appendChild(child)
    }
  }
  vnode.elm = elm
  return elm
}

function emptyVnode(elm) {
  let nodeName = elm.tagName.toLowerCase()
  return new vnode(nodeName, {}, [], undefined, elm);
}

export function diff(oldVnode, newVnode) {
  // const insertVnodeQueue = []
  let parent
  let elm
  //如果第一个参数不是vnode
  if (!isVnode(oldVnode)) {
    oldVnode = emptyVnode(oldVnode)
  }
  if (sameVnode(oldVnode, newVnode)) {
    patchVnode(oldVnode, newVnode)
  } else {
    elm = oldVnode.elm
    parent = elm.parentNode
    createElm(newVnode)
    if (parent) {
      parent.replaceChild(newVnode.elm, oldVnode.elm)
    }
  }
  return newVnode
}

function patchVnode(oldVnode, newVnode) {
  //todo
  let elm = oldVnode.elm
  if (!newVnode.text) {
    newVnode.elm = elm
    let oldProps = oldVnode.attributes,
      newProps = newVnode.attributes,
      oldCh = oldVnode.children,
      newCh = newVnode.children
    if (oldProps !== newProps) {
      diffProps(elm, oldVnode, newVnode)
    }
    if (oldCh !== newCh) {
      diffChildren(elm, oldVnode.children, newVnode.children)
    }
  } else if (oldVnode.text !== newVnode.text) {
    elm.textContent = newVnode.text
  }
}

function diffProps(elm, oldVnode, newVnode) {
  let key, old, cur,
    oldAttrs = oldVnode.attributes,
    newAttrs = newVnode.attributes

  if (!oldAttrs && !newAttrs) return
  oldAttrs = oldAttrs || {}
  newAttrs = newAttrs || {}

  //新增属性、更新属性
  for (key in newAttrs) {
    cur = newAttrs[key]
    if (oldAttrs[key] !== cur) {
      //todo 布尔属性，比如checked, selected
      elm.setAttribute(key, cur)
    }
  }
  //删除已被删除的属性
  for (key in oldAttrs) {
    if (isUndefined(newAttrs[key])) {
      elm.removeAttribute(key)
    }
  }
}
function diffChildren(parentElm, oldCh, newCh) {
  let oldStartIdx = 0,
    oldEndIdx = oldCh.length - 1,
    oldStartVnode = oldCh[0],
    oldEndVnode = oldCh[oldEndIdx],
    newStartIdx = 0,
    newEndIdx = newCh.length - 1,
    newStartVnode = newCh[0],
    newEndVnode = newCh[newEndIdx],
    oldKeyToIdx, idxInOld, elmToMove, before
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    if (isUndefined(oldStartVnode)) {
      oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
    } else if (isUndefined(oldEndVnode)) {
      oldEndVnode = oldCh[--oldEndIdx];
    } else if (sameVnode(oldStartVnode, newStartVnode)) {
      patchVnode(oldStartVnode, newStartVnode);
      oldStartVnode = oldCh[++oldStartIdx];
      newStartVnode = newCh[++newStartIdx];
    } else if (sameVnode(oldEndVnode, newEndVnode)) {
      patchVnode(oldEndVnode, newEndVnode);
      oldEndVnode = oldCh[--oldEndIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
      patchVnode(oldStartVnode, newEndVnode);
      parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
      oldStartVnode = oldCh[++oldStartIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
      patchVnode(oldEndVnode, newStartVnode);
      parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);
      oldEndVnode = oldCh[--oldEndIdx];
      newStartVnode = newCh[++newStartIdx];
    } else {
      if (isUndefined(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
      idxInOld = oldKeyToIdx[newStartVnode.key];
      if (isUndefined(idxInOld)) { // New element
        parentElm.insertBefore(createElm(newStartVnode), oldStartVnode.elm);
        newStartVnode = newCh[++newStartIdx];
      } else {
        elmToMove = oldCh[idxInOld];
        patchVnode(elmToMove, newStartVnode);
        oldCh[idxInOld] = undefined;
        parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
        newStartVnode = newCh[++newStartIdx];
      }
    }
  }
  if (oldStartIdx > oldEndIdx) {
    before = isUndefined(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
    addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx);
  } else if (newStartIdx > newEndIdx) {
    removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
  }

}

function setAttributes(elm, attrs) {
  let p
  for (p in attrs) {
    elm.setAttribute(p, attrs[p])
  }
}

function createKeyToOldIdx(children, beginIdx, endIdx) {
  var i, map = {}, key;
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key;
    if (key) map[key] = i;
  }
  return map;
}

function addVnodes(parentElm, before, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    parentElm.insertBefore(createElm(vnodes[startIdx]), before);
  }
}

function removeVnodes(parentElm, vnodes, startIdx, endIdx) {
  for (; startIdx <= endIdx; ++startIdx) {
    var ch = vnodes[startIdx];
    if (ch) {
      parentElm.removeChild(ch.elm);
    }
  }
}<|endoftext|>


<commit_before>
var get_matches;

{
    let counter = 0;
    var old_matches;
    var geocoder;
    var map;
    var markers = [];
    var match_template = Handlebars.compile($("#match-template").html());

    get_matches = () => {// only start when both the socket and map is ready
        if(++counter < 2) return;
        if(counter === 2){
            geocoder = new google.maps.Geocoder();
            map = new google.maps.Map(document.getElementById('req_getLocMap'), {
                center: new google.maps.LatLng(
                    $('#req_getLocMap').attr('data-lat'),
                    $('#req_getLocMap').attr('data-long')
                ),
                zoom: 13
            });
        }
        //get the list of matches
        socket.emit('matches.get');
        setInterval(()=>socket.emit('matches.get'), 5000);
    }

    socket.on('sockauth.success', get_matches);

    socket.on('matches.list', matches => {
        // add labels
        for(let i in matches) matches[i].label = (Number(i)+10).toString(36).toUpperCase();
        // set the html list
        $(".match-list li").remove();
        $(".match-list").html(match_template(matches));
        //do something about new matches

        old_matches = matches;
        //delete the old markers
        for(let i in markers) markers[i].setMap(null);
        markers = [];
        // get the street addresses of the locs and place their markers
        $('.get-loc-name').each(function(i){
            let label;
            if(i) label = (i+9).toString(36).toUpperCase();
            let position = new google.maps.LatLng($(this).attr('data-lat'),$(this).attr('data-long'));
            markers.push(new google.maps.Marker({
                map,
                position,
                label
            }));
            geocoder.geocode( { location: position, region: 'au'}, (results, status) => {
                if (status == 'OK') {
                    $(this).text(results[0].formatted_address);
                } else {
                    console.error('Adress lookup failed. ' + status);
                }
            });
        });
        // set the star ratings from the scores
        $('.star-score').each(function(){
            let score = Number($(this).attr('data-score')) || 0;
            let stars = ['star_border', 'star_border', 'star_border', 'star_border', 'star_border'];
            if(score > 0.05) stars[0] = 'star_half';
            if(score > 0.15) stars[0] = 'star';
            if(score > 0.25) stars[1] = 'star_half';
            if(score > 0.35) stars[1] = 'star';
            if(score > 0.45) stars[2] = 'star_half';
            if(score > 0.55) stars[2] = 'star';
            if(score > 0.65) stars[3] = 'star_half';
            if(score > 0.75) stars[3] = 'star';
            if(score > 0.85) stars[4] = 'star_half';
            if(score >= 0.95) stars[4] = 'star';
            $(this).html(
                'Match Quality: '+
                stars.join('')+
                ''
            );
        });
    });

    setInterval(() => { // display the times in a counting down fasion
        $('.get-time-left').each(function(){
            $(this).text( moment().to( Number( $(this).attr('data-time') ) ) );
        });
    }, 500);

    $('button.cancel').click(()=>{
        $.post('/request', {req_end: Date.now()-2*60*1000}, ()=>{
            window.location.reload(true);
        });
    });
}

var initMap = function(){

    get_matches();
};<commit_msg>check for changes<commit_after>
var get_matches;

{
    let counter = 0;
    var old_matches = [];
    var geocoder;
    var map;
    var markers = [];
    var match_template = Handlebars.compile($("#match-template").html());

    get_matches = () => {// only start when both the socket and map is ready
        if(++counter < 2) return;
        if(counter === 2){
            geocoder = new google.maps.Geocoder();
            map = new google.maps.Map(document.getElementById('req_getLocMap'), {
                center: new google.maps.LatLng(
                    $('#req_getLocMap').attr('data-lat'),
                    $('#req_getLocMap').attr('data-long')
                ),
                zoom: 13
            });
        }
        //get the list of matches
        socket.emit('matches.get');
        setInterval(()=>socket.emit('matches.get'), 5000);
    }

    socket.on('sockauth.success', get_matches);

    socket.on('matches.list', matches => {
        // add labels and check to see if anything has changed
        let changed = false;
        for(let i in matches){
            matches[i].label = (Number(i)+10).toString(36).toUpperCase();
            if(changed) continue;
            let same = false;
            for(let j in old_matches){
                if(matches[i].id === old_matches[j].id &&
                matches[i].updatedAt == old_matches[j].updatedAt){
                    same = true;
                    break;
                }
            }
            if(!same) changed = true;
        }
        for(let j in old_matches){
            if(changed) continue;
            let same = false;
            for(let i in matches){
                if(matches[i].id === old_matches[j].id &&
                matches[i].updatedAt == old_matches[j].updatedAt){
                    same = true;
                    break;
                }
            }
            if(!same) changed = true;
        }
        if(!changed) return;
        // set the html list
        $(".match-list li").remove();
        $(".match-list").html(match_template(matches));
        //do something about new matches

        old_matches = matches;
        //delete the old markers
        for(let i in markers) markers[i].setMap(null);
        markers = [];
        // get the street addresses of the locs and place their markers
        $('.get-loc-name').each(function(i){
            let label;
            if(i) label = (i+9).toString(36).toUpperCase();
            let position = new google.maps.LatLng($(this).attr('data-lat'),$(this).attr('data-long'));
            markers.push(new google.maps.Marker({
                map,
                position,
                label
            }));
            geocoder.geocode( { location: position, region: 'au'}, (results, status) => {
                if (status == 'OK') {
                    $(this).text(results[0].formatted_address);
                } else {
                    console.error('Adress lookup failed. ' + status);
                }
            });
        });
        // set the star ratings from the scores
        $('.star-score').each(function(){
            let score = Number($(this).attr('data-score')) || 0;
            let stars = ['star_border', 'star_border', 'star_border', 'star_border', 'star_border'];
            if(score > 0.05) stars[0] = 'star_half';
            if(score > 0.15) stars[0] = 'star';
            if(score > 0.25) stars[1] = 'star_half';
            if(score > 0.35) stars[1] = 'star';
            if(score > 0.45) stars[2] = 'star_half';
            if(score > 0.55) stars[2] = 'star';
            if(score > 0.65) stars[3] = 'star_half';
            if(score > 0.75) stars[3] = 'star';
            if(score > 0.85) stars[4] = 'star_half';
            if(score >= 0.95) stars[4] = 'star';
            $(this).html(
                'Match Quality: '+
                stars.join('')+
                ''
            );
        });
    });

    setInterval(() => { // display the times in a counting down fasion
        $('.get-time-left').each(function(){
            $(this).text( moment().to( Number( $(this).attr('data-time') ) ) );
        });
    }, 500);

    $('button.cancel').click(()=>{
        $.post('/request', {req_end: Date.now()-2*60*1000}, ()=>{
            window.location.reload(true);
        });
    });
}

var initMap = function(){

    get_matches();
};<|endoftext|>


<commit_before>var Promise = require('bluebird'),
    cp = require('child_process'),
    escapeArg = require('phpjs').escapeshellarg;

Promise.promisifyAll(cp);

var prepareCommand(command, params) {
    return command.replace(/\{\{([a-z0-9_]+)\}\}/i, function(match, key) {
        if (!params[key] || !params[key].length)
            throw 'exec: "' + key + '" is missing or empty';
        return escapeArg(params[key]);
    });
}

module.exports = function(command, params) {
    return cp.execAsync(prepareCommand(command, params));
}
<commit_msg>fix new exec function<commit_after>var Promise = require('bluebird'),
    cp = require('child_process'),
    escapeArg = require('phpjs').escapeshellarg;

Promise.promisifyAll(cp);

function prepareCommand(command, params) {
    return command.replace(/\{\{([a-z0-9_]+)\}\}/i, function(match, key) {
        if (!params[key] || !params[key].length)
            throw 'exec: "' + key + '" is missing or empty';
        return escapeArg(params[key]);
    });
}

module.exports = function(command, params) {
    return cp.execAsync(prepareCommand(command, params));
}
<|endoftext|>


<commit_before>'use strict'

const CONSTANTS = {
  NONE: 'none',
  FILL: 'fill',
  BEST_FILL: 'best-fill',
  BEST_FIT: 'best-fit',
  BEST_FIT_DOWN_ONLY: 'best-fit-down',
  ALIGN_LEFT: 'left',
  ALIGN_RIGHT: 'right',
  ALIGN_CENTER: 'center',
  ALIGN_TOP: 'top',
  ALIGN_BOTTOM: 'bottom',
  ALIGN_TOP_LEFT: 'top-left',
  ALIGN_TOP_RIGHT: 'top-right',
  ALIGN_BOTTOM_LEFT: 'bottom-left',
  ALIGN_BOTTOM_RIGHT: 'bottom-right'
}

class Resizer {
  constructor() {
    this.options = {
      scale       : 'best-fill',
      align       : 'center',
      force_style : true,
      parse       : true,
      target      : document.body,
      auto_resize : true,
      classes     : {
        to_resize : 'do-container',
        content   : 'do-content'
      }
    }
    // Set up
    this.elements = []

    // Parse
    if(this.options.parse)
      this.parse()

    // Auto resize
    if(this.options.auto_resize)
      this.initAutoResize()
  }

  initAutoResize() {
    //TODO: Implement auto-resize
    let that = this

    this.resizeAll()

    return this
  }

  parse(target, selector) {
    // Default options
    let self = this
    target   = target   || this.options.target
    selector = selector || this.options.classes.to_resize

    this.elements = []
    this.cachedElements = []
    let containers = target.querySelectorAll('.' + selector)

    for(let i = 0, len = containers.length; i < len; i++) {
      let container = containers[i],
        content   = container.querySelector('.' + this.options.classes.content)

      if(content) {
        this.elements.push({
            container : container,
            content   : content
          })
        content.style.display = 'none'
        ;(function waitTillContentReady(container, content, index) {
          content.onload = function() {
            content.style.display = 'block'
            self.cachedElements[index] = {
              container: {
                width: container.width,
                height: container.height
              },
              content: {
                width: content.width,
                height: content.height
              }
            }
            self.resize(container, content)
          }
        })(container, content, i)
      }
    }
    return this
  }

  resizeAll(options) {
    for(let i = 0, len = this.elements.length; i < len; i++) {
      let element = this.elements[i]
      if(this.cachedElements[i]) {
        let cache = this.cachedElements[i]
        Object.assign(element.content, cache.content)
        Object.assign(element.container, cache.container)
        this.resize(element.container, element.content, options)
      }
    }
    return this
  }

  resize(container, content, options) {
    // Errors
    let errors = []

    if(!( container instanceof HTMLElement))
      errors.push('wrong container parameter')

    if(!(content instanceof HTMLElement))
      errors.push('wrong content parameter')

    if(errors.length)
    {
      for(let i = 0; i < errors.length; i++)
        console.warn(errors[i])

      return false
    }

    // Parameters
    let parameters = {}
    options = options ? options : {}
    parameters.container_width  = options.containerWidth || container.getAttribute('data-width')  || container.getAttribute('width')  || container.offsetWidth
    parameters.container_height = options.containerHeight || container.getAttribute('data-height') || container.getAttribute('height') || container.offsetHeight
    parameters.content_width    = options.contentWidth || content.getAttribute('data-width')    || content.getAttribute('width')    || content.offsetWidth
    parameters.content_height   = options.contentHeight || content.getAttribute('data-height')   || content.getAttribute('height')   || content.offsetHeight
    parameters.align = {
      x: options.align_x || content.getAttribute('data-align-x'),
      y: options.align_y || content.getAttribute('data-align-y')
    }
    parameters.scale            = options.scale || content.getAttribute('data-scale')

    options.force_style = !!options.force_style

    if(options.force_style) {
      let container_style = window.getComputedStyle(container),
        content_style   = window.getComputedStyle(content)

      if(container_style.position !== 'fixed' && container_style.position !== 'relative' && container_style.position !== 'absolute')
        container.style.position = 'relative'

      if(content_style.position !== 'fixed' && content_style.position !== 'relative' && content_style.position !== 'absolute')
        content.style.position = 'absolute'

      if(container_style.overflow !== 'hidden')
        container.style.overflow = 'hidden'
    }

    let dest = {}
    dest.width = parameters.container_width
    dest.height = parameters.container_height

    let source = {}
    source.width = parameters.content_width
    source.height = parameters.content_height

    let layout = this._innerFrameForSize(parameters.scale, parameters.align, source, dest)

    content.style.position = 'relative'
    content.style.top = layout.y+'px'
    content.style.left = layout.x+'px'
    content.style.width = layout.width+'px'
    content.style.height = layout.height+'px'
    content.style.maxWidth = 'none'
    content.style.margin = 0
    content.style.display = 'block'

    return this
  }

  _innerFrameForSize(scale, align, source, dest){

    let scaleX, scaleY, result, scaleFactor

    result = { x: 0, y: 0, width: dest.width, height: dest.height }
    if (scale === CONSTANTS.FILL) return result

    scaleX = dest.width / source.width
    scaleY = dest.height / source.height

    switch (scale) {
      case CONSTANTS.BEST_FIT_DOWN_ONLY:
        if ((source.width > dest.width) || (source.height > dest.height)) {
          scaleFactor = scaleX < scaleY ? scaleX : scaleY
        } else {
          scaleFactor = 1.0
        }
        break
      case CONSTANTS.BEST_FIT:
        scaleFactor = scaleX < scaleY ? scaleX : scaleY
        break
      case CONSTANTS.NONE:
        scaleFactor = 1.0
        break
      case CONSTANTS.BEST_FILL:
      default:
        scaleFactor = scaleX > scaleY ? scaleX : scaleY
        break
    }

    result.width = Math.round(source.width * scaleFactor)
    result.height = Math.round(source.height * scaleFactor)

    switch(align.x) {
      case 'left':
        result.x = 0;
        break

      case 'middle':
      case 'center':
        result.x = (dest.width - result.width) / 2
        break

      case 'right':
        result.x = dest.width - result.width
        break
    }

    switch(align.y) {
      case 'top':
        result.y = 0;
        break
      case 'middle':
      case 'center':
        result.y = (dest.height - result.height) / 2
        break
      case 'bottom':
        result.y = dest.height - result.height
        break
    }

    return result

  }
}
module.exports = Resizer
<commit_msg>rounding fixed<commit_after>'use strict'

const CONSTANTS = {
  NONE: 'none',
  FILL: 'fill',
  BEST_FILL: 'best-fill',
  BEST_FIT: 'best-fit',
  BEST_FIT_DOWN_ONLY: 'best-fit-down',
  ALIGN_LEFT: 'left',
  ALIGN_RIGHT: 'right',
  ALIGN_CENTER: 'center',
  ALIGN_TOP: 'top',
  ALIGN_BOTTOM: 'bottom'
}

class Resizer {
  constructor() {
    this.options = {
      scale       : 'best-fill',
      align       : 'center',
      force_style : true,
      parse       : true,
      target      : document.body,
      auto_resize : true,
      classes     : {
        to_resize : 'do-container',
        content   : 'do-content'
      }
    }
    // Set up
    this.elements = []

    // Parse
    if(this.options.parse)
      this.parse()

    // Auto resize
    if(this.options.auto_resize)
      this.initAutoResize()
  }

  initAutoResize() {
    //TODO: Implement auto-resize
    let that = this

    this.resizeAll()

    return this
  }

  parse(target, selector) {
    // Default options
    let self = this
    target   = target   || this.options.target
    selector = selector || this.options.classes.to_resize

    this.elements = []
    this.cachedElements = []
    let containers = target.querySelectorAll('.' + selector)

    for(let i = 0, len = containers.length; i < len; i++) {
      let container = containers[i],
        content   = container.querySelector('.' + this.options.classes.content)

      if(content) {
        this.elements.push({
            container : container,
            content   : content
          })
        content.style.display = 'none'
        ;(function waitTillContentReady(container, content, index) {
          content.onload = function() {
            content.style.display = 'block'
            self.cachedElements[index] = {
              container: {
                width: container.width,
                height: container.height
              },
              content: {
                width: content.width,
                height: content.height
              }
            }
            self.resize(container, content)
          }
        })(container, content, i)
      }
    }
    return this
  }

  resizeAll(options) {
    for(let i = 0, len = this.elements.length; i < len; i++) {
      let element = this.elements[i]
      if(this.cachedElements[i]) {
        let cache = this.cachedElements[i]
        Object.assign(element.content, cache.content)
        Object.assign(element.container, cache.container)
        this.resize(element.container, element.content, options)
      }
    }
    return this
  }

  resize(container, content, options) {
    // Errors
    let errors = []

    if(!( container instanceof HTMLElement))
      errors.push('wrong container parameter')

    if(!(content instanceof HTMLElement))
      errors.push('wrong content parameter')

    if(errors.length)
    {
      for(let i = 0; i < errors.length; i++)
        console.warn(errors[i])

      return false
    }

    // Parameters
    let parameters = {}
    options = options ? options : {}
    parameters.container_width  = options.containerWidth || container.getAttribute('data-width')  || container.getAttribute('width')  || container.offsetWidth
    parameters.container_height = options.containerHeight || container.getAttribute('data-height') || container.getAttribute('height') || container.offsetHeight
    parameters.content_width    = options.contentWidth || content.getAttribute('data-width')    || content.getAttribute('width')    || content.offsetWidth
    parameters.content_height   = options.contentHeight || content.getAttribute('data-height')   || content.getAttribute('height')   || content.offsetHeight
    parameters.scale            = options.scale || content.getAttribute('data-scale')
    parameters.rounding         = options.rounding || content.getAttribute( 'data-rounding' )
    parameters.align = {
      x: options.align_x || content.getAttribute('data-align-x'),
      y: options.align_y || content.getAttribute('data-align-y')
    }

    parameters.rounding = parameters.rounding.toLowerCase()

    options.force_style = !!options.force_style

    if(options.force_style) {
      let container_style = window.getComputedStyle(container),
        content_style   = window.getComputedStyle(content)

      if(container_style.position !== 'fixed' && container_style.position !== 'relative' && container_style.position !== 'absolute')
        container.style.position = 'relative'

      if(content_style.position !== 'fixed' && content_style.position !== 'relative' && content_style.position !== 'absolute')
        content.style.position = 'absolute'

      if(container_style.overflow !== 'hidden')
        container.style.overflow = 'hidden'
    }

    let dest = {}
    dest.width = parameters.container_width
    dest.height = parameters.container_height

    let source = {}
    source.width = parameters.content_width
    source.height = parameters.content_height

    let layout = this._innerFrameForSize(parameters.scale, parameters.align, source, dest)

    if(['ceil', 'floor', 'round'].indexOf(parameters.rounding)!== -1)
    {
      layout.width  = Math[parameters.rounding].call(this, layout.width)
      layout.height = Math[parameters.rounding].call(this, layout.height)
      layout.x      = Math[parameters.rounding].call(this, layout.x)
      layout.y      = Math[parameters.rounding].call(this, layout.y)
    }

    content.style.position = 'relative'
    content.style.top = layout.y+'px'
    content.style.left = layout.x+'px'
    content.style.width = layout.width+'px'
    content.style.height = layout.height+'px'
    content.style.maxWidth = 'none'
    content.style.margin = 0
    content.style.display = 'block'

    return this
  }

  _innerFrameForSize(scale, align, source, dest){

    let scaleX, scaleY, result, scaleFactor

    result = { x: 0, y: 0, width: dest.width, height: dest.height }
    if (scale === CONSTANTS.FILL) return result

    scaleX = dest.width / source.width
    scaleY = dest.height / source.height

    switch (scale) {
      case CONSTANTS.BEST_FIT_DOWN_ONLY:
        if ((source.width > dest.width) || (source.height > dest.height)) {
          scaleFactor = scaleX < scaleY ? scaleX : scaleY
        } else {
          scaleFactor = 1.0
        }
        break
      case CONSTANTS.BEST_FIT:
        scaleFactor = scaleX < scaleY ? scaleX : scaleY
        break
      case CONSTANTS.NONE:
        scaleFactor = 1.0
        break
      case CONSTANTS.BEST_FILL:
      default:
        scaleFactor = scaleX > scaleY ? scaleX : scaleY
        break
    }

    result.width = Math.round(source.width * scaleFactor)
    result.height = Math.round(source.height * scaleFactor)

    switch(align.x) {
      case 'left':
        result.x = 0;
        break

      case 'middle':
      case 'center':
        result.x = (dest.width - result.width) / 2
        break

      case 'right':
        result.x = dest.width - result.width
        break
    }

    switch(align.y) {
      case 'top':
        result.y = 0;
        break
      case 'middle':
      case 'center':
        result.y = (dest.height - result.height) / 2
        break
      case 'bottom':
        result.y = dest.height - result.height
        break
    }

    return result

  }
}
module.exports = Resizer
<|endoftext|>


<commit_before>define(['sprout/util', 'sprout/base', 'sprout/dom'], function (_, base, $) {
	'use strict';

	/**
     * Checks whether an instruction condition passes.
     * @private
     * @param {Boolean|Function|Array|Object} condition A boolean, function, array of promises, or one promise to check.
     * @return {Boolean} Returns true if the condition passes, false otherwise.
     */
	function passes (condition)
	{
		// If the condition is a boolean then just use its value
		if (_.isBoolean(condition)) {
			return condition;
		}
		// Else if the condition is a function then use its return value
		else  if (_.isFunction(condition)) {
			return condition();
		}
		// Else if the condition is an array of conditions then use their states
		else if (_.isArray(condition)) {
			return !_.any(condition, function () {
				return passes(condition);
			});
		}
		// Else if the condition is a promise then use its state
		else if (_.isObject(condition)) {
			return condition.state() !== 'rejected';
		}

		return false;
	}

	/**
     * Runs an instruction.
     * @private
     * @param {Object} instruction The instruction to execute.
     */
	function runInstruction (instruction)
	{
		try {
			switch (instruction.type) {
			case 'wait':
				// Delay execution of the next instruction
				this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				break;
			case 'waitIf':
				// If the delay should be applied then delay execution of the next instruction
				if (passes(instruction.condition)) {
					this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				}
				// Else Execute the next instruction now
				else {
					runNextInstruction.call(this);
				}
				break;
			case 'waitIfNot':
				// If the delay should be applied then delay execution of the next instruction
				if (!passes(instruction.condition)) {
					this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				}
				// Else Execute the next instruction now
				else {
					runNextInstruction.call(this);
				}
				break;
			case 'run':
				// Invoke the function
				instruction.func.apply(instruction.context, instruction.args);

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'runIf':
				// If any of the promises have been rejected at this point then do not invoke the function
				if (passes(instruction.condition)) {
					instruction.func.apply(instruction.context, instruction.args);
				}

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'runIfNot':
				// If any of the promises have been rejected at this point then invoke the function
				if (!passes(instruction.condition)) {
					instruction.func.apply(instruction.context, instruction.args);
				}

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'done':
				this.deferred.resolve();
				this.destroy();
				break;
			default:
				// This is an unknown instruction so just move on to the next
				runNextInstruction.call(this);
				break;
			}
		}
		catch (ex) {
			this.deferred.reject(ex);
			this.clear();
		}
	}

	/**
     * Runs the next instruction in the queue.
     * @private
     */
	function runNextInstruction ()
	{
		try {
			this.timeout = null;

			if (this.instructions.length > 0) {
				runInstruction.call(this, this.instructions.shift());
			}
			else {
				this.running = false;
			}
		}
		catch (ex) {
			this.deferred.reject(ex);
			this.clear();
		}
	}

	/**
     * If instructions are not currently being exected then this starts them up.
     * @private
     */
	function startInstructions ()
	{
		if (!this.running) {
			this.running = true;
			runNextInstruction.call(this);
		}
	}

	/**
     * @class flow
     * A flow objects helps chain together asynchronous operations. After creating a flow object you pass it instructions to run which it executes one after the other.
     *

     *     var anim = flow.create();
     *     anim.wait(150).run(slide, this, item).wait(350).run(fadeOut, this, this.fadeLists);
     *     ...
     *     anim.destroy();
     *

     * The above code creates a flow object and tells it to wait 150 ms before sliding an item. And then to wait another 350 ms after that before fading out some lists.
     *

     * One off flows can be created without having to worry about calling destroy on the flow object once it is done executing its instructions.
     * This is possible by calling the done method as the last instruction. The done method also returns a promise which is resolved after the done instruction is run.
     *

     *     flow.create().wait(150).run(slide, this, item).wait(350).run(fadeOut, this, this.fadeLists).done();
     *

     * The above code will create a flow object, wait 150 ms, slide an item, wait 350 ms, fade some lists out, and then destroy itself.
     *

     * When an instruction is added to an empty flow it is executed immediately.
     * @extends base
     */
	return base.extend({
		/**
         * Initializes the flow object.
         */
		constructor: function ()
		{
			base.constructor.call(this);

			this.instructions = [];
			this.running = false;
			this.timeout = null;
			this.deferred = new $.Deferred();
		},

		/**
         * Deinitializes the object.
         */
		destructor: function ()
		{
			this.clear();
			this.instructions = null;
			this.deferred = null;

			base.destructor.call(this);
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause it to destroy itself.
         * @return {Object} Returns itself for chaining.
         */
		done: function ()
		{
			this.instructions.push({
				type: 'done'
			});

			startInstructions.call(this);

			return this.deferred.promise();
		},

		/**
         * A flow instruction. Clears all instructions that have not been executed yet. Any instructions delayed to run by the wait instruction are also cleared.
         * @return {Object} Returns itself for chaining.
         */
		clear: function ()
		{
			this.instructions = [];
			this.running = false;

			if (this.timeout !== null) {
				clearTimeout(this.timeout);
			}

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		wait: function (delay)
		{
			this.instructions.push({
				type: 'wait',
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * The delay is only applied if the condition passes. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * If the promises have not been reject or any of the other condition types are truthy then the delay is applied.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the delay.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		waitIf: function (condition, delay)
		{
			this.instructions.push({
				type: 'waitIf',
				condition: condition,
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * The delay is only applied if the condition does not pass. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the delay.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		waitIfNot: function (condition, delay)
		{
			this.instructions.push({
				type: 'waitIfNot',
				condition: condition,
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * @return {Object} Returns itself for chaining.
         */
		defer: function ()
		{
			return this.wait(0);
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * The delay is only applied if the condition passes. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the defer.
         * @return {Object} Returns itself for chaining.
         */
		deferIf: function (condition)
		{
			return this.waitIf(condition, 0);
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * The delay is only applied if the condition does not pass. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the defer.
         * @return {Object} Returns itself for chaining.
         */
		deferIfNot: function (condition)
		{
			return this.waitIfNot(condition, 0);
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to undefined.
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		run: function (func, context)
		{
			this.instructions.push({
				type: 'run',
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(2)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * The function is only invoked if the condition passes.
         * This means promises that are pending or resolved will invoke the function.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to undefined.
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		runIf: function (condition, func, context)
		{
			this.instructions.push({
				type: 'runIf',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * The function is only invoked if the condition does not pass.
         * This means promises that are pending or resolved will not invoke the function.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to undefined.
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		runIfNot: function (condition, func, context)
		{
			this.instructions.push({
				type: 'runIfNot',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		}
	});
});<commit_msg>Added flow.requestAnimationFrame, flow.requestAnimationFrameIf, and flow.requestAnimationFrameIfNot for running instructions within requestAnimationFrame.<commit_after>define(['sprout/util', 'sprout/base', 'sprout/dom'], function (_, base, $) {
	'use strict';

	/**
     * Checks whether an instruction condition passes.
     * @private
     * @param {Boolean|Function|Array|Object} condition A boolean, function, array of promises, or one promise to check.
     * @return {Boolean} Returns true if the condition passes, false otherwise.
     */
	function passes (condition)
	{
		// If the condition is a boolean then just use its value
		if (_.isBoolean(condition)) {
			return condition;
		}
		// Else if the condition is a function then use its return value
		else  if (_.isFunction(condition)) {
			return condition();
		}
		// Else if the condition is an array of conditions then use their states
		else if (_.isArray(condition)) {
			return !_.any(condition, function () {
				return passes(condition);
			});
		}
		// Else if the condition is a promise then use its state
		else if (_.isObject(condition)) {
			return condition.state() !== 'rejected';
		}

		return false;
	}

	/**
     * Runs an instruction.
     * @private
     * @param {Object} instruction The instruction to execute.
     */
	function runInstruction (instruction)
	{
		try {
			switch (instruction.type) {
			case 'wait':
				// Delay execution of the next instruction
				this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				break;
			case 'waitIf':
				// If the delay should be applied then delay execution of the next instruction
				if (passes(instruction.condition)) {
					this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				}
				// Else Execute the next instruction now
				else {
					runNextInstruction.call(this);
				}
				break;
			case 'waitIfNot':
				// If the delay should be applied then delay execution of the next instruction
				if (!passes(instruction.condition)) {
					this.timeout = setTimeout(_.bind(runNextInstruction, this), instruction.delay);
				}
				// Else Execute the next instruction now
				else {
					runNextInstruction.call(this);
				}
				break;
			case 'run':
				// Invoke the function
				instruction.func.apply(instruction.context, instruction.args);

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'runIf':
				// If the condition passes then invoke the function
				if (passes(instruction.condition)) {
					instruction.func.apply(instruction.context, instruction.args);
				}

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'runIfNot':
				// If the condition does not pass then invoke the function
				if (!passes(instruction.condition)) {
					instruction.func.apply(instruction.context, instruction.args);
				}

				// Execute the next instruction
				runNextInstruction.call(this);
				break;
			case 'requestAnimationFrame':
				// Make a requestAnimationFrame call
				this.animationFrame = requestAnimationFrame(_.bind(onRequestAnimationFrame, this, instruction));
				break;
			case 'requestAnimationFrameIf':
				// If the condition passes then make a requestAnimationFrame call
				if (passes(instruction.condition)) {
					// Make a requestAnimationFrame call
					this.animationFrame = requestAnimationFrame(_.bind(onRequestAnimationFrame, this, instruction));
				}
				break;
			case 'requestAnimationFrameIfNot':
				// If the condition does not pass then make a requestAnimationFrame call
				if (!passes(instruction.condition)) {
					// Make a requestAnimationFrame call
					this.animationFrame = requestAnimationFrame(_.bind(onRequestAnimationFrame, this, instruction));
				}
				break;
			case 'done':
				this.deferred.resolve();
				this.destroy();
				break;
			default:
				// This is an unknown instruction so just move on to the next
				runNextInstruction.call(this);
				break;
			}
		}
		catch (ex) {
			this.deferred.reject(ex);
			this.clear();
		}
	}

	/**
     * Runs the next instruction in the queue.
     * @private
     */
	function runNextInstruction ()
	{
		try {
			this.timeout = null;
			this.animationFrame = null;

			if (this.instructions.length > 0) {
				runInstruction.call(this, this.instructions.shift());
			}
			else {
				this.running = false;
			}
		}
		catch (ex) {
			this.deferred.reject(ex);
			this.clear();
		}
	}

	/**
     * If instructions are not currently being exected then this starts them up.
     * @private
     */
	function startInstructions ()
	{
		if (!this.running) {
			this.running = true;
			runNextInstruction.call(this);
		}
	}

	/**
     * Runs a requestAnimationFrame instruction and kicks off the next instruction.
     * @private
     */
	function onRequestAnimationFrame (instruction)
	{
		try {
			// Invoke the function
			instruction.func.apply(instruction.context, instruction.args.concat(_.toArray(arguments).slice(1)));

			// Execute the next instruction
			runNextInstruction.call(this);
		}
		catch (ex) {
			this.deferred.reject(ex);
			this.clear();
		}
	}

	/**
     * @class flow
     * A flow objects helps chain together asynchronous operations. After creating a flow object you pass it instructions to run which it executes one after the other.
     *

     *     var anim = flow.create();
     *     anim.wait(150).run(slide, this, item).wait(350).run(fadeOut, this, this.fadeLists);
     *     ...
     *     anim.destroy();
     *

     * The above code creates a flow object and tells it to wait 150 ms before sliding an item. And then to wait another 350 ms after that before fading out some lists.
     *

     * One off flows can be created without having to worry about calling destroy on the flow object once it is done executing its instructions.
     * This is possible by calling the done method as the last instruction. The done method also returns a promise which is resolved after the done instruction is run.
     *

     *     flow.create().wait(150).run(slide, this, item).wait(350).run(fadeOut, this, this.fadeLists).done();
     *

     * The above code will create a flow object, wait 150 ms, slide an item, wait 350 ms, fade some lists out, and then destroy itself.
     *

     * When an instruction is added to an empty flow it is executed immediately.
     * @extends base
     */
	return base.extend({
		/**
         * Initializes the flow object.
         */
		constructor: function ()
		{
			base.constructor.call(this);

			this.instructions = [];
			this.running = false;
			this.timeout = null;
			this.animationFrame = null;
			this.deferred = new $.Deferred();
		},

		/**
         * Deinitializes the object.
         */
		destructor: function ()
		{
			this.clear();
			this.instructions = null;
			this.deferred = null;

			base.destructor.call(this);
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause it to destroy itself.
         * @return {Object} Returns itself for chaining.
         */
		done: function ()
		{
			this.instructions.push({
				type: 'done'
			});

			startInstructions.call(this);

			return this.deferred.promise();
		},

		/**
         * A flow instruction. Clears all instructions that have not been executed yet. Any instructions delayed to run by the wait instruction are also cleared.
         * @return {Object} Returns itself for chaining.
         */
		clear: function ()
		{
			this.instructions = [];
			this.running = false;

			if (this.timeout !== null) {
				clearTimeout(this.timeout);
			}

			if (this.animationFrame !== null) {
				cancelAnimationFrame(this.animationFrame);
			}

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		wait: function (delay)
		{
			this.instructions.push({
				type: 'wait',
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * The delay is only applied if the condition passes. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * If the promises have not been reject or any of the other condition types are truthy then the delay is applied.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the delay.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		waitIf: function (condition, delay)
		{
			this.instructions.push({
				type: 'waitIf',
				condition: condition,
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instructions by a specified number of milliseconds.
         * The delay is only applied if the condition does not pass. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the delay.
         * @param {Number} delay The number of milliseconds to delay execution of the following instructions.
         * @return {Object} Returns itself for chaining.
         */
		waitIfNot: function (condition, delay)
		{
			this.instructions.push({
				type: 'waitIfNot',
				condition: condition,
				delay: delay
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * @return {Object} Returns itself for chaining.
         */
		defer: function ()
		{
			return this.wait(0);
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * The delay is only applied if the condition passes. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the defer.
         * @return {Object} Returns itself for chaining.
         */
		deferIf: function (condition)
		{
			return this.waitIf(condition, 0);
		},

		/**
         * A flow instruction. Add this instruction to delay execution of the following instruction to the next call stack.
         * The delay is only applied if the condition does not pass. The condition can be a boolean, function (that returns truthy or falsy), or promises.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before applying the defer.
         * @return {Object} Returns itself for chaining.
         */
		deferIfNot: function (condition)
		{
			return this.waitIfNot(condition, 0);
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		run: function (func, context)
		{
			this.instructions.push({
				type: 'run',
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(2)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * The function is only invoked if the condition passes.
         * This means promises that are pending or resolved will invoke the function.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		runIf: function (condition, func, context)
		{
			this.instructions.push({
				type: 'runIf',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked.
         * The function is only invoked if the condition does not pass.
         * This means promises that are pending or resolved will not invoke the function.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		runIfNot: function (condition, func, context)
		{
			this.instructions.push({
				type: 'runIfNot',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked within requestAnimationFrame.
         * The arguments from requestAnimationFrame are passed to the instruction function after the custom args.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		requestAnimationFrame: function (func, context)
		{
			this.instructions.push({
				type: 'requestAnimationFrame',
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(2)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked within requestAnimationFrame.
         * The function is only invoked if the condition passes.
         * This means promises that are pending or resolved will invoke the function.
         * The arguments from requestAnimationFrame are passed to the instruction function after the custom args.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		requestAnimationFrameIf: function (condition, func, context)
		{
			this.instructions.push({
				type: 'requestAnimationFrameIf',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		},

		/**
         * A flow instruction. Add this instruction to a flow object to cause a function to be invoked within requestAnimationFrame.
         * The function is only invoked if the condition does not pass.
         * This means promises that are pending or resolved will not invoke the function.
         * The arguments from requestAnimationFrame are passed to the instruction function after the custom args.
         * @param {Boolean|Function|Array|Object} condition A boolean, function, promise, or array of any of the former to check against before invoking the function.
         * @param {Function} func The function to run.
         * @param {Object} context (Optional) The context to run the function in. Defaults to this.get('context').
         * @param {...} args (Optional) Any remaining arguments are passed as arguments to the function.
         * @return {Object} Returns itself for chaining.
         */
		requestAnimationFrameIfNot: function (condition, func, context)
		{
			this.instructions.push({
				type: 'requestAnimationFrameIfNot',
				condition: condition,
				func: func,
				context: context || this.get('context'),
				args: _.toArray(arguments).slice(3)
			});

			startInstructions.call(this);

			return this;
		}
	});
});<|endoftext|>


<commit_before>var React = require('react'),
	DOM = React.DOM;

module.exports = React.createClass({

	propTypes: {
		version: React.PropTypes.string,
		year: React.PropTypes.number,
		author: React.PropTypes.string,
		email: React.PropTypes.string,
		githubUrl: React.PropTypes.string
	},

	getDefaultProps: function () {
		return {
			year: new Date().getFullYear(),
			author: 'YourNameHere',
			email: 'your@email.com',
			githubUrl: null
		};
	},

	render: function () {
		return DOM.footer(null, [

			DOM.hr(null, null),

			DOM.div({ className: 'row' }, DOM.div({ className: 'col-xs-12 text-center' }, [
				DOM.small({ dangerouslySetInnerHTML: { __html: '© ' + this.props.year + ' ' }}),
				DOM.a({ className: 'footer__author', href: 'mailto:' + this.props.email }, this.props.author),
				DOM.small(null, ' v' + this.props.version)
			])),

			DOM.div({ className: 'row' },
				DOM.div({ className: 'col-xs-12 text-center' },
					DOM.small(null,
						DOM.a({ className: '', href: this.props.githubUrl }, 'View sourcecode on github')
					)
				)
			)

		]);
	}

});<commit_msg>Update component to pass tests.<commit_after>var React = require('react'),
	DOM = React.DOM;

module.exports = React.createClass({

	propTypes: {
		version: React.PropTypes.string,
		year: React.PropTypes.number,
		author: React.PropTypes.string,
		email: React.PropTypes.string,
		githubUrl: React.PropTypes.string
	},

	getDefaultProps: function () {
		return {
			year: new Date().getFullYear(),
			author: 'YourNameHere',
			email: 'your@email.com',
			githubUrl: null
		};
	},

	render: function () {
		return DOM.footer(null, [

			DOM.hr(null, null),

			DOM.div({ className: 'row' }, DOM.div({ className: 'col-xs-12 text-center' }, [
				DOM.small({ dangerouslySetInnerHTML: { __html: '© ' + this.props.year + ' ' }}),
				DOM.a({ className: 'footer__author', href: 'mailto:' + this.props.email }, this.props.author),
				DOM.small({ className: 'footer__version'}, ' v' + this.props.version)
			])),

			DOM.div({ className: 'row' },
				DOM.div({ className: 'col-xs-12 text-center' },
					DOM.small(null,
						DOM.a({ className: 'footer__url', href: this.props.githubUrl }, 'View sourcecode on github')
					)
				)
			)

		]);
	}

});<|endoftext|>


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

(function() {

  var isWorker = typeof importScripts !== 'undefined';
  var isServer = ( ! isWorker ) && typeof window === 'undefined';

  var flags    = this.FOAM_FLAGS = this.FOAM_FLAGS || {};
  flags.web    = ! isServer,
  flags.node   = isServer;
  flags.loader = ! isServer;
  if ( ! flags.hasOwnProperty('java') ) flags.java   = true;
  if ( ! flags.hasOwnProperty('swift') ) flags.swift = true;
  if ( ! flags.hasOwnProperty('debug') ) flags.debug = true;
  if ( ! flags.hasOwnProperty('js')    ) flags.js    = true;

  function createLoadBrowser() {
    var path = document.currentScript && document.currentScript.src;

    // document.currentScript isn't supported on all browsers, so the following
    // hack gets the job done on those browsers.
    if ( ! path ) {
      var scripts = document.getElementsByTagName('script');
      for ( var i = 0 ; i < scripts.length ; i++ ) {
        if ( scripts[i].src.match(/\/foam.js$/) ) {
          path = scripts[i].src;
          break;
        }
      }
    }

    path = path.substring(0, path.lastIndexOf('src/')+4);

    if ( typeof global !== 'undefined' ) global.FOAM_ROOT = path;
    if ( typeof window !== 'undefined' ) window.FOAM_ROOT = path;

    return function(filename) {
      document.writeln(
        '<script type="text/javascript" src="' + path + filename + '.js"></script>\n');
    };
  }

  function loadServer() {
    var caller = flags.src || __filename;
    var path = caller.substring(0, caller.lastIndexOf('src/')+4);

    if ( typeof global !== 'undefined' ) global.FOAM_ROOT = path;

    return function (filename) {
      require(path + filename + '.js');
    }
  }

  function createLoadWorker(filename) {
    var path = FOAM_BOOT_PATH;
    return function(filename) {
      importScripts(path + filename + '.js');
    };
  }

  function getLoader() {
    return isServer ? loadServer() :
      isWorker ? createLoadWorker() :
      createLoadBrowser();
  }

  this.FOAM_FILES = function(files) {
    var load = getLoader();

    files.
      map(function(f) { return f.name; }).
      forEach(load);

  //  delete this.FOAM_FILES;
  };

  getLoader()('files');
})();
<commit_msg>Only set FOAM_ROOT once. It's currently getting clobbered whenever we load other files.js files.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function() {

  var isWorker = typeof importScripts !== 'undefined';
  var isServer = ( ! isWorker ) && typeof window === 'undefined';

  var flags    = this.FOAM_FLAGS = this.FOAM_FLAGS || {};
  flags.web    = ! isServer,
  flags.node   = isServer;
  flags.loader = ! isServer;
  if ( ! flags.hasOwnProperty('java') ) flags.java   = true;
  if ( ! flags.hasOwnProperty('swift') ) flags.swift = true;
  if ( ! flags.hasOwnProperty('debug') ) flags.debug = true;
  if ( ! flags.hasOwnProperty('js')    ) flags.js    = true;

  function createLoadBrowser() {
    var path = document.currentScript && document.currentScript.src;

    // document.currentScript isn't supported on all browsers, so the following
    // hack gets the job done on those browsers.
    if ( ! path ) {
      var scripts = document.getElementsByTagName('script');
      for ( var i = 0 ; i < scripts.length ; i++ ) {
        if ( scripts[i].src.match(/\/foam.js$/) ) {
          path = scripts[i].src;
          break;
        }
      }
    }

    path = path.substring(0, path.lastIndexOf('src/')+4);

    if ( typeof global !== 'undefined' && ! global.FOAM_ROOT ) global.FOAM_ROOT = path;
    if ( typeof window !== 'undefined' && ! window.FOAM_ROOT ) window.FOAM_ROOT = path;

    return function(filename) {
      document.writeln(
        '<script type="text/javascript" src="' + path + filename + '.js"></script>\n');
    };
  }

  function loadServer() {
    var caller = flags.src || __filename;
    var path = caller.substring(0, caller.lastIndexOf('src/')+4);

    if ( typeof global !== 'undefined' && ! global.FOAM_ROOT ) global.FOAM_ROOT = path;

    return function (filename) {
      require(path + filename + '.js');
    }
  }

  function createLoadWorker(filename) {
    var path = FOAM_BOOT_PATH;
    return function(filename) {
      importScripts(path + filename + '.js');
    };
  }

  function getLoader() {
    return isServer ? loadServer() :
      isWorker ? createLoadWorker() :
      createLoadBrowser();
  }

  this.FOAM_FILES = function(files) {
    var load = getLoader();

    files.
      map(function(f) { return f.name; }).
      forEach(load);

  //  delete this.FOAM_FILES;
  };

  getLoader()('files');
})();
<|endoftext|>