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

var devel_mode = true;

var express = require('express');
var fs = require('fs');
var ejs = require('ejs');
var red_inc = require('./include_libs');

var app = express.createServer();
if(devel_mode) {
	red_inc.main = red_inc.main_src;
} else {
	red_inc.main = red_inc.main_build;
}
var text_after = function(str, portion) {
	var index = str.lastIndexOf(portion);
	if(index >= 0) {
		return str.slice(index + portion.length);
	} else {
		return null;
	}
};
var text_before = function(str, portion) {
	var index = str.lastIndexOf(portion);
	if(index >= 0) {
		return str.substring(0, index + portion.length);
	} else {
		return null;
	}
};

var callback_map = function(arr, func, callback) {
	var rv = [];
	var waiting_for = arr.length;
	arr.forEach(function(item, index) {
		func(item, function(mapped) {
			rv[index] = mapped;
			waiting_for--;
			if(waiting_for <= 0) {
				callback(rv);
			}
		});
	});
};
var jslint_options = { //http://www.jslint.com/lint.html
	sloppy: true // true if the ES5 'use strict'; pragma is not required. Do not use this pragma unless you know what you are doing.
	, vars: true // true if multiple var statement per function should be allowed.
	, nomen: true // true if names should not be checked for initial or trailing underbars.
	, white: true // true if strict whitespace rules should be ignored.
	, plusplus: true // true if ++ and -- should be allowed.
	, predef: ["red", "module", "exports"]
};

app.configure(function() {
	app.use(app.router);
	app.use(express.static(__dirname));

	app.get("*/list_files*", function(req, res, next) {
		var path = req.query.path;
		fs.readdir(path, function(err, files) {
			if(err) {
				var files_str = JSON.stringify({errno: err.errno});
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			} else {
				var files_str = JSON.stringify(files);
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			}
		});
	});
	app.get("*/file_type*", function(req, res, next) {
		var path = req.query.path;
		fs.stat(path, function(err, stats) {
			if(err) {
				var files_str = JSON.stringify({errno: err.errno});
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			} else {
				var type_str;
				if(stats.isDirectory()) {
					type_str = "directory";
				} else  {
					type_str = "file";
				}
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': type_str.length
				});
				res.end(type_str);
			}
		});
	});
	app.get("*/command/*", function(req, res, next) {
		var command = text_after(req.originalUrl, "/command/");
		var do_confirm = function() {
			var body = "done";
			res.writeHead(200, {
				  'Content-Type': 'text/html'
				, 'Content-Length': body.length
			});
			res.end(body);
		};
		if(command==="recompile") {
			var dev_mode = red_inc.main === red_inc.main_src;
			delete require.cache[__dirname+'/include_libs.js']
			red_inc = require(__dirname + '/include_libs');
			delete require.cache[__dirname+'/Makefile.dryice.js']
			var makefile = require("./Makefile.dryice");
			red_inc.main = dev_mode ? red_inc.main_src : red_inc.main_build;
			makefile.build(do_confirm);
		} else if(command === "refresh_include") {
			var dev_mode = red_inc.main === red_inc.main_src;
			delete require.cache[__dirname+'/include_libs.js']
			red_inc = require(__dirname + '/include_libs');
			red_inc.main = dev_mode ? red_inc.main_src : red_inc.main_build;
			do_confirm();
		} else if(command === "make_src_mode") {
			red_inc.main = red_inc.main_src;
			do_confirm();
		} else if(command === "make_build_mode") {
			red_inc.main = red_inc.main_build;
			do_confirm();
		}
	});

	app.get("*.ejs.html*|/", function(req, res, next) {
		var relative_url = req.originalUrl.slice(1); //remove the initial '/'
		var filename;
		if(relative_url === "") {
			filename = "index.ejs.html";
		} else {
			filename = text_before(relative_url, ".ejs.html");
		}

		get_file_string(filename, function(str) {
			if(!str) {
				next();
			} else {
				var num_slashes = (relative_url.split('/').length-1);
				var relative_path = "";
				for(var i = 0; i<num_slashes; i++) {
					relative_path += "../";
				}
				var locals = {
					include: function(files) {
						return red_inc.include_templates(files.map(function(file) {
							return relative_path+file;
						}));
					}
					, red_inc: red_inc
					, dev_mode: red_inc.core === red_inc.src
				};

				if(filename.indexOf("jslint")>=0) {
					var jslint = require("jslint/lib/nodelint");
					var errors_only = true;
					var lintFile = function(file, options, callback) {
						fs.readFile(file, function (err, data) {
							if (err) {
								throw err;
							}
							data = data.toString("utf8");

							jslint(data, options);
							var report = jslint.report(errors_only);
							if(callback) {
								callback(report);
							}
						});
					};
					var files = req.query.filename ? [req.query.filename] : red_inc.main_src;
					callback_map(files, function(file_name, good_callback) {
						lintFile(file_name, jslint_options, function(report) {
							good_callback(report);
						});
					}, function(rv) {
						locals.reports = rv.map(function(report, index) {
							return {
								file: files[index]
								, lint: report
							};
						});

						body = ejs.render(str, {locals: locals});
						res.writeHead(200, {
							  'Content-Type': 'text/html'
							, 'Content-Length': body.length
						});
						res.end(body);
					});
					return;
				}

				var body = ejs.render(str, {locals: locals});
				res.writeHead(200, {
					  'Content-Type': 'text/html'
					, 'Content-Length': body.length
				});
				res.end(body);
			}
		});
	});
});

var makefile = require("./Makefile.dryice");
makefile.build(function() {
	app.listen(8000);
	console.log("Interactive times at http://localhost:8000/");
	process.on('SIGINT', function () {
		console.log("iao...");
		process.exit(0);
	});
});

var render_files = function(res, files) {
	concat_files(files, function(str) {
		res.writeHead(200, {
		  'Content-Length': str.length,
		  'Content-Type': 'text/javascript' });
		res.end(str);
	});
};

var concat_files = function(file_list, callback) {
	if(typeof file_list === "string") file_list = [file_list];
	var current_index = 0;
	var rv = "";
	var get_curr = function() {
		get_file_string(file_list[current_index], function(str) {
			rv += str;
			current_index++;
			if(current_index >= file_list.length) {
				callback(rv);
			} else {
				get_curr();
			}
		});
	};
	get_curr();
};

var get_file_string = function(path, callback) {
	fs.readFile(path, 'ascii', function(err, data) {
		callback(data);
	});
};
<commit_msg>Updated for latest express<commit_after>#!/usr/bin/env node

var devel_mode = true;

var express = require('express');
var fs = require('fs');
var ejs = require('ejs');
var red_inc = require('./include_libs');

var app = express();
if(devel_mode) {
	red_inc.main = red_inc.main_src;
} else {
	red_inc.main = red_inc.main_build;
}
var text_after = function(str, portion) {
	var index = str.lastIndexOf(portion);
	if(index >= 0) {
		return str.slice(index + portion.length);
	} else {
		return null;
	}
};
var text_before = function(str, portion) {
	var index = str.lastIndexOf(portion);
	if(index >= 0) {
		return str.substring(0, index + portion.length);
	} else {
		return null;
	}
};

var callback_map = function(arr, func, callback) {
	var rv = [];
	var waiting_for = arr.length;
	arr.forEach(function(item, index) {
		func(item, function(mapped) {
			rv[index] = mapped;
			waiting_for--;
			if(waiting_for <= 0) {
				callback(rv);
			}
		});
	});
};
var jslint_options = { //http://www.jslint.com/lint.html
	sloppy: true // true if the ES5 'use strict'; pragma is not required. Do not use this pragma unless you know what you are doing.
	, vars: true // true if multiple var statement per function should be allowed.
	, nomen: true // true if names should not be checked for initial or trailing underbars.
	, white: true // true if strict whitespace rules should be ignored.
	, plusplus: true // true if ++ and -- should be allowed.
	, predef: ["red", "module", "exports"]
};

app.configure(function() {
	app.use(app.router);
	app.use(express.static(__dirname));

	app.get("*/list_files*", function(req, res, next) {
		var path = req.query.path;
		fs.readdir(path, function(err, files) {
			if(err) {
				var files_str = JSON.stringify({errno: err.errno});
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			} else {
				var files_str = JSON.stringify(files);
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			}
		});
	});
	app.get("*/file_type*", function(req, res, next) {
		var path = req.query.path;
		fs.stat(path, function(err, stats) {
			if(err) {
				var files_str = JSON.stringify({errno: err.errno});
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': files_str.length
				});
				res.end(files_str);
			} else {
				var type_str;
				if(stats.isDirectory()) {
					type_str = "directory";
				} else  {
					type_str = "file";
				}
				res.writeHead(200, {
					  'Content-Type': 'text/plain'
					, 'Content-Length': type_str.length
				});
				res.end(type_str);
			}
		});
	});
	app.get("*/command/*", function(req, res, next) {
		var command = text_after(req.originalUrl, "/command/");
		var do_confirm = function() {
			var body = "done";
			res.writeHead(200, {
				  'Content-Type': 'text/html'
				, 'Content-Length': body.length
			});
			res.end(body);
		};
		if(command==="recompile") {
			var dev_mode = red_inc.main === red_inc.main_src;
			delete require.cache[__dirname+'/include_libs.js']
			red_inc = require(__dirname + '/include_libs');
			delete require.cache[__dirname+'/Makefile.dryice.js']
			var makefile = require("./Makefile.dryice");
			red_inc.main = dev_mode ? red_inc.main_src : red_inc.main_build;
			makefile.build(do_confirm);
		} else if(command === "refresh_include") {
			var dev_mode = red_inc.main === red_inc.main_src;
			delete require.cache[__dirname+'/include_libs.js']
			red_inc = require(__dirname + '/include_libs');
			red_inc.main = dev_mode ? red_inc.main_src : red_inc.main_build;
			do_confirm();
		} else if(command === "make_src_mode") {
			red_inc.main = red_inc.main_src;
			do_confirm();
		} else if(command === "make_build_mode") {
			red_inc.main = red_inc.main_build;
			do_confirm();
		}
	});

	app.get("*.ejs.html*|/", function(req, res, next) {
		var relative_url = req.originalUrl.slice(1); //remove the initial '/'
		var filename;
		if(relative_url === "") {
			filename = "index.ejs.html";
		} else {
			filename = text_before(relative_url, ".ejs.html");
		}

		get_file_string(filename, function(str) {
			if(!str) {
				next();
			} else {
				var num_slashes = (relative_url.split('/').length-1);
				var relative_path = "";
				for(var i = 0; i<num_slashes; i++) {
					relative_path += "../";
				}
				var locals = {
					include: function(files) {
						return red_inc.include_templates(files.map(function(file) {
							return relative_path+file;
						}));
					}
					, red_inc: red_inc
					, dev_mode: red_inc.core === red_inc.src
				};

				if(filename.indexOf("jslint")>=0) {
					var jslint = require("jslint/lib/nodelint");
					var errors_only = true;
					var lintFile = function(file, options, callback) {
						fs.readFile(file, function (err, data) {
							if (err) {
								throw err;
							}
							data = data.toString("utf8");

							jslint(data, options);
							var report = jslint.report(errors_only);
							if(callback) {
								callback(report);
							}
						});
					};
					var files = req.query.filename ? [req.query.filename] : red_inc.main_src;
					callback_map(files, function(file_name, good_callback) {
						lintFile(file_name, jslint_options, function(report) {
							good_callback(report);
						});
					}, function(rv) {
						locals.reports = rv.map(function(report, index) {
							return {
								file: files[index]
								, lint: report
							};
						});

						body = ejs.render(str, {locals: locals});
						res.writeHead(200, {
							  'Content-Type': 'text/html'
							, 'Content-Length': body.length
						});
						res.end(body);
					});
					return;
				}

				var body = ejs.render(str, {locals: locals});
				res.writeHead(200, {
					  'Content-Type': 'text/html'
					, 'Content-Length': body.length
				});
				res.end(body);
			}
		});
	});
});

