<commit_before>// Functions in this file provide functionality which is not present in
// one of { InternetExplorer 8, Chrome v28, Firefox 3 } but may be present
// in later verisons of the browsers and/or libriries such as Ext/Prototype
// However the goal was to release a dependency-free package, thus some
// of the mehtods available in other libraries were re-implemented.
// None of the methods modify any of the built-in type prototypes.
// Loop types are picked based on http://jsperf.com/loops/128

var Helpers = {};

// To allow debug code to run in IE7 && IE8 && IE9
if (!window.console) {
	window.console = {log: function () {
	}};
}

// For IE7 && IE8 again
if (typeof String.prototype.trim !== 'function') {
	String.prototype.trim = function () {
		return this.replace(/^\s+|\s+$/g, '');
	}
}

// And again (IE7 && IE8 fix)
if (!Array.prototype.forEach) {
	Array.prototype.forEach = function (fun) {
		var t = Object(this);
		var len = t.length >>> 0;
		if (typeof fun !== "function")
			throw new TypeError();

		var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
		for (var i = 0; i < len; i++) {
			if (i in t)
				fun.call(thisArg, t[i], i, t);
		}
	};
}

// Fix for Safari v4 && v5
if (typeof HTMLElement !== 'undefined' && !HTMLElement.prototype.click && document.createEvent) {
	HTMLElement.prototype.click = function () {
		var eventObj = document.createEvent('MouseEvents');
		eventObj.initEvent('click', true, true);
		this.dispatchEvent(eventObj);
	}
}

// Used for: cloning a 2D array of integers (i.e. no deep copy of elements is necessary)
// Specific implementation is pciked based on http://jsperf.com/clone-2d-array/4
Helpers.clone2DArray = function (arr2D) {
	var new2D = [];
	for (var i = 0; i < arr2D.length; ++i) {
		new2D.push(arr2D[i].slice());
	}
	return new2D;
}

// Creates a shallow copy of the given object
// Specific implementation is picked based on http://jsperf.com/cloning-an-object/4
Helpers.cloneObject = function (obj) {
	var target = {};
	for (var i in obj) {
		if (obj.hasOwnProperty(i))
			target[i] = obj[i];
	}
	return target;
}

// (Recursively) for every property in template check if data has the same property
// and set template value to the one in data.
Helpers.setByTemplate = function (template, data) {
	if (typeof template !== 'object' || typeof data !== 'object') {
		return;
	}
	for (var key in template) {
		if (data.hasOwnProperty(key) && template.hasOwnProperty(key)) {
			if (typeof template[key] === 'object') {
				if (Object.prototype.toString.call(template[key]) === '[object Array]') {
					template[key] = data[key].slice(); // array -> make a copy
				} else {
					Helpers.setByTemplate(template[key], data[key]); // other type of object -> set properties recursively
				}
			} else {
				template[key] = data[key];
			}
		}
	}
}

// Assigns values to all properties which are set in Source to the Target
Helpers.copyProperties = function (objectSource, objectTarget) {
	for (var p in objectSource) {
		if (objectSource.hasOwnProperty(p)) {
			objectTarget[p] = objectSource[p];
		}
	}
}

// Equivalent to (Array.indexOf() != -1)
Helpers.arrayContains = function (array, item) {
	if (Array.prototype.indexOf) {
		return !(array.indexOf(item) < 0);
	}
	else {
		for (var i = 0, len = array.length; i < len; ++i) {
			if (array[i] === item)
				return true;
		}
		return false;
	}
}

// Equivalent to Array.indexOf
Helpers.arrayIndexOf = function (array, item) {
	if (Array.prototype.indexOf) {
		return (array.indexOf(item));
	}
	else {
		for (var i = 0, len = array.length; i < len; ++i) {
			if (array[i] === item)
				return i;
		}
		return -1;
	}
}

Helpers.indexOfLastMinElementInArray = function (array) {
	var min = array[0];
	var minIndex = 0;

	for (var i = 1, len = array.length; i < len; ++i) {
		if (array[i] <= min) {
			minIndex = i;
			min = array[i];
		}
	}
	return minIndex;
}

// Returns an array of unique values from the given array
// Specific implementation is picked based on http://jsperf.com/array-unique2/19
Helpers.filterUnique = function (array) {
	var hash = {},
		result = [],
		i = array.length;
	while (i--) {
		if (!hash[array[i]]) {
			hash[array[i]] = true;
			result.push(array[i]);
		}
	}
	return result;
}

// Replaces the first occurence of `value` in `array` by `newValue`. Does nothing if `value` is not in `array`
Helpers.replaceInArray = function (array, value, newValue) {
	for (var i = 0, len = array.length; i < len; ++i) {
		if (array[i] === value) {
			array[i] = newValue;
			break;
		}
	}
}

// Removes the first occurence of `value` in `array`. Does nothing if `value` is not in `array`
Helpers.removeFirstOccurrenceByValue = function (array, item) {
	for (var i = 0, len = array.length; i < len; ++i) {
		if (array[i] == item) {
			array.splice(i, 1);
			break;
		}
	}
}

// Returns true iff the object has no properties
Helpers.isObjectEmpty = function (map) {
	for (var key in map) {
		if (map.hasOwnProperty(key)) {
			return false;
		}
	}
	return true;
}

// Returns num lines in a text block, or 0 for empty lines. Ignores leading and trailing whitespace
Helpers.numTextLines = function (text) {
	if (text === null || text == "") {
		return 0;
	}
	var useText = text.replace(/^\s+|\s+$/g, '');
	var numLines = (useText.match(/\n/g) || []).length + 1;
	return numLines;
}

// Used for: user input validation
Helpers.isInt = function (n) {
	//return +n === n && !(n % 1);
	//return !(n % 1);
	return (!isNaN(n) && parseInt(n) == parseFloat(n));
}

Helpers.toObjectWithTrue = function (array) {
	var obj = {};
	for (var i = 0; i < array.length; ++i)
		if (array[i] !== undefined) obj[array[i]] = true;
	return obj;
}

Helpers.romanize = function (num) {
	if (!+num)
		return false;
	var digits = String(+num).split(""),
		key = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
			"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
			"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],
		roman = "",
		i = 3;
	while (i--)
		roman = (key[+digits.pop() + (i * 10)] || "") + roman;
	return Array(+digits.join("") + 1).join("M") + roman;
}

/*function objectKeys(obj) {
 if (Object.keys)
 return Object.keyhs(obj);

 var keys = [];
 for (var i in obj) {
 if (obj.hasOwnProperty(i)) {
 keys.push(i);
 }
 }
 return keys;
 }*/

Helpers.stopEventPropagation = function (event) {
	event.preventDefault();
	event.stopPropagation();
	event.stopImmediatePropagation();

}
Helpers.disableMouseclicks = function (element) {
	element.__oldMouseDown = element.onmousedown;
	element.onmousedown = Helpers.stopEventPropagation;
	element.__oldClick = element.onclick;
	element.onclick = Helpers.stopEventPropagation;

}
Helpers.enableMouseclicks = function (element) {
	if (element.hasOwnProperty("__oldMouseDown")) {
		element.onmousedown = element.__oldMouseDown;
		delete element.__oldMouseDown;
	} else {
		element.onmousedown = null;
	}
	if (element.hasOwnProperty("__oldClick")) {
		element.onclick = element.__oldClick;
		delete element.__oldClick;
	} else {
		element.onclick = null;
	}
}

//-------------------------------------------------------------
// Used during ordering for bucket order permutations
//-------------------------------------------------------------
Helpers.makeFlattened2DArrayCopy = function (array) {
	var flattenedcopy = [].concat.apply([], array);
	return flattenedcopy;
}

Helpers.swap = function (array, i, j) {
	var b = array[j];
	array[j] = array[i];
	array[i] = b;
}

Helpers.permute2DArrayInFirstDimension = function (permutations, array, from) {
	var len = array.length;

	if (from == len - 1) {
		permutations.push(Helpers.makeFlattened2DArrayCopy(array));
		return;
	}

	for (var j = from; j < len; j++) {
		Helpers.swap(array, from, j);
		Helpers.permute2DArrayInFirstDimension(permutations, array, from + 1);
		Helpers.swap(array, from, j);
	}
}
//-------------------------------------------------------------

//-------------------------------------------------------------
// Used for profiling code
Helpers.Timer = function () {
	this.startTime = undefined;
	this.lastCheck = undefined;
	this.start();
};

Helpers.Timer.prototype = {

	start: function () {
		this.startTime = new Date().getTime();
		this.lastCheck = this.startTime;
	},

	restart: function () {
		this.start();
	},

	report: function () {
		var current = new Date().getTime();
		var elapsed = current - this.lastCheck;
		return elapsed;
	},

	printSinceLast: function (msg) {
		var current = new Date().getTime();
		var elapsed = current - this.lastCheck;
		this.lastCheck = current;
		console.log(msg + elapsed + "ms");
	},
};
//-------------------------------------------------------------

//-------------------------------------------------------------
Helpers.stringifyObject = function (obj) {
	return _printObjectInternal(obj, 1);
}

Helpers.printObject = function (obj) {
	console.log(_printObjectInternal(obj, 0));
}

_printObjectInternal = function (o, level) {
	if (level > 10) return "...[too deep, possibly a recursive object]...";

	var output = '';

	if (typeof o === 'object') {

		if (Object.prototype.toString.call(o) === '[object Array]') {
			output = '[';
			for (var i = 0; i < o.length; i++) {
				if (i > 0) output += ', ';
				output += _printObjectInternal(o[i], level + 1);
			}
			output += ']';
		}
		else {
			output = '{';
			var idx = 0;
			if (level == 0) output += '\n';
			for (var property in o) {
				if (!o.hasOwnProperty(property)) continue;

				if (level != 0 && idx != 0)
					output += ', ';
				output += property + ': ' + _printObjectInternal(o[property], level + 1);

				if (level == 0)
					output += '\n';
				idx++;
			}
			output += '}';
		}
	}
	else if (typeof o === 'string') {
		output = "'" + o + "'";
	}
	else
		output = '' + o;

	return output;
}

Helpers.padString = function (string, width, padding, onLeft) {
	return (width <= string.length) ? string : Helpers.padString((onLeft ? (padding + string) : (string + padding)), width, padding, onLeft);
}
//-------------------------------------------------------------

