<commit_before>/*	devProxy.js 0.1
 *	通过将数据请求转发到远程服务器, 来在本地开发环境中模拟服务器环境, 以实现完整的网站功能
 *	脚本执行时会从当前目录载入proxyConfig.js
 */

'use strict';
var http = require('http');
var https = require('https');
var util = require('util');
var path = require('path');
var fs = require('fs');
var dir = process.argv.length > 2 ? process.argv[2] : process.cwd();
var config = require(path.join(dir, 'proxyConfig.js'));

var mimes = {
	'': 'application/octet-stream',
	'html': 'text/html',
	'js': 'text/javascript',
	'css': 'text/css',
	'jpg': 'image/jpeg',
	'png': 'image/png',
	'gif': 'image/gif',
	'svg': 'image/svg+xml',
	'json': 'text/json'
};

if (config instanceof Array) {
	for (var i = 0; i < config.length; i++) {
		run(config[i]);
	}
} else {
	run(config);
}

function run(config) {
	var s;
	console.log(config);
	s = parseServer(config.remote);
	if (s){
		config.remote = s;
		if (typeof config.local === 'string') {
			s = parseServer(config.local);
			if (s) {
				config.local = s;
			}
		} else {
			if (!config.local.prefix) {
				config.local.prefix = '/';
			}
		}
		if (typeof config.local === 'string'){
			http.createServer(function(req, res) {
				if (req.method === 'POST' || (config.rule && config.rule.test(req.url))) {
					httpproxy(config.remote, req, res);
				} else {
					if (config.local instanceof Array) {
						httpproxy(config.local, req, res);
					} else {
						staticfile(config, req, res);
					}
				}
			}).listen(config.port, '0.0.0.0');
		} else {
			console.log('bad local server address: ' + config.local);
		}
	} else {
		console.log('bad remote server address: ' + config.remote);
	}
}

function staticfile(config, req, res) {
	var u = req.url.replace(/\?.*$/, '');
	if (u === '/') {
		u = config.local.prefix + config.local.index;
	} else if (u[u.length - 1] === '/') {
		u += config.local.index;
	}
	var p, v = config.local.prefix.length;
	if (u.substr(0, v) === config.local.prefix) {
		p = path.join(dir, config.local.root, u.substr(v));
		fs.stat(p, function(err, stat) {
			if (err) {
				httpproxy(config.remote, req, res);
			} else {
				if (stat.isDirectory()) {
					res.writeHeader(302, 'Found', {
						'Location': u + '/'
					});
					res.end();
				} else {
					var m = mimes[path.extname(p).substr(1)];
					if (!m) {
						m = mimes[''];
					}
					var f = fs.createReadStream(p);
					res.writeHeader(200, 'OK', {
						'Content-Type': m,
						'Content-Length': stat.size,
						'Last-Modified': stat.mtime
					});
					f.pipe(res);
					console.log('static: ' + req.url);
				}
			}
		});
	} else {
		httpproxy(config.remote, req, res);
	}
}

function httpproxy(server, req, res) {
	var n;
	var info = {
		host: server[1],
		port: server[2],
		path: server[3] + req.url,
		method: req.method
	};
	var proxy = server[0].request(info, function(res2) {
		var cookie = res2.headers['set-cookie'];
		if (cookie instanceof Array) {
			for (var i = 0; i < cookie.length; i++) {
				cookie[i] = cookie[i].replace(/; domain=[^;]+/, '');
			}
		}
		delete res2.headers['access-control-allow-origin'];
		res.writeHeader(res2.statusCode, res2.headers);
		res2.pipe(res);
		console.log(buildServerStr(server) + req.url);
	});
	proxy.on('error', function(err) {
		console.log(err);
		res.end();
	});
	for (n in req.headers) {
		if (['host', 'origin', 'referer'].indexOf(n) < 0) {
			//console.log(n + ': ' + req.headers[n]);
			proxy.setHeader(n, req.headers[n]);
		}
		//console.log(n);
	}
	req.pipe(proxy);
}

function parseServer(str) {
	var r = str.match(/^http(s?):\/\/([^\/:]+)(?::(\d+))?(\/.*[^\/])?\/$/);
	if (r) {
		delete r.index;
		delete r.source;
		r.shift();
		r[2] = r[2] ? parseInt(r[2]) : r[0] ? 443 : 80;
		r[0] = r[0] ? https : http;
		!r[3] && (r[3] = '');
	}
	return r;
}

function buildServerStr(server) {
	var s = 'http';
	if (server[0] === https) {
		s += 's';
	}
	s += '://' + server[1];
	if ((server[0] === https && server[2] !== 443) || (server[0] === http && server[2] !== 80)) {
		s += ':' + server[2];
	}
	s += server[3];
	return s;
}<commit_msg>bug fix<commit_after>/*	devProxy.js 0.1
 *	通过将数据请求转发到远程服务器, 来在本地开发环境中模拟服务器环境, 以实现完整的网站功能
 *	脚本执行时会从当前目录载入proxyConfig.js
 */

'use strict';
var http = require('http');
var https = require('https');
var util = require('util');
var path = require('path');
var fs = require('fs');
var dir = process.argv.length > 2 ? process.argv[2] : process.cwd();
var config = require(path.join(dir, 'proxyConfig.js'));

var mimes = {
	'': 'application/octet-stream',
	'html': 'text/html',
	'js': 'text/javascript',
	'css': 'text/css',
	'jpg': 'image/jpeg',
	'png': 'image/png',
	'gif': 'image/gif',
	'svg': 'image/svg+xml',
	'json': 'text/json'
};

if (config instanceof Array) {
	for (var i = 0; i < config.length; i++) {
		run(config[i]);
	}
} else {
	run(config);
}

function run(config) {
	var s;
	console.log(config);
	s = parseServer(config.remote);
	if (s) {
		config.remote = s;
		if (typeof config.local === 'string') {
			s = parseServer(config.local);
			if (s) {
				config.local = s;
			}
		} else {
			if (!config.local.prefix) {
				config.local.prefix = '/';
			}
		}
		if (config.local instanceof Object) {
			http.createServer(function(req, res) {
				if (req.method === 'POST' || (config.rule && config.rule.test(req.url))) {
					httpproxy(config.remote, req, res);
				} else {
					if (config.local instanceof Array) {
						httpproxy(config.local, req, res);
					} else {
						staticfile(config, req, res);
					}
				}
			}).listen(config.port, '0.0.0.0');
		} else {
			console.log('bad local server address: ' + config.local);
		}
	} else {
		console.log('bad remote server address: ' + config.remote);
	}
}

function staticfile(config, req, res) {
	var u = req.url.replace(/\?.*$/, '');
	if (u === '/') {
		u = config.local.prefix + config.local.index;
	} else if (u[u.length - 1] === '/') {
		u += config.local.index;
	}
	var p, v = config.local.prefix.length;
	if (u.substr(0, v) === config.local.prefix) {
		p = path.join(dir, config.local.root, u.substr(v));
		fs.stat(p, function(err, stat) {
			if (err) {
				httpproxy(config.remote, req, res);
			} else {
				if (stat.isDirectory()) {
					res.writeHeader(302, 'Found', {
						'Location': u + '/'
					});
					res.end();
				} else {
					var m = mimes[path.extname(p).substr(1)];
					if (!m) {
						m = mimes[''];
					}
					var f = fs.createReadStream(p);
					res.writeHeader(200, 'OK', {
						'Content-Type': m,
						'Content-Length': stat.size,
						'Last-Modified': stat.mtime
					});
					f.pipe(res);
					console.log('static: ' + req.url);
				}
			}
		});
	} else {
		httpproxy(config.remote, req, res);
	}
}

function httpproxy(server, req, res) {
	var n;
	var info = {
		host: server[1],
		port: server[2],
		path: server[3] + req.url,
		method: req.method
	};
	var proxy = server[0].request(info, function(res2) {
		var cookie = res2.headers['set-cookie'];
		if (cookie instanceof Array) {
			for (var i = 0; i < cookie.length; i++) {
				cookie[i] = cookie[i].replace(/; domain=[^;]+/, '');
			}
		}
		delete res2.headers['access-control-allow-origin'];
		res.writeHeader(res2.statusCode, res2.headers);
		res2.pipe(res);
		console.log(buildServerStr(server) + req.url);
	});
	proxy.on('error', function(err) {
		console.log(err);
		res.end();
	});
	for (n in req.headers) {
		if (['host', 'origin', 'referer'].indexOf(n) < 0) {
			//console.log(n + ': ' + req.headers[n]);
			proxy.setHeader(n, req.headers[n]);
		}
		//console.log(n);
	}
	req.pipe(proxy);
}

function parseServer(str) {
	var r = str.match(/^http(s?):\/\/([^\/:]+)(?::(\d+))?(\/.*[^\/])?\/$/);
	if (r) {
		delete r.index;
		delete r.source;
		r.shift();
		r[2] = r[2] ? parseInt(r[2]) : r[0] ? 443 : 80;
		r[0] = r[0] ? https : http;
		!r[3] && (r[3] = '');
	}
	return r;
}

function buildServerStr(server) {
	var s = 'http';
	if (server[0] === https) {
		s += 's';
	}
	s += '://' + server[1];
	if ((server[0] === https && server[2] !== 443) || (server[0] === http && server[2] !== 80)) {
		s += ':' + server[2];
	}
	s += server[3];
	return s;
}<|endoftext|>


<commit_before>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator 1.7.0 from webgme on Thu May 12 2016 19:55:04 GMT-0500 (CDT).
 * A plugin that inherits from the PluginBase. To see source code documentation about available
 * properties and methods visit %host%/docs/source/PluginBase.html.
 */