var makefile = require("./Makefile.dryice");
makefile.build(function() {
	app.listen(8000);
	console.log("Interactive times at http://localhost:8000/");
	process.on('SIGINT', function () {
		console.log("iao...");
		process.exit(0);
	});
});

var render_files = function(res, files) {
	concat_files(files, function(str) {
		res.writeHead(200, {
		  'Content-Length': str.length,
		  'Content-Type': 'text/javascript' });
		res.end(str);
	});
};

var concat_files = function(file_list, callback) {
	if(typeof file_list === "string") file_list = [file_list];
	var current_index = 0;
	var rv = "";
	var get_curr = function() {
		get_file_string(file_list[current_index], function(str) {
			rv += str;
			current_index++;
			if(current_index >= file_list.length) {
				callback(rv);
			} else {
				get_curr();
			}
		});
	};
	get_curr();
};

var get_file_string = function(path, callback) {
	fs.readFile(path, 'ascii', function(err, data) {
		callback(data);
	});
};
<|endoftext|>


<commit_before>/*
* This is the logger file that places log. under the global scope. We will be able to add centralized logging here.
* */
var log4js = require('log4js'),
  util = require('util'),
  Component = require('../core/component')();

Component.default({
  appenders: [{
    type: 'console'
  }]
});

var logger = function CruxLogger() {
  Component.apply(this, arguments);
  this.name = 'log';
  this.appenders = [{
    type: 'console'
  }];
  this.type = 'console';  // default logging type.
  global['log'] = log4js.getLogger(this.type);
};
util.inherits(logger, Component);

logger.prototype.run = function RunLogger(cb) {
  cb(null);
}

logger.prototype.stop = function StopLogger() {};

logger.prototype.get = function GetLogger() {
  return this;
}

module.exports = logger;<commit_msg>-added logging configuration<commit_after>/*
* This is the logger file that places log. under the global scope. We will be able to add centralized logging here.
* */
var log4js = require('log4js'),
  util = require('util'),
  Component = require('../core/component')();

Component.default({
  appenders: [{
    type: 'console'
  }],
  level: 'trace'
});

var logger = function CruxLogger() {
  Component.apply(this, arguments);
  this.name = 'log';
  this.type = 'console';  // default logging type.
  global['log'] = log4js.getLogger(this.type);
  log.setLevel(this.config.level.toUpperCase());
};
util.inherits(logger, Component);

logger.prototype.run = function RunLogger(cb) {
  cb(null);
}

logger.prototype.stop = function StopLogger() {};

logger.prototype.get = function GetLogger() {
  return this;
}

module.exports = logger;<|endoftext|>


<commit_before>/**
 * HTTP Server Settings
 * (sails.config.http)
 *
 * Configuration for the underlying HTTP server in Sails.
 * Only applies to HTTP requests (not WebSockets)
 *
 * For more information on configuration, check out:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.http.html
 */

module.exports.http = {

  /****************************************************************************
  *                                                                           *
  * Express middleware to use for every Sails request. To add custom          *
  * middleware to the mix, add a function to the middleware config object and *
  * add its key to the "order" array. The $custom key is reserved for         *
  * backwards-compatibility with Sails v0.9.x apps that use the               *
  * `customMiddleware` config option.                                         *
  *                                                                           *
  ****************************************************************************/

  middleware: {

  /***************************************************************************
  *                                                                          *
  * The order in which middleware should be run for HTTP request. (the Sails *
  * router is invoked by the "router" middleware below.)                     *
  *                                                                          *
  ***************************************************************************/

    // order: [
    //   'startRequestTimer',
    //   'cookieParser',
    //   'session',
    //   'myRequestLogger',
    //   'bodyParser',
    //   'handleBodyParserError',
    //   'compress',
    //   'methodOverride',
    //   'poweredBy',
    //   '$custom',
    //   'router',
    //   'www',
    //   'favicon',
    //   '404',
    //   '500'
    // ],

  /****************************************************************************
  *                                                                           *
  * Example custom middleware; logs each request to the console.              *
  *                                                                           *
  ****************************************************************************/

    // myRequestLogger: function (req, res, next) {
    //     console.log("Requested :: ", req.method, req.url);
    //     return next();
    // }

  /***************************************************************************
  *                                                                          *
  * The body parser that will handle incoming multipart HTTP requests. By    *
  * default as of v0.10, Sails uses                                          *
  * [skipper](http://github.com/balderdashy/skipper). See                    *
  * http://www.senchalabs.org/connect/multipart.html for other options.      *
  *                                                                          *
  * Note that Sails uses an internal instance of Skipper by default; to      *
  * override it and specify more options, make sure to "npm install skipper" *
  * in your project first.  You can also specify a different body parser or  *
  * a custom function with req, res and next parameters (just like any other *
  * middleware function).                                                    *
  *                                                                          *
  ***************************************************************************/

    // bodyParser: require('skipper')({strict: true})

  },

  /***************************************************************************
  *                                                                          *
  * The number of seconds to cache flat files on disk being served by        *
  * Express static middleware (by default, these files are in `.tmp/public`) *
  *                                                                          *
  * The HTTP static cache is only active in a 'production' environment,      *
  * since that's the only time Express will cache flat-files.                *
  *                                                                          *
  ***************************************************************************/

  // cache: 31557600000
};
<commit_msg>hook up passport initialize and session middleware<commit_after>/**
 * HTTP Server Settings
 * (sails.config.http)
 *
 * Configuration for the underlying HTTP server in Sails.
 * Only applies to HTTP requests (not WebSockets)
 *
 * For more information on configuration, check out:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.http.html
 */

module.exports.http = {

  /****************************************************************************
  *                                                                           *
  * Express middleware to use for every Sails request. To add custom          *
  * middleware to the mix, add a function to the middleware config object and *
  * add its key to the "order" array. The $custom key is reserved for         *
  * backwards-compatibility with Sails v0.9.x apps that use the               *
  * `customMiddleware` config option.                                         *
  *                                                                           *
  ****************************************************************************/

  middleware: {

  // Define another couple of custom HTTP middleware fns with keys `passportInit` and `passportSession`
  // (notice that this time we're using an existing middleware library from npm)
    passportInit    : require('passport').initialize(),
    passportSession : require('passport').session(),

  /***************************************************************************
  *                                                                          *
  * The order in which middleware should be run for HTTP request. (the Sails *
  * router is invoked by the "router" middleware below.)                     *
  *                                                                          *
  ***************************************************************************/

    order: [
      'startRequestTimer',
      'cookieParser',
      'session',
      'passportInit',
      'passportSession',
      'myRequestLogger',
      'bodyParser',
      'handleBodyParserError',
      'compress',
      'methodOverride',
      'poweredBy',
      '$custom',
      'router',
      'www',
      'favicon',
      '404',
      '500'
    ],

  /****************************************************************************
  *                                                                           *
  * Example custom middleware; logs each request to the console.              *
  *                                                                           *
  ****************************************************************************/

    // myRequestLogger: function (req, res, next) {
    //     console.log("Requested :: ", req.method, req.url);
    //     return next();
    // }

  /***************************************************************************
  *                                                                          *
  * The body parser that will handle incoming multipart HTTP requests. By    *
  * default as of v0.10, Sails uses                                          *
  * [skipper](http://github.com/balderdashy/skipper). See                    *
  * http://www.senchalabs.org/connect/multipart.html for other options.      *
  *                                                                          *
  * Note that Sails uses an internal instance of Skipper by default; to      *
  * override it and specify more options, make sure to "npm install skipper" *
  * in your project first.  You can also specify a different body parser or  *
  * a custom function with req, res and next parameters (just like any other *
  * middleware function).                                                    *
  *                                                                          *
  ***************************************************************************/

    // bodyParser: require('skipper')({strict: true})

  },

  /***************************************************************************
  *                                                                          *
  * The number of seconds to cache flat files on disk being served by        *
  * Express static middleware (by default, these files are in `.tmp/public`) *
  *                                                                          *
  * The HTTP static cache is only active in a 'production' environment,      *
  * since that's the only time Express will cache flat-files.                *
  *                                                                          *
  ***************************************************************************/

  // cache: 31557600000
};
<|endoftext|>


<commit_before>/**
 * Dummy implementation of analytics.
 */
"use strict";

plugin.consumes = [];
plugin.provides = ["analytics"];

module.exports = plugin;

function plugin(options, imports, register) {

     register(null, {
        "analytics": {
            log: function() {},
            track: function() {},
            identify: function() {},
            logClean: function() {},
            trackClean: function() {},
            identifyClean: function() {},
        }
    });
}<commit_msg>Revert "Revert "Fix broken funnel""<commit_after>/**
 * Dummy implementation of analytics.
 */