Helpers.createRandomID = function()
{
	var text = "";
	var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

	for( var i=0; i < 5; i++ )
		text += possible.charAt(Math.floor(Math.random() * possible.length));

	return text;
}<commit_msg>Add a method to return current site URL<commit_after>// Functions in this file provide functionality which is not present in
// one of { InternetExplorer 8, Chrome v28, Firefox 3 } but may be present
// in later verisons of the browsers and/or libriries such as Ext/Prototype
// However the goal was to release a dependency-free package, thus some
// of the mehtods available in other libraries were re-implemented.
// None of the methods modify any of the built-in type prototypes.
// Loop types are picked based on http://jsperf.com/loops/128

var Helpers = {};

// To allow debug code to run in IE7 && IE8 && IE9
if (!window.console) {
	window.console = {log: function () {
	}};
}

// For IE7 && IE8 again
if (typeof String.prototype.trim !== 'function') {
	String.prototype.trim = function () {
		return this.replace(/^\s+|\s+$/g, '');
	}
}

// And again (IE7 && IE8 fix)
if (!Array.prototype.forEach) {
	Array.prototype.forEach = function (fun) {
		var t = Object(this);
		var len = t.length >>> 0;
		if (typeof fun !== "function")
			throw new TypeError();

		var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
		for (var i = 0; i < len; i++) {
			if (i in t)
				fun.call(thisArg, t[i], i, t);
		}
	};
}

// Fix for Safari v4 && v5
if (typeof HTMLElement !== 'undefined' && !HTMLElement.prototype.click && document.createEvent) {
	HTMLElement.prototype.click = function () {
		var eventObj = document.createEvent('MouseEvents');
		eventObj.initEvent('click', true, true);
		this.dispatchEvent(eventObj);
	}
}

// Used for: cloning a 2D array of integers (i.e. no deep copy of elements is necessary)
// Specific implementation is pciked based on http://jsperf.com/clone-2d-array/4
Helpers.clone2DArray = function (arr2D) {
	var new2D = [];
	for (var i = 0; i < arr2D.length; ++i) {
		new2D.push(arr2D[i].slice());
	}
	return new2D;
}

// Creates a shallow copy of the given object
// Specific implementation is picked based on http://jsperf.com/cloning-an-object/4
Helpers.cloneObject = function (obj) {
	var target = {};
	for (var i in obj) {
		if (obj.hasOwnProperty(i))
			target[i] = obj[i];
	}
	return target;
}

// (Recursively) for every property in template check if data has the same property
// and set template value to the one in data.
Helpers.setByTemplate = function (template, data) {
	if (typeof template !== 'object' || typeof data !== 'object') {
		return;
	}
	for (var key in template) {
		if (data.hasOwnProperty(key) && template.hasOwnProperty(key)) {
			if (typeof template[key] === 'object') {
				if (Object.prototype.toString.call(template[key]) === '[object Array]') {
					template[key] = data[key].slice(); // array -> make a copy
				} else {
					Helpers.setByTemplate(template[key], data[key]); // other type of object -> set properties recursively
				}
			} else {
				template[key] = data[key];
			}
		}
	}
}

// Assigns values to all properties which are set in Source to the Target
Helpers.copyProperties = function (objectSource, objectTarget) {
	for (var p in objectSource) {
		if (objectSource.hasOwnProperty(p)) {
			objectTarget[p] = objectSource[p];
		}
	}
}

// Equivalent to (Array.indexOf() != -1)
Helpers.arrayContains = function (array, item) {
	if (Array.prototype.indexOf) {
		return !(array.indexOf(item) < 0);
	}
	else {
		for (var i = 0, len = array.length; i < len; ++i) {
			if (array[i] === item)
				return true;
		}
		return false;
	}
}

// Equivalent to Array.indexOf
Helpers.arrayIndexOf = function (array, item) {
	if (Array.prototype.indexOf) {
		return (array.indexOf(item));
	}
	else {
		for (var i = 0, len = array.length; i < len; ++i) {
			if (array[i] === item)
				return i;
		}
		return -1;
	}
}

Helpers.indexOfLastMinElementInArray = function (array) {
	var min = array[0];
	var minIndex = 0;

	for (var i = 1, len = array.length; i < len; ++i) {
		if (array[i] <= min) {
			minIndex = i;
			min = array[i];
		}
	}
	return minIndex;
}

// Returns an array of unique values from the given array
// Specific implementation is picked based on http://jsperf.com/array-unique2/19
Helpers.filterUnique = function (array) {
	var hash = {},
		result = [],
		i = array.length;
	while (i--) {
		if (!hash[array[i]]) {
			hash[array[i]] = true;
			result.push(array[i]);
		}
	}
	return result;
}

// Replaces the first occurence of `value` in `array` by `newValue`. Does nothing if `value` is not in `array`
Helpers.replaceInArray = function (array, value, newValue) {
	for (var i = 0, len = array.length; i < len; ++i) {
		if (array[i] === value) {
			array[i] = newValue;
			break;
		}
	}
}

// Removes the first occurence of `value` in `array`. Does nothing if `value` is not in `array`
Helpers.removeFirstOccurrenceByValue = function (array, item) {
	for (var i = 0, len = array.length; i < len; ++i) {
		if (array[i] == item) {
			array.splice(i, 1);
			break;
		}
	}
}

// Returns true iff the object has no properties
Helpers.isObjectEmpty = function (map) {
	for (var key in map) {
		if (map.hasOwnProperty(key)) {
			return false;
		}
	}
	return true;
}

// Returns num lines in a text block, or 0 for empty lines. Ignores leading and trailing whitespace
Helpers.numTextLines = function (text) {
	if (text === null || text == "") {
		return 0;
	}
	var useText = text.replace(/^\s+|\s+$/g, '');
	var numLines = (useText.match(/\n/g) || []).length + 1;
	return numLines;
}

// Used for: user input validation
Helpers.isInt = function (n) {
	//return +n === n && !(n % 1);
	//return !(n % 1);
	return (!isNaN(n) && parseInt(n) == parseFloat(n));
}

Helpers.toObjectWithTrue = function (array) {
	var obj = {};
	for (var i = 0; i < array.length; ++i)
		if (array[i] !== undefined) obj[array[i]] = true;
	return obj;
}

Helpers.romanize = function (num) {
	if (!+num)
		return false;
	var digits = String(+num).split(""),
		key = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
			"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
			"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],
		roman = "",
		i = 3;
	while (i--)
		roman = (key[+digits.pop() + (i * 10)] || "") + roman;
	return Array(+digits.join("") + 1).join("M") + roman;
}

/*function objectKeys(obj) {
 if (Object.keys)
 return Object.keyhs(obj);

 var keys = [];
 for (var i in obj) {
 if (obj.hasOwnProperty(i)) {
 keys.push(i);
 }
 }
 return keys;
 }*/

Helpers.stopEventPropagation = function (event) {
	event.preventDefault();
	event.stopPropagation();
	event.stopImmediatePropagation();

}
Helpers.disableMouseclicks = function (element) {
	element.__oldMouseDown = element.onmousedown;
	element.onmousedown = Helpers.stopEventPropagation;
	element.__oldClick = element.onclick;
	element.onclick = Helpers.stopEventPropagation;

}
Helpers.enableMouseclicks = function (element) {
	if (element.hasOwnProperty("__oldMouseDown")) {
		element.onmousedown = element.__oldMouseDown;
		delete element.__oldMouseDown;
	} else {
		element.onmousedown = null;
	}
	if (element.hasOwnProperty("__oldClick")) {
		element.onclick = element.__oldClick;
		delete element.__oldClick;
	} else {
		element.onclick = null;
	}
}

//-------------------------------------------------------------
// Used during ordering for bucket order permutations
//-------------------------------------------------------------
Helpers.makeFlattened2DArrayCopy = function (array) {
	var flattenedcopy = [].concat.apply([], array);
	return flattenedcopy;
}

Helpers.swap = function (array, i, j) {
	var b = array[j];
	array[j] = array[i];
	array[i] = b;
}

Helpers.permute2DArrayInFirstDimension = function (permutations, array, from) {
	var len = array.length;

	if (from == len - 1) {
		permutations.push(Helpers.makeFlattened2DArrayCopy(array));
		return;
	}

	for (var j = from; j < len; j++) {
		Helpers.swap(array, from, j);
		Helpers.permute2DArrayInFirstDimension(permutations, array, from + 1);
		Helpers.swap(array, from, j);
	}
}
//-------------------------------------------------------------

//-------------------------------------------------------------
// Used for profiling code
Helpers.Timer = function () {
	this.startTime = undefined;
	this.lastCheck = undefined;
	this.start();
};

Helpers.Timer.prototype = {

	start: function () {
		this.startTime = new Date().getTime();
		this.lastCheck = this.startTime;
	},

	restart: function () {
		this.start();
	},

	report: function () {
		var current = new Date().getTime();
		var elapsed = current - this.lastCheck;
		return elapsed;
	},

	printSinceLast: function (msg) {
		var current = new Date().getTime();
		var elapsed = current - this.lastCheck;
		this.lastCheck = current;
		console.log(msg + elapsed + "ms");
	},
};
//-------------------------------------------------------------

//-------------------------------------------------------------
Helpers.stringifyObject = function (obj) {
	return _printObjectInternal(obj, 1);
}

Helpers.printObject = function (obj) {
	console.log(_printObjectInternal(obj, 0));
}

_printObjectInternal = function (o, level) {
	if (level > 10) return "...[too deep, possibly a recursive object]...";

	var output = '';

	if (typeof o === 'object') {

		if (Object.prototype.toString.call(o) === '[object Array]') {
			output = '[';
			for (var i = 0; i < o.length; i++) {
				if (i > 0) output += ', ';
				output += _printObjectInternal(o[i], level + 1);
			}
			output += ']';
		}
		else {
			output = '{';
			var idx = 0;
			if (level == 0) output += '\n';
			for (var property in o) {
				if (!o.hasOwnProperty(property)) continue;

				if (level != 0 && idx != 0)
					output += ', ';
				output += property + ': ' + _printObjectInternal(o[property], level + 1);

				if (level == 0)
					output += '\n';
				idx++;
			}
			output += '}';
		}
	}
	else if (typeof o === 'string') {
		output = "'" + o + "'";
	}
	else
		output = '' + o;

	return output;
}

Helpers.padString = function (string, width, padding, onLeft) {
	return (width <= string.length) ? string : Helpers.padString((onLeft ? (padding + string) : (string + padding)), width, padding, onLeft);
}
//-------------------------------------------------------------

Helpers.createRandomID = function()
{
	var text = "";
	var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

	for( var i=0; i < 5; i++ )
		text += possible.charAt(Math.floor(Math.random() * possible.length));

	return text;
}}