define([
    'plugin/PluginConfig',
    'text!./metadata.json',
    'plugin/PluginBase',
    'common/util/ejs', // for ejs templates
    'common/util/xmljsonconverter', // used to save model as json
    'plugin/SimulateTES/SimulateTES/Templates/Templates',
    'gridlabd/meta',
    'gridlabd/modelLoader',
    'gridlabd/renderer',
    'q'
], function (
    PluginConfig,
    pluginMetadata,
    PluginBase,
    ejs,
    Converter,
    TEMPLATES,
    MetaTypes,
    loader,
    renderer,
    Q) {
    'use strict';

    pluginMetadata = JSON.parse(pluginMetadata);

    /**
     * Initializes a new instance of SimulateTES.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin SimulateTES.
     * @constructor
     */
    var SimulateTES = function () {
        // Call base class' constructor.
        PluginBase.call(this);
        this.pluginMetadata = pluginMetadata;
        this.metaTypes = MetaTypes;
    };

    /**
     * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
     * This is also available at the instance at this.pluginMetadata.
     * @type {object}
     */
    SimulateTES.metadata = pluginMetadata;

    // Prototypical inheritance from PluginBase.
    SimulateTES.prototype = Object.create(PluginBase.prototype);
    SimulateTES.prototype.constructor = SimulateTES;

    SimulateTES.prototype.notify = function(level, msg) {
	var self = this;
	var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
	if (level=='error')
	    self.logger.error(msg);
	else if (level=='debug')
	    self.logger.debug(msg);
	else if (level=='info')
	    self.logger.info(msg);
	else if (level=='warning')
	    self.logger.warn(msg);
	self.createMessage(self.activeNode, msg, level);
	self.sendNotification(prefix+msg);
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    SimulateTES.prototype.main = function (callback) {
        // Use self to access core, project, result, logger etc from PluginBase.
        // These are all instantiated at this point.
        var self = this,
        modelNode;

	self.result.success = false;

        if (typeof WebGMEGlobal !== 'undefined') {
	    var msg = 'You must run this plugin on the server!';
	    self.notify('error', msg);
	    callback(new Error(msg), self.result);
        }

	self.updateMETA(self.metaTypes);

	// What did the user select for our configuration?
	var currentConfig = self.getCurrentConfig();
	self.simulationTime = currentConfig.simulationTime;
	self.delayMean = currentConfig.delayMean;
	self.delayStdDev = currentConfig.delayStdDev;
	self.community1 = currentConfig.community1;
	self.community2 = currentConfig.community2;
	self.generator1 = currentConfig.generator1;
	self.generator2 = currentConfig.generator2;
	self.returnZip = currentConfig.returnZip;

        modelNode = self.activeNode;
	self.modelName = self.core.getAttribute(modelNode, 'name');
	self.fileName = self.modelName + '.glm';

	var path = require('path');
	var filendir = require('filendir');
	self.root_dir = path.join(process.cwd(),
				  'generated',
				  self.project.projectId,
				  self.branchName,
				  'models');

	return loader.loadModel(self.core, modelNode)
	    .then(function(powerModel) {
		self.powerModel = powerModel;
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		return self.renderModel();
	    })
	    .then(function() {
		return self.writeInputs();
	    })
	    .then(function() {
		return self.runSimulation();
	    })
	    .then(function() {
		return self.copyArtifacts();
	    })
	    .then(function() {
		return self.plotLogs();
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		self.result.success = true;
		self.createMessage(self.activeNode, 'Simulation Complete.');
		callback(null, self.result);
	    })
	    .catch(function(err) {
		self.result.success = false;
		self.createMessage(self.activeNode, err, 'error');
		callback(err, self.result);
	    });
    };

    SimulateTES.prototype.clean = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo",
	path = require('path'),
	cp = require('child_process');

	self.notify('info', 'Cleaning experiment artifacts and processes from system.');

	// clear out any previous inputs
	cp.execSync('rm -rf ' + basePath + '/input/*');
	// clear out any previous outputs
	cp.execSync('rm -rf ' + basePath + '/output/*');

	// need to kill docker container processes with sudo pkill
	cp.execSync('docker stop $(docker ps -a -q)');
    };

    SimulateTES.prototype.renderModel = function() {
	var self = this;
	self.fileData = renderer.renderGLM(self.powerModel, self.core, self.META);
    };

    SimulateTES.prototype.writeInputs = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/input/",
	inputFiles = {
	    "model.glm": self.fileData,
	    "Community1DemandController.config": JSON.stringify({ "Threshold": self.community1 }, null, 2),
	    "Community2DemandController.config": JSON.stringify({ "Threshold": self.community2 }, null, 2),
	    "Generator1PriceController.config": JSON.stringify({ "Threshold": self.generator1 }, null, 2),
	    "Generator2PriceController.config": JSON.stringify({ "Threshold": self.generator2 }, null, 2),
	    "script.xml": ejs.render(
		TEMPLATES['script.xml.ejs'],
		{
		    simEnd: self.simulationTime,
		    delayMean: self.delayMean,
		    delayStdDev: self.delayStdDev
		})
	},
	fs = require('fs'),
	path = require('path'),
	filendir = require('filendir');

	var fileNames = Object.keys(inputFiles);
	var tasks = fileNames.map((fileName) => {
	    var deferred = Q.defer();
	    var data = inputFiles[fileName];
	    filendir.writeFile(path.join(basePath, fileName), data, (err) => {
		if (err) {
		    deferred.reject('Couldnt write ' + fileName + ': ' + err);
		}
		else {
		    deferred.resolve();
		}
	    });
	    return deferred.promise;
	});

	return Q.all(tasks)
	    .then(function() {
		self.notify('info', 'Generated artifacts.');
	    });
    };

    SimulateTES.prototype.runSimulation = function() {
	var self = this;
	var path = require('path');
	var cp = require('child_process');

	self.notify('info', 'Starting Simulation');

	var deferred = Q.defer();

	var fname = path.join(self.root_dir, self.fileName);

	// start fed manager
	return self.startFedMgr()
	    .then(function() {
		return self.startExperimentFederates();
	    })
	    .then(function() {
		return self.monitorContainers();
	    })
	    .then(function() {
		return self.killFedMgr();
	    });

	return deferred.promise;
    };

    SimulateTES.prototype.startFedMgr = function() {
	// run-cpp-feds.sh 0
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var fedMgr = cp.spawn('bash', [], {cwd:basePath});
	fedMgr.stdout.on('data', function (data) {});
	fedMgr.stderr.on('data', function (error) {
	});
	fedMgr.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started Fed Mgr.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('fedMgr:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting Fed Mgr.');
	    fedMgr.stdin.write('./run-cpp-feds.sh 0\n');
	    fedMgr.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.startExperimentFederates = function() {
	// run-cpp-feds.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var feds = cp.spawn('bash', [], {cwd:basePath});
	feds.stdout.on('data', function (data) {});
	feds.stderr.on('data', function (error) {
	});
	feds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('feds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting experiment feds.');
	    feds.stdin.write('./run-cpp-feds.sh\n');
	    feds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.monitorContainers = function() {
	var cp = require('child_process');
	var deferred = Q.defer();
	//return deferred.promise;
    };

    SimulateTES.prototype.killFedMgr = function() {
	// kill-all.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var stopFeds = cp.spawn('bash', [], {cwd:basePath});
	stopFeds.stdout.on('data', function (data) {});
	stopFeds.stderr.on('data', function (error) {
	});
	stopFeds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Killed all experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('stopFeds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Killing experiment feds.');
	    stopFeds.stdin.write('docker stop $(docker ps -a -q)\n');
	    stopFeds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.copyArtifacts = function() {
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";

	self.notify('info', 'Copying output.');

	return new Promise(function(resolve, reject) {
	    var zlib = require('zlib'),
	    tar = require('tar'),
	    fstream = require('fstream'),
	    input = basePath;

	    var bufs = [];
	    var packer = tar.Pack()
		.on('error', function(e) { reject(e); });

	    var gzipper = zlib.Gzip()
		.on('error', function(e) { reject(e); })
		.on('data', function(d) { bufs.push(d); })
		.on('end', function() {
		    var buf = Buffer.concat(bufs);
		    self.blobClient.putFile('output.tar.gz',buf)
			.then(function (hash) {
			    self.result.addArtifact(hash);
			    resolve();
			})
			.catch(function(err) {
			    reject(err);
			})
			    .done();
		});

	    var reader = fstream.Reader({ 'path': input, 'type': 'Directory' })
		.on('error', function(e) { reject(e); });

	    reader
		.pipe(packer)
		.pipe(gzipper);
	})
	    .then(function() {
		self.notify('info', 'Created archive.');
	    });
    };

    SimulateTES.prototype.plotLogs = function() {
    };

    SimulateTES.prototype.generateBlobArtifacts = function() {
	var self = this;
	if (!self.returnZip) {
	    self.notify('info', 'User did not request the output to be returned.');
	    return;
	}

	// till we get output from the output folder
	return;

	var path = require('path');
	var stdoutFile = self.modelName + '.stdout';
	var stderrFile = self.modelName + '.stderr';

	self.notify('info', 'Returning output to user.');

	return self.blobClient.putFile(stdoutFile, self.sim_stdout)
	    .then(function (hash) {
		self.result.addArtifact(hash);
	    })
	    .then(function() {
		return self.blobClient.putFile(stderrFile, self.sim_stderr);
	    })
	    .then(function (hash) {
		self.result.addArtifact(hash);
	    });
    };

    return SimulateTES;
});
<commit_msg>updated to wait properly for federation to die.<commit_after>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator 1.7.0 from webgme on Thu May 12 2016 19:55:04 GMT-0500 (CDT).
 * A plugin that inherits from the PluginBase. To see source code documentation about available
 * properties and methods visit %host%/docs/source/PluginBase.html.
 */

define([
    'plugin/PluginConfig',
    'text!./metadata.json',
    'plugin/PluginBase',
    'common/util/ejs', // for ejs templates
    'common/util/xmljsonconverter', // used to save model as json
    'plugin/SimulateTES/SimulateTES/Templates/Templates',
    'gridlabd/meta',
    'gridlabd/modelLoader',
    'gridlabd/renderer',
    'q'
], function (
    PluginConfig,
    pluginMetadata,
    PluginBase,
    ejs,
    Converter,
    TEMPLATES,
    MetaTypes,
    loader,
    renderer,
    Q) {
    'use strict';

    pluginMetadata = JSON.parse(pluginMetadata);

    /**
     * Initializes a new instance of SimulateTES.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin SimulateTES.
     * @constructor
     */
    var SimulateTES = function () {
        // Call base class' constructor.
        PluginBase.call(this);
        this.pluginMetadata = pluginMetadata;
        this.metaTypes = MetaTypes;
    };

    /**
     * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
     * This is also available at the instance at this.pluginMetadata.
     * @type {object}
     */
    SimulateTES.metadata = pluginMetadata;

    // Prototypical inheritance from PluginBase.
    SimulateTES.prototype = Object.create(PluginBase.prototype);
    SimulateTES.prototype.constructor = SimulateTES;

    SimulateTES.prototype.notify = function(level, msg) {
	var self = this;
	var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
	if (level=='error')
	    self.logger.error(msg);
	else if (level=='debug')
	    self.logger.debug(msg);
	else if (level=='info')
	    self.logger.info(msg);
	else if (level=='warning')
	    self.logger.warn(msg);
	self.createMessage(self.activeNode, msg, level);
	self.sendNotification(prefix+msg);
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    SimulateTES.prototype.main = function (callback) {
        // Use self to access core, project, result, logger etc from PluginBase.
        // These are all instantiated at this point.
        var self = this,
        modelNode;

	self.result.success = false;

        if (typeof WebGMEGlobal !== 'undefined') {
	    var msg = 'You must run this plugin on the server!';
	    self.notify('error', msg);
	    callback(new Error(msg), self.result);
        }

	self.updateMETA(self.metaTypes);

	// What did the user select for our configuration?
	var currentConfig = self.getCurrentConfig();
	self.simulationTime = currentConfig.simulationTime;
	self.delayMean = currentConfig.delayMean;
	self.delayStdDev = currentConfig.delayStdDev;
	self.community1 = currentConfig.community1;
	self.community2 = currentConfig.community2;
	self.generator1 = currentConfig.generator1;
	self.generator2 = currentConfig.generator2;
	self.returnZip = currentConfig.returnZip;

        modelNode = self.activeNode;
	self.modelName = self.core.getAttribute(modelNode, 'name');
	self.fileName = self.modelName + '.glm';

	var path = require('path');
	var filendir = require('filendir');
	self.root_dir = path.join(process.cwd(),
				  'generated',
				  self.project.projectId,
				  self.branchName,
				  'models');

	return loader.loadModel(self.core, modelNode)
	    .then(function(powerModel) {
		self.powerModel = powerModel;
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		return self.renderModel();
	    })
	    .then(function() {
		return self.writeInputs();
	    })
	    .then(function() {
		return self.runSimulation();
	    })
	    .then(function() {
		return self.copyArtifacts();
	    })
	    .then(function() {
		return self.plotLogs();
	    })
	    .then(function() {
		return self.clean();
	    })
	    .then(function() {
		self.result.success = true;
		self.notify('info', 'Simulation Complete.');
		callback(null, self.result);
	    })
	    .catch(function(err) {
		self.result.success = false;
		self.notify('error', err);
		callback(err, self.result);
	    });
    };

    SimulateTES.prototype.clean = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo",
	path = require('path'),
	cp = require('child_process');

	self.notify('info', 'Cleaning experiment artifacts and processes from system.');

	// clear out any previous inputs
	cp.execSync('rm -rf ' + basePath + '/input/*');
	// clear out any previous outputs
	cp.execSync('rm -rf ' + basePath + '/output/*');

	// need to kill docker container processes with sudo pkill
	cp.execSync('docker stop $(docker ps -a -q)');
    };

    SimulateTES.prototype.renderModel = function() {
	var self = this;
	self.fileData = renderer.renderGLM(self.powerModel, self.core, self.META);
    };

    SimulateTES.prototype.writeInputs = function() {
	var self = this,
	basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/input/",
	inputFiles = {
	    "model.glm": self.fileData,
	    "Community1DemandController.config": JSON.stringify({ "Threshold": self.community1 }, null, 2),
	    "Community2DemandController.config": JSON.stringify({ "Threshold": self.community2 }, null, 2),
	    "Generator1PriceController.config": JSON.stringify({ "Threshold": self.generator1 }, null, 2),
	    "Generator2PriceController.config": JSON.stringify({ "Threshold": self.generator2 }, null, 2),
	    "script.xml": ejs.render(
		TEMPLATES['script.xml.ejs'],
		{
		    simEnd: self.simulationTime,
		    delayMean: self.delayMean,
		    delayStdDev: self.delayStdDev
		})
	},
	fs = require('fs'),
	path = require('path'),
	filendir = require('filendir');

	var fileNames = Object.keys(inputFiles);
	var tasks = fileNames.map((fileName) => {
	    var deferred = Q.defer();
	    var data = inputFiles[fileName];
	    filendir.writeFile(path.join(basePath, fileName), data, (err) => {
		if (err) {
		    deferred.reject('Couldnt write ' + fileName + ': ' + err);
		}
		else {
		    deferred.resolve();
		}
	    });
	    return deferred.promise;
	});

	return Q.all(tasks)
	    .then(function() {
		self.notify('info', 'Generated artifacts.');
	    });
    };

    SimulateTES.prototype.runSimulation = function() {
	var self = this;
	var path = require('path');
	var cp = require('child_process');

	self.notify('info', 'Starting Simulation');

	var deferred = Q.defer();

	var fname = path.join(self.root_dir, self.fileName);

	// start fed manager
	return self.startFedMgr()
	    .then(function() {
		return self.startExperimentFederates();
	    })
	    .then(function() {
		return self.monitorContainers();
	    })
	    .then(function() {
		return self.killFedMgr();
	    });

	return deferred.promise;
    };

    SimulateTES.prototype.startFedMgr = function() {
	// run-cpp-feds.sh 0
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var fedMgr = cp.spawn('bash', [], {cwd:basePath});
	fedMgr.stdout.on('data', function (data) {});
	fedMgr.stderr.on('data', function (error) {
	});
	fedMgr.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started Fed Mgr.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('fedMgr:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting Fed Mgr.');
	    fedMgr.stdin.write('./run-cpp-feds.sh 0\n');
	    fedMgr.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.startExperimentFederates = function() {
	// run-cpp-feds.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var feds = cp.spawn('bash', [], {cwd:basePath});
	feds.stdout.on('data', function (data) {});
	feds.stderr.on('data', function (error) {
	});
	feds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Started experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('feds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Starting experiment feds.');
	    feds.stdin.write('./run-cpp-feds.sh\n');
	    feds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.monitorContainers = function() {
	var self = this;
	var cp = require('child_process');
	var deferred = Q.defer();

	var stdout = cp.execSync('docker ps');
	var regex = /(demo_c2wt_cpp_fedmgr_run_[\w+]*)/gi;
	var results = regex.exec(stdout);
	if (results) {
	    var dockerName = results[1];
	    self.notify('info', 'Waiting for simulation to complete when ' + dockerName + ' exits.');
	    stdout = cp.execSync('docker wait ' + dockerName);
	    self.notify('info', 'Docker federate exited with stdout: ' + stdout);
	}
	else {
	    self.notify('error', 'Couldnt find the federate docker container in docker ps!');
	}
    };

    SimulateTES.prototype.killFedMgr = function() {
	// kill-all.sh
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/";
	var cp = require('child_process');
	var deferred = Q.defer();

	var stopFeds = cp.spawn('bash', [], {cwd:basePath});
	stopFeds.stdout.on('data', function (data) {});
	stopFeds.stderr.on('data', function (error) {
	});
	stopFeds.on('exit', function (code) {
	    if (code == 0) {
		self.notify('info', 'Killed all experiment feds.');
		deferred.resolve(code);
	    }
	    else {
		deferred.reject('stopFeds:: child process exited with code ' + code);
	    }
	});
	setTimeout(function() {
	    self.notify('info', 'Killing experiment feds.');
	    stopFeds.stdin.write('docker stop $(docker ps -a -q)\n');
	    stopFeds.stdin.end();
	}, 1000);
	return deferred.promise;
    };

    SimulateTES.prototype.copyArtifacts = function() {
	var self = this;
	var basePath = "/home/jeb/tesDemo/repo/c2wtng-fedimgs/dockerfeds/examples/TES2016Demo/Demo/output";

	self.notify('info', 'Copying output.');

	return new Promise(function(resolve, reject) {
	    var zlib = require('zlib'),
	    tar = require('tar'),
	    fstream = require('fstream'),
	    input = basePath;

	    var bufs = [];
	    var packer = tar.Pack()
		.on('error', function(e) { reject(e); });

	    var gzipper = zlib.Gzip()
		.on('error', function(e) { reject(e); })
		.on('data', function(d) { bufs.push(d); })
		.on('end', function() {
		    var buf = Buffer.concat(bufs);
		    self.blobClient.putFile('output.tar.gz',buf)
			.then(function (hash) {
			    self.result.addArtifact(hash);
			    resolve();
			})
			.catch(function(err) {
			    reject(err);
			})
			    .done();
		});

	    var reader = fstream.Reader({ 'path': input, 'type': 'Directory' })
		.on('error', function(e) { reject(e); });

	    reader
		.pipe(packer)
		.pipe(gzipper);
	})
	    .then(function() {
		self.notify('info', 'Created archive.');
	    });
    };

    SimulateTES.prototype.plotLogs = function() {
    };

    SimulateTES.prototype.generateBlobArtifacts = function() {
	var self = this;
	if (!self.returnZip) {
	    self.notify('info', 'User did not request the output to be returned.');
	    return;
	}

	// till we get output from the output folder
	return;

	var path = require('path');
	var stdoutFile = self.modelName + '.stdout';
	var stderrFile = self.modelName + '.stderr';

	self.notify('info', 'Returning output to user.');

	return self.blobClient.putFile(stdoutFile, self.sim_stdout)
	    .then(function (hash) {
		self.result.addArtifact(hash);
	    })
	    .then(function() {
		return self.blobClient.putFile(stderrFile, self.sim_stderr);
	    })
	    .then(function (hash) {
		self.result.addArtifact(hash);
	    });
    };

    return SimulateTES;
});
<|endoftext|>


<commit_before>/*
Copyright 2014 OpenMarket Ltd

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.
*/

/*
 * Main controller
 */

'use strict';

angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'eventStreamService'])
.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', '$timeout', 'matrixService', 'mPresence', 'eventStreamService', 'eventHandlerService', 'matrixPhoneService', 'modelService', 'eventReaperService',
                               function($scope, $location, $rootScope, $timeout, matrixService, mPresence, eventStreamService, eventHandlerService, matrixPhoneService, modelService, eventReaperService) {

    // Check current URL to avoid to display the logout button on the login page
    $scope.location = $location.path();

    // Update the location state when the ng location changed
    $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
        $scope.location = $location.path();
    });

    if (matrixService.isUserLoggedIn()) {
        eventStreamService.resume();
        mPresence.start();
    }

    $scope.user_id;
    var config = matrixService.config();
    if (config) {
        $scope.user_id = matrixService.config().user_id;
    }

    eventReaperService.setEnabled(true);

    /**
     * Open a given page.
     * @param {String} url url of the page
     */
    $rootScope.goToPage = function(url) {
        $location.url(url);
    };

    // Open the given user profile page
    $scope.goToUserPage = function(user_id) {
        if (user_id === $scope.user_id) {
            $location.url("/settings");
        }
        else {
            $location.url("/user/" + user_id);
        }
    };

    $scope.leave = function(room_id) {
        matrixService.leave(room_id).then(
            function(response) {
                console.log("Left room " + room_id);
            },
            function(error) {
                console.log("Failed to leave room " + room_id + ": " + error.data.error);
            });
    };

    // Logs the user out
    $scope.logout = function() {

        // kill the event stream
        eventStreamService.stop();

        // Do not update presence anymore
        mPresence.stop();

        // Clean permanent data
        matrixService.setConfig({});
        matrixService.saveConfig();

        // Reset cached data
        modelService.clearRooms();
        eventHandlerService.reset();

        // And go to the login page
        $location.url("login");
    };

    // Listen to the event indicating that the access token is no longer valid.
    // In this case, the user needs to log in again.
    $scope.$on("M_UNKNOWN_TOKEN", function() {
        console.log("Invalid access token -> log user out");
        $scope.logout();
    });

    $rootScope.updateHeader = function() {
        $scope.user_id = matrixService.config().user_id;
    };

    $rootScope.$watch('currentCall', function(newVal, oldVal) {
        if (!$rootScope.currentCall) {
            // This causes the still frame to be flushed out of the video elements,
            // avoiding a flash of the last frame of the previous call when starting the next
            if (angular.element('#localVideo')[0].load) angular.element('#localVideo')[0].load();
            if (angular.element('#remoteVideo')[0].load) angular.element('#remoteVideo')[0].load();
            return;
        }

        var roomMembers = angular.copy(modelService.getRoom($rootScope.currentCall.room_id).current_room_state.members);
        delete roomMembers[matrixService.config().user_id];

        $rootScope.currentCall.user_id = Object.keys(roomMembers)[0];

        // set it to the user ID until we fetch the display name
        $rootScope.currentCall.userProfile = { displayname: $rootScope.currentCall.user_id };

        matrixService.getProfile($rootScope.currentCall.user_id).then(
            function(response) {
                if (response.data.displayname) $rootScope.currentCall.userProfile.displayname = response.data.displayname;
                if (response.data.avatar_url) $rootScope.currentCall.userProfile.avatar_url = response.data.avatar_url;
            },
            function(error) {
                $scope.feedback = "Can't load user profile";
            }
        );
    });
    $rootScope.$watch('currentCall.state', function(newVal, oldVal) {
        if (newVal == 'ringing') {
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#ringAudio')[0].load();
            angular.element('#ringAudio')[0].play();
        } else if (newVal == 'invite_sent') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].load();
            angular.element('#ringbackAudio')[0].play();
        } else if (newVal == 'ended' && oldVal == 'connected') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#callendAudio')[0].play();
            $scope.videoMode = undefined;
        } else if (newVal == 'ended' && oldVal == 'invite_sent' && $rootScope.currentCall.hangupParty == 'remote') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#busyAudio')[0].play();
        } else if (newVal == 'ended' && oldVal == 'invite_sent' && $rootScope.currentCall.hangupParty == 'local' && $rootScope.currentCall.hangupReason == 'invite_timeout') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#busyAudio')[0].play();
        } else if (oldVal == 'invite_sent') {
            angular.element('#ringbackAudio')[0].pause();
        } else if (oldVal == 'ringing') {
            angular.element('#ringAudio')[0].pause();
        } else if (newVal == 'connected') {
            $timeout(function() {
                if ($scope.currentCall.type == 'video') $scope.videoMode = 'large';
            }, 500);
        }

        if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
            $scope.videoMode = 'mini';
        }
    });
    $rootScope.$watch('currentCall.type', function(newVal, oldVal) {
        // need to listen for this too as the type of the call won't be know when it's created
        if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
            $scope.videoMode = 'mini';
        }
    });

    $rootScope.$on(matrixPhoneService.INCOMING_CALL_EVENT, function(ngEvent, call) {
        console.log("incoming call");
        if ($rootScope.currentCall && $rootScope.currentCall.state != 'ended') {
            console.log("rejecting call because we're already in a call");
            call.hangup();
            return;
        }
        call.onError = $scope.onCallError;
        call.onHangup = $scope.onCallHangup;
        call.localVideoSelector  = '#localVideo';
        call.remoteVideoSelector  = '#remoteVideo';
        $rootScope.currentCall = call;
    });

    $rootScope.$on(matrixPhoneService.REPLACED_CALL_EVENT, function(ngEvent, oldCall, newCall) {
        console.log("call ID "+oldCall.call_id+" has been replaced by call ID "+newCall.call_id+"!");
        newCall.onError = $scope.onCallError;
        newCall.onHangup = $scope.onCallHangup;
        $rootScope.currentCall = newCall;
    });

    $scope.answerCall = function() {
        $rootScope.currentCall.answer();
    };

    $scope.hangupCall = function() {
        $rootScope.currentCall.hangup();
    };

    $rootScope.onCallError = function(errStr) {
        $scope.feedback = errStr;
    };

    $rootScope.onCallHangup = function(call) {
        if (call == $rootScope.currentCall) {
            $timeout(function(){
                if (call == $rootScope.currentCall) $rootScope.currentCall = undefined;
            }, 4070);
        }
    };
}]);
<commit_msg>SYWEB-75: Show desktop notifications for inbound VoIP calls.<commit_after>/*
Copyright 2014 OpenMarket Ltd

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.
*/