"use strict";

plugin.consumes = [];
plugin.provides = ["analytics"];

module.exports = plugin;

function plugin(options, imports, register) {

     register(null, {
        "analytics": {
            log: function() {},
            track: function() {},
            identify: function() {},
            logClean: function() {},
            trackClean: function() {}
        }
    });
}<|endoftext|>


<commit_before>var fs = require('fs');
var Discord = require('discord.js');
var Request = require('request');
var parseIrc = require('irc-message').parse;
var config = require('./config.js');
var request = Request.defaults({
    headers: {
        'User-Agent': 'riotlv v' + require('./package.json').version
    }
});

const invitelink = 'https://discordapp.com/oauth2/authorize?client_id='
    + config.client_id + '&scope=bot&permissions=19456';
const defaults_file = './defaults.json';

var channel_defaults = {};

var client = new Discord.Client({
    autoReconnect: true
});

client.on('ready', function () {
    console.log("Ready");
    client.setStatus('online', 'with butts');
});

client.on('message', function (message) {
    let words = message.cleanContent.match(/(?:[^\s"]+|"[^"]*")+/g);
    if (words && words[0].startsWith(config.prefix)) {
        let cmd = words[0].substring(config.prefix.length);
        if (commands[cmd]) {
            words.shift();
            commands[cmd](message, words);
        }
    }
});

client.on('warn', function (warn) {
    console.error('WARN', warn);
});

client.on('error', function (error) {
    console.error('ERROR', error);
});

client.loginWithToken(config.token, function (error) {
    if (error) {
        console.error("Couldn't login: ", error);
        process.exit(15);
    }
});

function getToken(message) {
    return message.channel.server ? (config.lvtokens[message.channel.server.id] || "") : "";
}

function apiRequest(api, cb, errorcb) {
    request('http://' + config.lvdomain + '/api/' + api, function (error, response, body) {
        let data;
        if (error) {
            if (typeof errorcb === "function") errorcb("an error occurred with the API request");
            console.error('RERROR', error);
        }
        else {
            try {
                data = JSON.parse(body);
            } catch (e) {
                data = null;
                if (typeof errorcb === "function") errorcb("an error occurred parsing the API response");
                console.error('PERROR', e);
            }
            if (data != null && typeof cb === "function") {
                cb(data);
            }
            else if (typeof errorcb === "function") {
                errorcb("no data returned");
            }
        }
    });
}

var commands = {
    help: function (message, words) {
        sendReply(message, "command prefix: " + config.prefix + " - commands: " + Object.keys(commands).join(', '));
    },
    list: function (message, words) {
        let token = getToken(message);
        apiRequest('channels?token=' + token, function (data) {
            let reply = "";
            data.forEach(function (ch) {
                if (reply.length > 1900) {
                    sendReply(message, reply.slice(0, -2));
                    reply = "";
                }
                reply += ch.name + ", ";
            });
            sendReply(message, reply.slice(0, -2));
        }, function (error) {
            sendReply(message, error);
        });
    },
    setdefault: function (message, words) {
        if (message.channel.permissionsOf(message.author).hasPermission('manageChannel')) {
            let default_channel = words[0] || null;
            if (default_channel !== null) {
                channel_defaults[message.channel.id] = default_channel.toLowerCase();
                sendReply(message, "default for this channel set to " + channel_defaults[message.channel.id]);
            } else {
                sendReply(message, "usage: !setdefault [channel name]");
            }
        } else {
            sendReply(message, "shush, you don't have permission to do this!");
        }
    },
    lv: function (message, words) {
        let limit = words[2] || 10;
        let channel = words[1] || channel_defaults[message.channel.id] || "riotgames";
        let user = words[0] || null;

        try {
            limit = Math.min(parseInt(limit), 50);
        } catch (e) {
            sendReply(message, "limit must be a number");
            return;
        }

        console.log("Log request for: `" + JSON.stringify({ user: words[0], channel: channel, limit: limit }) + "`");

        if (user === null) {
            sendReply(message, "usage: " + config.prefix + "lv <user> [channel] [limit]");
            return;
        }

        let token = getToken(message);

        apiRequest('logs/' + encodeURIComponent(channel) + "/?token=" + token
                + "&nick=" + encodeURIComponent(user) + "&before=" + limit,
        function (data) {
            if (data.before) {
                reply = "here are logs for **" + user + "** from **" + channel + "**\n\n```";
                for (let i = data.before.length - 1; i >= 0; --i) {
                    let index = data.before.length - 1 - i;
                    let ircmsg = parseIrc(data.before[index].text);
                    let line = "\n" + (new Date(data.before[index].time * 1000)).toISOString().replace('T', ' ').replace('Z', ' UTC')
                        + " | " + ircmsg.params[1];
                    if (reply.length + line.length > 1900) {
                        reply += "\n```";
                        sendReply(message, reply);
                        reply = "\n```";
                    }
                    reply += line;
                }
                reply += "\n```";
            }
            else {
                reply = "no data found.";
            }
            reply += '\nSee http://' + config.lvpublicdomain + '/' + encodeURIComponent(channel) + "/?user=" + encodeURIComponent(user);
            sendReply(message, reply);
        }, function (error) {
            sendReply(message, error);
        });
    },
    game: function (message, words) {
        let game = words.join(' ') || "with butts";
        client.setStatus('online', game);
    },
    invite: function(message, words) {
        sendReply(message, invitelink);
    }
};

function sendReply(message, reply) {
    client.reply(message, reply, { tts: false }, function (error) {
        if (error) {
            console.error('WERROR', error);
        }
    });
}

process.on('SIGINT', function () {
    var exit_tasks_done = 0;
    var exit_tasks_total = 2;
    function exitTaskCheck() {
        if (++exit_tasks_done >= exit_tasks_total) {
            process.exit();
        }
    }
    console.log("Logging out and saving data...");
    client.logout(exitTaskCheck);
    saveDefaults(exitTaskCheck);
});

function saveDefaults(cb) {
    fs.access(defaults_file, fs.W_OK, (err) => {
        if (err) {
            console.error("No access to write", defaults_file);
            cb();
        } else {
            fs.writeFile(defaults_file, JSON.stringify(channel_defaults), (err) => {
                if (err) {
                    console.error("Write error", defaults_file);
                }
                cb();
            });
        }
    });
}

// Load defaults
fs.access(defaults_file, fs.R_OK, (err) => {
    if (err) {
        console.error("No access", defaults_file);
        saveDefaults(function () {});
    } else {
        fs.readFile(defaults_file, (err, data) => {
            if (err) {
                console.error("Read error", defaults_file, err);
            } else {
                try {
                    channel_defaults = JSON.parse(data);
                } catch (e) {
                    console.error("JSON error", e);
                }
            }
        });
    }
});
<commit_msg>Removed milliseconds from timestamps<commit_after>var fs = require('fs');
var Discord = require('discord.js');
var Request = require('request');
var parseIrc = require('irc-message').parse;
var config = require('./config.js');
var request = Request.defaults({
    headers: {
        'User-Agent': 'riotlv v' + require('./package.json').version
    }
});

const invitelink = 'https://discordapp.com/oauth2/authorize?client_id='
    + config.client_id + '&scope=bot&permissions=19456';
const defaults_file = './defaults.json';

var channel_defaults = {};

var client = new Discord.Client({
    autoReconnect: true
});

client.on('ready', function () {
    console.log("Ready");
    client.setStatus('online', 'with butts');
});

client.on('message', function (message) {
    let words = message.cleanContent.match(/(?:[^\s"]+|"[^"]*")+/g);
    if (words && words[0].startsWith(config.prefix)) {
        let cmd = words[0].substring(config.prefix.length);
        if (commands[cmd]) {
            words.shift();
            commands[cmd](message, words);
        }
    }
});

client.on('warn', function (warn) {
    console.error('WARN', warn);
});

client.on('error', function (error) {
    console.error('ERROR', error);
});

client.loginWithToken(config.token, function (error) {
    if (error) {
        console.error("Couldn't login: ", error);
        process.exit(15);
    }
});

function getToken(message) {
    return message.channel.server ? (config.lvtokens[message.channel.server.id] || "") : "";
}

function apiRequest(api, cb, errorcb) {
    request('http://' + config.lvdomain + '/api/' + api, function (error, response, body) {
        let data;
        if (error) {
            if (typeof errorcb === "function") errorcb("an error occurred with the API request");
            console.error('RERROR', error);
        }
        else {
            try {
                data = JSON.parse(body);
            } catch (e) {
                data = null;
                if (typeof errorcb === "function") errorcb("an error occurred parsing the API response");
                console.error('PERROR', e);
            }
            if (data != null && typeof cb === "function") {
                cb(data);
            }
            else if (typeof errorcb === "function") {
                errorcb("no data returned");
            }
        }
    });
}

var commands = {
    help: function (message, words) {
        sendReply(message, "command prefix: " + config.prefix + " - commands: " + Object.keys(commands).join(', '));
    },
    list: function (message, words) {
        let token = getToken(message);
        apiRequest('channels?token=' + token, function (data) {
            let reply = "";
            data.forEach(function (ch) {
                if (reply.length > 1900) {
                    sendReply(message, reply.slice(0, -2));
                    reply = "";
                }
                reply += ch.name + ", ";
            });
            sendReply(message, reply.slice(0, -2));
        }, function (error) {
            sendReply(message, error);
        });
    },
    setdefault: function (message, words) {
        if (message.channel.permissionsOf(message.author).hasPermission('manageChannel')) {
            let default_channel = words[0] || null;
            if (default_channel !== null) {
                channel_defaults[message.channel.id] = default_channel.toLowerCase();
                sendReply(message, "default for this channel set to " + channel_defaults[message.channel.id]);
            } else {
                sendReply(message, "usage: !setdefault [channel name]");
            }
        } else {
            sendReply(message, "shush, you don't have permission to do this!");
        }
    },
    lv: function (message, words) {
        let limit = words[2] || 10;
        let channel = words[1] || channel_defaults[message.channel.id] || "riotgames";
        let user = words[0] || null;

        try {
            limit = Math.min(parseInt(limit), 50);
        } catch (e) {
            sendReply(message, "limit must be a number");
            return;
        }

        console.log("Log request for: `" + JSON.stringify({ user: words[0], channel: channel, limit: limit }) + "`");

        if (user === null) {
            sendReply(message, "usage: " + config.prefix + "lv <user> [channel] [limit]");
            return;
        }

        let token = getToken(message);

        apiRequest('logs/' + encodeURIComponent(channel) + "/?token=" + token
                + "&nick=" + encodeURIComponent(user) + "&before=" + limit,
        function (data) {
            if (data.before) {
                reply = "here are logs for **" + user + "** from **" + channel + "**\n\n```";
                for (let i = data.before.length - 1; i >= 0; --i) {
                    let index = data.before.length - 1 - i;
                    let ircmsg = parseIrc(data.before[index].text);
                    let line = "\n" + (new Date(data.before[index].time * 1000)).toISOString().replace('T', ' ').replace('.000', '').replace('Z', ' UTC')
                        + " | " + ircmsg.params[1];
                    if (reply.length + line.length > 1900) {
                        reply += "\n```";
                        sendReply(message, reply);
                        reply = "\n```";
                    }
                    reply += line;
                }
                reply += "\n```";
            }
            else {
                reply = "no data found.";
            }
            reply += '\nSee http://' + config.lvpublicdomain + '/' + encodeURIComponent(channel) + "/?user=" + encodeURIComponent(user);
            sendReply(message, reply);
        }, function (error) {
            sendReply(message, error);
        });
    },
    game: function (message, words) {
        let game = words.join(' ') || "with butts";
        client.setStatus('online', game);
    },
    invite: function(message, words) {
        sendReply(message, invitelink);
    }
};

function sendReply(message, reply) {
    client.reply(message, reply, { tts: false }, function (error) {
        if (error) {
            console.error('WERROR', error);
        }
    });
}

process.on('SIGINT', function () {
    var exit_tasks_done = 0;
    var exit_tasks_total = 2;
    function exitTaskCheck() {
        if (++exit_tasks_done >= exit_tasks_total) {
            process.exit();
        }
    }
    console.log("Logging out and saving data...");
    client.logout(exitTaskCheck);
    saveDefaults(exitTaskCheck);
});

function saveDefaults(cb) {
    fs.access(defaults_file, fs.W_OK, (err) => {
        if (err) {
            console.error("No access to write", defaults_file);
            cb();
        } else {
            fs.writeFile(defaults_file, JSON.stringify(channel_defaults), (err) => {
                if (err) {
                    console.error("Write error", defaults_file);
                }
                cb();
            });
        }
    });
}

// Load defaults
fs.access(defaults_file, fs.R_OK, (err) => {
    if (err) {
        console.error("No access", defaults_file);
        saveDefaults(function () {});
    } else {
        fs.readFile(defaults_file, (err, data) => {
            if (err) {
                console.error("Read error", defaults_file, err);
            } else {
                try {
                    channel_defaults = JSON.parse(data);
                } catch (e) {
                    console.error("JSON error", e);
                }
            }
        });
    }
});
<|endoftext|>


<commit_before>define(function(require) {
  var FILE_SYSTEM_NAME = require('src/constants').FILE_SYSTEM_NAME;
  var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
  var u8toArray = require('src/shared').u8toArray;
  var Errors = require('src/errors');

  function XHRContext(db, isReadOnly) {
    this.isReadOnly = isReadOnly;
  }
  XHRContext.prototype.clear = function(callback) {
    // TODO: do we want to support clear?
    callback(new Error('clear is not supported on XHRContext'));
  };
  XHRContext.prototype.get = function(key, callback) {
    var request = new XMLHttpRequest();
    request.addEventListener("load", function() {
      var data = new Uint8Array(request.response);
      fs.writeFile(path, data, function(err) {
        if(err) {
          callback(err);
        } else {
          callback(null, path);
        }
      });
    }, false);
    request.addEventListener("error", function(err) { callback(err); }, false);
    request.open("GET", url);
    request.responseType = "arraybuffer";
    request.send();

    function onSuccess(transaction, result) {
      // If the key isn't found, return null
      var value = result.rows.length === 0 ? null : result.rows.item(0).data;
      try {
        if(value) {
          value = JSON.parse(value);
          // Deal with special-cased flattened typed arrays in WebSQL (see put() below)
          if(value.__isUint8Array) {
            value = new Uint8Array(value.__array);
          }
        }
        callback(null, value);
      } catch(e) {
        callback(e);
      }
    }
    function onError(transaction, error) {
      callback(error);
    }
    this.getTransaction(function(transaction) {
      transaction.executeSql("SELECT data FROM " + FILE_STORE_NAME + " WHERE id = ?;",
                             [key], onSuccess, onError);
    });
  };
  XHRContext.prototype.put = function(key, value, callback) {
    // We do extra work to make sure typed arrays survive
    // being stored in the db and still get the right prototype later.
    if(Object.prototype.toString.call(value) === "[object Uint8Array]") {
      value = {
        __isUint8Array: true,
        __array: u8toArray(value)
      };
    }
    value = JSON.stringify(value);
    function onSuccess(transaction, result) {
      callback(null);
    }
    function onError(transaction, error) {
      callback(error);
    }
    this.getTransaction(function(transaction) {
      transaction.executeSql("INSERT OR REPLACE INTO " + FILE_STORE_NAME + " (id, data) VALUES (?, ?);",
                             [key, value], onSuccess, onError);
    });
  };
  WebSQLContext.prototype.delete = function(key, callback) {
    function onSuccess(transaction, result) {
      callback(null);
    }
    function onError(transaction, error) {
      callback(error);
    }
    this.getTransaction(function(transaction) {
      transaction.executeSql("DELETE FROM " + FILE_STORE_NAME + " WHERE id = ?;",
                             [key], onSuccess, onError);
    });
  };

  function XHR() {
  }
  XHR.isSupported = function() {
    return !!window.XMLHttpRequest;
  };

  XHR.prototype.open = function(callback) {
    var that = this;

    // TODO: Webmaker user auth/verify...
  };
  XHR.prototype.getReadOnlyContext = function() {
    return new XHRContext(this.db, true);
  };
  XHR.prototype.getReadWriteContext = function() {
    return new XHRContext(this.db, false);
  };

  return XHR;
});
<commit_msg>Delete xhr-provider.js<commit_after><|endoftext|>


<commit_before>/** Class implementing the table. */
class Table {
    /**
     * Creates a Table Object
     */
    constructor(teamData, treeObject) {

        //Maintain reference to the tree Object;
        this.tree = treeObject;

        // Create list of all elements that will populate the table
        // Initially, the tableElements will be identical to the teamData
        this.tableElements = teamData.slice(); //

        ///** Store all match data for the 2014 Fifa cup */
        this.teamData = teamData;

        //Default values for the Table Headers
        this.tableHeaders = ["Delta Goals", "Result", "Wins", "Losses", "TotalGames"];

        /** To be used when sizing the svgs in the table cells.*/
        this.cell = {
            "width": 70,
            "height": 20,
            "buffer": 15
        };

        this.bar = {
            "height": 20
        };

        /** Set variables for commonly accessed data columns*/
        this.goalsMadeHeader = 'Goals Made';
        this.goalsConcededHeader = 'Goals Conceded';

        let goals = [];
        goals.push(d3.max(this.tableElements, d => d.value[this.goalsConcededHeader]));
        goals.push(d3.max(this.tableElements, d => d.value[this.goalsMadeHeader]));

        /** Setup the scales*/
        this.goalScale = d3.scaleLinear()
            .domain([0, d3.max(goals, d => d)])
            //.range([this.cell.buffer, this.cell.width * 2 - this.cell.buffer]);
            .range([this.cell.buffer, this.cell.width * 2]);

        /** Used for games/wins/losses*/
        this.gameScale = null;

        /**Color scales*/
        let colorMax = [];
        colorMax.push(d3.max(this.tableElements, d => d.value["Wins"]));
        colorMax.push(d3.max(this.tableElements, d => d.value["Losses"]));
        colorMax.push(d3.max(this.tableElements, d => d.value["Result"].ranking));

        /**For aggregate columns  Use colors '#ece2f0', '#016450' for the range.*/
        this.aggregateColorScale = d3.scaleLinear()
            .range([
                "#ece2f0",
                '#016450'
            ])
            .domain([0, d3.max(colorMax, d => d)]);

        /**For goal Column. Use colors '#cb181d', '#034e7b'  for the range.*/

        this.deltaMin = d3.min(this.tableElements, d => d.value["Delta Goals"]);
        this.deltaMax = d3.max(this.tableElements, d => d.value["Delta Goals"]);

        this.goalColorScale = d3.scaleLinear()
        //.domain([d3.min(goals, d => d), 0, d3.max(goals, d => d)])
            .domain([this.deltaMin, 0, this.deltaMax])
            .range(["#cb181d", "lightgray", "#034e7b"]);
    }

    /**
     * Creates a table skeleton including headers that when clicked allow you to sort the table by the chosen attribute.
     * Also calculates aggregate values of goals, wins, losses and total games as a function of country.
     *
     */
    createTable() {

        // ******* TODO: PART II *******

        //Update Scale Domains

        // Create the x axes for the goalScale.

        this.Xaxis("#goalHeader", "none", this.cell.width, this.cell.height, "none");

        //add GoalAxis to header of col 1.

        // ******* TODO: PART V *******

        // Set sorting callback for clicking on headers

        // Clicking on headers should also trigger collapseList() and updateTable().

    }

    /**
     * Updates the table contents with a row for each element in the global variable tableElements.
     */
    updateTable() {
        // ******* TODO: PART III *******
        //Create table rows
        let tr = d3.select("tbody").selectAll("tr")
            .data(this.tableElements);

        tr.exit().remove();

        let newTr = tr.enter()
            .append("tr");

        tr = newTr.merge(tr);

        //Append th elements for the Team Names
        this.populateTeamCells(tr);

        //Append td elements for the remaining columns.
        //Data for each cell is of the type: {'type':<'game' or 'aggregate'>, 'value':<[array of 1 or two elements]>}
        let goalsMadeHeader = 'Goals Made';
        let goalsConcededHeader = 'Goals Conceded';

        let td = tr.selectAll("td").data(function (d) {
            /* create data array here */
            console.log(d);
            let res = [
                //{'type': d.value['aggregate'], 'vis': 'text', 'value': d.key},
                {
                    'type': d.value['type'],
                    'vis': 'goals',
                    'value': [d.value[goalsMadeHeader], d.value[goalsConcededHeader], d.value["Delta Goals"]]
                },
                {'type': d.value['type'], 'vis': 'text', 'value': [d.value["Result"].label]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["Wins"]]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["Losses"]]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["TotalGames"]]}
            ];
            return res;
        });

        td.exit().remove();

        let newTd = td.enter().append('td');
        td = newTd.merge(td);

        //Add scores as title property to appear on hover
        //Populate cells (do one type of cell at a time )
        this.populateAggregateCells(td);

        //Create diagrams in the goals column
        //Set the color of all games that tied to light gray
        this.goalsDiagram(td);
    };

    /**
     * Updates the global tableElements variable, with a row for each row to be rendered in the table.
     *
     */
    updateList(i) {
        // ******* TODO: PART IV *******

        //Only update list for aggregate clicks, not game clicks
        console.log(this.tableElements[i]);

        let games = this.tableElements[i].value["games"].slice();
        for (let j = 1; j < games.length; j++) {
            let game = games[j];
            game.key = "x" + game.key;
            this.tableElements.splice(i + j, 0, game);
        }
        this.updateTable();
    }

    /**
     * Collapses all expanded countries, leaving only rows for aggregate values per country.
     *
     */
    collapseList() {

        // ******* TODO: PART IV *******

    }

    Xaxis(idName, dataName, width, height, data, scale) {
        let svg = d3.select(idName)
            .append("svg")
            .attr("width", width * 2 + 20)
            .attr("height", height);

        let xAxis = d3.axisBottom();
        xAxis.scale(this.goalScale);

        // css class for the axis
        svg.classed("axis", true)
            .attr("transform", "translate(" + 0 + "," + 0 + ")")
            .call(xAxis);
    }

    goalsDiagram(td) {
        let goalTd = td.filter(function (d) {
            return d.vis === "goals" && d.type === "game";
        });

        let goals = goalTd.selectAll("svg")
            .data(function (d) {
                return [d];
            });

        goals.exit().remove();
        goals = goals.enter();

        goals = goals.append("svg").merge(goals);

        goals.attr("width", this.cell.width * 2 + 20)
            .attr("height", this.cell.height + 5);

        this.drawTeamGoalVis(goals);

        /********** For game **************/
        let goalGameTd = td.filter(function (d) {
            return d.vis === "goals" && d.type === "aggregate";
        });

        let goals2 = goalGameTd.selectAll("svg")
            .data(function (d) {
                return [d];
            });

        goals2.exit().remove();
        goals2 = goals2.enter();

        goals2 = goals2.append("svg").merge(goals2);

        goals2.attr("width", this.cell.width * 2 + 20)
            .attr("height", this.cell.height + 5);

        this.drawGameGoalVis(goals2);
    }

    drawTeamGoalVis(goals) {
        let goalScale = this.goalScale;
        let goalColorScale = this.goalColorScale;

        let deltaMin = this.deltaMin;
        let deltaMax = this.deltaMax;

        this.drawDeltaGoals(goals, goalScale, goalColorScale, "aggregate");

        this.drawTeamGoalsMade(goals, goalScale, goalColorScale, deltaMax);
        this.drawTeamGamesConsided(goals, goalScale, goalColorScale, deltaMin);

    }

    drawGameGoalVis(goals) {
        let goalScale = this.goalScale;
        let goalColorScale = this.goalColorScale;

        let deltaMin = this.deltaMin;
        let deltaMax = this.deltaMax;

        this.drawDeltaGoals(goals, goalScale, goalColorScale, "game");

        this.drawGameGoalsMade(goals, goalScale, goalColorScale, deltaMax);
        this.drawGameGoalsCon(goals, goalScale, goalColorScale, deltaMin);
    }

    drawGameGoalsMade(goals, goalScale, goalColorScale, deltaMax) {
        this.drawGame(goals, goalScale, goalColorScale, deltaMax, "made");
    }

    drawGameGoalsCon(goals, goalScale, goalColorScale, deltaMin) {
        this.drawGame(goals, goalScale, goalColorScale, deltaMin, "con");
    }

    drawGame(goals, goalScale, goalColorScale, deltaMin, type) {
        let height = 20;
        let width = 20;
        let y = 0;

        let pie = d3.pie();

        pie.value(function (d) {
            return 10;
        });

        let pieData = pie([100]);
        let arc = d3.arc();

        arc.outerRadius(5);
        arc.innerRadius(3);

        let groupArea = goals
            .append("g")
            .attr("height", height)
            .attr("width", function (d) {
                return goalScale(Math.abs(d.value[2])) - 15;
            })
            .attr("x", function (d) {
                return goalScale(d.value[0]);
            })
            .attr("y", function (d) {
                return 5;
            })
            .attr("transform", function (d) {
                let value = d.value[1];
                if (type === "made") {
                    value = d.value[0];
                }
                return ("translate(" + goalScale(value) + "," + 5 + ")");
            });

        let groups = groupArea.selectAll("g")
            .data(function (d) {
                return pie([d]);
            })
            .enter()
            .append("g")
            .attr("x", function (d) {
                return 0;
            })
            .attr("y", function (d) {
                return 0;
            })
            .style("fill", function (d) {
                //return goalColorScale(d.data.value[2]);
                let value = d.value[1];
                if (type === "made") {
                    value = d.value[0];
                }
                return value === 0 ? goalColorScale(0) : goalColorScale(deltaMin);
            });
        groups.append("path")
            .attr("d", arc);
    }

    populateAggregateCells(td) {
        let barTd = td.filter(function (d) {
            return d.vis === 'bar' && d.type === "aggregate";
        });

        let bars = barTd.selectAll("svg")
            .data(function (d) {
                return [d];
            });

        bars.exit().remove();
        bars = bars.enter();

        bars = bars.append("svg").merge(bars);

        bars.attr("width", this.cell.width + 20)
            .attr("height", this.cell.height + 5);

        let colorScale = this.aggregateColorScale;

        let rect = bars.selectAll("rect")
            .data(function (d) {
                return [d];
            });

        rect.exit().remove();

        rect = rect
            .enter()
            .append("rect")
            .merge(rect);

        rect.attr("height", 20)
            .attr("width", function (d) {
                return d.value[0] * 10;
            })
            .style("fill", function (d) {
                return colorScale(d.value[0]);
            });

        let text = bars.selectAll("text")
            .data(function (d) {
                return [d];
            });

        text.exit().remove();

        text = text.enter().append("text").merge(text);

        text.text(function (d) {
            return d.value[0];
        })
            .attr("transform", function (d) {
                return "translate(" + (d.value[0] * 10 - 5) + "," + 10 + ")";
            })
            .attr("dy", ".35em")
            .style("fill", "white")
            .style("text-anchor", "middle")
            .style("font-size", "10px");

        // Population of text cells
        this.populateTextCells(td);
    }

    drawDeltaGoals(goals, goalScale, goalColorScale, type) {
        let height = 20;
        let y = 0;
        if (type === "game") {
            height = 3;
            y = 3;
        }
        let deltaGoals = goals.append("rect")
            .attr("height", height)
            .attr("width", function (d) {
                return goalScale(Math.abs(d.value[2])) - 15;
                //return goalScale(Math.abs(d.value[2])) - 15;
            })
            .attr("x", function (d) {
                return goalScale(d3.min([d.value[0], d.value[1]])) + 3;
            })
            .attr("y", function (d) {
                return y;
            })
            .style("fill", function (d) {
                return goalColorScale(d.value[2]);
            });
    }

    drawTeamGoalsMade(goals, goalScale, goalColorScale, deltaMax) {
        let goalsMade = goals.append("circle")
            .attr("cx", function (d) {
                return goalScale(d.value[0]);
            })
            .attr("cy", function (d) {
                return 5;
            })
            .attr("r", function (d) {
                return 5;
            })
            .attr("title", function (d) {
                return d.value[0];
            })
            .style("fill", function (d) {

                return d.value[2] === 0 ? goalColorScale(0) : goalColorScale(deltaMax);
            });
    }

    drawTeamGamesConsided(goals, goalScale, goalColorScale, deltaMin) {
        let goalsCon = goals.append("circle")
            .attr("cx", function (d) {
                return goalScale(d.value[1]);
            })
            .attr("cy", function (d) {
                return 5;
            })
            .attr("r", function (d) {
                return 5;
            })
            .attr("title", function (d) {
                return d.value[1];
            })
            .style("fill", function (d) {
                return d.value[2] === 0 ? goalColorScale(0) : goalColorScale(deltaMin);
            });
    }

    populateTextCells(td) {
        let text = td.filter(function (d) {
            return d.vis === 'text';
        });

        text.exit().remove();

        text = text.enter().append("text").merge(text);

        text.text(function (d) {
            return d.value;
        });
    }

    populateTeamCells(tr) {

        let table = this;
        let th = tr.selectAll("th").data(function (d, i) {
            //console.log("i " + i);
            return [[d, i]];
        });

        th.exit().remove();

        th = th.enter()
            .append("th")
            .merge(th);

        th.text(function (d) {
            return d[0].key;
        }).on("click", function (d) {
            table.updateList(d[1]);
        })

    }
}
<commit_msg>Got the ring and circle to be displaying in one method<commit_after>/** Class implementing the table. */
class Table {
    /**
     * Creates a Table Object
     */
    constructor(teamData, treeObject) {

        //Maintain reference to the tree Object;
        this.tree = treeObject;

        // Create list of all elements that will populate the table
        // Initially, the tableElements will be identical to the teamData
        this.tableElements = teamData.slice(); //

        ///** Store all match data for the 2014 Fifa cup */
        this.teamData = teamData;

        //Default values for the Table Headers
        this.tableHeaders = ["Delta Goals", "Result", "Wins", "Losses", "TotalGames"];

        /** To be used when sizing the svgs in the table cells.*/
        this.cell = {
            "width": 70,
            "height": 20,
            "buffer": 15
        };

        this.bar = {
            "height": 20
        };

        /** Set variables for commonly accessed data columns*/
        this.goalsMadeHeader = 'Goals Made';
        this.goalsConcededHeader = 'Goals Conceded';

        let goals = [];
        goals.push(d3.max(this.tableElements, d => d.value[this.goalsConcededHeader]));
        goals.push(d3.max(this.tableElements, d => d.value[this.goalsMadeHeader]));

        /** Setup the scales*/
        this.goalScale = d3.scaleLinear()
            .domain([0, d3.max(goals, d => d)])
            //.range([this.cell.buffer, this.cell.width * 2 - this.cell.buffer]);
            .range([this.cell.buffer, this.cell.width * 2]);

        /** Used for games/wins/losses*/
        this.gameScale = null;

        /**Color scales*/
        let colorMax = [];
        colorMax.push(d3.max(this.tableElements, d => d.value["Wins"]));
        colorMax.push(d3.max(this.tableElements, d => d.value["Losses"]));
        colorMax.push(d3.max(this.tableElements, d => d.value["Result"].ranking));

        /**For aggregate columns  Use colors '#ece2f0', '#016450' for the range.*/
        this.aggregateColorScale = d3.scaleLinear()
            .range([
                "#ece2f0",
                '#016450'
            ])
            .domain([0, d3.max(colorMax, d => d)]);

        /**For goal Column. Use colors '#cb181d', '#034e7b'  for the range.*/

        this.deltaMin = d3.min(this.tableElements, d => d.value["Delta Goals"]);
        this.deltaMax = d3.max(this.tableElements, d => d.value["Delta Goals"]);

        this.goalColorScale = d3.scaleLinear()
        //.domain([d3.min(goals, d => d), 0, d3.max(goals, d => d)])
            .domain([this.deltaMin, 0, this.deltaMax])
            .range(["#cb181d", "lightgray", "#034e7b"]);
    }

    /**
     * Creates a table skeleton including headers that when clicked allow you to sort the table by the chosen attribute.
     * Also calculates aggregate values of goals, wins, losses and total games as a function of country.
     *
     */
    createTable() {

        // ******* TODO: PART II *******

        //Update Scale Domains

        // Create the x axes for the goalScale.

        this.Xaxis("#goalHeader", "none", this.cell.width, this.cell.height, "none");

        //add GoalAxis to header of col 1.

        // ******* TODO: PART V *******

        // Set sorting callback for clicking on headers

        // Clicking on headers should also trigger collapseList() and updateTable().

    }

    /**
     * Updates the table contents with a row for each element in the global variable tableElements.
     */
    updateTable() {
        // ******* TODO: PART III *******
        //Create table rows
        let tr = d3.select("tbody").selectAll("tr")
            .data(this.tableElements);

        tr.exit().remove();

        let newTr = tr.enter()
            .append("tr");

        tr = newTr.merge(tr);

        //Append th elements for the Team Names
        this.populateTeamCells(tr);

        //Append td elements for the remaining columns.
        //Data for each cell is of the type: {'type':<'game' or 'aggregate'>, 'value':<[array of 1 or two elements]>}
        let goalsMadeHeader = 'Goals Made';
        let goalsConcededHeader = 'Goals Conceded';

        let td = tr.selectAll("td").data(function (d) {
            /* create data array here */
            console.log(d);
            let res = [
                //{'type': d.value['aggregate'], 'vis': 'text', 'value': d.key},
                {
                    'type': d.value['type'],
                    'vis': 'goals',
                    'value': [d.value[goalsMadeHeader], d.value[goalsConcededHeader], d.value["Delta Goals"]]
                },
                {'type': d.value['type'], 'vis': 'text', 'value': [d.value["Result"].label]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["Wins"]]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["Losses"]]},
                {'type': d.value['type'], 'vis': 'bar', 'value': [d.value["TotalGames"]]}
            ];
            return res;
        });

        td.exit().remove();

        let newTd = td.enter().append('td');
        td = newTd.merge(td);

        //Add scores as title property to appear on hover
        //Populate cells (do one type of cell at a time )
        this.populateAggregateCells(td);

        //Create diagrams in the goals column
        //Set the color of all games that tied to light gray
        this.goalsDiagram(td);
    };

    /**
     * Updates the global tableElements variable, with a row for each row to be rendered in the table.
     *
     */
    updateList(i) {
        // ******* TODO: PART IV *******

        //Only update list for aggregate clicks, not game clicks
        console.log(this.tableElements[i]);

        let games = this.tableElements[i].value["games"].slice();
        for (let j = 1; j < games.length; j++) {
            let game = games[j];
            game.key = "x" + game.key;
            this.tableElements.splice(i + j, 0, game);
        }
        this.updateTable();
    }

    /**
     * Collapses all expanded countries, leaving only rows for aggregate values per country.
     *
     */
    collapseList() {

        // ******* TODO: PART IV *******

    }

    Xaxis(idName, dataName, width, height, data, scale) {
        let svg = d3.select(idName)
            .append("svg")
            .attr("width", width * 2 + 20)
            .attr("height", height);

        let xAxis = d3.axisBottom();
        xAxis.scale(this.goalScale);

        // css class for the axis
        svg.classed("axis", true)
            .attr("transform", "translate(" + 0 + "," + 0 + ")")
            .call(xAxis);
    }

    goalsDiagram(td) {

        let allGoals = td.filter(function (d) {
            return d.vis === "goals";
        });

        let goalsTeam = allGoals.selectAll("svg")
            .data(function (d) {
                return [d];
            });

        /********** For Team **************/
        goalsTeam.exit().remove();
        goalsTeam = goalsTeam.enter();

        goalsTeam = goalsTeam.append("svg").merge(goalsTeam);

        goalsTeam.attr("width", this.cell.width * 2 + 20)
            .attr("height", this.cell.height + 5);

        this.drawGameGoalVis(goalsTeam);

    }

    drawTeamGoalVis(goals) {
        let goalScale = this.goalScale;
        let goalColorScale = this.goalColorScale;

        let deltaMin = this.deltaMin;
        let deltaMax = this.deltaMax;

        this.drawDeltaGoals(goals, goalScale, goalColorScale, "aggregate");

        this.drawTeamGoalsMade(goals, goalScale, goalColorScale, deltaMax);
        this.drawTeamGamesConsided(goals, goalScale, goalColorScale, deltaMin);

    }

    drawGameGoalVis(goals) {
        let goalScale = this.goalScale;
        let goalColorScale = this.goalColorScale;

        let deltaMin = this.deltaMin;
        let deltaMax = this.deltaMax;

        this.drawDeltaGoals(goals, goalScale, goalColorScale, "game");

        this.drawGameGoalsMade(goals, goalScale, goalColorScale, deltaMax);
        this.drawGameGoalsCon(goals, goalScale, goalColorScale, deltaMin);
    }

    drawGameGoalsMade(goals, goalScale, goalColorScale, deltaMax) {
        this.drawGame(goals, goalScale, goalColorScale, deltaMax, "made");
    }

    drawGameGoalsCon(goals, goalScale, goalColorScale, deltaMin) {
        this.drawGame(goals, goalScale, goalColorScale, deltaMin, "con");
    }

    drawGame(goals, goalScale, goalColorScale, deltaMin, type) {
        let height = 20;
        let width = 20;
        let y = 0;

        let pie = d3.pie();

        pie.value(function (d) {
            return 10;
        });

        let pieData = pie([100]);
        let arc = d3.arc();

        arc.outerRadius(5);
        arc.innerRadius(3);

        let groupArea = goals
            .append("g")
            .attr("height", height)
            .attr("width", function (d) {
                return goalScale(Math.abs(d.value[2])) - 15;
            })
            .attr("x", function (d) {
                return goalScale(d.value[0]);
            })
            .attr("y", function (d) {
                return 5;
            })
            .attr("transform", function (d) {
                let value = d.value[1];
                if (type === "made") {
                    value = d.value[0];
                }
                return ("translate(" + goalScale(value) + "," + 5 + ")");
            });

        let groups = groupArea.selectAll("g")
            .data(function (d) {

                return pie([d]);
            })
            .enter()
            .append("g")
            .attr("x", function (d) {
                return 0;
            })
            .attr("y", function (d) {
                return 0;
            })
            .style("fill", function (d) {
                //return goalColorScale(d.data.value[2]);
                let value = d.value[1];
                if (type === "made") {
                    value = d.value[0];
                }
                return value === 0 ? goalColorScale(0) : goalColorScale(deltaMin);
            });

        groups.append("path")
            .attr("d", d3.arc()
                .outerRadius(5)
                .innerRadius(function (d) {
                    if (d.data["type"] === "aggregate") {
                        return 0;
                    }
                    return 3;
                }));
    }

    populateAggregateCells(td) {
        let barTd = td.filter(function (d) {
            return d.vis === 'bar' && d.type === "aggregate";
        });

        let bars = barTd.selectAll("svg")
            .data(function (d) {
                return [d];
            });

        bars.exit().remove();
        bars = bars.enter();

        bars = bars.append("svg").merge(bars);

        bars.attr("width", this.cell.width + 20)
            .attr("height", this.cell.height + 5);

        let colorScale = this.aggregateColorScale;

        let rect = bars.selectAll("rect")
            .data(function (d) {
                return [d];
            });

        rect.exit().remove();

        rect = rect
            .enter()
            .append("rect")
            .merge(rect);

        rect.attr("height", 20)
            .attr("width", function (d) {
                return d.value[0] * 10;
            })
            .style("fill", function (d) {
                return colorScale(d.value[0]);
            });

        let text = bars.selectAll("text")
            .data(function (d) {
                return [d];
            });

        text.exit().remove();

        text = text.enter().append("text").merge(text);

        text.text(function (d) {
            return d.value[0];
        })
            .attr("transform", function (d) {
                return "translate(" + (d.value[0] * 10 - 5) + "," + 10 + ")";
            })
            .attr("dy", ".35em")
            .style("fill", "white")
            .style("text-anchor", "middle")
            .style("font-size", "10px");

        // Population of text cells
        this.populateTextCells(td);
    }

    drawDeltaGoals(goals, goalScale, goalColorScale, type) {

        let deltaGoals = goals.append("rect")
            .attr("height", function (d) {
                if (d.value["type"] === "game") {
                    return 3;
                }
                return 10;
            })
            .attr("width", function (d) {
                //return goalScale(Math.abs(d.value[2])) - 15 - 6;
                return goalScale(Math.abs(d.value[2])) - 15;
            })
            .attr("x", function (d) {
                return goalScale(d3.min([d.value[0], d.value[1]])) + 3;
            })
            .attr("y", function (d) {
                if (d.value["type"] === "game") {
                    return 3;
                }
                return 0;
            })
            .style("fill", function (d) {
                return goalColorScale(d.value[2]);
            });
    }

    drawTeamGoalsMade(goals, goalScale, goalColorScale, deltaMax) {
        let goalsMade = goals.append("circle")
            .attr("cx", function (d) {
                return goalScale(d.value[0]);
            })
            .attr("cy", function (d) {
                return 5;
            })
            .attr("r", function (d) {
                return 5;
            })
            .attr("title", function (d) {
                return d.value[0];
            })
            .style("fill", function (d) {

                return d.value[2] === 0 ? goalColorScale(0) : goalColorScale(deltaMax);
            });
    }

    drawTeamGamesConsided(goals, goalScale, goalColorScale, deltaMin) {
        let goalsCon = goals.append("circle")
            .attr("cx", function (d) {
                return goalScale(d.value[1]);
            })
            .attr("cy", function (d) {
                return 5;
            })
            .attr("r", function (d) {
                return 5;
            })
            .attr("title", function (d) {
                return d.value[1];
            })
            .style("fill", function (d) {
                return d.value[2] === 0 ? goalColorScale(0) : goalColorScale(deltaMin);
            });
    }

    populateTextCells(td) {
        let text = td.filter(function (d) {
            return d.vis === 'text';
        });

        text.exit().remove();

        text = text.enter().append("text").merge(text);

        text.text(function (d) {
            return d.value;
        });
    }

    populateTeamCells(tr) {

        let table = this;
        let th = tr.selectAll("th").data(function (d, i) {
            //console.log("i " + i);
            return [[d, i]];
        });

        th.exit().remove();

        th = th.enter()
            .append("th")
            .merge(th);

        th.text(function (d) {
            return d[0].key;
        }).on("click", function (d) {
            table.updateList(d[1]);
        })

    }
}
<|endoftext|>