Helpers.getSiteURL = function(){
	//returns site address like : "https://gmc.genomicsengland.nhs.uk/rarediseases/demo" OR "http://localhost:8083/openclinica"
	return window.location.origin + window.location.pathname.substr(0, window.location.pathname.lastIndexOf('/'));
}<|endoftext|>


<commit_before>var stats = function(dbot){
    var name = 'stats';
    var userStats = dbot.db.userStats;
    var chanStats = dbot.db.chanStats;

    var linkUser = function(server, name){
        if(dbot.db.hasOwnProperty("knownUsers") && dbot.db.knownUsers.hasOwnProperty(server)){
            if(dbot.db.knownUsers[server]["aliases"].hasOwnProperty(name)){
                return dbot.db.knownUsers[server]["aliases"][name].trim().toLowerCase();
            }
        }
        return name.trim().toLowerCase();
    };

    var formatDate = function(d){
        return new Date(d).toDateString();
    };

    var getTimezone = function(d){
        var date = new Date(d);
        var d = date.toString().match("^(\\w{3} \\w{3} \\d{1,2} \\d{4}) ((\\d{2}:){2}\\d{2}).*\\((.*)\\)$");
        return d[4];
    };

    var commands = {
        '~lines': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    event.reply(dbot.t("user_lines", {
                        "user": input,
                        "chan": event.channel,
                        "lines": userStats[event.server][input][event.channel]["total_lines"].numberFormat(0),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                event.reply(dbot.t("chan_lines", {
                    "chan": event.channel,
                    "lines": chanStats[event.server][event.channel]["total_lines"].numberFormat(0),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~words': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    event.reply(dbot.t("user_words", {
                        "user": input,
                        "chan": event.channel,
                        "words": userStats[event.server][input][event.channel]["total_words"].numberFormat(0),
                        "avg": (userStats[event.server][input][event.channel]["total_words"]
                            / userStats[event.server][input][event.channel]["total_lines"]).numberFormat(2),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                event.reply(dbot.t("chan_words", {
                    "chan": event.channel,
                    "words": chanStats[event.server][event.channel]["total_words"].numberFormat(0),
                    "avg": (chanStats[event.server][event.channel]["total_words"]
                        / chanStats[event.server][event.channel]["total_lines"]).numberFormat(2),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~lincent': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(chanStats[event.server][event.channel]["users"].hasOwnProperty(input)){
                    var percent = ((chanStats[event.server][event.channel]["users"][input]["lines"]
                        / chanStats[event.server][event.channel]["total_lines"])*100);
                    event.reply(dbot.t("lines_percent", {
                        "user": input,
                        "chan": event.channel,
                        "percent": percent.numberFormat(2),
                        "lines": chanStats[event.server][event.channel]["users"][input]["lines"].numberFormat(0),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                var user = linkUser(event.server, event.user);
                var percent = ((chanStats[event.server][event.channel]["users"][user]["lines"]
                    / chanStats[event.server][event.channel]["total_lines"])*100);
                event.reply(dbot.t("lines_percent", {
                    "user": user,
                    "chan": event.channel,
                    "percent": percent.numberFormat(2),
                    "lines": chanStats[event.server][event.channel]["users"][user]["lines"].numberFormat(0),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~active': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    var max = -1;
                    var max_index = -1;
                    for(var i=0; i<=23; i++) {
                        if(userStats[event.server][input][event.channel]["freq_hours"][i] > max){
                            max = userStats[event.server][input][event.channel]["freq_hours"][i];
                            max_index = i;
                        }
                    }
                    var start = max_index;
                    var end = max_index + 1;
                    if(start == 23){
                        end = "00";
                    }
                    event.reply(dbot.t("hours_active", {
                        "name": input,
                        "start_hour": start,
                        "end_hour": end,
                        "start": formatDate(userStats[event.server][event.user][event.channel]["startstamp"]),
                        "tz": getTimezone(userStats[event.server][event.user][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                //Channel active
                var max = -1;
                var max_index = -1;
                for(var i=0; i<=23; i++) {
                    if(chanStats[event.server][event.channel]["freq_hours"][i] > max){
                        max = chanStats[event.server][event.channel]["freq_hours"][i];
                        max_index = i;
                    }
                }
                var start = max_index;
                var end = max_index + 1;
                if(start == 23){
                    end = "00";
                }
                event.reply(dbot.t("hours_active", {
                    "name": event.channel,
                    "start_hour": start,
                    "end_hour": end,
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"]),
                    "tz": getTimezone(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~loudest': function(event){
            var max = -1;
            var max_user = "nobody";
            for(var user in chanStats[event.server][event.channel]["users"]){
                if(chanStats[event.server][event.channel]["users"].hasOwnProperty(user)){
                    if(chanStats[event.server][event.channel]["users"][user]["lines"] > max){
                        max = chanStats[event.server][event.channel]["users"][user]["lines"];
                        max_user = user;
                    }
                }
            }
            event.reply(dbot.t("loudest_user", {
                "user": max_user,
                "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
            ));
        },
    };

    return {
        'name': 'stats',
        'ignorable': true,
        'commands': commands,
        'listener': function(event){

            // Ignore command messages
            if(event.message[0] == "~" || event.user == dbot.name){
                return;
            }

            // Check server dbKeys exist
            if(!userStats.hasOwnProperty(event.server)){
                userStats[event.server] = {}
            }
            if(!chanStats.hasOwnProperty(event.server)){
                chanStats[event.server] = {}
            }

            //var user = event.user.trim().toLowerCase();
            var user = linkUser(event.server, event.user);

            // User-centric Stats
            if(!userStats[event.server].hasOwnProperty(user)){
                userStats[event.server][user] = {}
            }
            if(!userStats[event.server][user].hasOwnProperty(event.channel)){
                userStats[event.server][user][event.channel] = {
                    "total_lines": 0,
                    "total_words": 0,
                    "freq_hours": {},
                    "in_mentions": 0,
                    "out_mentions": {},
                    "startstamp": Date.now(),
                };

                // Initialize hour frequency counters
                for(var i=0; i<=23; i++){
                    userStats[event.server][user][event.channel]["freq_hours"][i] = 0;
                }
            }
            userStats[event.server][user][event.channel]["freq_hours"][event.time.getHours()] += 1;
            userStats[event.server][user][event.channel]["total_lines"] += 1;
            userStats[event.server][user][event.channel]["total_words"] += event.message.split(" ").length;

            // Channel-centric Stats
            if(!chanStats[event.server].hasOwnProperty(event.channel)){
                chanStats[event.server][event.channel] = {
                    "total_lines": 0,
                    "total_words": 0,
                    "freq_hours": {},
                    "users": {},
                    "startstamp": Date.now(),
                };

                // Initialize hour frequency counters
                for(var i=0; i<=23; i++){
                    chanStats[event.server][event.channel]["freq_hours"][i] = 0;
                }
            }
            if(!chanStats[event.server][event.channel]["users"].hasOwnProperty(user)){
                chanStats[event.server][event.channel]["users"][user] = {
                    "lines": 0,
                    "mentions": 0 };
            }
            chanStats[event.server][event.channel]["users"][user]["lines"] += 1;
            chanStats[event.server][event.channel]["freq_hours"][event.time.getHours()] += 1;
            chanStats[event.server][event.channel]["total_lines"] += 1;
            chanStats[event.server][event.channel]["total_words"] += event.message.split(" ").length;

            // Check whether the line includes any mentions
            if(dbot.db.hasOwnProperty("knownUsers")){
                var cat = dbot.db.knownUsers[event.server].users.concat(
                        Object.keys(dbot.db.knownUsers[event.server].aliases));
                for (var i = 0; i < cat.length; i++){
                    var name = cat[i];
                    var mentioned = linkUser(event.server, name);
                    if(userStats[event.server].hasOwnProperty(mentioned)){
                        var toMatch = "( |^)"+name.escape().toLowerCase()+":?(?=\\s|$)";
                        if(event.message.toLowerCase().search(toMatch) > -1){
                            if(!userStats[event.server][user][event.channel]["out_mentions"].hasOwnProperty(mentioned)){
                                userStats[event.server][user][event.channel]["out_mentions"][mentioned] = 0;
                            }
                            userStats[event.server][user][event.channel]["out_mentions"][mentioned] += 1;
                            userStats[event.server][mentioned][event.channel]["in_mentions"] += 1;
                        }
                    }
                }
            }
        },
        'on': 'PRIVMSG'
    };
};

exports.fetch = function(dbot){
    return stats(dbot);
};
<commit_msg>Hook to update stats dbKeys [#19]<commit_after>var stats = function(dbot){
    var name = 'stats';
    var userStats = dbot.db.userStats;
    var chanStats = dbot.db.chanStats;

    var linkUser = function(server, name){
        if(dbot.db.hasOwnProperty("knownUsers") && dbot.db.knownUsers.hasOwnProperty(server)){
            if(dbot.db.knownUsers[server]["aliases"].hasOwnProperty(name)){
                return dbot.db.knownUsers[server]["aliases"][name].trim().toLowerCase();
            }
        }
        return name.trim().toLowerCase();
    };

    var formatDate = function(d){
        return new Date(d).toDateString();
    };

    var getTimezone = function(d){
        var date = new Date(d);
        var d = date.toString().match("^(\\w{3} \\w{3} \\d{1,2} \\d{4}) ((\\d{2}:){2}\\d{2}).*\\((.*)\\)$");
        return d[4];
    };

    var commands = {
        '~lines': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    event.reply(dbot.t("user_lines", {
                        "user": input,
                        "chan": event.channel,
                        "lines": userStats[event.server][input][event.channel]["total_lines"].numberFormat(0),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                event.reply(dbot.t("chan_lines", {
                    "chan": event.channel,
                    "lines": chanStats[event.server][event.channel]["total_lines"].numberFormat(0),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~words': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    event.reply(dbot.t("user_words", {
                        "user": input,
                        "chan": event.channel,
                        "words": userStats[event.server][input][event.channel]["total_words"].numberFormat(0),
                        "avg": (userStats[event.server][input][event.channel]["total_words"]
                            / userStats[event.server][input][event.channel]["total_lines"]).numberFormat(2),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                event.reply(dbot.t("chan_words", {
                    "chan": event.channel,
                    "words": chanStats[event.server][event.channel]["total_words"].numberFormat(0),
                    "avg": (chanStats[event.server][event.channel]["total_words"]
                        / chanStats[event.server][event.channel]["total_lines"]).numberFormat(2),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~lincent': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(chanStats[event.server][event.channel]["users"].hasOwnProperty(input)){
                    var percent = ((chanStats[event.server][event.channel]["users"][input]["lines"]
                        / chanStats[event.server][event.channel]["total_lines"])*100);
                    event.reply(dbot.t("lines_percent", {
                        "user": input,
                        "chan": event.channel,
                        "percent": percent.numberFormat(2),
                        "lines": chanStats[event.server][event.channel]["users"][input]["lines"].numberFormat(0),
                        "start": formatDate(userStats[event.server][input][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                var user = linkUser(event.server, event.user);
                var percent = ((chanStats[event.server][event.channel]["users"][user]["lines"]
                    / chanStats[event.server][event.channel]["total_lines"])*100);
                event.reply(dbot.t("lines_percent", {
                    "user": user,
                    "chan": event.channel,
                    "percent": percent.numberFormat(2),
                    "lines": chanStats[event.server][event.channel]["users"][user]["lines"].numberFormat(0),
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~active': function(event){
            if(event.params[1]){
                var input = linkUser(event.server, event.params[1]);
                if(userStats[event.server].hasOwnProperty(input)){
                    var max = -1;
                    var max_index = -1;
                    for(var i=0; i<=23; i++) {
                        if(userStats[event.server][input][event.channel]["freq_hours"][i] > max){
                            max = userStats[event.server][input][event.channel]["freq_hours"][i];
                            max_index = i;
                        }
                    }
                    var start = max_index;
                    var end = max_index + 1;
                    if(start == 23){
                        end = "00";
                    }
                    event.reply(dbot.t("hours_active", {
                        "name": input,
                        "start_hour": start,
                        "end_hour": end,
                        "start": formatDate(userStats[event.server][event.user][event.channel]["startstamp"]),
                        "tz": getTimezone(userStats[event.server][event.user][event.channel]["startstamp"])}
                    ));
                }
                else{
                    event.reply(dbot.t("no_data", {
                        "user": input}
                    ));
                }
            }
            else{
                //Channel active
                var max = -1;
                var max_index = -1;
                for(var i=0; i<=23; i++) {
                    if(chanStats[event.server][event.channel]["freq_hours"][i] > max){
                        max = chanStats[event.server][event.channel]["freq_hours"][i];
                        max_index = i;
                    }
                }
                var start = max_index;
                var end = max_index + 1;
                if(start == 23){
                    end = "00";
                }
                event.reply(dbot.t("hours_active", {
                    "name": event.channel,
                    "start_hour": start,
                    "end_hour": end,
                    "start": formatDate(chanStats[event.server][event.channel]["startstamp"]),
                    "tz": getTimezone(chanStats[event.server][event.channel]["startstamp"])}
                ));
            }
        },

        '~loudest': function(event){
            var max = -1;
            var max_user = "nobody";
            for(var user in chanStats[event.server][event.channel]["users"]){
                if(chanStats[event.server][event.channel]["users"].hasOwnProperty(user)){
                    if(chanStats[event.server][event.channel]["users"][user]["lines"] > max){
                        max = chanStats[event.server][event.channel]["users"][user]["lines"];
                        max_user = user;
                    }
                }
            }
            event.reply(dbot.t("loudest_user", {
                "user": max_user,
                "start": formatDate(chanStats[event.server][event.channel]["startstamp"])}
            ));
        },
    };

    return {
        'name': 'stats',
        'ignorable': true,
        'commands': commands,
        'listener': function(event){

            // Ignore command messages
            if(event.message[0] == "~" || event.user == dbot.name){
                return;
            }

            // Check server dbKeys exist
            if(!userStats.hasOwnProperty(event.server)){
                userStats[event.server] = {}
            }
            if(!chanStats.hasOwnProperty(event.server)){
                chanStats[event.server] = {}
            }

            //var user = event.user.trim().toLowerCase();
            var user = linkUser(event.server, event.user);

            // User-centric Stats
            if(!userStats[event.server].hasOwnProperty(user)){
                userStats[event.server][user] = {}
            }
            if(!userStats[event.server][user].hasOwnProperty(event.channel)){
                userStats[event.server][user][event.channel] = {
                    "total_lines": 0,
                    "total_words": 0,
                    "freq_hours": {},
                    "in_mentions": 0,
                    "out_mentions": {},
                    "startstamp": Date.now(),
                };

                // Initialize hour frequency counters
                for(var i=0; i<=23; i++){
                    userStats[event.server][user][event.channel]["freq_hours"][i] = 0;
                }
            }
            userStats[event.server][user][event.channel]["freq_hours"][event.time.getHours()] += 1;
            userStats[event.server][user][event.channel]["total_lines"] += 1;
            userStats[event.server][user][event.channel]["total_words"] += event.message.split(" ").length;

            // Channel-centric Stats
            if(!chanStats[event.server].hasOwnProperty(event.channel)){
                chanStats[event.server][event.channel] = {
                    "total_lines": 0,
                    "total_words": 0,
                    "freq_hours": {},
                    "users": {},
                    "startstamp": Date.now(),
                };

                // Initialize hour frequency counters
                for(var i=0; i<=23; i++){
                    chanStats[event.server][event.channel]["freq_hours"][i] = 0;
                }
            }
            if(!chanStats[event.server][event.channel]["users"].hasOwnProperty(user)){
                chanStats[event.server][event.channel]["users"][user] = {
                    "lines": 0,
                    "mentions": 0 };
            }
            chanStats[event.server][event.channel]["users"][user]["lines"] += 1;
            chanStats[event.server][event.channel]["freq_hours"][event.time.getHours()] += 1;
            chanStats[event.server][event.channel]["total_lines"] += 1;
            chanStats[event.server][event.channel]["total_words"] += event.message.split(" ").length;

            // Check whether the line includes any mentions
            if(dbot.db.hasOwnProperty("knownUsers")){
                var cat = dbot.db.knownUsers[event.server].users.concat(
                        Object.keys(dbot.db.knownUsers[event.server].aliases));
                for (var i = 0; i < cat.length; i++){
                    var name = cat[i];
                    var mentioned = linkUser(event.server, name);
                    if(userStats[event.server].hasOwnProperty(mentioned)){
                        var toMatch = "( |^)"+name.escape().toLowerCase()+":?(?=\\s|$)";
                        if(event.message.toLowerCase().search(toMatch) > -1){
                            if(!userStats[event.server][user][event.channel]["out_mentions"].hasOwnProperty(mentioned)){
                                userStats[event.server][user][event.channel]["out_mentions"][mentioned] = 0;
                            }
                            userStats[event.server][user][event.channel]["out_mentions"][mentioned] += 1;
                            userStats[event.server][mentioned][event.channel]["in_mentions"] += 1;
                        }
                    }
                }
            }
        },
        'fixStats': function(server, name){
            if(dbot.db.userStats[server].hasOwnProperty(name)){
                var newName = dbot.db.knownUsers[server]["aliases"][name];
                var userStats = dbot.db.userStats[server];
                var chanStats = dbot.db.chanStats[server];

                // Rename userStats key
                userStats[newName] = userStats[name];
                delete userStats[name];

                // Rename keys in all out_mentions on this server
                for(var curr_user in userStats){
                    if(userStats.hasOwnProperty(curr_user)){
                        for(var curr_channel in userStats[curr_user]){
                            if(!userStats[curr_user].hasOwnProperty(curr_channel)) continue;
                            if(userStats[curr_user][curr_channel]["out_mentions"].hasOwnProperty(name)){
                                userStats[curr_user][curr_channel]["out_mentions"][newName] = userStats[curr_user][curr_channel]["out_mentions"][name];
                                delete userStats[curr_user][curr_channel]["out_mentions"][name];
                            }
                        }
                    }
                }

                // Rename user in all chanStats keys for this server
                for(var curr_chan in chanStats){
                    if(chanStats.hasOwnProperty(curr_chan)){
                        if(chanStats[curr_chan]["users"].hasOwnProperty(name)){
                            chanStats[curr_chan]["users"][newName] = chanStats[curr_chan]["users"][name];
                            delete chanStats[curr_chan]["users"][name];
                        }
                    }
                }
            }
        },
        'on': 'PRIVMSG'
    };
};

exports.fetch = function(dbot){
    return stats(dbot);
};
<|endoftext|>


<commit_before>'use strict';

// HOLOSIM

/*
TODO:
-get FOV and aspect right
-UI controls
--input specific FOV
-WebVR 1.0 support (via polyfill, etc.)
-better scene for viewing
-resize handler
-push out
*/

var clock = new THREE.Clock();

var renderer;
var camera, holoCamera;

var scene, holoScene;

var cube, holoCube;

var controls;
var mouseControls;

var renderWidth, renderHeight;

var renderHolograms = true;

var FOV = 70;
var hololensFOV = [30, 17.5]; // based off estimates

var holoFOV = hololensFOV;
var holoAspect = holoFOV[0] / holoFOV[1];

var targetFOV;
setTargetFOV(holoFOV);

init();

function init() {
  scene = new THREE.Scene();
  holoScene = new THREE.Scene();

  // vertical FOV, aspect
  camera = new THREE.PerspectiveCamera( FOV, window.innerWidth/window.innerHeight, 0.1, 1000 );
  holoCamera = new THREE.PerspectiveCamera( holoFOV[1], holoAspect, 0.1, 1000 );

  renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById('canvas'),
    antialias: true
  });
  renderer.autoClear = false;

  renderWidth = window.innerWidth;
  renderHeight = window.innerHeight;

  renderer.setSize( renderWidth, renderHeight );

  addLights(scene);
  addLights(holoScene);

  setupWorld();
  setupHoloWorld();

  setupControls();

  setupUI();

  animate();
}

function randRange(min, max) {
  return Math.random() * (max - min) + min;
}

function addLights(scene) {
  var light = new THREE.DirectionalLight(0xffffff, 1.5);
  light.position.set(1, 1, 1);
  scene.add(light);

  light = new THREE.DirectionalLight(0xffffff, 0.75);
  light.position.set(-1, - 0.5, - 1);
  scene.add(light);

  light = new THREE.AmbientLight(0x666666);
  scene.add(light);
}

function setupWorld() {
  // floor
  var height = 2;
  var map = new THREE.TextureLoader().load('textures/hardwood2_diffuse.jpg');
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  map.anisotropy = 4;
  map.repeat.set( 6, 12 );
  var geo = new THREE.PlaneGeometry(20,20, 4,4);
  geo.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );

  // wall
  var wallGeo = new THREE.PlaneGeometry(20, 5);
  var wallMap = new THREE.TextureLoader().load('textures/brick_diffuse.jpg');
  var mat = new THREE.MeshLambertMaterial({ map: wallMap });
  wallMap.wrapS = THREE.RepeatWrapping;
  wallMap.wrapT = THREE.RepeatWrapping;
  wallMap.anisotropy = 4;
  wallMap.repeat.set( 3, 1 );
  var wall = new THREE.Mesh( wallGeo, mat );
  wall.position.set( 0, 0, -5 );
  scene.add( wall );

  var mat = new THREE.MeshLambertMaterial( { map: map, side: THREE.DoubleSide } );
  var object = new THREE.Mesh( geo, mat );
  object.position.set( 0, -height, 0 );
  scene.add( object );

  var geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
  var material = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );

  var r = 3;

  for (var i = 0; i < 200; i++) {
    cube = new THREE.Mesh( geometry, material );

    cube.position.set( randRange(-r, r), randRange(-r, r), randRange(-r, r) );

    scene.add( cube );
  }

}

function setupHoloWorld() {
  var geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
  var material = new THREE.MeshLambertMaterial( { color: 0xff3399 } );

  var r = 2;
  for (var i = 0; i < 200; i++) {
    var cube = new THREE.Mesh( geometry, material );

    cube.position.set( randRange(-r, r), randRange(-r, r), randRange(-r, r) );

    holoScene.add( cube );
  }

  // skeleton model
  var mtlLoader = new THREE.MTLLoader();
  mtlLoader.setBaseUrl( 'models/' );
  mtlLoader.setPath( 'models/' );
  mtlLoader.load( 'skeleton.mtl', function( materials ) {
    materials.preload();
    var objLoader = new THREE.OBJLoader();
    objLoader.setMaterials( materials );
    objLoader.setPath( 'models/' );
    objLoader.load( 'skeleton.obj', function ( object ) {
      var s = 0.012;
      object.scale.set( s,s,s );
      object.position.y = -1.845;
      object.position.z = -1;
      holoScene.add( object );
    }, function(){ }, function(err){ console.log(err); } );
  });

}

function setupControls() {
  mouseControls = new THREE.MouseControls(camera);

  window.addEventListener('keydown', function(ev){
    var X = 1.1;
    console.log('keydown', event.keyCode);
    switch ( event.keyCode ) {
      case 74: /*J*/
        setTargetFOV(scaleFOV(targetFOV, -1));
        break;
      case 75: /*K*/
        setTargetFOV(scaleFOV(targetFOV, 1));
        break;
      case 70: /*F*/
        break;
      case 71: /*G*/
        var hFOV = FOV * renderWidth/renderHeight;
        setTargetFOV([hFOV, FOV]);
        break;
      case 72: /*H*/
        setTargetFOV(hololensFOV);
        break;
      case 82: /*R*/

        break;
    }
  }, false);
}

function setupUI() {
  var holoBtn = document.getElementById('holo-btn');
  var fullBtn = document.getElementById('full-btn');
  var incBtn = document.getElementById('inc-btn');
  var decBtn = document.getElementById('dec-btn');

  holoBtn.addEventListener('click', function(){
    setTargetFOV(hololensFOV);
  }, false);
  fullBtn.addEventListener('click', function(){
    var hFOV = FOV * renderWidth/renderHeight;
    setTargetFOV([hFOV, FOV]);
  }, false);
  incBtn.addEventListener('click', function(){
    setTargetFOV(scaleFOV(targetFOV, 1));
  }, false);
  decBtn.addEventListener('click', function(){
    setTargetFOV(scaleFOV(targetFOV, -1));
  }, false);

}

function setTargetFOV(tFOV) {
  if (tFOV[1] > FOV) {
    tFOV = [FOV * renderWidth/renderHeight, FOV];
  }

  targetFOV = tFOV;
  var fovStr = targetFOV[0].toFixed(1) + '° × ' + targetFOV[1].toFixed(1) + '°';
  document.getElementById('current-fov').innerHTML = fovStr;
}

function scaleFOV(fov, direction, percentage) {
  var _FOV = [];
  var factor = (percentage !== undefined) ? 1+(percentage/100) : 1+0.1;
  factor = (direction == 1) ? factor : 1/factor;
  _FOV = [ fov[0]*factor, fov[1]*factor ];
  console.log('scaleFOV: ' + _FOV);
  return _FOV;
}

function animate(t) {
  requestAnimationFrame(animate);

  var dt = clock.getDelta();

  update(dt);
  render(dt);
}

function update(dt) {
  mouseControls.update(dt);

  updateFOV(dt);
}

function updateFOV(dt) {
  var dH = targetFOV[0] - holoFOV[0];
  var dV = targetFOV[1] - holoFOV[1];

  var rate = 5;
  var hFOV = holoFOV[0] + dH*rate*dt;
  var vFOV = holoFOV[1] + dV*rate*dt;

  holoFOV = [hFOV, vFOV];
}

function render(dt) {
  renderer.clear();

  renderer.render(scene, camera);

  if (renderHolograms) {
    renderHolo();

    // reset
    renderer.setViewport( 0, 0, renderWidth, renderHeight );
    renderer.setScissor( 0, 0, renderWidth, renderHeight );
    renderer.setScissorTest( false );
  }
}

function renderHolo() {
  var H = renderHeight;
  var W = renderWidth;

  var hFOV = FOV * renderWidth/renderHeight;

  var x,y,w,h;
  w = holoFOV[0] / hFOV;
  h = holoFOV[1] /  FOV;
  x = 0.5 - w/2;
  y = 0.5 - h/2;

  crop( W*x, H*y, W*w, H*h );

  renderer.render( holoScene, camera );
}

function crop( x, y, w, h ) {
  //renderer.setViewport( x, y, w, h );
  renderer.setScissor( x, y, w, h );
  renderer.setScissorTest( true );
}
<commit_msg>Init rendertexture usage<commit_after>'use strict';

// HOLOSIM

/*
TODO:
-get FOV and aspect right
-UI controls
--input specific FOV
-WebVR 1.0 support (via polyfill, etc.)
-better scene for viewing
-resize handler
-push out
*/

var clock = new THREE.Clock();

var renderer;
var camera, holoCamera;

var scene, holoScene;

var cube, holoCube;

var controls;
var mouseControls;

var renderWidth, renderHeight;

var renderHolograms = true;

var FOV = 70;
var hololensFOV = [30, 17.5]; // based off estimates

var holoFOV = hololensFOV;
var holoAspect = holoFOV[0] / holoFOV[1];

var targetFOV;
setTargetFOV(holoFOV);

var holoPlane;
var holoTexture;

init();

/*
TODO:
-set right distance
-put in player

-update correctly
---set distance
---change FOV of holoCamera
---
*/

function init() {
  scene = new THREE.Scene();
  holoScene = new THREE.Scene();

  // vertical FOV, aspect
  camera = new THREE.PerspectiveCamera( FOV, window.innerWidth/window.innerHeight, 0.1, 1000 );

  holoCamera = new THREE.PerspectiveCamera( holoFOV[1], holoAspect, 0.1, 1000 );

  // ^
  var holoResolution = 512;
  holoTexture = new THREE.WebGLRenderTarget( holoResolution, holoResolution*holoAspect,
    { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat } );

  var planeGeo = new THREE.PlaneGeometry(1,1*1/holoAspect);
  var planeMat = new THREE.MeshBasicMaterial({
    map: holoTexture.texture,
    transparent: true
  });
  holoPlane = new THREE.Mesh(planeGeo, planeMat);
  holoPlane.position.set(0, 0, -0.5); // todo: set right distance
  scene.add( holoPlane );
  // ^

  renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById('canvas'),
    antialias: true
  });
  renderer.autoClear = false;

  renderWidth = window.innerWidth;
  renderHeight = window.innerHeight;

  renderer.setSize( renderWidth, renderHeight );

  addLights(scene);
  addLights(holoScene);

  setupWorld();
  setupHoloWorld();

  setupControls();

  setupUI();

  animate();
}

function randRange(min, max) {
  return Math.random() * (max - min) + min;
}

function addLights(scene) {
  var light = new THREE.DirectionalLight(0xffffff, 1.5);
  light.position.set(1, 1, 1);
  scene.add(light);

  light = new THREE.DirectionalLight(0xffffff, 0.75);
  light.position.set(-1, - 0.5, - 1);
  scene.add(light);

  light = new THREE.AmbientLight(0x666666);
  scene.add(light);
}

function setupWorld() {
  // floor
  var height = 2;
  var map = new THREE.TextureLoader().load('textures/hardwood2_diffuse.jpg');
  map.wrapS = THREE.RepeatWrapping;
  map.wrapT = THREE.RepeatWrapping;
  map.anisotropy = 4;
  map.repeat.set( 6, 12 );
  var geo = new THREE.PlaneGeometry(20,20, 4,4);
  geo.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );

  // wall
  var wallGeo = new THREE.PlaneGeometry(20, 5);
  var wallMap = new THREE.TextureLoader().load('textures/brick_diffuse.jpg');
  var mat = new THREE.MeshLambertMaterial({ map: wallMap });
  wallMap.wrapS = THREE.RepeatWrapping;
  wallMap.wrapT = THREE.RepeatWrapping;
  wallMap.anisotropy = 4;
  wallMap.repeat.set( 3, 1 );
  var wall = new THREE.Mesh( wallGeo, mat );
  wall.position.set( 0, 0, -5 );
  //scene.add( wall );

  var mat = new THREE.MeshLambertMaterial( { map: map, side: THREE.DoubleSide } );
  var object = new THREE.Mesh( geo, mat );
  object.position.set( 0, -height, 0 );
  scene.add( object );

  var geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
  var material = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );

  var r = 3;

  for (var i = 0; i < 200; i++) {
    cube = new THREE.Mesh( geometry, material );

    cube.position.set( randRange(-r, r), randRange(-r, r), randRange(-r, r) );

    scene.add( cube );
  }

}

function setupHoloWorld() {
  var geometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
  var material = new THREE.MeshLambertMaterial( { color: 0xff3399 } );

  var r = 2;
  for (var i = 0; i < 200; i++) {
    var cube = new THREE.Mesh( geometry, material );

    cube.position.set( randRange(-r, r), randRange(-r, r), randRange(-r, r) );

    holoScene.add( cube );
  }

  // skeleton model
  var mtlLoader = new THREE.MTLLoader();
  mtlLoader.setBaseUrl( 'models/' );
  mtlLoader.setPath( 'models/' );
  mtlLoader.load( 'skeleton.mtl', function( materials ) {
    materials.preload();
    var objLoader = new THREE.OBJLoader();
    objLoader.setMaterials( materials );
    objLoader.setPath( 'models/' );
    objLoader.load( 'skeleton.obj', function ( object ) {
      var s = 0.012;
      object.scale.set( s,s,s );
      object.position.y = -1.845;
      object.position.z = -1;
      holoScene.add( object );
    }, function(){ }, function(err){ console.log(err); } );
  });

}

function setupControls() {
  mouseControls = new THREE.MouseControls(camera);

  window.addEventListener('keydown', function(ev){
    var X = 1.1;
    console.log('keydown', event.keyCode);
    switch ( event.keyCode ) {
      case 74: /*J*/
        setTargetFOV(scaleFOV(targetFOV, -1));
        break;
      case 75: /*K*/
        setTargetFOV(scaleFOV(targetFOV, 1));
        break;
      case 70: /*F*/
        break;
      case 71: /*G*/
        var hFOV = FOV * renderWidth/renderHeight;
        setTargetFOV([hFOV, FOV]);
        break;
      case 72: /*H*/
        setTargetFOV(hololensFOV);
        break;
      case 82: /*R*/

        break;
    }
  }, false);
}

function setupUI() {
  var holoBtn = document.getElementById('holo-btn');
  var fullBtn = document.getElementById('full-btn');
  var incBtn = document.getElementById('inc-btn');
  var decBtn = document.getElementById('dec-btn');

  holoBtn.addEventListener('click', function(){
    setTargetFOV(hololensFOV);
  }, false);
  fullBtn.addEventListener('click', function(){
    var hFOV = FOV * renderWidth/renderHeight;
    setTargetFOV([hFOV, FOV]);
  }, false);
  incBtn.addEventListener('click', function(){
    setTargetFOV(scaleFOV(targetFOV, 1));
  }, false);
  decBtn.addEventListener('click', function(){
    setTargetFOV(scaleFOV(targetFOV, -1));
  }, false);

}

function setTargetFOV(tFOV) {
  if (tFOV[1] > FOV) {
    tFOV = [FOV * renderWidth/renderHeight, FOV];
  }

  targetFOV = tFOV;
  var fovStr = targetFOV[0].toFixed(1) + '° × ' + targetFOV[1].toFixed(1) + '°';
  document.getElementById('current-fov').innerHTML = fovStr;
}

function scaleFOV(fov, direction, percentage) {
  var _FOV = [];
  var factor = (percentage !== undefined) ? 1+(percentage/100) : 1+0.1;
  factor = (direction == 1) ? factor : 1/factor;
  _FOV = [ fov[0]*factor, fov[1]*factor ];
  console.log('scaleFOV: ' + _FOV);
  return _FOV;
}

function animate(t) {
  requestAnimationFrame(animate);

  var dt = clock.getDelta();

  update(dt);
  render(dt);
}

function update(dt) {
  mouseControls.update(dt);

  updateFOV(dt);
}

function updateFOV(dt) {
  var dH = targetFOV[0] - holoFOV[0];
  var dV = targetFOV[1] - holoFOV[1];

  var rate = 5;
  var hFOV = holoFOV[0] + dH*rate*dt;
  var vFOV = holoFOV[1] + dV*rate*dt;

  holoFOV = [hFOV, vFOV];
}

function render(dt) {
  renderer.clear();

  //
  renderer.clearTarget(holoTexture);
  renderer.render(holoScene, camera, holoTexture);

  renderer.render(scene, camera);

  /*if (renderHolograms) {
    renderHolo();

    // reset
    renderer.setViewport( 0, 0, renderWidth, renderHeight );
    renderer.setScissor( 0, 0, renderWidth, renderHeight );
    renderer.setScissorTest( false );
  }*/
}

function renderHolo() {
  var H = renderHeight;
  var W = renderWidth;

  var hFOV = FOV * renderWidth/renderHeight;

  var x,y,w,h;
  w = holoFOV[0] / hFOV;
  h = holoFOV[1] /  FOV;
  x = 0.5 - w/2;
  y = 0.5 - h/2;

  crop( W*x, H*y, W*w, H*h );

  renderer.render( holoScene, camera );
}

function crop( x, y, w, h ) {
  //renderer.setViewport( x, y, w, h );
  renderer.setScissor( x, y, w, h );
  renderer.setScissorTest( true );
}
<|endoftext|>


<commit_before>'use strict';

/**
 * This module does a number of things:
 *
 * - It overrides the built in Angular exception handling, so that any exceptions that would normally be logged
 *   to the console, are POSTed via AJAX to a server-side service. It does the cross-browser, by using stacktrace.js
 *
 * - It exposes an applicationLoggingService that can be injected into any Angular module. This service exposes
 *   'trace', 'debug', 'info', 'warn' and 'error' methods which will log to the console but also send those messages
 *   to a server-side service.
 */
var loggingModule = angular.module('talis.services.logging', []);

/**
 * Create a service that gives us a nice Angular-esque wrapper around the
 * stackTrace.js printStackTrace() method. We use a service because calling
 * methods in the global context is not the 'angular way'
 */
loggingModule.factory(
    'stacktraceService',
    function () {
        return ({
            print: printStackTrace
        });
    }
);

/**
 * Override Angular's built in exception handler, and tell it to use our new exceptionLoggingService
 */
loggingModule.provider('$exceptionHandler', {
    $get: function (exceptionLoggingService) {
        return (exceptionLoggingService);
    }
});

/**
 * Exception Logging Service, currently only used by the $exceptionHandler but logs to the console and uses the
 * stacktraceService to generate a browser independent stacktrace which is POSTed to server side clientlogging
 * service.
 */
loggingModule.factory(
    'exceptionLoggingService',
    ['$log', '$window', 'stacktraceService', 'LOGGING_CONFIG', function ($log, $window, stacktraceService, LOGGING_CONFIG) {
        function error(exception, cause) {
            if (LOGGING_CONFIG.LOGGING_TYPE !== 'none') {
                // preserve default behaviour i.e. dump to browser console
                $log.error.apply($log, arguments);
            }

            if($window.talisLogger.onBeforeLogError && !$window.talisLogger.onBeforeLogError(exception)) {
                return false;
            }

            if (LOGGING_CONFIG.FORWARD_TO_NEWRELIC && $window.NREUM && $window.NREUM.noticeError) {
                $window.NREUM.noticeError(exception);
            }

            // check if the config says we should log to the remote, and also if a remote endpoint was specified
            if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT) {
                // now log server side.
                try {
                    var errorMessage = exception.toString();
                    var stackTrace = stacktraceService.print({ e: exception });

                    // use AJAX not an angular service because if something has gone wrong
                    // angular might be fubar'd
                    $.ajax({
                        type: 'POST',
                        url: LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT,
                        contentType: 'application/json',
                        data: angular.toJson({
                            url: $window.location.href,
                            message: errorMessage,
                            type: 'exception',
                            stackTrace: stackTrace,
                            cause: (cause || '')
                        })
                    });
                } catch (loggingError) {
                    $log.warn('Error logging failed');
                    $log.log(loggingError);
                }
            }
        }
        return (error);
    }]
);

/**
 * Application Logging Service added to give us a way of logging error / debug statements from the client to the server.
 * For example a 502 gateway error on a http call wont thrown a browser exception, but we may want to have that logged on
 * server specifically eg:  $http.get().error( function(){ call applicationloggingservice here })
 */
loggingModule.factory(
    'applicationLoggingService',
    ['$log', '$window', 'LOGGING_CONFIG', function ($log, $window, LOGGING_CONFIG) {
        var arrLoggingLevels = ['trace', 'debug', 'info', 'warn', 'error'];
        var loggingThreshold = LOGGING_CONFIG.LOGGING_THRESHOLD || 'info';
        var iLoggingThreshold = arrLoggingLevels.indexOf(loggingThreshold);
        $window.talisLogger = {};

        /*
         * If we've told applicationLoggingService to override the logging threshold set in config then also pass
         * it back to the remote client logging URL.
         */
        var overrideLoggingThreshold = false;

        /*
         * Allows the calling code to set some default data that will get logged on
         * every call to applicationLoggingService.
         */
        var defaultData = null;

        var isLoggingEnabledForSeverity = function (severity) {
            var iRequestedLevel = arrLoggingLevels.indexOf(severity);
            if (iRequestedLevel === -1) {
                // Invalid level requested
                return false;
            }

            return (iRequestedLevel >= iLoggingThreshold);
        };

        var log = function (severity, message, desc, sendToNewRelic) {
            if (!isLoggingEnabledForSeverity(severity)) {
                return;
            }

            if (LOGGING_CONFIG.LOGGING_TYPE !== 'none') {
                // preserve default behaviour
                var angularLogSeverity = severity;
                if (angularLogSeverity === 'trace') {
                    // Angular $log doesn't support trace so we use 'log' instead.
                    angularLogSeverity = 'log';
                }

                if (desc) {
                    desc = JSON.stringify(desc);
                    $log[angularLogSeverity](message, desc);
                } else {
                    $log[angularLogSeverity](message);
                }
            }

            if($window.talisLogger.onBeforeLogError && !$window.talisLogger.onBeforeLogError(message)) {
                return false;
            }

            if (sendToNewRelic && $window.NREUM && $window.NREUM.noticeError) {
                $window.NREUM.noticeError(message, {desc: desc});
            }

            // check if the config says we should log to the remote, and also if a remote endpoint was specified
            if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT) {
                // send server side
                var data = {
                    type: severity,
                    message: message,
                    url: $window.location.href,
                    overrideLoggingThreshold: overrideLoggingThreshold
                };
                if (desc) {
                    data.desc = desc;
                }
                if (defaultData) {
                    data.defaultData = defaultData;
                }
                $.ajax({
                    type: 'POST',
                    url: LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT,
                    contentType: 'application/json',
                    data: angular.toJson(data)
                });
            }
        };

        return ({
            trace: function (message, desc) {
                log('trace', message, desc);
            },
            debug: function (message, desc) {
                log('debug', message, desc);
            },
            info: function (message, desc) {
                log('info', message, desc);
            },
            warn: function (message, desc) {
                log('warn', message, desc);
            },
            error: function (message, desc) {
                var sendToNewRelic = LOGGING_CONFIG.FORWARD_TO_NEWRELIC && $window.NREUM && $window.NREUM.noticeError;
                log('error', message, desc, sendToNewRelic);
            },
            setLoggingThreshold: function (level) {
                /*
                 * Normally the logger would use the logging threshold passed in on the config hash but an
                 * application may want to override this dynamically, e.g. to enable a different logging
                 * threshold for a given user.
                 */
                if (arrLoggingLevels.indexOf(level) !== -1) {
                    iLoggingThreshold = arrLoggingLevels.indexOf(level);
                    overrideLoggingThreshold = true;
                }
            },
            setDefaultData: function (data) {
                defaultData = data;
            }
        });
    }]
);

loggingModule.factory(
    'userErrorReport',
    ['$window', '$rootScope', 'LOGGING_CONFIG', function ($window, $rootScope, LOGGING_CONFIG) {
        return ({
            send: function (userMessage, error) {
                var payload = {
                    url: $window.location.href,
                    systemError: error,
                    userMessage: userMessage
                };
                if ($rootScope.user != null) payload.user = $rootScope.user.profile;

                // check if the config says we should log to the remote, and also if a remote endpoint was specified
                if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_ERROR_REPORT_ENDPOINT) {
                    $.ajax({
                        type: 'POST',
                        url: LOGGING_CONFIG.REMOTE_ERROR_REPORT_ENDPOINT,
                        contentType: 'application/json',
                        data: angular.toJson(payload)
                    });
                }
            }
        });
    }]
);
<commit_msg>Log URL as custom attribute in NR<commit_after>'use strict';

/**
 * This module does a number of things:
 *
 * - It overrides the built in Angular exception handling, so that any exceptions that would normally be logged
 *   to the console, are POSTed via AJAX to a server-side service. It does the cross-browser, by using stacktrace.js
 *
 * - It exposes an applicationLoggingService that can be injected into any Angular module. This service exposes
 *   'trace', 'debug', 'info', 'warn' and 'error' methods which will log to the console but also send those messages
 *   to a server-side service.
 */
var loggingModule = angular.module('talis.services.logging', []);

/**
 * Create a service that gives us a nice Angular-esque wrapper around the
 * stackTrace.js printStackTrace() method. We use a service because calling
 * methods in the global context is not the 'angular way'
 */
loggingModule.factory(
    'stacktraceService',
    function () {
        return ({
            print: printStackTrace
        });
    }
);

/**
 * Override Angular's built in exception handler, and tell it to use our new exceptionLoggingService
 */
loggingModule.provider('$exceptionHandler', {
    $get: function (exceptionLoggingService) {
        return (exceptionLoggingService);
    }
});

/**
 * Exception Logging Service, currently only used by the $exceptionHandler but logs to the console and uses the
 * stacktraceService to generate a browser independent stacktrace which is POSTed to server side clientlogging
 * service.
 */
loggingModule.factory(
    'exceptionLoggingService',
    ['$log', '$window', 'stacktraceService', 'LOGGING_CONFIG', function ($log, $window, stacktraceService, LOGGING_CONFIG) {
        function error(exception, cause) {
            if (LOGGING_CONFIG.LOGGING_TYPE !== 'none') {
                // preserve default behaviour i.e. dump to browser console
                $log.error.apply($log, arguments);
            }

            if($window.talisLogger.onBeforeLogError && !$window.talisLogger.onBeforeLogError(exception)) {
                return false;
            }

            if (LOGGING_CONFIG.FORWARD_TO_NEWRELIC && $window.NREUM && $window.NREUM.noticeError) {
                $window.NREUM.noticeError(exception, { url: $window.location.href });
            }

            // check if the config says we should log to the remote, and also if a remote endpoint was specified
            if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT) {
                // now log server side.
                try {
                    var errorMessage = exception.toString();
                    var stackTrace = stacktraceService.print({ e: exception });

                    // use AJAX not an angular service because if something has gone wrong
                    // angular might be fubar'd
                    $.ajax({
                        type: 'POST',
                        url: LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT,
                        contentType: 'application/json',
                        data: angular.toJson({
                            url: $window.location.href,
                            message: errorMessage,
                            type: 'exception',
                            stackTrace: stackTrace,
                            cause: (cause || '')
                        })
                    });
                } catch (loggingError) {
                    $log.warn('Error logging failed');
                    $log.log(loggingError);
                }
            }
        }
        return (error);
    }]
);

/**
 * Application Logging Service added to give us a way of logging error / debug statements from the client to the server.
 * For example a 502 gateway error on a http call wont thrown a browser exception, but we may want to have that logged on
 * server specifically eg:  $http.get().error( function(){ call applicationloggingservice here })
 */
loggingModule.factory(
    'applicationLoggingService',
    ['$log', '$window', 'LOGGING_CONFIG', function ($log, $window, LOGGING_CONFIG) {
        var arrLoggingLevels = ['trace', 'debug', 'info', 'warn', 'error'];
        var loggingThreshold = LOGGING_CONFIG.LOGGING_THRESHOLD || 'info';
        var iLoggingThreshold = arrLoggingLevels.indexOf(loggingThreshold);
        $window.talisLogger = {};

        /*
         * If we've told applicationLoggingService to override the logging threshold set in config then also pass
         * it back to the remote client logging URL.
         */
        var overrideLoggingThreshold = false;

        /*
         * Allows the calling code to set some default data that will get logged on
         * every call to applicationLoggingService.
         */
        var defaultData = null;

        var isLoggingEnabledForSeverity = function (severity) {
            var iRequestedLevel = arrLoggingLevels.indexOf(severity);
            if (iRequestedLevel === -1) {
                // Invalid level requested
                return false;
            }

            return (iRequestedLevel >= iLoggingThreshold);
        };

        var log = function (severity, message, desc, sendToNewRelic) {
            if (!isLoggingEnabledForSeverity(severity)) {
                return;
            }

            if (LOGGING_CONFIG.LOGGING_TYPE !== 'none') {
                // preserve default behaviour
                var angularLogSeverity = severity;
                if (angularLogSeverity === 'trace') {
                    // Angular $log doesn't support trace so we use 'log' instead.
                    angularLogSeverity = 'log';
                }

                if (desc) {
                    desc = JSON.stringify(desc);
                    $log[angularLogSeverity](message, desc);
                } else {
                    $log[angularLogSeverity](message);
                }
            }

            if($window.talisLogger.onBeforeLogError && !$window.talisLogger.onBeforeLogError(message)) {
                return false;
            }

            if (sendToNewRelic && $window.NREUM && $window.NREUM.noticeError) {
                $window.NREUM.noticeError(message, { desc: desc, url: $window.location.href });
            }

            // check if the config says we should log to the remote, and also if a remote endpoint was specified
            if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT) {
                // send server side
                var data = {
                    type: severity,
                    message: message,
                    url: $window.location.href,
                    overrideLoggingThreshold: overrideLoggingThreshold
                };
                if (desc) {
                    data.desc = desc;
                }
                if (defaultData) {
                    data.defaultData = defaultData;
                }
                $.ajax({
                    type: 'POST',
                    url: LOGGING_CONFIG.REMOTE_LOGGING_ENDPOINT,
                    contentType: 'application/json',
                    data: angular.toJson(data)
                });
            }
        };

        return ({
            trace: function (message, desc) {
                log('trace', message, desc);
            },
            debug: function (message, desc) {
                log('debug', message, desc);
            },
            info: function (message, desc) {
                log('info', message, desc);
            },
            warn: function (message, desc) {
                log('warn', message, desc);
            },
            error: function (message, desc) {
                var sendToNewRelic = LOGGING_CONFIG.FORWARD_TO_NEWRELIC && $window.NREUM && $window.NREUM.noticeError;
                log('error', message, desc, sendToNewRelic);
            },
            setLoggingThreshold: function (level) {
                /*
                 * Normally the logger would use the logging threshold passed in on the config hash but an
                 * application may want to override this dynamically, e.g. to enable a different logging
                 * threshold for a given user.
                 */
                if (arrLoggingLevels.indexOf(level) !== -1) {
                    iLoggingThreshold = arrLoggingLevels.indexOf(level);
                    overrideLoggingThreshold = true;
                }
            },
            setDefaultData: function (data) {
                defaultData = data;
            }
        });
    }]
);

loggingModule.factory(
    'userErrorReport',
    ['$window', '$rootScope', 'LOGGING_CONFIG', function ($window, $rootScope, LOGGING_CONFIG) {
        return ({
            send: function (userMessage, error) {
                var payload = {
                    url: $window.location.href,
                    systemError: error,
                    userMessage: userMessage
                };
                if ($rootScope.user != null) payload.user = $rootScope.user.profile;

                // check if the config says we should log to the remote, and also if a remote endpoint was specified
                if (LOGGING_CONFIG.LOGGING_TYPE === 'remote' && LOGGING_CONFIG.REMOTE_ERROR_REPORT_ENDPOINT) {
                    $.ajax({
                        type: 'POST',
                        url: LOGGING_CONFIG.REMOTE_ERROR_REPORT_ENDPOINT,
                        contentType: 'application/json',
                        data: angular.toJson(payload)
                    });
                }
            }
        });
    }]
);
<|endoftext|>


<commit_before>var MiniMap;

MiniMap = function () {
    var map, container, buildingsLayer, unitsLayer, width, height, mapWidth,
            mapHeight, buildingsLayerCtx, unitsLayerCtx, xRatio, yRatio,
            tileWidth, tileHeight, changedTerain, changedBuildings,
            changedUnits, drawTileLine, fill, buildingsLayerIndex, createIndex,
            xRatioC, yRatioC, initRenderer, renderUnitsLayer,
            renderBuildingsLayer, renderTerainLayer;

    map = [];
    buildingsLayer = document.createElement('canvas');
    buildingsLayerCtx = buildingsLayer.getContext('2d');
    unitsLayer = document.createElement('canvas');
    unitsLayerCtx = unitsLayer.getContext('2d');
    changedTerain = false;
    changedBuildings = false;
    changedUnits = false;

    this.setMap = function (newMap) {
        if (!(newMap instanceof Array) || !newMap[0] ||
                !(newMap[0] instanceof Array)) {
            throw new Error("invalid format of map");
        }
        map = newMap;
        mapHeight = map.length;
        mapWidth = map[0].length;
        if (container) {
            initRenderer();
        }
    };

    this.setContainer = function (newContainer) {
        if (!(newContainer instanceof HTMLElement)) {
            throw new Error("container must be an HTML element");
        }
        container = newContainer;
        width = container.offsetWidth;
        height = container.offsetHeight;
        buildingsLayer.width = unitsLayer.width = width;
        buildingsLayer.height = unitsLayer.height = height;
        unitsLayer.style.marginTop = -height + 'px';
        container.appendChild(buildingsLayer);
        container.appendChild(unitsLayer);
        if (mapWidth) {
            initRenderer();
        }
    };

    this.onBuildingChange = function (building) {
        changedBuildings.push(building);
    };

    this.render = function () {
        changedTerain && this.renderTerainLayer();
        changedBuildings.length && this.renderBuildingsLayer();
        changedUnits.length && this.renderUnitsLayer();
    };

    renderUnitsLayer = function () {
        // TODO
        changedUnits = false;
    };

    renderBuildingsLayer = function () {
        var i, building, x1, y1, x2, y2, x3, y3, x4, y4;
        for (i = changedBuildings.length; i--;) {
            building = changedBuildings[i];
            buildingsLayerCtx.globalCompositeOperation = building.type ===
                    false ? 'destination-out' : 'source-over';
            x1 = building.x;
            y1 = building.y;
            x2 = x1 + building.width;
            y2 = y1 + Math.floor(building.width / 2);
            x3 = x1 - Math.floor(building.height / 2);
            y3 = y1 + building.height;
            x4 = x3 + building.width;
            y4 = y3 + Math.floor(building.width / 2);
            buildingsLayerCtx.fillStyle = building.color;
            drawTileLine(x1, y1, x2, y2, buildingsLayerCtx);
            drawTileLine(x1, y1, x3, y3, buildingsLayerCtx);
            drawTileLine(x2, y2, x4, y4, buildingsLayerCtx);
            drawTileLine(x3, y3, x4, y4, buildingsLayerCtx);
            fill(Math.round((x1 + x4) / 2), Math.round((y1 + y4) / 2),
                    buildingsLayerCtx);
        }
        changedBuildings = [];
    };

    renderTerainLayer = function () {
        var i, j, row;
        for (i = map.length; i--;) {
            row = map[i];
            for (j = row.length; j--;) {
                buildingsLayerCtx.fillStyle = row[j].minimap;
                buildingsLayerCtx.fillRect(xRatio * j, yRatio * i,
                        tileWidth, tileHeight);
            }
        }
        container.style.backgroundImage = 'url(' + buildingsLayer.toDataURL() +
                ')';
        buildingsLayerCtx.clearRect(0, 0, width, height);
        changedTerain = false;
    };

    createIndex = function () {
        var index, i, j;
        index = new Array(mapWidth);
        for (i = mapWidth; i--;) {
            index[i] = new Array(mapHeight);
            for (j = mapHeight; j--;) {
                index[i][j] = false;
            }
        }
        return index;
    };

    fill = function (x, y, ctx, fillColor) {
        var thisColor;
        if ((x >= mapWidth) || (x < 0) || (y >= mapHeight) || (y < 0)) {
            return;
        }
        thisColor = buildingsLayerIndex[x][y];
        if (fillColor === undefined) {
            fillColor = thisColor;
        }
        if (thisColor == fillColor) {
            ctx.fillRect(x * xRatio, y * yRatio, xRatioC, yRatioC);
            buildingsLayerIndex[x][y] = !buildingsLayerIndex[x][y];
            fill(x - 1, y, ctx, fillColor);
            fill(x + 1, y, ctx, fillColor);
            fill(x, y - 1, ctx, fillColor);
            fill(x, y + 1, ctx, fillColor);
        }
    };

    drawTileLine = function (x1, y1, x2, y2, ctx) {
        var len, vx, vy, rx, ry;
        vx = x2 - x1;
        vy = y2 - y1;
        len = Math.sqrt(vx * vx + vy * vy);
        vx /= len;
        vy /= len;
        ctx.fillRect(xRatio * Math.round(x1), yRatio * Math.round(y1),
                xRatioC, yRatioC);
        do {
            x1 += vx;
            y1 += vy;
            rx = Math.round(x1);
            ry = Math.round(y1);
            buildingsLayerIndex[rx][ry] = true;
            ctx.fillRect(xRatio * rx, yRatio * ry, xRatioC, yRatioC);
        } while ((Math.round(x1) != x2) && (Math.round(y1) != y2))
    };

    initRenderer = function () {
        xRatio = width / mapWidth;
        yRatio = height / mapHeight;
        xRatioC = Math.ceil(xRatio);
        yRatioC = Math.ceil(yRatio);
        tileWidth = Math.ceil(xRatio);
        tileHeight = Math.ceil(yRatio);
        changedTerain = true;
        changedBuildings = [];
        changedUnits = [];
        buildingsLayerIndex = createIndex();
    };
};<commit_msg>bugfix of previous commit<commit_after>var MiniMap;

MiniMap = function () {
    var map, container, buildingsLayer, unitsLayer, width, height, mapWidth,
            mapHeight, buildingsLayerCtx, unitsLayerCtx, xRatio, yRatio,
            tileWidth, tileHeight, changedTerain, changedBuildings,
            changedUnits, drawTileLine, fill, buildingsLayerIndex, createIndex,
            xRatioC, yRatioC, initRenderer, renderUnitsLayer,
            renderBuildingsLayer, renderTerainLayer;

    map = [];
    buildingsLayer = document.createElement('canvas');
    buildingsLayerCtx = buildingsLayer.getContext('2d');
    unitsLayer = document.createElement('canvas');
    unitsLayerCtx = unitsLayer.getContext('2d');
    changedTerain = false;
    changedBuildings = false;
    changedUnits = false;

    this.setMap = function (newMap) {
        if (!(newMap instanceof Array) || !newMap[0] ||
                !(newMap[0] instanceof Array)) {
            throw new Error("invalid format of map");
        }
        map = newMap;
        mapHeight = map.length;
        mapWidth = map[0].length;
        if (container) {
            initRenderer();
        }
    };

    this.setContainer = function (newContainer) {
        if (!(newContainer instanceof HTMLElement)) {
            throw new Error("container must be an HTML element");
        }
        container = newContainer;
        width = container.offsetWidth;
        height = container.offsetHeight;
        buildingsLayer.width = unitsLayer.width = width;
        buildingsLayer.height = unitsLayer.height = height;
        unitsLayer.style.marginTop = -height + 'px';
        container.appendChild(buildingsLayer);
        container.appendChild(unitsLayer);
        if (mapWidth) {
            initRenderer();
        }
    };

    this.onBuildingChange = function (building) {
        changedBuildings.push(building);
    };

    this.render = function () {
        changedTerain && renderTerainLayer();
        changedBuildings.length && renderBuildingsLayer();
        changedUnits.length && renderUnitsLayer();
    };

    renderUnitsLayer = function () {
        // TODO
        changedUnits = false;
    };

    renderBuildingsLayer = function () {
        var i, building, x1, y1, x2, y2, x3, y3, x4, y4;
        for (i = changedBuildings.length; i--;) {
            building = changedBuildings[i];
            buildingsLayerCtx.globalCompositeOperation = building.type ===
                    false ? 'destination-out' : 'source-over';
            x1 = building.x;
            y1 = building.y;
            x2 = x1 + building.width;
            y2 = y1 + Math.floor(building.width / 2);
            x3 = x1 - Math.floor(building.height / 2);
            y3 = y1 + building.height;
            x4 = x3 + building.width;
            y4 = y3 + Math.floor(building.width / 2);
            buildingsLayerCtx.fillStyle = building.color;
            drawTileLine(x1, y1, x2, y2, buildingsLayerCtx);
            drawTileLine(x1, y1, x3, y3, buildingsLayerCtx);
            drawTileLine(x2, y2, x4, y4, buildingsLayerCtx);
            drawTileLine(x3, y3, x4, y4, buildingsLayerCtx);
            fill(Math.round((x1 + x4) / 2), Math.round((y1 + y4) / 2),
                    buildingsLayerCtx);
        }
        changedBuildings = [];
    };

    renderTerainLayer = function () {
        var i, j, row;
        for (i = map.length; i--;) {
            row = map[i];
            for (j = row.length; j--;) {
                buildingsLayerCtx.fillStyle = row[j].minimap;
                buildingsLayerCtx.fillRect(xRatio * j, yRatio * i,
                        tileWidth, tileHeight);
            }
        }
        container.style.backgroundImage = 'url(' + buildingsLayer.toDataURL() +
                ')';
        buildingsLayerCtx.clearRect(0, 0, width, height);
        changedTerain = false;
    };

    createIndex = function () {
        var index, i, j;
        index = new Array(mapWidth);
        for (i = mapWidth; i--;) {
            index[i] = new Array(mapHeight);
            for (j = mapHeight; j--;) {
                index[i][j] = false;
            }
        }
        return index;
    };

    fill = function (x, y, ctx, fillColor) {
        var thisColor;
        if ((x >= mapWidth) || (x < 0) || (y >= mapHeight) || (y < 0)) {
            return;
        }
        thisColor = buildingsLayerIndex[x][y];
        if (fillColor === undefined) {
            fillColor = thisColor;
        }
        if (thisColor == fillColor) {
            ctx.fillRect(x * xRatio, y * yRatio, xRatioC, yRatioC);
            buildingsLayerIndex[x][y] = !buildingsLayerIndex[x][y];
            fill(x - 1, y, ctx, fillColor);
            fill(x + 1, y, ctx, fillColor);
            fill(x, y - 1, ctx, fillColor);
            fill(x, y + 1, ctx, fillColor);
        }
    };

    drawTileLine = function (x1, y1, x2, y2, ctx) {
        var len, vx, vy, rx, ry;
        vx = x2 - x1;
        vy = y2 - y1;
        len = Math.sqrt(vx * vx + vy * vy);
        vx /= len;
        vy /= len;
        ctx.fillRect(xRatio * Math.round(x1), yRatio * Math.round(y1),
                xRatioC, yRatioC);
        do {
            x1 += vx;
            y1 += vy;
            rx = Math.round(x1);
            ry = Math.round(y1);
            buildingsLayerIndex[rx][ry] = true;
            ctx.fillRect(xRatio * rx, yRatio * ry, xRatioC, yRatioC);
        } while ((Math.round(x1) != x2) && (Math.round(y1) != y2))
    };

    initRenderer = function () {
        xRatio = width / mapWidth;
        yRatio = height / mapHeight;
        xRatioC = Math.ceil(xRatio);
        yRatioC = Math.ceil(yRatio);
        tileWidth = Math.ceil(xRatio);
        tileHeight = Math.ceil(yRatio);
        changedTerain = true;
        changedBuildings = [];
        changedUnits = [];
        buildingsLayerIndex = createIndex();
    };
};<|endoftext|>