/*
 * Main controller
 */

'use strict';

angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'eventStreamService'])
.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', '$timeout', 'matrixService', 'mPresence', 'eventStreamService', 'eventHandlerService', 'matrixPhoneService', 'modelService', 'eventReaperService', 'notificationService', 'mUserDisplayNameFilter',
                               function($scope, $location, $rootScope, $timeout, matrixService, mPresence, eventStreamService, eventHandlerService, matrixPhoneService, modelService, eventReaperService, notificationService, mUserDisplayNameFilter) {

    // Check current URL to avoid to display the logout button on the login page
    $scope.location = $location.path();

    // Update the location state when the ng location changed
    $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
        $scope.location = $location.path();
    });

    if (matrixService.isUserLoggedIn()) {
        eventStreamService.resume();
        mPresence.start();
    }

    $scope.user_id;
    var config = matrixService.config();
    if (config) {
        $scope.user_id = matrixService.config().user_id;
    }

    eventReaperService.setEnabled(true);

    /**
     * Open a given page.
     * @param {String} url url of the page
     */
    $rootScope.goToPage = function(url) {
        $location.url(url);
    };

    // Open the given user profile page
    $scope.goToUserPage = function(user_id) {
        if (user_id === $scope.user_id) {
            $location.url("/settings");
        }
        else {
            $location.url("/user/" + user_id);
        }
    };

    $scope.leave = function(room_id) {
        matrixService.leave(room_id).then(
            function(response) {
                console.log("Left room " + room_id);
            },
            function(error) {
                console.log("Failed to leave room " + room_id + ": " + error.data.error);
            });
    };

    // Logs the user out
    $scope.logout = function() {

        // kill the event stream
        eventStreamService.stop();

        // Do not update presence anymore
        mPresence.stop();

        // Clean permanent data
        matrixService.setConfig({});
        matrixService.saveConfig();

        // Reset cached data
        modelService.clearRooms();
        eventHandlerService.reset();

        // And go to the login page
        $location.url("login");
    };

    // Listen to the event indicating that the access token is no longer valid.
    // In this case, the user needs to log in again.
    $scope.$on("M_UNKNOWN_TOKEN", function() {
        console.log("Invalid access token -> log user out");
        $scope.logout();
    });

    $rootScope.updateHeader = function() {
        $scope.user_id = matrixService.config().user_id;
    };

    $rootScope.$watch('currentCall', function(newVal, oldVal) {
        if (!$rootScope.currentCall) {
            // This causes the still frame to be flushed out of the video elements,
            // avoiding a flash of the last frame of the previous call when starting the next
            if (angular.element('#localVideo')[0].load) angular.element('#localVideo')[0].load();
            if (angular.element('#remoteVideo')[0].load) angular.element('#remoteVideo')[0].load();
            return;
        }

        // set it to the user ID until we fetch the display name
        $rootScope.currentCall.userProfile = { displayname: $rootScope.currentCall.user_id };

        matrixService.getProfile($rootScope.currentCall.user_id).then(
            function(response) {
                if (response.data.displayname) $rootScope.currentCall.userProfile.displayname = response.data.displayname;
                if (response.data.avatar_url) $rootScope.currentCall.userProfile.avatar_url = response.data.avatar_url;
            },
            function(error) {
                $scope.feedback = "Can't load user profile";
            }
        );
    });
    $rootScope.$watch('currentCall.state', function(newVal, oldVal) {
        if (newVal == 'ringing') {
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#ringAudio')[0].load();
            angular.element('#ringAudio')[0].play();
        } else if (newVal == 'invite_sent') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].load();
            angular.element('#ringbackAudio')[0].play();
        } else if (newVal == 'ended' && oldVal == 'connected') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#callendAudio')[0].play();
            $scope.videoMode = undefined;
        } else if (newVal == 'ended' && oldVal == 'invite_sent' && $rootScope.currentCall.hangupParty == 'remote') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#busyAudio')[0].play();
        } else if (newVal == 'ended' && oldVal == 'invite_sent' && $rootScope.currentCall.hangupParty == 'local' && $rootScope.currentCall.hangupReason == 'invite_timeout') {
            angular.element('#ringAudio')[0].pause();
            angular.element('#ringbackAudio')[0].pause();
            angular.element('#busyAudio')[0].play();
        } else if (oldVal == 'invite_sent') {
            angular.element('#ringbackAudio')[0].pause();
        } else if (oldVal == 'ringing') {
            angular.element('#ringAudio')[0].pause();
        } else if (newVal == 'connected') {
            $timeout(function() {
                if ($scope.currentCall.type == 'video') $scope.videoMode = 'large';
            }, 500);
        }

        if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
            $scope.videoMode = 'mini';
        }
    });
    $rootScope.$watch('currentCall.type', function(newVal, oldVal) {
        // need to listen for this too as the type of the call won't be know when it's created
        if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
            $scope.videoMode = 'mini';
        }
    });

    $rootScope.$on(matrixPhoneService.INCOMING_CALL_EVENT, function(ngEvent, call) {
        console.log("incoming call");
        if ($rootScope.currentCall && $rootScope.currentCall.state != 'ended') {
            console.log("rejecting call because we're already in a call");
            call.hangup();
            return;
        }
        call.onError = $scope.onCallError;
        call.onHangup = $scope.onCallHangup;
        call.localVideoSelector  = '#localVideo';
        call.remoteVideoSelector  = '#remoteVideo';

        var roomMembers = angular.copy(modelService.getRoom(call.room_id).current_room_state.members);
        delete roomMembers[matrixService.config().user_id];
        call.user_id = Object.keys(roomMembers)[0];

        $rootScope.currentCall = call;

        var usr = modelService.getUser(call.user_id);
        var avatar;
        if (usr && usr.event && usr.event.content) {
            avatar = usr.event.content.avatar_url;
        }

        notificationService.showNotification(
            "Incoming "+call.type+" call",
            "Call from "+mUserDisplayNameFilter(call.user_id),
            avatar,
            undefined,
            "matrixcall"
        );
    });

    $rootScope.$on(matrixPhoneService.REPLACED_CALL_EVENT, function(ngEvent, oldCall, newCall) {
        console.log("call ID "+oldCall.call_id+" has been replaced by call ID "+newCall.call_id+"!");
        newCall.onError = $scope.onCallError;
        newCall.onHangup = $scope.onCallHangup;
        $rootScope.currentCall = newCall;
    });

    $scope.answerCall = function() {
        $rootScope.currentCall.answer();
    };

    $scope.hangupCall = function() {
        $rootScope.currentCall.hangup();
    };

    $rootScope.onCallError = function(errStr) {
        $scope.feedback = errStr;
    };

    $rootScope.onCallHangup = function(call) {
        if (call == $rootScope.currentCall) {
            $timeout(function(){
                if (call == $rootScope.currentCall) $rootScope.currentCall = undefined;
            }, 4070);
        }
    };
}]);
<|endoftext|>