<commit_before>/*
Title:			BrianCh.uk Home Screen Javascript ThreeJS Animation v1
Author:			Brian Chuk (brianch.uk)
Copyright: 		2015, Brian Chuk - All rights reserved (you have permission to use it, just tell me :D)
*/
// Creating the scene
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );

// Interacting with the HTML
var $container = $('#canvas');
$container.append(renderer.domElement);

// Creating objects
var geometry = new THREE.BoxGeometry( 0, 0, 0 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
cube.rotation.x += 0.1;
scene.add( cube );

camera.position.z = 5;

// Window resize settings
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
}

var move = 0.01;
var count = 1;
var rotationswag = 0;

// Rendering the scene
function render() {
	count++;
	if (count % 10 == 0) {
		var geometryy = new THREE.BoxGeometry( 1, 1, 1 );
		var materiall = new THREE.MeshBasicMaterial( { color: 0x6699ff } );
		var cubey = new THREE.Mesh( geometryy, materiall );
		scene.add( cubey );
		cubey.position.x = cube.position.x;
		rotationswag += 0.1;
		cubey.rotation.x += rotationswag;
		console.log(count);
		renderer.render( scene, camera );
	}
	requestAnimationFrame( render );
	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;
	cube.position.x += move;
	if (cube.position.x >= 3 || cube.position.x <= -3)
		move *= -1;
	renderer.render( scene, camera );
}
render();<commit_msg>learned destruction<commit_after>/*
Title:			BrianCh.uk Home Screen Javascript ThreeJS Animation v1
Author:			Brian Chuk (brianch.uk)
Copyright: 		2015, Brian Chuk - All rights reserved (you have permission to use it, just tell me :D)
*/
// Creating the scene
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );

// Interacting with the HTML
var $container = $('#canvas');
$container.append(renderer.domElement);

// Creating objects
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
cube.rotation.x += 0.1;
scene.add( cube );

camera.position.z = 5;

// Window resize settings
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
}

var move = 0.01;
var count = 1;
var rotationswag = 0;

// Rendering the scene
function render() {
	count++;
	if (count % 10 == 0) {
		var geometryy = new THREE.BoxGeometry( 1, 1, 1 );
		var materiall = new THREE.MeshBasicMaterial( { color: 0x6699ff } );
		var cubey = new THREE.Mesh( geometryy, materiall );
		scene.add( cubey );
		cubey.position.x = cube.position.x;
		rotationswag += 0.01;
		cubey.rotation.x += rotationswag;
		console.log(count);
		renderer.render( scene, camera );
	}
	console.log(count);
	if (count > 1000)
		scene.remove(cube);
	requestAnimationFrame( render );
	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;
	cube.position.x += move;
	if (cube.position.x >= 3 || cube.position.x <= -3)
		move *= -1;
	renderer.render( scene, camera );
}
render();<|endoftext|>


<commit_before>'use strict';

const { shell, BrowserWindow, BrowserView } = require('electron');
const { isDevelopment } = require('./constants');

// Keep reference to IPC
let mainWindow;