<commit_before>var HomeScreen = {
    $rightView: null,
    $artists: null,
    $recommendations: null,
    $playlists: null,
    menuItem: null,
    tabs: null,
    page: -1,
    hasMore: true,
    FILTER: [
        'dignitasApollo',
        'mrcoolvideoboy',
        'huskystarcraft',
        'husky',
        'collegehumor',
        'day9tv'
    ],

    init: function() {
        var self = HomeScreen;
        self.$rightView = $('#right > .home');
        self.$recommendations = self.$rightView.find('.pane.recommendations');
        self.$playlists = self.$rightView.find('.pane.playlists');
        self.$artists = self.$rightView.find('.pane.artists');
        self.menuItem = new MenuItem({
            cssClasses: ['home'],
            title: TranslationSystem.get('Home'),
            $contentPane: self.$rightView,
            onSelected: function() {
                HomeScreen.show();
            },
            translatable: true
        });
        Menu.getGroup('misc').addMenuItem(self.menuItem);

        self.tabs = new Tabs(self.$rightView, {
            'artists': self.loadArtists,
            'playlists': self.loadTopPlaylists,
            'recommendations': self.loadRecommendedArtists
        });

        // Continous scroll for "Popular artists"
        (function() {
            var timeout;
            self.$rightView.scroll(function(event) {
                if (timeout) {
                    clearTimeout(timeout);
                }
                timeout = setTimeout(function() {
                    if (self.$rightView.scrollTop() >= (self.$artists.height() - self.$rightView.height()) && self.hasMore) {
                        self.loadArtists(true);
                    }
                }, 100);
            });
        }());
    },

    show: function(tab) {
        var self = HomeScreen;
        tab = tab || 'artists';
        history.pushState(null, null, '/');
        self.$rightView.find('.tabs .' + tab).click();

        $('#right > div').hide();
        self.$rightView.show();
    },

    loadRecommendedArtists: function() {
        var self = HomeScreen;
        var $content = self.$recommendations.find('.content');

        history.pushState(null, null, '/recommendations');

        $content.html('');
        self.$recommendations.find('.help-box').hide();

        if (!UserManager.isLoggedIn()) {
            self.$recommendations.find('.help-box.not-logged-in').show();
        } else if (!UserManager.currentUser.lastfmUserName) {
            self.$recommendations.find('.help-box.not-connected-to-lastfm').show();
        } else {
            Recommendations.findRecommendedArtists(function(artists) {
                $.each(artists, function(i, artist) {
                    if (artist.name) {
                        var artistSuggestion = new ArtistSuggestion({
                            name: artist.name,
                            imageUrl: artist.image[2]['#text'],
                            mbid: artist.mbid
                        });
                        $content.append(artistSuggestion.getSmallView()).show();
                    }
                });
            });
        }
    },

    loadTopPlaylists: function() {
        var self = HomeScreen;

        self.$playlists.html('');

        history.pushState(null, null, '/toplist/playlists');

        LoadingBar.show();
        $.get('/api/toplists/playlists', function(playlists) {
            $.each(playlists, function(index, item) {
                var playlist = new Playlist(item.title, item.videos, item.remoteId, item.owner, item.isPrivate, item.followers);
                if (playlist.videos.length) {
                    self.$playlists.append(PlaylistView.createSmallPlaylistView(playlist));
                }
            });
            LoadingBar.hide();
        });
    },

    videoPlayCallback: function() {
        HomeScreen.menuItem.setAsPlaying();
    },

    addArtist: function(externalUser) {
        var self = this;

        if (!externalUser.avatar_url) {
            return;
        }

        // If they block us, we block them :)
        if (externalUser.username.match(/VEVO$/)) {
            return;
        }

        if ($.inArray(externalUser.username, self.FILTER) !== -1) {
            return;
        }

        var $item = $('
'),
            $hover = $('
'),
            $title = $('
'),
            image = new Image();

        image.onload = function() {
            $item.css({'opacity': '1'});
        };
        image.src = externalUser.avatar_url;

        $item.css({'background-image': 'url('+ externalUser.avatar_url + ')'});
        $hover.click(function() {
            if ($item.hasClass('loading')) {
                return;
            }

            player.pause();

            var user = new ExternalUser({
                type: externalUser.type,
                username: externalUser.username
            });
            user.videoPlayCallback = self.videoPlayCallback;

            $item.addClass('loading');
            LoadingBar.show();
            user.load(function(user) {
                $item.removeClass('loading');
                LoadingBar.hide();
                user.getRightView().find('.video:first-child').dblclick();
            });
        });
        $title.click(function() {
            ExternalUserPage.load(externalUser.type, externalUser.username);
        });

        $title.text(externalUser.username);
        $item.append($title);
        $item.append($hover);

        self.$artists.append($item);
    },

    loadArtists: function(loadMore) {
        var self = HomeScreen,
            i = 0,
            artist = null,
            pageSize = 50;

        if (!loadMore) {
            self.$artists.html('');
            self.page = -1;
            self.hasMore = true;
            history.pushState(null, null, '/');
        }

        self.page += 1;

        LoadingBar.show();
        $.getJSON('/api/external_users/top/' + pageSize, {page: self.page}, function(data) {
            var i,
                externalUser;

            LoadingBar.hide();

            if (data.length < pageSize) {
                self.hasMore = false;
            }

            for (i = loadMore ? 1 : 0; i < data.length; i += 1) {
                self.addArtist(data[i]);
            }

            // Load more automatically if we haven't filled the entire screen
            if (data.length > 0 && self.$artists.height() < self.$rightView.height() && self.page < 50) {
                self.loadArtists(true);
            }
        });
    }
};
<commit_msg>Added Unplayable to HomeScreen filter<commit_after>var HomeScreen = {
    $rightView: null,
    $artists: null,
    $recommendations: null,
    $playlists: null,
    menuItem: null,
    tabs: null,
    page: -1,
    hasMore: true,
    FILTER: [
        /* Not music */
        'dignitasApollo',
        'mrcoolvideoboy',
        'huskystarcraft',
        'husky',
        'collegehumor',
        'day9tv',
        /* Unplayable */
        'lanadelreyunreleased'
    ],

    init: function() {
        var self = HomeScreen;
        self.$rightView = $('#right > .home');
        self.$recommendations = self.$rightView.find('.pane.recommendations');
        self.$playlists = self.$rightView.find('.pane.playlists');
        self.$artists = self.$rightView.find('.pane.artists');
        self.menuItem = new MenuItem({
            cssClasses: ['home'],
            title: TranslationSystem.get('Home'),
            $contentPane: self.$rightView,
            onSelected: function() {
                HomeScreen.show();
            },
            translatable: true
        });
        Menu.getGroup('misc').addMenuItem(self.menuItem);

        self.tabs = new Tabs(self.$rightView, {
            'artists': self.loadArtists,
            'playlists': self.loadTopPlaylists,
            'recommendations': self.loadRecommendedArtists
        });

        // Continous scroll for "Popular artists"
        (function() {
            var timeout;
            self.$rightView.scroll(function(event) {
                if (timeout) {
                    clearTimeout(timeout);
                }
                timeout = setTimeout(function() {
                    if (self.$rightView.scrollTop() >= (self.$artists.height() - self.$rightView.height()) && self.hasMore) {
                        self.loadArtists(true);
                    }
                }, 100);
            });
        }());
    },

    show: function(tab) {
        var self = HomeScreen;
        tab = tab || 'artists';
        history.pushState(null, null, '/');
        self.$rightView.find('.tabs .' + tab).click();

        $('#right > div').hide();
        self.$rightView.show();
    },

    loadRecommendedArtists: function() {
        var self = HomeScreen;
        var $content = self.$recommendations.find('.content');

        history.pushState(null, null, '/recommendations');

        $content.html('');
        self.$recommendations.find('.help-box').hide();

        if (!UserManager.isLoggedIn()) {
            self.$recommendations.find('.help-box.not-logged-in').show();
        } else if (!UserManager.currentUser.lastfmUserName) {
            self.$recommendations.find('.help-box.not-connected-to-lastfm').show();
        } else {
            Recommendations.findRecommendedArtists(function(artists) {
                $.each(artists, function(i, artist) {
                    if (artist.name) {
                        var artistSuggestion = new ArtistSuggestion({
                            name: artist.name,
                            imageUrl: artist.image[2]['#text'],
                            mbid: artist.mbid
                        });
                        $content.append(artistSuggestion.getSmallView()).show();
                    }
                });
            });
        }
    },

    loadTopPlaylists: function() {
        var self = HomeScreen;

        self.$playlists.html('');

        history.pushState(null, null, '/toplist/playlists');

        LoadingBar.show();
        $.get('/api/toplists/playlists', function(playlists) {
            $.each(playlists, function(index, item) {
                var playlist = new Playlist(item.title, item.videos, item.remoteId, item.owner, item.isPrivate, item.followers);
                if (playlist.videos.length) {
                    self.$playlists.append(PlaylistView.createSmallPlaylistView(playlist));
                }
            });
            LoadingBar.hide();
        });
    },

    videoPlayCallback: function() {
        HomeScreen.menuItem.setAsPlaying();
    },

    addArtist: function(externalUser) {
        var self = this;

        if (!externalUser.avatar_url) {
            return;
        }

        // If they block us, we block them :)
        if (externalUser.username.match(/VEVO$/)) {
            return;
        }

        if ($.inArray(externalUser.username, self.FILTER) !== -1) {
            return;
        }

        var $item = $('
'),
            $hover = $('
'),
            $title = $('
'),
            image = new Image();

        image.onload = function() {
            $item.css({'opacity': '1'});
        };
        image.src = externalUser.avatar_url;

        $item.css({'background-image': 'url('+ externalUser.avatar_url + ')'});
        $hover.click(function() {
            if ($item.hasClass('loading')) {
                return;
            }

            player.pause();

            var user = new ExternalUser({
                type: externalUser.type,
                username: externalUser.username
            });
            user.videoPlayCallback = self.videoPlayCallback;

            $item.addClass('loading');
            LoadingBar.show();
            user.load(function(user) {
                $item.removeClass('loading');
                LoadingBar.hide();
                user.getRightView().find('.video:first-child').dblclick();
            });
        });
        $title.click(function() {
            ExternalUserPage.load(externalUser.type, externalUser.username);
        });

        $title.text(externalUser.username);
        $item.append($title);
        $item.append($hover);

        self.$artists.append($item);
    },

    loadArtists: function(loadMore) {
        var self = HomeScreen,
            i = 0,
            artist = null,
            pageSize = 50;

        if (!loadMore) {
            self.$artists.html('');
            self.page = -1;
            self.hasMore = true;
            history.pushState(null, null, '/');
        }

        self.page += 1;

        LoadingBar.show();
        $.getJSON('/api/external_users/top/' + pageSize, {page: self.page}, function(data) {
            var i,
                externalUser;

            LoadingBar.hide();

            if (data.length < pageSize) {
                self.hasMore = false;
            }

            for (i = loadMore ? 1 : 0; i < data.length; i += 1) {
                self.addArtist(data[i]);
            }

            // Load more automatically if we haven't filled the entire screen
            if (data.length > 0 && self.$artists.height() < self.$rightView.height() && self.page < 50) {
                self.loadArtists(true);
            }
        });
    }
};
<|endoftext|>


<commit_before>function confirmDatePlugin(pluginConfig) {
	const defaultConfig = {
		confirmIcon: "<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='17' height='17' viewBox='0 0 17 17'> <g> </g> <path d='M15.418 1.774l-8.833 13.485-4.918-4.386 0.666-0.746 4.051 3.614 8.198-12.515 0.836 0.548z' fill='#000000' /> </svg>",
		confirmText: "OK ",
		showAlways: false
	};

	const config = Object.assign({}, defaultConfig, pluginConfig || {});

	return function(fp) {
		fp.confirmContainer = fp._createElement("div", "flatpickr-confirm", config.confirmText);
		fp.confirmContainer.tabIndex = -1;
		fp.confirmContainer.innerHTML += config.confirmIcon;

		fp.confirmContainer.addEventListener("click", fp.close);

		const hooks = {
			onReady () {
				fp.calendarContainer.appendChild(fp.confirmContainer);
			}
		};

		if (config.showAlways)
			fp.confirmContainer.classList.add("visible");

		else
			hooks.onChange = function(dateObj, dateStr) {
				if(dateStr && !fp.config.inline)
					return fp.confirmContainer.classList.add("visible");
				fp.confirmContainer.classList.remove("visible");
			}

		hooks.onKeyDown = (_, __, ___, e) => {
			if (fp.config.enableTime && e.key === "Tab" && e.target === fp.amPM) {
				e.preventDefault();
				fp.confirmContainer.focus();
			}

			else if (e.key === "Enter" && e.target === fp.confirmContainer)
				fp.close();
		};

		return hooks;
	}
}

if (typeof module !== "undefined")
	module.exports = confirmDatePlugin;
<commit_msg>confirmDate: avoid object.assign<commit_after>function confirmDatePlugin(pluginConfig) {
	const defaultConfig = {
		confirmIcon: "<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='17' height='17' viewBox='0 0 17 17'> <g> </g> <path d='M15.418 1.774l-8.833 13.485-4.918-4.386 0.666-0.746 4.051 3.614 8.198-12.515 0.836 0.548z' fill='#000000' /> </svg>",
		confirmText: "OK ",
		showAlways: false
	};

	const config = {};
	for (let key in defaultConfig) {
		config[key] = pluginConfig[key] !== undefined
			? pluginConfig[key]
			: defaultConfig[key];

	return function(fp) {
		fp.confirmContainer = fp._createElement("div", "flatpickr-confirm", config.confirmText);
		fp.confirmContainer.tabIndex = -1;
		fp.confirmContainer.innerHTML += config.confirmIcon;

		fp.confirmContainer.addEventListener("click", fp.close);

		const hooks = {
			onReady () {
				fp.calendarContainer.appendChild(fp.confirmContainer);
			}
		};

		if (config.showAlways)
			fp.confirmContainer.classList.add("visible");

		else
			hooks.onChange = function(dateObj, dateStr) {
				if(dateStr && !fp.config.inline)
					return fp.confirmContainer.classList.add("visible");
				fp.confirmContainer.classList.remove("visible");
			}

		hooks.onKeyDown = (_, __, ___, e) => {
			if (fp.config.enableTime && e.key === "Tab" && e.target === fp.amPM) {
				e.preventDefault();
				fp.confirmContainer.focus();
			}

			else if (e.key === "Enter" && e.target === fp.confirmContainer)
				fp.close();
		};

		return hooks;
	}
}

if (typeof module !== "undefined")
	module.exports = confirmDatePlugin;
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mean-seed');

var db = mongoose.connection;
db.on('error', function(err){
    console.log('Erro de conexao.', err)
});
db.on('open', function () {
  console.log('Conexão aberta.')
});
db.on('connected', function(err){
    console.log('Conectado')
});
db.on('disconnected', function(err){
    console.log('Desconectado')
});

module.exports = db;<commit_msg>Translate PTBR to EN<commit_after>var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mean-seed');

var db = mongoose.connection;
db.on('error', function(err){
    console.log('Connection Error! ', err)
});
db.on('open', function () {
  console.log('Connection Open...')
});
db.on('connected', function(err){
    console.log('Connected')
});
db.on('disconnected', function(err){
    console.log('Disconnected')
});

module.exports = db;
<|endoftext|>


<commit_before>var ui = new InterpreterUI();

$(document).ready(function () {
    $("#btn-start").click(function (event) {
        event.preventDefault();
        ui.start();
    });
    $("#btn-pause").click(function (event) {
        event.preventDefault();
        ui.pause();
    });
    $("#btn-step").click(function (event) {
        event.preventDefault();
        ui.step();
    });
    $("#btn-stop").click(function (event) {
        event.preventDefault();
        ui.stop();
    });
    $("#btn-optimize").click(function (event) {
        event.preventDefault();
        $('#program').val(optimize($('#program').val()));
    });
    resizePanels();
})

$(window).resize(function (event) {
    resizePanels();
});

function resizePanels() {
    var height = $(window).height() + 30;

    $('#program').css('height', 0);
    $('#input').css('height', 0);
    $('#debug').css('height', 0);
    $('#output').css('height', 0);

    height -= ($('#button-bar').height() +
               $('#panels-body').height());

    $('#program').css('height', height * .3);
    $('#input').css('height', height * .3);
    $('#debug').css('height', height * .7);
    $('#output').css('height', height * .7);
}

function optimize(program) {
    /* remove invalid ops: */
    var valid_op = function(op) {
        return '-+<>[],.'.indexOf(op) > -1;
    }

    program = program.split('').filter(valid_op).join('');

    return program;
}

function renderMemory(memory, limit) {
    var ret = '';

    function zeropad(string, length) {
        while(string.length < length) {
            string = '0' + string;
        }

        return string;
    }

    for (var row = 0; (row * 8) < limit; ++row) {
        ret += '0x' + zeropad((row * 8).toString(16), 6) + '  ';
        for (var column = 0;
             column < 8 && (row * 8 + column) < limit;
             ++column) {
            var byte = memory[row * 8 + column];
            ret += zeropad(byte.toString(16), 2) + ' ';
        }
        ret += '\n';
    }

    return ret;
}

function InterpreterUI() {
    this.start_date = undefined;
    this.cycles = 0;
    this.interpreter = undefined;
    this.state = new UIStopped();
}

InterpreterUI.prototype.start = function() {
    this.state = this.state.start();
}

InterpreterUI.prototype.pause = function() {
    this.state = this.state.pause();
}

InterpreterUI.prototype.step = function() {
    this.state = this.state.step();
}

InterpreterUI.prototype.stop = function() {
    this.state = this.state.stop();
}

InterpreterUI.prototype.onStart = function() {
    var self = this;

    this.start_date = Date.now();
    this.cycles = 0;

    $('#output').val('');

    $('#cycles-count').html(this.cycles);
    $('#running-time').html("0.00 seconds");

    this.interpreter = new Interpreter(
        $('#program').val(),
        $("#input").val(),
        function() {
            self.onTick()
        },
        function(err) {
            self.onFinish(err);
        }
    );
}

InterpreterUI.prototype.onTick = function () {
    this.cycles += 1;
    delta = (Date.now() - this.start_date) / 1000;

    $('#program').get(0).setSelectionRange(this.interpreter.pc,
                                           this.interpreter.pc+1);

    $('#debug').html(renderMemory(this.interpreter.memory, 512));
    $('#output').val(this.interpreter.output);
    $('#program-counter').html(this.interpreter.pc);
    $('#memory-ptr').html(this.interpreter.mem_ptr);
    $('#input-ptr').html(this.interpreter.input_ptr);
    $('#cycles-count').html(this.cycles);
    $('#running-time').html(delta.toFixed(2) + " seconds");
}

InterpreterUI.prototype.onFinish = function (err) {
    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Start");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').addClass("disabled");

    this.state = new UIStopped();
}

function UIStopped() {}

UIStopped.prototype.start = function() {
    ui.onStart();
    ui.interpreter.start(parseInt($('#inst-per-cycle').val()));

    $('#btn-start').addClass("disabled");
    $('#btn-pause').removeClass("disabled");
    $('#btn-step').addClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIRunning();
}

UIStopped.prototype.pause = function() {
    throw "Invalid transition";
}

UIStopped.prototype.step = function() {
    ui.onStart();
    ui.interpreter.step();

    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Resume");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIPaused();
}

UIStopped.prototype.stop = function() {
    throw "Invalid transition";
}

function UIRunning() {}

UIRunning.prototype.start = function() {
    throw "Invalid transition";
}

UIRunning.prototype.pause = function() {
    ui.interpreter.pause();

    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Resume");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIPaused();
}

UIRunning.prototype.step = function() {
    throw "Invalid transition";
}

UIRunning.prototype.stop = function() {
    ui.interpreter.stop();
    return new UIStopped();
}

function UIPaused() {}

UIPaused.prototype.start = function () {
    ui.interpreter.start(parseInt($('#inst-per-cycle').val()));

    $('#btn-start').addClass("disabled");
    $('#btn-pause').removeClass("disabled");
    $('#btn-step').addClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIRunning();
}

UIPaused.prototype.pause = function () {
    throw "Invalid transition";
}

UIPaused.prototype.step = function () {
    ui.interpreter.step();
    return this;
}

UIPaused.prototype.stop = function () {
    ui.interpreter.stop();
    return new UIStopped();
}

////////////
function Interpreter(program, input, onTick, onFinish) {
    this.program = program;
    this.input = input;
    this.output = '';

    this.onTick = onTick;
    this.onFinish = onFinish;

    this.stopRequested = false;
    this.intervalId = undefined;
    this.jumps = {};

    this.memory = {0: 0};
    this.mem_ptr = 0;
    this.input_ptr = 0;
    this.pc = 0;

    this.state = new Stopped(this);

    this.init();
}

Interpreter.prototype.init = function(mem_size) {
    /* precompute jumps: */
    for(var pc = 0, stack = []; pc < this.program.length; ++pc) {
        var opcode = this.program[pc];

        if (opcode == '[') {
            stack.push(pc);
        } else if (opcode == ']') {
            var target = stack.pop();
            this.jumps[target] = pc;
            this.jumps[pc] = target;
        }
    }

    /* preload memory: */
    for(var i = 0; i < (mem_size || 30000); ++i) {
        this.memory[i] = 0;
    }
}

Interpreter.prototype.runCycle = function(instPerCycle) {
    try {
        for(var i = 0;
            i < instPerCycle && this.pc < this.program.length;
            ++i) {
            var opcode = this.program[this.pc];
            switch(opcode) {
                case '>':
                    ++this.mem_ptr;
                    break;
                case '<':
                    --this.mem_ptr;
                    break;
                case '+':
                    this.memory[this.mem_ptr]++;
                    break;
                case '-':
                    this.memory[this.mem_ptr]--;
                    break;
                case '.':
                    this.output += String.fromCharCode(this.memory[this.mem_ptr]);
                    break;
                case ',':
                    if (this.input_ptr < this.input.length) {
                        this.memory[this.mem_ptr] =
                            this.input.charCodeAt(this.input_ptr++);
                    } else {
                        this.tick();
                        throw "EOF";
                    }
                    break;
                case '[':
                    if (this.memory[this.mem_ptr] == 0) {
                        this.pc = this.jumps[this.pc];
                    }
                    break;
                case ']':
                    if (this.memory[this.mem_ptr] != 0) {
                        this.pc = this.jumps[this.pc];
                    }
                    break;
                default:
                    break;
            }
            ++this.pc;
        }

        this.tick();

        if (this.pc == this.program.length) {
            throw "EOP";
        }
    } catch(e) {
        console.log("Received: ", e);
        this.finish(e);
    }
}

Interpreter.prototype.start = function (instPerCycle) {
    this.state = this.state.start(instPerCycle);
}

Interpreter.prototype.pause = function () {
    this.state = this.state.pause();
}

Interpreter.prototype.step = function () {
    this.state = this.state.step();
}

Interpreter.prototype.stop = function () {
    this.state = this.state.stop();
}

Interpreter.prototype.tick = function () {
    if (this.stopRequested) {
        throw "STOP REQUESTED";
    }

    this.onTick(this);
}

Interpreter.prototype.finish = function (e) {
    clearInterval(this.intervalId);
    this.state = new Stopped(this);
    this.onFinish(e, this);
}

////
function Stopped(interpreter) {
    this.interpreter = interpreter;
}

Stopped.prototype.start = function (instPerCycle) {
    var self = this;

    this.interpreter.intervalId = setInterval(function () {
        self.interpreter.runCycle(instPerCycle);
    }, 0);

    return new Running(this.interpreter);
}

Stopped.prototype.pause = function () {
    throw "Invalid transition";
}

Stopped.prototype.step = function () {
    this.interpreter.runCycle(1);
    return new Paused(this.interpreter);
}

Stopped.prototype.stop = function () {
    throw "Invalid transition";
}

////
function Running(interpreter) {
    this.interpreter = interpreter;
}

Running.prototype.start = function () {
    throw "Invalid transition";
}

Running.prototype.pause = function () {
    clearInterval(this.interpreter.intervalId);
    return new Paused(this.interpreter);
}

Running.prototype.step = function () {
    throw "Invalid transition";
}

Running.prototype.stop = function () {
    this.interpreter.stopRequested = true;
    return new Stopped(this.interpreter);
}

////
function Paused(interpreter) {
    this.interpreter = interpreter;
}

Paused.prototype.start = function (instPerCycle) {
    var self = this;

    this.interpreter.intervalId = setInterval(function () {
        self.interpreter.runCycle(instPerCycle);
    }, 0);

    return new Running(this.interpreter);
}

Paused.prototype.paused = function () {
    throw "Invalid transition";
}

Paused.prototype.step = function () {
    this.interpreter.runCycle(1);
    return this;
}

Paused.prototype.stop = function () {
    this.interpreter.finish();
    return new Stopped(this.interpreter);
}
<commit_msg>Improvement in debug window<commit_after>var ui = new InterpreterUI();

$(document).ready(function () {
    $("#btn-start").click(function (event) {
        event.preventDefault();
        ui.start();
    });
    $("#btn-pause").click(function (event) {
        event.preventDefault();
        ui.pause();
    });
    $("#btn-step").click(function (event) {
        event.preventDefault();
        ui.step();
    });
    $("#btn-stop").click(function (event) {
        event.preventDefault();
        ui.stop();
    });
    $("#btn-optimize").click(function (event) {
        event.preventDefault();
        $('#program').val(optimize($('#program').val()));
    });
    resizePanels();
})

$(window).resize(function (event) {
    resizePanels();
});

function resizePanels() {
    var height = $(window).height() + 30;

    $('#program').css('height', 0);
    $('#input').css('height', 0);
    $('#debug').css('height', 0);
    $('#output').css('height', 0);

    height -= ($('#button-bar').height() +
               $('#panels-body').height());

    $('#program').css('height', height * .3);
    $('#input').css('height', height * .3);
    $('#debug').css('height', height * .7);
    $('#output').css('height', height * .7);
}

function optimize(program) {
    /* remove invalid ops: */
    var valid_op = function(op) {
        return '-+<>[],.'.indexOf(op) > -1;
    }

    program = program.split('').filter(valid_op).join('');

    return program;
}

function renderMemory(memory, current, limit) {
    var ret = '';

    function zeropad(string, length) {
        while(string.length < length) {
            string = '0' + string;
        }

        return string;
    }

    for (var row = 0; (row * 8) < limit; ++row) {
        ret += zeropad((row * 8).toString(16), 6) + ' ';
        for (var column = 0;
             column < 8 && (row * 8 + column) < limit;
             ++column) {
            var index = row * 8 + column,
                prefix = index == current ? '*' : ' ';
            ret += prefix + zeropad(memory[index].toString(16), 2) + ' ';
        }
        ret += '\n';
    }

    return ret;
}

function InterpreterUI() {
    this.start_date = undefined;
    this.cycles = 0;
    this.interpreter = undefined;
    this.state = new UIStopped();
}

InterpreterUI.prototype.start = function() {
    this.state = this.state.start();
}

InterpreterUI.prototype.pause = function() {
    this.state = this.state.pause();
}

InterpreterUI.prototype.step = function() {
    this.state = this.state.step();
}

InterpreterUI.prototype.stop = function() {
    this.state = this.state.stop();
}

InterpreterUI.prototype.onStart = function() {
    var self = this;

    this.start_date = Date.now();
    this.cycles = 0;

    $('#output').val('');

    $('#cycles-count').html(this.cycles);
    $('#running-time').html("0.00 seconds");

    this.interpreter = new Interpreter(
        $('#program').val(),
        $("#input").val(),
        function() {
            self.onTick()
        },
        function(err) {
            self.onFinish(err);
        }
    );
}

InterpreterUI.prototype.onTick = function () {
    this.cycles += 1;
    delta = (Date.now() - this.start_date) / 1000;

    $('#program').get(0).setSelectionRange(this.interpreter.pc,
                                           this.interpreter.pc+1);

    $('#debug').html(renderMemory(this.interpreter.memory,
                                  this.interpreter.mem_ptr,
                                  512));
    $('#output').val(this.interpreter.output);
    $('#program-counter').html(this.interpreter.pc);
    $('#memory-ptr').html(this.interpreter.mem_ptr);
    $('#input-ptr').html(this.interpreter.input_ptr);
    $('#cycles-count').html(this.cycles);
    $('#running-time').html(delta.toFixed(2) + " seconds");
}

InterpreterUI.prototype.onFinish = function (err) {
    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Start");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').addClass("disabled");

    this.state = new UIStopped();
}

function UIStopped() {}

UIStopped.prototype.start = function() {
    ui.onStart();
    ui.interpreter.start(parseInt($('#inst-per-cycle').val()));

    $('#btn-start').addClass("disabled");
    $('#btn-pause').removeClass("disabled");
    $('#btn-step').addClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIRunning();
}

UIStopped.prototype.pause = function() {
    throw "Invalid transition";
}

UIStopped.prototype.step = function() {
    ui.onStart();
    ui.interpreter.step();

    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Resume");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIPaused();
}

UIStopped.prototype.stop = function() {
    throw "Invalid transition";
}

function UIRunning() {}

UIRunning.prototype.start = function() {
    throw "Invalid transition";
}

UIRunning.prototype.pause = function() {
    ui.interpreter.pause();

    $('#btn-start').removeClass("disabled");
    $('#btn-start-label').html("Resume");
    $('#btn-pause').addClass("disabled");
    $('#btn-step').removeClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIPaused();
}

UIRunning.prototype.step = function() {
    throw "Invalid transition";
}

UIRunning.prototype.stop = function() {
    ui.interpreter.stop();
    return new UIStopped();
}

function UIPaused() {}

UIPaused.prototype.start = function () {
    ui.interpreter.start(parseInt($('#inst-per-cycle').val()));

    $('#btn-start').addClass("disabled");
    $('#btn-pause').removeClass("disabled");
    $('#btn-step').addClass("disabled");
    $('#btn-stop').removeClass("disabled");

    return new UIRunning();
}

UIPaused.prototype.pause = function () {
    throw "Invalid transition";
}

UIPaused.prototype.step = function () {
    ui.interpreter.step();
    return this;
}

UIPaused.prototype.stop = function () {
    ui.interpreter.stop();
    return new UIStopped();
}

////////////
function Interpreter(program, input, onTick, onFinish) {
    this.program = program;
    this.input = input;
    this.output = '';

    this.onTick = onTick;
    this.onFinish = onFinish;

    this.stopRequested = false;
    this.intervalId = undefined;
    this.jumps = {};

    this.memory = {0: 0};
    this.mem_ptr = 0;
    this.input_ptr = 0;
    this.pc = 0;

    this.state = new Stopped(this);

    this.init();
}

Interpreter.prototype.init = function(mem_size) {
    /* precompute jumps: */
    for(var pc = 0, stack = []; pc < this.program.length; ++pc) {
        var opcode = this.program[pc];

        if (opcode == '[') {
            stack.push(pc);
        } else if (opcode == ']') {
            var target = stack.pop();
            this.jumps[target] = pc;
            this.jumps[pc] = target;
        }
    }

    /* preload memory: */
    for(var i = 0; i < (mem_size || 30000); ++i) {
        this.memory[i] = 0;
    }
}

Interpreter.prototype.runCycle = function(instPerCycle) {
    try {
        for(var i = 0;
            i < instPerCycle && this.pc < this.program.length;
            ++i) {
            var opcode = this.program[this.pc];
            switch(opcode) {
                case '>':
                    ++this.mem_ptr;
                    break;
                case '<':
                    --this.mem_ptr;
                    break;
                case '+':
                    this.memory[this.mem_ptr]++;
                    break;
                case '-':
                    this.memory[this.mem_ptr]--;
                    break;
                case '.':
                    this.output += String.fromCharCode(this.memory[this.mem_ptr]);
                    break;
                case ',':
                    if (this.input_ptr < this.input.length) {
                        this.memory[this.mem_ptr] =
                            this.input.charCodeAt(this.input_ptr++);
                    } else {
                        this.tick();
                        throw "EOF";
                    }
                    break;
                case '[':
                    if (this.memory[this.mem_ptr] == 0) {
                        this.pc = this.jumps[this.pc];
                    }
                    break;
                case ']':
                    if (this.memory[this.mem_ptr] != 0) {
                        this.pc = this.jumps[this.pc];
                    }
                    break;
                default:
                    break;
            }
            ++this.pc;
        }

        this.tick();

        if (this.pc == this.program.length) {
            throw "EOP";
        }
    } catch(e) {
        console.log("Received: ", e);
        this.finish(e);
    }
}

Interpreter.prototype.start = function (instPerCycle) {
    this.state = this.state.start(instPerCycle);
}

Interpreter.prototype.pause = function () {
    this.state = this.state.pause();
}

Interpreter.prototype.step = function () {
    this.state = this.state.step();
}

Interpreter.prototype.stop = function () {
    this.state = this.state.stop();
}

Interpreter.prototype.tick = function () {
    if (this.stopRequested) {
        throw "STOP REQUESTED";
    }

    this.onTick(this);
}

Interpreter.prototype.finish = function (e) {
    clearInterval(this.intervalId);
    this.state = new Stopped(this);
    this.onFinish(e, this);
}

////
function Stopped(interpreter) {
    this.interpreter = interpreter;
}

Stopped.prototype.start = function (instPerCycle) {
    var self = this;

    this.interpreter.intervalId = setInterval(function () {
        self.interpreter.runCycle(instPerCycle);
    }, 0);

    return new Running(this.interpreter);
}

Stopped.prototype.pause = function () {
    throw "Invalid transition";
}

Stopped.prototype.step = function () {
    this.interpreter.runCycle(1);
    return new Paused(this.interpreter);
}

Stopped.prototype.stop = function () {
    throw "Invalid transition";
}

////
function Running(interpreter) {
    this.interpreter = interpreter;
}

Running.prototype.start = function () {
    throw "Invalid transition";
}

Running.prototype.pause = function () {
    clearInterval(this.interpreter.intervalId);
    return new Paused(this.interpreter);
}

Running.prototype.step = function () {
    throw "Invalid transition";
}

Running.prototype.stop = function () {
    this.interpreter.stopRequested = true;
    return new Stopped(this.interpreter);
}

////
function Paused(interpreter) {
    this.interpreter = interpreter;
}

Paused.prototype.start = function (instPerCycle) {
    var self = this;

    this.interpreter.intervalId = setInterval(function () {
        self.interpreter.runCycle(instPerCycle);
    }, 0);

    return new Running(this.interpreter);
}

Paused.prototype.paused = function () {
    throw "Invalid transition";
}

Paused.prototype.step = function () {
    this.interpreter.runCycle(1);
    return this;
}

Paused.prototype.stop = function () {
    this.interpreter.finish();
    return new Stopped(this.interpreter);
}
<|endoftext|>


<commit_before>/*
 Copyright 2013 Daniel Wirtz <dcode@dcode.io>

 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.
 */

/**
 * grunt-closurecompiler Task (c) 2013 Daniel Wirtz <dcode@dcode.io>
 * Released under the Apache License, Version 2.0
 * see: https://github.com/dcodeIO/ClosureCompiler.js for details
 */

'use strict';

module.exports = function (grunt) {

    grunt.registerMultiTask('closurecompiler', 'Compile through ClosureCompiler.js', function () {

        var options = this.options({
            "compilation_level": "SIMPLE_OPTIMIZATIONS",
            "max_processes": Number.MAX_VALUE
        });

        var maxProcesses = options.max_processes;
        delete options.max_processes;

        if (maxProcesses < 1) {
            grunt.log.warn("max_processes must be at least 1");
            maxProcesses = 1;
        }

        var ClosureCompiler = require("closurecompiler");
        var done = this.async();
        var running = 0;
        var to = null;

        if (this.files.length === 0) {
            done();
            return;
        }

        var next = 0;

        var startClosure = function() {

            while(next < this.files.length && running < maxProcesses) {
                var file = this.files[next++];
                var sources = file.src;
                var dest = file.dest;

                grunt.log.subhead("Compiling "+sources+" -> "+dest);

                if (sources.length === 0 || !dest) {
                    grunt.log.error("Please provide at least one source and exactly one destination file.");
                } else {
                    running++;
                    ClosureCompiler.compile(sources, options, function(error, result) {
                        if (result) {
                            grunt.file.write(dest, result=""+result);
                            if (error) {
                                grunt.log.warn(""+error);
                            }
                            grunt.log.ok("Complete: "+result.length);
                        } else if (error) {
                            grunt.fail.warn(error);
                        } else {
                            grunt.log.ok("Complete: no output");
                        }
                        running--;
                        startClosure(); /* When a process exits, see if we can start more */
                    });
                }
            }

            if (running === 0) {
                done();
            }
        }.bind(this);

        startClosure();
    });

};
<commit_msg>Updating ClosureCompiler to support option banners.<commit_after>/*
 Copyright 2013 Daniel Wirtz <dcode@dcode.io>

 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.
 */

/**
 * grunt-closurecompiler Task (c) 2013 Daniel Wirtz <dcode@dcode.io>
 * Released under the Apache License, Version 2.0
 * see: https://github.com/dcodeIO/ClosureCompiler.js for details
 */

'use strict';

module.exports = function (grunt) {

    grunt.registerMultiTask('closurecompiler', 'Compile through ClosureCompiler.js', function () {

        var options = this.options({
            "compilation_level": "SIMPLE_OPTIMIZATIONS",
            "max_processes": Number.MAX_VALUE
        });
        var banner = "";

        if (options.banner !== undefined) {
            banner = options.banner+"\n";
            delete options.banner;
        }

        var maxProcesses = options.max_processes;
        delete options.max_processes;

        if (maxProcesses < 1) {
            grunt.log.warn("max_processes must be at least 1");
            maxProcesses = 1;
        }

        var ClosureCompiler = require("closurecompiler");
        var done = this.async();
        var running = 0;
        var to = null;

        if (this.files.length === 0) {
            done();
            return;
        }

        var next = 0;

        var startClosure = function() {

            while(next < this.files.length && running < maxProcesses) {
                var file = this.files[next++];
                var sources = file.src;
                var dest = file.dest;

                grunt.log.subhead("Compiling "+sources+" -> "+dest);

                if (sources.length === 0 || !dest) {
                    grunt.log.error("Please provide at least one source and exactly one destination file.");
                } else {
                    running++;
                    ClosureCompiler.compile(sources, options, function(error, result) {
                        if (result) {
                            grunt.file.write(dest, result=banner+result);
                            if (error) {
                                grunt.log.warn(""+error);
                            }
                            grunt.log.ok("Complete: "+result.length);
                        } else if (error) {
                            grunt.fail.warn(error);
                        } else {
                            grunt.log.ok("Complete: no output");
                        }
                        running--;
                        startClosure(); /* When a process exits, see if we can start more */
                    });
                }
            }

            if (running === 0) {
                done();
            }
        }.bind(this);

        startClosure();
    });

};
<|endoftext|>