function handleOpenURL(url) {
  if (mainWindow) {
    mainWindow.webContents.send('handleOpenURL', url);
  }
}

function openWindow(deeplink) {
  if (BrowserWindow.getAllWindows().length === 0) {
    // Create the browser window.
    mainWindow = new BrowserWindow({
      width: 500,
      height: 700,
      minWidth: 500,
      minHeight: 700,
      webPreferences: {
        devTools: isDevelopment,
        nodeIntegration: true,
      },
    });

    mainWindow.loadFile('./app/index.html');

    // Catch all attempts to open new window and open them in default browser
    mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options) => {
      event.preventDefault();
      if (frameName === '_modal') {
        const [mainWindowWidth, mainWindowHeight] = mainWindow.getSize();
        Object.assign(options, {
          webPreferences: {
            sandbox: true,
          },
        });
        const modal = new BrowserView(options);
        // https://github.com/electron/electron/issues/24833
        //event.newGuest = modal;
        mainWindow.setBrowserView(modal);
        // fix options in constructor
        modal.setBounds({
          x: 0,
          y: 0,
          width: mainWindowWidth,
          height: mainWindowHeight,
        });
        modal.setAutoResize({
          width: true,
          height: true,
          horizontal: true,
          vertical: true,
        });
        // fix transparent background
        modal.setBackgroundColor('#fff');
        modal.webContents.loadURL(url);
        return;
      }
      shell.openExternal(url);
    });
  } else {
    if (mainWindow.isMinimized()) {
      mainWindow.restore();
    }
    mainWindow.show();
  }

  for (const child of mainWindow.getChildWindows()) {
    // Close modals
    child.close();
  }

  for (const view of mainWindow.getBrowserViews()) {
    mainWindow.removeBrowserView(view);
    view.destroy();
  }

  if (deeplink) {
    handleOpenURL(deeplink);
  }
}

module.exports = openWindow;
<commit_msg>fix(electron): open on windows<commit_after>'use strict';

const { shell, BrowserWindow, BrowserView } = require('electron');
const { isDevelopment } = require('./constants');

// Keep reference to IPC
let mainWindow;

function handleOpenURL(url) {
  if (mainWindow) {
    mainWindow.webContents.send('handleOpenURL', url);
  }
}

function openWindow(deeplink) {
  if (BrowserWindow.getAllWindows().length === 0) {
    // Create the browser window.
    mainWindow = new BrowserWindow({
      width: 500,
      height: 700,
      minWidth: 500,
      minHeight: 700,
      webPreferences: {
        devTools: isDevelopment,
        nodeIntegration: true,
      },
    });

    mainWindow.loadFile('./app/index.html');

    // Catch all attempts to open new window and open them in default browser
    mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options) => {
      event.preventDefault();
      if (frameName === '_modal') {
        const [mainWindowWidth, mainWindowHeight] = mainWindow.getSize();
        Object.assign(options, {
          webPreferences: {
            sandbox: true,
          },
        });
        const modal = new BrowserView(options);
        // https://github.com/electron/electron/issues/24833
        //event.newGuest = modal;
        mainWindow.setBrowserView(modal);
        // fix options in constructor
        modal.setBounds({
          x: 0,
          y: 0,
          width: mainWindowWidth,
          height: mainWindowHeight,
        });
        modal.setAutoResize({
          width: true,
          height: true,
          horizontal: true,
          vertical: true,
        });
        // fix transparent background
        modal.setBackgroundColor('#fff');
        modal.webContents.loadURL(url);
        return;
      }
      shell.openExternal(url);
    });
  } else {
    if (mainWindow) {
      if (mainWindow.isMinimized()) {
        mainWindow.restore();
      }
      mainWindow.show();

      for (const child of mainWindow.getChildWindows()) {
        // Close modals
        child.close();
      }

      for (const view of mainWindow.getBrowserViews()) {
        mainWindow.removeBrowserView(view);
        view.destroy();
      }
    }
  }

  if (deeplink) {
    handleOpenURL(deeplink);
  }
}

module.exports = openWindow;
<|endoftext|>


<commit_before>/**
 * Provides Form and input features.
 *
 * @module furnace
 * @submodule furnace-forms
 */
import Ember from 'ember';
import Control from './input';
import ControlSupport from 'furnace-forms/mixins/controls/control-support';
import getControl from 'furnace-forms/utils/get-control';

/**
 * Input control component proxy
 *
 * @class Input
 * @namespace Furnace.Forms.Controls
 * @extends Furnace.Forms.Controls.Abstract
 * @protected
 */
export default Control.extend(ControlSupport,{
	_isList : true,

	_decoratorName : 'list',

	_itemControls : null,

	sortProperties: null,

	_currentSortProperties: null,

	sortAscending: true,

	isSorted: Ember.computed.notEmpty('sortProperties'),

//	orderBy:Ember.Enumerable.mixins[0].properties.sortBy,
//	sortFunction:Ember.SortableMixin.mixins[1].properties.sortFunction,

	init : function() {
		this.set('_itemControls',Ember.A());
		this._super();
		if(this.filterBy) {
			this.addObserver('value.[].'+this.filterBy.key,this,this._loadItemControls);
		}
		this._loadItemControls();
	},

	itemControls : Ember.computed('_itemControls,_itemControls.[]',{
		get  : function() {
			if(!this._itemControls) {
				return Ember.A();
			}
			var content = this._itemControls;
			var isSorted = this.get('isSorted');
			if (content && isSorted) {
				return content.sortBy.apply(content,this.sortProperties);
			}

			return content;
		}
	}).readOnly(),

	_sortObserver: Ember.observer('sortProperties',function() {
		if(this._currentSortProperties) {
			this._currentSortProperties.forEach(function(prop) {
				this.removeObserver('value.@each.'+prop,this,this._notifySortChanged);
			},this);
		}
		this._currentSortProperties=this.get('sortProperties');
		if(this._currentSortProperties) {
			this._currentSortProperties.forEach(function(prop) {
				this.addObserver('value.@each.'+prop,this,this._notifySortChanged);
			},this);
		}
	}).on('init'),

	_notifySortChanged() {
		Ember.run.scheduleOnce('sync',this,this.notifyPropertyChange,'_itemControls');
	},

	_loadItemControls : function() {
		var control=this;
		var value=this.get('value');

		var itemControls=this._itemControls;
		var oldControls=itemControls.toArray();

		Ember.assert('List control '+this+' doest not have its itemControl property set. Did you forget to call .item() in your form?',this._itemControl || this._itemControlFn);
		if(this.isDestroying) {
			return;
		}
		if(Ember.Enumerable.detect(value)) {
			var values;
			var _value=value;
			if(this.filter) {
				values=value.filter(this.filter);
			} else if(this.filterBy) {
				values=value.filterBy(this.filterBy.key,this.filterBy.value);
			} else {
				values=value;
			}

			values.forEach(function(value) {
				var index=_value.indexOf(value);
				var _itemControlDef = control._itemControl || control._itemControlFn.call(this,value);
				var oldControl=oldControls ? oldControls.findBy('for',value) : undefined;
				if(oldControl) {
					oldControls.removeObject(oldControl);
				} else {
					var meta=_itemControlDef._meta;
					itemControls.pushObject(getControl.call(control,index,meta,{'for' : null}));
				}

			});
		}
		if(oldControls) {
			oldControls.forEach(function(oldControl) {
				itemControls.removeObject(oldControl);
				oldControl.destroy();
			});
		}
	},

	_valueObserver:function(sender,key) {
		this._cleanControls();
		this._super();
		Ember.run.scheduleOnce('sync',this,this._loadItemControls);
	},

	_reset: function(modelChanged) {
		if(modelChanged) {
			this._cleanControls();
		}
		this._super(modelChanged);
	},

	_cleanControls : function() {
		// Immediately remove controls that are no longer backed by a value:
		// Our child controls won't like it when their property gets yanked
		var toRemove=Ember.A();
		var property=this.get('property');
		if(!property) {
			toRemove=this._itemControls.toArray();
		} else if(property instanceof Ember.RSVP.Promise || Ember.PromiseProxyMixin.detect(property)) {
			//toRemove=this._itemControls.toArray();
		} else {
			this._itemControls.forEach(function(control) {
				if(!property.includes(control.get('for'))) {
					toRemove.pushObject(control);
				}
			});
		}
		toRemove.invoke('destroy');
		this._itemControls.removeObjects(toRemove);
	},

	controls: Ember.computed.union('_controls','_itemControls').readOnly(),

	// We alias the for property for panels and forms
	'_model' : Ember.computed.alias('value'),

	_controlDirtyObserver: Ember.observer('_controls.@each.isDirty,_itemControls.@each.isDirty',function(){
		this._super();
	}),

	_controlValidObserver: Ember.observer('_controls.@each.isValid,_itemControls.@each.isValid',function(){
		this._super();
	}),

	willDestroy : function() {
		var controls=this._itemControls;
		if(controls && controls.length) {
			controls.invoke('willDestroy');
		}
		this._super();
	},

	destroy : function() {
		var controls=this._itemControls;
		if(controls && controls.length) {
			controls.invoke('destroy');
		}
		this._super();
	},

}).reopenClass({
	filter : function(callback) {
		this.reopen({
			filter:callback
		});
		return this;
	},
	filterBy: function(key,value) {
		this.reopen({
			filterBy:{key:key,value:value}
		});
		return this;
	},

	generate : function(mixins,meta,options) {
		options=options || {};
		mixins=mixins || [];
		mixins.push(meta.options);
		var typeKey=this.typeKey;
		var control = this.extend.apply(this,mixins);
		control.typeKey=typeKey;
		return control;
	}
});<commit_msg>Fixed performance issue in list control cleanup<commit_after>/**
 * Provides Form and input features.
 *
 * @module furnace
 * @submodule furnace-forms
 */
import Ember from 'ember';
import Control from './input';
import ControlSupport from 'furnace-forms/mixins/controls/control-support';
import getControl from 'furnace-forms/utils/get-control';

/**
 * Input control component proxy
 *
 * @class Input
 * @namespace Furnace.Forms.Controls
 * @extends Furnace.Forms.Controls.Abstract
 * @protected
 */
export default Control.extend(ControlSupport,{
	_isList : true,

	_decoratorName : 'list',

	_itemControls : null,

	sortProperties: null,

	_currentSortProperties: null,

	sortAscending: true,

	isSorted: Ember.computed.notEmpty('sortProperties'),

//	orderBy:Ember.Enumerable.mixins[0].properties.sortBy,
//	sortFunction:Ember.SortableMixin.mixins[1].properties.sortFunction,

	init : function() {
		this.set('_itemControls',Ember.A());
		this._super();
		if(this.filterBy) {
			this.addObserver('value.[].'+this.filterBy.key,this,this._loadItemControls);
		}
		this._loadItemControls();
	},

	itemControls : Ember.computed('_itemControls,_itemControls.[]',{
		get  : function() {
			if(!this._itemControls) {
				return Ember.A();
			}
			var content = this._itemControls;
			var isSorted = this.get('isSorted');
			if (content && isSorted) {
				return content.sortBy.apply(content,this.sortProperties);
			}

			return content;
		}
	}).readOnly(),

	_sortObserver: Ember.observer('sortProperties',function() {
		if(this._currentSortProperties) {
			this._currentSortProperties.forEach(function(prop) {
				this.removeObserver('value.@each.'+prop,this,this._notifySortChanged);
			},this);
		}
		this._currentSortProperties=this.get('sortProperties');
		if(this._currentSortProperties) {
			this._currentSortProperties.forEach(function(prop) {
				this.addObserver('value.@each.'+prop,this,this._notifySortChanged);
			},this);
		}
	}).on('init'),

	_notifySortChanged() {
		Ember.run.scheduleOnce('sync',this,this.notifyPropertyChange,'_itemControls');
	},

	_loadItemControls : function() {
		var control=this;
		var value=this.get('value');

		var itemControls=this._itemControls;
		var oldControls=itemControls.toArray();

		Ember.assert('List control '+this+' doest not have its itemControl property set. Did you forget to call .item() in your form?',this._itemControl || this._itemControlFn);
		if(this.isDestroying) {
			return;
		}
		if(Ember.Enumerable.detect(value)) {
			var values;
			var _value=value;
			if(this.filter) {
				values=value.filter(this.filter);
			} else if(this.filterBy) {
				values=value.filterBy(this.filterBy.key,this.filterBy.value);
			} else {
				values=value;
			}

			values.forEach(function(value) {
				var index=_value.indexOf(value);
				var _itemControlDef = control._itemControl || control._itemControlFn.call(this,value);
				var oldControl=oldControls ? oldControls.findBy('for',value) : undefined;
				if(oldControl) {
					oldControls.removeObject(oldControl);
				} else {
					var meta=_itemControlDef._meta;
					itemControls.pushObject(getControl.call(control,index,meta,{'for' : null}));
				}

			});
		}
		if(oldControls) {
			oldControls.forEach(function(oldControl) {
				itemControls.removeObject(oldControl);
				oldControl.destroy();
			});
		}
	},

	_valueObserver:function(sender,key) {
		this._cleanControls();
		this._super();
		Ember.run.scheduleOnce('sync',this,this._loadItemControls);
	},

	_reset: function(modelChanged) {
		if(modelChanged) {
			this._cleanControls();
		}
		this._super(modelChanged);
	},

	_cleanControls : function() {
		// Immediately remove controls that are no longer backed by a value:
		// Our child controls won't like it when their property gets yanked
		var toRemove=Ember.A();
		var property=this.get('property');
		if(!property) {
			toRemove=this._itemControls.toArray();
		} else if(property instanceof Ember.RSVP.Promise || Ember.PromiseProxyMixin.detect(property)) {
			//toRemove=this._itemControls.toArray();
		} else {
			// Simply removing controls based on their content has severy decremental effects on performance
			// Remove controls based on their length
			if(this._itemControls.length>property.length) {
				toRemove=this._itemControls.slice(property.length,this._itemControls.length);
			}
		}
		toRemove.invoke('destroy');
		this._itemControls.removeObjects(toRemove);
	},

	controls: Ember.computed.union('_controls','_itemControls').readOnly(),

	// We alias the for property for panels and forms
	'_model' : Ember.computed.alias('value'),

	_controlDirtyObserver: Ember.observer('_controls.@each.isDirty,_itemControls.@each.isDirty',function(){
		this._super();
	}),

	_controlValidObserver: Ember.observer('_controls.@each.isValid,_itemControls.@each.isValid',function(){
		this._super();
	}),

	willDestroy : function() {
		var controls=this._itemControls;
		if(controls && controls.length) {
			controls.invoke('willDestroy');
		}
		this._super();
	},

	destroy : function() {
		var controls=this._itemControls;
		if(controls && controls.length) {
			controls.invoke('destroy');
		}
		this._super();
	},

}).reopenClass({
	filter : function(callback) {
		this.reopen({
			filter:callback
		});
		return this;
	},
	filterBy: function(key,value) {
		this.reopen({
			filterBy:{key:key,value:value}
		});
		return this;
	},

	generate : function(mixins,meta,options) {
		options=options || {};
		mixins=mixins || [];
		mixins.push(meta.options);
		var typeKey=this.typeKey;
		var control = this.extend.apply(this,mixins);
		control.typeKey=typeKey;
		return control;
	}
});<|endoftext|>