<commit_before>"use strict";

var expat = require('node-expat');

class XMLUtils {
    constructor(definition) {
        this._definition = definition;
    }

    toXML(obj, rootName, indentation, optimizeEmpty, convertTypes = true) {
        return _toXML(obj, this._definition, rootName, indentation, optimizeEmpty, convertTypes);
    }

    fromXML(xml, inlineAttributes, convertTypes = true) {
        return _fromXML(xml, this._definition, inlineAttributes, convertTypes);
    }

    generateSample(rootName) {
        var result = {};
        result[rootName] =_generateSample(this._definition[rootName], rootName);
        return result;
    }
}

function _toXML (obj, definition, parentName, indentation, optimizeEmpty, convertTypes, level) {
    definition = definition ? definition : {};
    level = level ? level : 0;
    indentation = indentation ? indentation : 2;
    optimizeEmpty = optimizeEmpty ? true : false;

    var result = "";
    var namespace = "";
    var nsOffset = parentName.indexOf(':');
    if(nsOffset > - 1) {
        namespace = parentName.substr(0, nsOffset) + ":";
        parentName = parentName.substr(nsOffset + 1);

    } else if(definition[parentName + "$namespace"]) {
        namespace = definition[parentName + "$namespace"] + ":";
    }
    var attributes = definition[parentName + "$attributes"] || {};
    var order = obj[parentName + "$order"] || definition[parentName + "$order"];
    var type = obj[parentName + "$type"] || definition[parentName + "$type"];

    if(level === 0) {
        // Go into first level
        obj = obj[parentName];
    }

    var whitespace = " ".repeat(level * indentation);

    if(convertTypes && obj !== undefined && obj !== null) {
        if(type === "base64Binary") {
            obj = Buffer.from(obj).toString('base64');

        } else if(type === "hexBinary") {
            obj = Buffer.from(obj).toString('hex');
        }
    }

    if(typeof obj === undefined || obj === null) {
        // TODO: Handle null types

    } else if(Array.isArray(obj)) {
        obj.forEach(function(value) {
            result += _toXML(value, definition, namespace + parentName, indentation, optimizeEmpty, convertTypes, level);
        });

    } else if(typeof obj === "object") {
        var keys = Object.getOwnPropertyNames(obj);
        if(order) {
            keys = keys.sort(function(a, b) {
                return order.indexOf(a) - order.indexOf(b);
            });
        }

        let subResult = "";
        keys.forEach(function(key) {
            if(key === "$") {
                subResult += obj[key];

            } else if(key === "namespace$") {
                namespace = obj[key] + ":";

            } else if(key.indexOf("$") == 0) {
                attributes[key.substr(1)] = obj[key];

            } else if(key.indexOf("$") > 0) {
                // Skip definition information such as order

            } else {
                subResult += _toXML(obj[key], definition[parentName], key, indentation, optimizeEmpty, convertTypes, level + 1);
            }
        });

        // Generate start and end tag
        result += whitespace + "<" + namespace +  parentName;
        Object.getOwnPropertyNames(attributes).forEach(function(key){
            result += " " + key + '="' + attributes[key] + '"';
        });
        result += obj["$"] ? ">" + subResult : ">\n" + subResult + whitespace;
        result += "</" + namespace + parentName + ">" + (level > 0 ? "\n" : "");

    } else {
        result += whitespace + "<" + namespace +  parentName;
        Object.getOwnPropertyNames(attributes).forEach(function(key){
            result += " " + key + '="' + attributes[key] + '"';
        });

        if(obj === "" && optimizeEmpty) {
            result += " />\n";

        } else {
            result += ">" + escapeValue(obj) + "</" + namespace + parentName + ">\n";
        }
    }

    return result;
}

function escapeValue(value) {
    // https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents/1091953
    if(typeof value === 'string'){
        return value.replace(/((?:&(?!(?:apos|quot|[gl]t|amp);))|(?:<!--.+?-->)|(?:<!\[CDATA\[.+?]]>)|(?:<\?.+\?>)|[<>'"])/g, function(match, p1) {
            switch(p1) {
                case '>': return '>';
                case '<': return '<';
                case "'": return ''';
                case '"': return '"';
                case '&': return '&';
                default: return p1;
            }
        });

    } else {
        return value;
    }
}

function _fromXML (xml, objectDefinition, inlineAttributes, convertTypes) {
    var definitions = [objectDefinition || {}];

    var parser = new expat.Parser('UTF-8');
    var result = {};
    var currentValue = "";
    var currentObject = result;
    var currentType = "";
    var objects = [];
    var names = [];

    var orders = [];

    parser.on('startElement', function(name, attributes) {
        // TODO: Handle namespaces in a nice way
        // Parse namespace
        var ns = name.split(":");
        if(ns.length > 1) {
            name = ns[1];
            ns = ns[0];
        } else {
            ns = undefined;
        }

        var definition = definitions[definitions.length - 1];
        currentType = definition[name + "$type"];
        var nextObject = {};
        currentValue = ""; // TODO: Create $t value on object if this has data

        if(ns) {
            if(inlineAttributes) {
                nextObject["namespace" + "$"] = ns;

            } else {
                currentObject[name + "$namespace"] = ns;
            }
        }

        // Handle attributes
        if(Object.getOwnPropertyNames(attributes).length > 0) {
            if(inlineAttributes) {
                Object.keys(attributes).forEach(function(key){
                    nextObject["$" + key] = attributes[key];
                });

            } else {
                if(currentObject.hasOwnProperty(name + "$attributes")) {
                    if(Array.isArray(currentObject[name + "$attributes"])) {
                        currentObject[name + "$attributes"].push(attributes);

                    } else {
                        // Convert to array
                        currentObject[name + "$attributes"] = [currentObject[name + "$attributes"], attributes];
                    }

                } else {
                    if(Array.isArray(currentType)) { // TODO: Migrate to using string formatted definitions, fx. number[]
                        currentObject[name + "$attributes"] = [attributes];

                    } else {
                        currentObject[name + "$attributes"] = attributes;
                    }
                }
            }
        }

        // Handle tag
        if(currentObject.hasOwnProperty(name)) {
            if(Array.isArray(currentObject[name])) {
                currentObject[name].push(nextObject);

            } else {
                // Convert to array
                currentObject[name] = [currentObject[name], nextObject];
            }

        } else {
            // Check definition to see if we have a type defined
            if(Array.isArray(currentType)) {
                currentObject[name] = [nextObject];

            } else {
                currentObject[name] = nextObject;
            }
        }

        // Save order
        if(orders.length <= names.length) {
            orders.push([name]);

        } else if(!Array.isArray(currentObject[name])) {
           orders[names.length].push(name);
        }

        names.push(name);
        objects.push(currentObject);
        definitions.push(definition[name] || {});
        currentObject = nextObject;
    });

    parser.on('text', function(data) {
        currentValue += data.trim();
    });

    parser.on('endElement', function(name){
        var ns = name.split(":");
        if(ns.length > 1) {
            name = ns[1];
            ns = ns[0];
        }

        if(objects.length > 0) {
            currentObject = objects.pop();
            definitions.pop();

            if(names.length < orders.length) {
                var order = orders.pop();
                if(order.length > 1) {
                    currentObject[name + "$order"] = order;
                }
            }
            names.pop();

            if(Array.isArray(currentObject[name])) {
                if(Object.getOwnPropertyNames(currentObject[name][currentObject[name].length -1]).length === 0) {
                    currentObject[name][currentObject[name].length -1] = currentValue;

                } else {
                    currentObject[name][currentObject[name].length -1].$ = currentValue;
                    // TODO: Save "<tag>text<subtag>" type text
                }

            } else if(typeof currentObject[name] === "object") {
                if(Object.getOwnPropertyNames(currentObject[name]).length === 0) { // Move to utility function
                    if(convertTypes) {
                        if(currentType === "boolean") {
                            currentObject[name] = currentValue === 'true';

                        } else if(['decimal', 'double', 'float'].indexOf(currentType) > -1) {
                            currentObject[name] = parseFloat(currentValue);

                        } else if(['byte', 'int', 'integer', 'long', 'negativeInteger', 'nonNegativeInteger',
                                'nonPositiveInteger', 'short', 'unsignedByte', 'unsignedInt', 'unsignedLong',
                                'unsignedShort'].indexOf(currentType) > -1) {
                            currentObject[name] = parseInt(currentValue);

                        } else if(currentType === "base64Binary") {
                            currentObject[name] = Buffer.from(currentValue, 'base64');

                        } else if(currentType === "hexBinary") {
                            currentObject[name] = Buffer.from(currentValue, 'hex');

                        } else {
                            currentObject[name] = currentValue;
                        }

                    } else {
                        currentObject[name] = currentValue; // TODO: Handle inline attributes
                    }

                } else if(currentValue != '') {
                    currentObject[name].$ = currentValue;
                    // TODO: Save "<tag>text<subtag>" type text
                }
            }
        } else {
            console.log("No objects in objects");
        }

        currentValue = "";
    });

    if (!parser.parse(xml)) {
        throw new Error('There are errors in your xml file: ' + parser.getError());
    }

    return result;
}

function _generateSample(definition, level = 0) {
    let result = {};

    Object.keys(definition).forEach(function (key) {
        if(key.endsWith("$type")) {
            let keyName = key.replace(/\$type$/, '');
            let length = definition[keyName + "$length"] || [1, 1];

            if(Array.isArray(definition[key])) {
                let value = _xsdTypeLookup(definition[key][0], length[1]);
                result[keyName] = new Array(definition[key][2]).fill(value);

            } else {
                result[keyName] = _xsdTypeLookup(definition[key], length[1]);
            }

        } else if(key.indexOf("$") === -1 && typeof definition[key] === 'object') {
            result[key] = _generateSample(definition[key], key, level + 1);
        }
    });

    return result;
}

function _xsdTypeLookup(type, length) {
    // http://www.xml.dvint.com/docs/SchemaDataTypesQR-2.pdf
    switch(type) {
        case "boolean": return true;
        case "base64Binary": return " ".repeat(length);
        case "hexBinary": return " ".repeat(length);
        case "anyURI": return "http://sample.com";
        case "language": return "en";
        case "normalizedString": return " ".repeat(length);
        case "string": return " ".repeat(length);
        case "token": return " ".repeat(length);
        case "byte": return 0;
        case "decimal": return 0.0;
        case "double": return 0.0;
        case "float": return 0.0;
        case "int": return 0;
        case "integer": return 0;
        case "long": return 0;
        case "negativeInteger": return -1;
        case "nonNegativeInteger": return 1;
        case "nonPositiveInteger": return -1;
        case "short": return 0;
        case "unsignedByte": return 0;
        case "unsignedInt": return 0;
        case "unsignedLong": return 0;
        case "unsignedShort": return 0;
        case "empty": return "";
        case "any": return {};
        default: throw new Error("Unknown XSD type '" + type + "'");
    }
}

module.exports = XMLUtils;
<commit_msg>Only allow disabeling escaping when you inject a cdata tag first<commit_after>"use strict";

var expat = require('node-expat');

class XMLUtils {
    constructor(definition) {
        this._definition = definition;
    }

    toXML(obj, rootName, indentation, optimizeEmpty, convertTypes = true) {
        return _toXML(obj, this._definition, rootName, indentation, optimizeEmpty, convertTypes);
    }

    fromXML(xml, inlineAttributes, convertTypes = true) {
        return _fromXML(xml, this._definition, inlineAttributes, convertTypes);
    }

    generateSample(rootName) {
        var result = {};
        result[rootName] =_generateSample(this._definition[rootName], rootName);
        return result;
    }
}

function _toXML (obj, definition, parentName, indentation, optimizeEmpty, convertTypes, level) {
    definition = definition ? definition : {};
    level = level ? level : 0;
    indentation = indentation ? indentation : 2;
    optimizeEmpty = optimizeEmpty ? true : false;

    var result = "";
    var namespace = "";
    var nsOffset = parentName.indexOf(':');
    if(nsOffset > - 1) {
        namespace = parentName.substr(0, nsOffset) + ":";
        parentName = parentName.substr(nsOffset + 1);

    } else if(definition[parentName + "$namespace"]) {
        namespace = definition[parentName + "$namespace"] + ":";
    }
    var attributes = definition[parentName + "$attributes"] || {};
    var order = obj[parentName + "$order"] || definition[parentName + "$order"];
    var type = obj[parentName + "$type"] || definition[parentName + "$type"];

    if(level === 0) {
        // Go into first level
        obj = obj[parentName];
    }

    var whitespace = " ".repeat(level * indentation);

    if(convertTypes && obj !== undefined && obj !== null) {
        if(type === "base64Binary") {
            obj = Buffer.from(obj).toString('base64');

        } else if(type === "hexBinary") {
            obj = Buffer.from(obj).toString('hex');
        }
    }

    if(typeof obj === undefined || obj === null) {
        // TODO: Handle null types

    } else if(Array.isArray(obj)) {
        obj.forEach(function(value) {
            result += _toXML(value, definition, namespace + parentName, indentation, optimizeEmpty, convertTypes, level);
        });

    } else if(typeof obj === "object") {
        var keys = Object.getOwnPropertyNames(obj);
        if(order) {
            keys = keys.sort(function(a, b) {
                return order.indexOf(a) - order.indexOf(b);
            });
        }

        let subResult = "";
        keys.forEach(function(key) {
            if(key === "$") {
                subResult += obj[key];

            } else if(key === "namespace$") {
                namespace = obj[key] + ":";

            } else if(key.indexOf("$") == 0) {
                attributes[key.substr(1)] = obj[key];

            } else if(key.indexOf("$") > 0) {
                // Skip definition information such as order

            } else {
                subResult += _toXML(obj[key], definition[parentName], key, indentation, optimizeEmpty, convertTypes, level + 1);
            }
        });

        // Generate start and end tag
        result += whitespace + "<" + namespace +  parentName;
        Object.getOwnPropertyNames(attributes).forEach(function(key){
            result += " " + key + '="' + attributes[key] + '"';
        });
        result += obj["$"] ? ">" + subResult : ">\n" + subResult + whitespace;
        result += "</" + namespace + parentName + ">" + (level > 0 ? "\n" : "");

    } else {
        result += whitespace + "<" + namespace +  parentName;
        Object.getOwnPropertyNames(attributes).forEach(function(key){
            result += " " + key + '="' + attributes[key] + '"';
        });

        if(obj === "" && optimizeEmpty) {
            result += " />\n";

        } else {
            result += ">" + escapeValue(obj) + "</" + namespace + parentName + ">\n";
        }
    }

    return result;
}

function escapeValue(value) {
    // https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents/1091953
    if(typeof value === 'string'){
        return value.replace(/((?:&(?!(?:apos|quot|[gl]t|amp);))|(?:^<!\[CDATA\[.+?]]>)|[<>'"])/g, function(match, p1) {
            switch(p1) {
                case '>': return '>';
                case '<': return '<';
                case "'": return ''';
                case '"': return '"';
                case '&': return '&';
                default: return p1;
            }
        });

    } else {
        return value;
    }
}

function _fromXML (xml, objectDefinition, inlineAttributes, convertTypes) {
    var definitions = [objectDefinition || {}];

    var parser = new expat.Parser('UTF-8');
    var result = {};
    var currentValue = "";
    var currentObject = result;
    var currentType = "";
    var objects = [];
    var names = [];

    var orders = [];

    parser.on('startElement', function(name, attributes) {
        // TODO: Handle namespaces in a nice way
        // Parse namespace
        var ns = name.split(":");
        if(ns.length > 1) {
            name = ns[1];
            ns = ns[0];
        } else {
            ns = undefined;
        }

        var definition = definitions[definitions.length - 1];
        currentType = definition[name + "$type"];
        var nextObject = {};
        currentValue = ""; // TODO: Create $t value on object if this has data

        if(ns) {
            if(inlineAttributes) {
                nextObject["namespace" + "$"] = ns;

            } else {
                currentObject[name + "$namespace"] = ns;
            }
        }

        // Handle attributes
        if(Object.getOwnPropertyNames(attributes).length > 0) {
            if(inlineAttributes) {
                Object.keys(attributes).forEach(function(key){
                    nextObject["$" + key] = attributes[key];
                });

            } else {
                if(currentObject.hasOwnProperty(name + "$attributes")) {
                    if(Array.isArray(currentObject[name + "$attributes"])) {
                        currentObject[name + "$attributes"].push(attributes);

                    } else {
                        // Convert to array
                        currentObject[name + "$attributes"] = [currentObject[name + "$attributes"], attributes];
                    }

                } else {
                    if(Array.isArray(currentType)) { // TODO: Migrate to using string formatted definitions, fx. number[]
                        currentObject[name + "$attributes"] = [attributes];

                    } else {
                        currentObject[name + "$attributes"] = attributes;
                    }
                }
            }
        }

        // Handle tag
        if(currentObject.hasOwnProperty(name)) {
            if(Array.isArray(currentObject[name])) {
                currentObject[name].push(nextObject);

            } else {
                // Convert to array
                currentObject[name] = [currentObject[name], nextObject];
            }

        } else {
            // Check definition to see if we have a type defined
            if(Array.isArray(currentType)) {
                currentObject[name] = [nextObject];

            } else {
                currentObject[name] = nextObject;
            }
        }

        // Save order
        if(orders.length <= names.length) {
            orders.push([name]);

        } else if(!Array.isArray(currentObject[name])) {
           orders[names.length].push(name);
        }

        names.push(name);
        objects.push(currentObject);
        definitions.push(definition[name] || {});
        currentObject = nextObject;
    });

    parser.on('text', function(data) {
        currentValue += data.trim();
    });

    parser.on('endElement', function(name){
        var ns = name.split(":");
        if(ns.length > 1) {
            name = ns[1];
            ns = ns[0];
        }

        if(objects.length > 0) {
            currentObject = objects.pop();
            definitions.pop();

            if(names.length < orders.length) {
                var order = orders.pop();
                if(order.length > 1) {
                    currentObject[name + "$order"] = order;
                }
            }
            names.pop();

            if(Array.isArray(currentObject[name])) {
                if(Object.getOwnPropertyNames(currentObject[name][currentObject[name].length -1]).length === 0) {
                    currentObject[name][currentObject[name].length -1] = currentValue;

                } else {
                    currentObject[name][currentObject[name].length -1].$ = currentValue;
                    // TODO: Save "<tag>text<subtag>" type text
                }

            } else if(typeof currentObject[name] === "object") {
                if(Object.getOwnPropertyNames(currentObject[name]).length === 0) { // Move to utility function
                    if(convertTypes) {
                        if(currentType === "boolean") {
                            currentObject[name] = currentValue === 'true';

                        } else if(['decimal', 'double', 'float'].indexOf(currentType) > -1) {
                            currentObject[name] = parseFloat(currentValue);

                        } else if(['byte', 'int', 'integer', 'long', 'negativeInteger', 'nonNegativeInteger',
                                'nonPositiveInteger', 'short', 'unsignedByte', 'unsignedInt', 'unsignedLong',
                                'unsignedShort'].indexOf(currentType) > -1) {
                            currentObject[name] = parseInt(currentValue);

                        } else if(currentType === "base64Binary") {
                            currentObject[name] = Buffer.from(currentValue, 'base64');

                        } else if(currentType === "hexBinary") {
                            currentObject[name] = Buffer.from(currentValue, 'hex');

                        } else {
                            currentObject[name] = currentValue;
                        }

                    } else {
                        currentObject[name] = currentValue; // TODO: Handle inline attributes
                    }

                } else if(currentValue != '') {
                    currentObject[name].$ = currentValue;
                    // TODO: Save "<tag>text<subtag>" type text
                }
            }
        } else {
            console.log("No objects in objects");
        }

        currentValue = "";
    });

    if (!parser.parse(xml)) {
        throw new Error('There are errors in your xml file: ' + parser.getError());
    }

    return result;
}

function _generateSample(definition, level = 0) {
    let result = {};

    Object.keys(definition).forEach(function (key) {
        if(key.endsWith("$type")) {
            let keyName = key.replace(/\$type$/, '');
            let length = definition[keyName + "$length"] || [1, 1];

            if(Array.isArray(definition[key])) {
                let value = _xsdTypeLookup(definition[key][0], length[1]);
                result[keyName] = new Array(definition[key][2]).fill(value);

            } else {
                result[keyName] = _xsdTypeLookup(definition[key], length[1]);
            }

        } else if(key.indexOf("$") === -1 && typeof definition[key] === 'object') {
            result[key] = _generateSample(definition[key], key, level + 1);
        }
    });

    return result;
}

function _xsdTypeLookup(type, length) {
    // http://www.xml.dvint.com/docs/SchemaDataTypesQR-2.pdf
    switch(type) {
        case "boolean": return true;
        case "base64Binary": return " ".repeat(length);
        case "hexBinary": return " ".repeat(length);
        case "anyURI": return "http://sample.com";
        case "language": return "en";
        case "normalizedString": return " ".repeat(length);
        case "string": return " ".repeat(length);
        case "token": return " ".repeat(length);
        case "byte": return 0;
        case "decimal": return 0.0;
        case "double": return 0.0;
        case "float": return 0.0;
        case "int": return 0;
        case "integer": return 0;
        case "long": return 0;
        case "negativeInteger": return -1;
        case "nonNegativeInteger": return 1;
        case "nonPositiveInteger": return -1;
        case "short": return 0;
        case "unsignedByte": return 0;
        case "unsignedInt": return 0;
        case "unsignedLong": return 0;
        case "unsignedShort": return 0;
        case "empty": return "";
        case "any": return {};
        default: throw new Error("Unknown XSD type '" + type + "'");
    }
}

module.exports = XMLUtils;
<|endoftext|>


<commit_before>/* debugging */
function debugLog(msg) {
	var container = document.getElementById('debugLog');
	var elt = document.createElement('li');

	elt.innerHTML = msg;
    container.insertBefore(elt, container.firstChild);
}

/* game engine */
function GameEngine(container) {
	debugLog("creating game");

	// game variables
	this.players = [];
	this.idToPlayer = []; // maps playerId to index of this.players
	this.gameStartTimestamp = null;
	this.lastUpdateTimestamp = null;
	this.gameOver = true;

	// game properties
	this.velocity = null;
	this.turnSpeed = null;

	// connection state
	this.websocket = null;
	this.connected = false;

	// canvas related
	this.container = container; // DOM object that contains canvas layers
	this.canvasStack = null; // object that manages canvas layers
	this.baseContext = null; // on this we draw conclusive segments
}

GameEngine.prototype.connect = function(url, name) {
	if(typeof MozWebSocket != "undefined")
		this.websocket = new MozWebSocket(url, name);
	else
		this.websocket = new WebSocket(url, name);

	this.websocket.parent = this;
	var game = this;

	try {
		this.websocket.onopen = function() {
			debugLog('Connected to websocket server');
			game.connected = true;
		}
		this.websocket.onmessage = function got_packet(msg) {
			if(ultraVerbose)
				debugLog('received data: ' + msg.data);

			try {
				var obj = JSON.parse(msg.data);
			}
			catch(ex) {
				debugLog('JSON parse exception!');
			}

			switch(obj.mode) {
				case 'accept':
					this.players[0].playerId = obj.playerId;
					this.idToPlayer[obj.playerId] = 0;
					break;
				case 'joinGame':
					debugLog('you joined game.');
					break;
				case 'gameParameters':
					game.setParams(obj);
					debugLog('received game params.');
					break;
				case 'newPlayer':
					var newPlayer = new Player(playerColors[game.players.length]);
					newPlayer.playerId = obj.playerId;
					newPlayer.playerName = obj.playerName;
					game.addPlayer(newPlayer);
					debugLog(obj.playerName + ' joined the game (id = ' + obj.playerId + ')');
					break;
				case 'startGame':
					game.start(obj.startPositions);
					break;
				case 'newInput':
					game.players[game.idToPlayer[obj.playerId]].turn(obj);
					break;

				// TODO: handle case where player leaves before game start
				// its gonna be ugly.. restructure game.players and game.idToPlayer

				case 'playerDied':
				case 'playerLeft':
					player[game.idToPlayer[obj.playerId]].alive = false;
					debugLog(player[game.idToPlayer[obj.playerId]].playerName +
					 obj.mode.substr(5));
					break;
				case 'gameEnded':
					game.gameOver = true;
					debugLog('game ended. ' +
					 player[game.idToPlayer[obj.winnerId]].playerName + ' won');
					break;
				default:
					debugLog('unknown mode!');
			}
		}
		this.websocket.onclose = function() {
			debugLog('Websocket connection closed!');
			game.connected = false;
		}
	} catch(exception) {
		debugLog('websocket exception! name = ' + exception.name + ", message = "
		 + exception.message);
	}
}

/* initialises the game */
GameEngine.prototype.setParams = function(obj) {
	/* Create CanvasStack */
	this.container.style.margin = 0;
	this.container.style.padding = 0;
	this.container.style.width = obj.w;
	this.container.style.height = obj.h;

	/* Set game variables */
	this.velocity = obj.v;
	this.turnSpeed = obj.ts;

	debugLog("this game is for " + obj.nmin + " to " + obj.nmax + " players");
}

GameEngine.prototype.requestGame = function() {
	//var playerName = prompt('Enter your nickname');
	// for testing reasons, we will use constant name
	var playerName = "testPlayer" + Math.floor(Math.random() * 1000);

	if(typeof playerName != "string" || playerName.length < 1)
		return;

	this.players[0].playerName = playerName;
	this.sendMsg('requestGame', {'playerName': playerName, 'minPlayers': 2, 'maxPlayers': 8});
}

GameEngine.prototype.sendMsg = function(mode, data) {
	// re-enabled!
	if(this.connected === false) {
		debugLog('tried to send msg, but no websocket connection');
		return;
	}

	data.mode = mode;
	data.playerId = this.players[0].playerId;

	var str = JSON.stringify(data);
	this.websocket.send(str);

	if(ultraVerbose)
		debugLog('sending data: ' + str);
}

GameEngine.prototype.draw = function(callback) {
	for(var i = 0; i < this.players.length; i++)
		this.players[i].draw();
}

GameEngine.prototype.update = function(deltaTime) {
	for(var i = 0; i < this.players.length; i++)
		this.players[i].update(deltaTime);
}

GameEngine.prototype.loop = function() {
	var now = Date.now();
	var deltaTime = now - this.lastUpdateTimestamp;

	this.update(deltaTime);
	this.draw();
	this.lastUpdateTimestamp = now;
}

GameEngine.prototype.addPlayer = function(player) {
	player.game = this;

	if(player.playerId != null) {
		/* internet player */
		var canvas = document.getObjectById(this.canvasStack.createLayer());
		this.context = canvas.getContext('2d');
		this.context.lineWidth = lineWidth;
		this.idToPlayer[player.playerId] = this.players.length;
	}

	this.players.push(player);
	debugLog("adding player to game");
}

GameEngine.prototype.stop = function() {
	debugLog("game ended");
}

GameEngine.prototype.start = function(startPositions) {
	debugLog("starting game");

	/* init some vals */
	this.lastUpdateTimestamp = Date.now();
	this.gameStartTimestamp = this.lastUpdateTimestamp;
	this.gameOver = false;

	/* create canvas stack */
	this.canvasStack = new CanvasStack(this.container, canvasBgcolor);

	/* draw on background context, since we never need to redraw anything
	 * on this layer (only clear for new game) */
	var canvas = document.getObjectById(this.canvasStack.getBackgroundCanvasId());
	this.baseContext = canvas.getContext('2d');
	this.baseContext.lineWidth = lineWidth;

	/* create context for human player */
	canvas = document.getObjectById(this.canvasStack.createLayer());
	this.players[0].context = canvas.getContext('2d');
	this.players[0].context.lineWidth = lineWidth;

	/* init players */
	for(var i = 0; i < startPositions.length; i++) {
		var index = this.idToPlayer[ startPositions[i].playerId ];
		this.players[index].initialise(startPositions[i].startX,
		 startPositions[i].startY, startPositions[i].startAngle);
	}

	var that = this;

	(function gameLoop() {
		that.loop();

		if(that.gameOver)
			that.stop();
		else
			requestAnimFrame(gameLoop, that.canvas);
	})();
}

window.requestAnimFrame = (function() {
	return  window.requestAnimationFrame       ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame    ||
			window.oRequestAnimationFrame      ||
			window.msRequestAnimationFrame     ||
			function(/* function */ callback, /* DOMElement */ element) {
				window.setTimeout(callback, 1000 / 60);
			};
})();

/* players */
function Player(color) {
	this.playerId = null;
	this.playerName = null;
	this.velocity = null; //pixels per sec
	this.turnSpeed = null;
	this.angle = 0; // radians
	this.x = 0;
	this.y = 0;
	this.lcx = 0; // last confirmed x
	this.lcy = 0;
	this.lca = 0; // last confirmed angle
	this.lct = 0; // game time of last confirmed location (in millisec)
	this.color = color;
	this.turn = 0; // -1 is turn left, 0 is straight, 1 is turn right
	this.undrawnPts = []; // list of undrawn points x1, y1, x2, y2, ...
	this.game = null; // to which game does this player belong
	this.context = null; // this is the canvas context in which we draw simulation
	this.alive = false;

	debugLog("creating player");
}

Player.prototype.turn = function(obj) {
	/* run simulation from lcx, lcy on the conclusive canvas from time
	 * lct to timestamp in object */
	this.simulate(this.lcx, this.lcy, this.lca, this.turn,
	 obj.gameTime - this.lct, this.game.baseContext, obj.x, obj.y);

	/* here we sync with server */
	this.lcx = this.x = obj.x;
	this.lcy = this.y = obj.y;
	this.lca = this.angle = obj.angle;
	this.lct = obj.gameTime;
	this.turn = obj.turn;

	/* clear this players canvas and run simulation on this player's
	 * context from timestamp in object to NOW */
	this.context.clear(); // might not work -- must test
	this.simulate(this.lcx, this.lcy, this.lca, this.turn,
	 Date.now() - obj.gameTime, this.context, null, null);
}

Player.prototype.simulate = function(x, y, angle, turn, time, ctx, destX, destY) {
	ctx.strokeStyle = this.color;
	ctx.beginPath();
	ctx.moveTo(x, y);

	var step = Math.min(simStep, time);

	if(destX != null)
		t -= step;

	while(time > 0) {
		x += this.velocity * step/ 1000 * Math.cos(angle);
		y += this.velocity * step/ 1000 * Math.sin(angle);
		angle += turn * this.turnSpeed * step/ 1000;

		ctx.lineTo(x, y);

		step = Math.min(simStep, obj.gameTime - t);
		t -= step;
	}

	if(destX != null)
		ctx.lineTo(destX, destY);

	ctx.closePath();
	ctx.stroke();
}

Player.prototype.initialise = function(x, y, angle) {
	this.velocity = this.game.velocity;
	this.turnSpeed = this.game.turnSpeed;
	this.undrawnSegs = [];
	this.alive = true;

	this.lcx = this.x = x;
	this.lcy = this.y = y;
	this.context.moveTo(x, y);
	this.context.strokeStyle = this.color;

	this.lct = 0;
	this.angle = angle;
	this.turn = 0;

	debugLog("initialising player at (" + this.x + ", " + this.y + "), angle = " + this.angle);
}

Player.prototype.update = function(deltaTime) {
	if(!this.alive)
		return false;

	this.x += this.velocity * deltaTime/ 1000 * Math.cos(this.angle);
	this.y += this.velocity * deltaTime/ 1000 * Math.sin(this.angle);
	this.undrawnPts.push(this.x);
	this.undrawnPts.push(this.y);

	this.angle += this.turn * this.turnSpeed * deltaTime/ 1000;
}

Player.prototype.draw = function() {
	if(!this.alive)
		return;

	var len = this.undrawnPts.length/ 2;

	this.context.beginPath();
	for(var i = 0; i < len; i++)
		this.context.lineTo(this.undrawnPts[i], this.undrawnPts[i + 1]);
	this.context.closePath();
	this.context.stroke();

	this.undrawnPts = [];
}

/* input control */
function InputController(left, right) {
	this.rightKeyCode = left;
	this.leftKeyCode = right;
	this.player = null;
	this.game = null;

	debugLog("creating keylogger")
}

InputController.prototype.setPlayer = function(player) {
	this.player = player;
}

InputController.prototype.setGame = function(game) {
	this.game = game;
}

InputController.prototype.keyDown = function(keyCode) {
	if(!this.player.alive)
		return;

	if(keyCode == this.rightKeyCode && this.player.turn != -1) {
		this.player.turn = -1;
		this.game.sendMsg('newInput', {'turn': -1,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
	else if(keyCode == this.leftKeyCode && this.player.turn != 1){
		this.player.turn = 1;
		this.game.sendMsg('newInput', {'turn': 1,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
}

InputController.prototype.keyUp = function(keyCode) {
	if(!this.player.alive)
		return;

	if((keyCode == this.rightKeyCode && this.player.turn == -1) ||
	 (keyCode == this.leftKeyCode && this.player.turn == 1)) {
		this.player.turn = 0;
		this.game.sendMsg('newInput', {'turn': 0,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
}

/* create game */
window.onload = function() {

	/* some constants */
	var container = document.getElementById('container');
	var game = new GameEngine(container);
	var player = new Player(playerColors[0]);
	var inputControl = new InputController(keyCodeLeft, keyCodeRight);

	inputControl.setGame(game);
	game.addPlayer(player);
	inputControl.setPlayer(player);

	/* register key presses and releases */
	document.onkeydown = function(event) {
		var keyCode;

	 	if(event == null)
			keyCode = window.event.keyCode;
		else
			keyCode = event.keyCode;

		inputControl.keyDown(keyCode);
	}

	document.onkeyup = function(event) {
		var keyCode;

	 	if(event == null)
			keyCode = window.event.keyCode;
		else
			keyCode = event.keyCode;

		inputControl.keyUp(keyCode);
	}

	/* start! */
	function startGame() {
		game.requestGame();
	};

	var startButton = document.getElementById('start');
	startButton.addEventListener('click', startGame, false);
	game.connect(serverURL, "game-protocol");
}
<commit_msg>last change before bed<commit_after>/* debugging */
function debugLog(msg) {
	var container = document.getElementById('debugLog');
	var elt = document.createElement('li');

	elt.innerHTML = msg;
    container.insertBefore(elt, container.firstChild);
}

/* game engine */
function GameEngine(container) {
	debugLog("creating game");

	// game variables
	this.players = [];
	this.idToPlayer = []; // maps playerId to index of this.players
	this.gameStartTimestamp = null;
	this.lastUpdateTimestamp = null;
	this.gameOver = true;

	// game properties
	this.velocity = null;
	this.turnSpeed = null;

	// connection state
	this.websocket = null;
	this.connected = false;

	// canvas related
	this.container = container; // DOM object that contains canvas layers
	this.canvasStack = null; // object that manages canvas layers
	this.baseContext = null; // on this we draw conclusive segments
}

GameEngine.prototype.connect = function(url, name) {
	if(typeof MozWebSocket != "undefined")
		this.websocket = new MozWebSocket(url, name);
	else
		this.websocket = new WebSocket(url, name);

	this.websocket.parent = this;
	var game = this;

	try {
		this.websocket.onopen = function() {
			debugLog('Connected to websocket server');
			game.connected = true;
		}
		this.websocket.onmessage = function got_packet(msg) {
			if(ultraVerbose)
				debugLog('received data: ' + msg.data);

			try {
				var obj = JSON.parse(msg.data);
			}
			catch(ex) {
				debugLog('JSON parse exception!');
			}

			switch(obj.mode) {
				case 'accept':
					this.players[0].playerId = obj.playerId;
					this.idToPlayer[obj.playerId] = 0;
					break;
				case 'joinGame':
					debugLog('you joined game.');
					break;
				case 'gameParameters':
					game.setParams(obj);
					debugLog('received game params.');
					break;
				case 'newPlayer':
					var newPlayer = new Player(playerColors[game.players.length]);
					newPlayer.playerId = obj.playerId;
					newPlayer.playerName = obj.playerName;
					game.addPlayer(newPlayer);
					debugLog(obj.playerName + ' joined the game (id = ' + obj.playerId + ')');
					break;
				case 'startGame':
					game.start(obj.startPositions);
					break;
				case 'newInput':
					game.players[game.idToPlayer[obj.playerId]].turn(obj);
					break;

				// TODO: handle case where player leaves before game start
				// its gonna be ugly.. restructure game.players and game.idToPlayer

				case 'playerDied':
				case 'playerLeft':
					player[game.idToPlayer[obj.playerId]].alive = false;
					debugLog(player[game.idToPlayer[obj.playerId]].playerName +
					 obj.mode.substr(5));
					break;
				case 'gameEnded':
					game.gameOver = true;
					debugLog('game ended. ' +
					 player[game.idToPlayer[obj.winnerId]].playerName + ' won');
					break;
				default:
					debugLog('unknown mode!');
			}
		}
		this.websocket.onclose = function() {
			debugLog('Websocket connection closed!');
			game.connected = false;
		}
	} catch(exception) {
		debugLog('websocket exception! name = ' + exception.name + ", message = "
		 + exception.message);
	}
}

/* initialises the game */
GameEngine.prototype.setParams = function(obj) {
	/* Create CanvasStack */
	this.container.style.margin = 0;
	this.container.style.padding = 0;
	this.container.style.width = obj.w;
	this.container.style.height = obj.h;

	/* Set game variables */
	this.velocity = obj.v;
	this.turnSpeed = obj.ts;

	debugLog("this game is for " + obj.nmin + " to " + obj.nmax + " players");
}

GameEngine.prototype.requestGame = function() {
	//var playerName = prompt('Enter your nickname');
	// for testing reasons, we will use constant name
	var playerName = "testPlayer" + Math.floor(Math.random() * 1000);

	if(typeof playerName != "string" || playerName.length < 1)
		return;

	this.players[0].playerName = playerName;
	this.sendMsg('requestGame', {'playerName': playerName, 'minPlayers': 2, 'maxPlayers': 8});
}

GameEngine.prototype.sendMsg = function(mode, data) {
	// re-enabled!
	if(this.connected === false) {
		debugLog('tried to send msg, but no websocket connection');
		return;
	}

	data.mode = mode;
	data.playerId = this.players[0].playerId;

	var str = JSON.stringify(data);
	this.websocket.send(str);

	if(ultraVerbose)
		debugLog('sending data: ' + str);
}

GameEngine.prototype.draw = function(callback) {
	for(var i = 0; i < this.players.length; i++)
		this.players[i].draw();
}

GameEngine.prototype.update = function(deltaTime) {
	for(var i = 0; i < this.players.length; i++)
		this.players[i].update(deltaTime);
}

GameEngine.prototype.loop = function() {
	var now = Date.now();
	var deltaTime = now - this.lastUpdateTimestamp;

	this.update(deltaTime);
	this.draw();
	this.lastUpdateTimestamp = now;
}

GameEngine.prototype.addPlayer = function(player) {
	player.game = this;

	if(player.playerId != null) {
		/* internet player */
		var canvas = document.getObjectById(this.canvasStack.createLayer());
		this.context = canvas.getContext('2d');
		this.context.lineWidth = lineWidth;
		this.idToPlayer[player.playerId] = this.players.length;
	}

	this.players.push(player);
	debugLog("adding player to game");
}

GameEngine.prototype.stop = function() {
	debugLog("game ended");
}

GameEngine.prototype.start = function(startPositions) {
	debugLog("starting game");

	/* init some vals */
	this.lastUpdateTimestamp = Date.now();
	this.gameStartTimestamp = this.lastUpdateTimestamp;
	this.gameOver = false;

	/* create canvas stack */
	this.canvasStack = new CanvasStack(this.container, canvasBgcolor);

	/* draw on background context, since we never need to redraw anything
	 * on this layer (only clear for new game) */
	var canvas = document.getObjectById(this.canvasStack.getBackgroundCanvasId());
	this.baseContext = canvas.getContext('2d');
	this.baseContext.lineWidth = lineWidth;

	/* create context for human player */
	canvas = document.getObjectById(this.canvasStack.createLayer());
	this.players[0].context = canvas.getContext('2d');
	this.players[0].context.lineWidth = lineWidth;

	/* init players */
	for(var i = 0; i < startPositions.length; i++) {
		var index = this.idToPlayer[ startPositions[i].playerId ];
		this.players[index].initialise(startPositions[i].startX,
		 startPositions[i].startY, startPositions[i].startAngle);
	}

	var that = this;

	(function gameLoop() {
		that.loop();

		if(that.gameOver)
			that.stop();
		else
			requestAnimFrame(gameLoop, that.canvas);
	})();
}

window.requestAnimFrame = (function() {
	return  window.requestAnimationFrame       ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame    ||
			window.oRequestAnimationFrame      ||
			window.msRequestAnimationFrame     ||
			function(/* function */ callback, /* DOMElement */ element) {
				window.setTimeout(callback, 1000 / 60);
			};
})();

/* players */
function Player(color) {
	this.playerId = null;
	this.playerName = null;
	this.velocity = null; //pixels per sec
	this.turnSpeed = null;
	this.angle = 0; // radians
	this.x = 0;
	this.y = 0;
	this.lcx = 0; // last confirmed x
	this.lcy = 0;
	this.lca = 0; // last confirmed angle
	this.lct = 0; // game time of last confirmed location (in millisec)
	this.color = color;
	this.turn = 0; // -1 is turn left, 0 is straight, 1 is turn right
	this.undrawnPts = []; // list of undrawn points x1, y1, x2, y2, ...
	this.game = null; // to which game does this player belong
	this.context = null; // this is the canvas context in which we draw simulation
	this.alive = false;

	debugLog("creating player");
}

Player.prototype.turn = function(obj) {
	/* run simulation from lcx, lcy on the conclusive canvas from time
	 * lct to timestamp in object */
	this.simulate(this.lcx, this.lcy, this.lca, this.turn,
	 obj.gameTime - this.lct, this.game.baseContext, obj.x, obj.y);

	/* here we sync with server */
	this.lcx = this.x = obj.x;
	this.lcy = this.y = obj.y;
	this.lca = this.angle = obj.angle;
	this.lct = obj.gameTime;
	this.turn = obj.turn;

	/* clear this players canvas and run simulation on this player's
	 * context from timestamp in object to NOW */
	this.context.clear(); // might not work -- must test
	this.simulate(this.lcx, this.lcy, this.lca, this.turn,
	 Date.now() - obj.gameTime, this.context, null, null);
}

Player.prototype.simulate = function(x, y, angle, turn, time, ctx, destX, destY) {
	ctx.strokeStyle = this.color;
	ctx.beginPath();
	ctx.moveTo(x, y);

	var step = Math.min(simStep, time);

	if(destX != null)
		time -= step;

	while(time > 0) {
		x += this.velocity * step/ 1000 * Math.cos(angle);
		y += this.velocity * step/ 1000 * Math.sin(angle);
		angle += turn * this.turnSpeed * step/ 1000;

		ctx.lineTo(x, y);

		step = Math.min(simStep, obj.gameTime - time);
		time -= step;
	}

	if(destX != null)
		ctx.lineTo(destX, destY);

	ctx.closePath();
	ctx.stroke();
}

Player.prototype.initialise = function(x, y, angle) {
	this.velocity = this.game.velocity;
	this.turnSpeed = this.game.turnSpeed;
	this.undrawnSegs = [];
	this.alive = true;

	this.lcx = this.x = x;
	this.lcy = this.y = y;
	this.context.moveTo(x, y);
	this.context.strokeStyle = this.color;

	this.lct = 0;
	this.angle = angle;
	this.turn = 0;

	debugLog("initialising player at (" + this.x + ", " + this.y + "), angle = " + this.angle);
}

Player.prototype.update = function(deltaTime) {
	if(!this.alive)
		return false;

	this.x += this.velocity * deltaTime/ 1000 * Math.cos(this.angle);
	this.y += this.velocity * deltaTime/ 1000 * Math.sin(this.angle);
	this.undrawnPts.push(this.x);
	this.undrawnPts.push(this.y);

	this.angle += this.turn * this.turnSpeed * deltaTime/ 1000;
}

Player.prototype.draw = function() {
	if(!this.alive)
		return;

	var len = this.undrawnPts.length/ 2;

	this.context.beginPath();
	for(var i = 0; i < len; i++)
		this.context.lineTo(this.undrawnPts[i], this.undrawnPts[i + 1]);
	this.context.closePath();
	this.context.stroke();

	this.undrawnPts = [];
}

/* input control */
function InputController(left, right) {
	this.rightKeyCode = left;
	this.leftKeyCode = right;
	this.player = null;
	this.game = null;

	debugLog("creating keylogger")
}

InputController.prototype.setPlayer = function(player) {
	this.player = player;
}

InputController.prototype.setGame = function(game) {
	this.game = game;
}

InputController.prototype.keyDown = function(keyCode) {
	if(!this.player.alive)
		return;

	if(keyCode == this.rightKeyCode && this.player.turn != -1) {
		this.player.turn = -1;
		this.game.sendMsg('newInput', {'turn': -1,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
	else if(keyCode == this.leftKeyCode && this.player.turn != 1){
		this.player.turn = 1;
		this.game.sendMsg('newInput', {'turn': 1,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
}

InputController.prototype.keyUp = function(keyCode) {
	if(!this.player.alive)
		return;

	if((keyCode == this.rightKeyCode && this.player.turn == -1) ||
	 (keyCode == this.leftKeyCode && this.player.turn == 1)) {
		this.player.turn = 0;
		this.game.sendMsg('newInput', {'turn': 0,
		 'gameTime': Date.now() - this.game.gameStartTimestamp});
	}
}

/* create game */
window.onload = function() {

	/* some constants */
	var container = document.getElementById('container');
	var game = new GameEngine(container);
	var player = new Player(playerColors[0]);
	var inputControl = new InputController(keyCodeLeft, keyCodeRight);

	inputControl.setGame(game);
	game.addPlayer(player);
	inputControl.setPlayer(player);

	/* register key presses and releases */
	document.onkeydown = function(event) {
		var keyCode;

	 	if(event == null)
			keyCode = window.event.keyCode;
		else
			keyCode = event.keyCode;

		inputControl.keyDown(keyCode);
	}

	document.onkeyup = function(event) {
		var keyCode;

	 	if(event == null)
			keyCode = window.event.keyCode;
		else
			keyCode = event.keyCode;

		inputControl.keyUp(keyCode);
	}

	/* start! */
	function startGame() {
		game.requestGame();
	};

	var startButton = document.getElementById('start');
	startButton.addEventListener('click', startGame, false);
	game.connect(serverURL, "game-protocol");
}
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe(FILL_ME_IN);
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe(FILL_ME_IN);
      expect(meglomaniac.henchWoman).toBe(FILL_ME_IN);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    battleCry = meglomaniac.battleCry(4);
    expect(FILL_ME_IN).toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
      function Circle(radius)
      {
        this.radius = radius;
      }

      var simpleCircle = new Circle(10);
      var colouredCircle = new Circle(5);
      colouredCircle.colour = "red";

      expect(simpleCircle.colour).toBe(FILL_ME_IN);
      expect(colouredCircle.colour).toBe(FILL_ME_IN);

      Circle.prototype.describe = function () {
        return "This circle has a radius of: " + this.radius;
      };

      expect(simpleCircle.describe()).toBe(FILL_ME_IN);
      expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>Made global variables local<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe(FILL_ME_IN);
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe(FILL_ME_IN);
      expect(meglomaniac.henchWoman).toBe(FILL_ME_IN);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect(FILL_ME_IN).toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
      function Circle(radius)
      {
        this.radius = radius;
      }

      var simpleCircle = new Circle(10);
      var colouredCircle = new Circle(5);
      colouredCircle.colour = "red";

      expect(simpleCircle.colour).toBe(FILL_ME_IN);
      expect(colouredCircle.colour).toBe(FILL_ME_IN);

      Circle.prototype.describe = function () {
        return "This circle has a radius of: " + this.radius;
      };

      expect(simpleCircle.describe()).toBe(FILL_ME_IN);
      expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>import {observable, autorun} from 'mobservable';
import * as Utils from '../utils';

export class TodoModel {
	constructor(key) {
		observable(this, {
			key,
			todos: [],
			activeTodoCount: () =>
				this.todos.reduce(
					(sum, todo) => sum + (todo.completed ? 0 : 1),
					0
				)
			,
			completedCount: () => this.todos.length - this.activeTodoCount
		});

		this.readFromLocalStorage();
		this.subscribeLocalStorageToModel();
	}

	readFromLocalStorage(model) {
		this.todos = Utils.getDataFromLocalStore(this.key).map(
			data => Todo.fromJson(this, data)
		);
	}

	subscribeLocalStorageToModel(model) {
		autorun(() =>
			Utils.storeDataToLocalStore(this.key, this.todos.map(todo => todo.toJson()))
		);
	}

	addTodo (title) {
		this.todos.push(new Todo(this, Utils.uuid(), title, false));
	}

	toggleAll (checked) {
		this.todos.forEach(
			todo => todo.completed = checked
		);
	}

	clearCompleted () {
		this.todos = this.todos.filter(
			todo => !todo.completed
		);
	}
}

export class Todo {
	constructor(store, id, title, completed) {
		this.store = store;
		observable(this, { id, title, completed });
	}

	toggle() {
		this.completed = !this.completed;
	}

	destroy() {
		this.store.todos.remove(this);
	}

	setTitle(title) {
		this.title = title;
	}

	toJson() {
		return {
			id: this.id,
			title: this.title,
			completed: this.completed
		};
	}

	static fromJson(store, json) {
		return new Todo(store, json.id, json.title, json.completed);
	}
}
<commit_msg>Fixed migration error introduced after upgrading to 1.0<commit_after>import {extendObservable, autorun} from 'mobservable';
import * as Utils from '../utils';

export class TodoModel {
	constructor(key) {
		extendObservable(this, {
			key,
			todos: [],
			activeTodoCount: () =>
				this.todos.reduce(
					(sum, todo) => sum + (todo.completed ? 0 : 1),
					0
				)
			,
			completedCount: () => this.todos.length - this.activeTodoCount
		});

		this.readFromLocalStorage();
		this.subscribeLocalStorageToModel();
	}

	readFromLocalStorage(model) {
		this.todos = Utils.getDataFromLocalStore(this.key).map(
			data => Todo.fromJson(this, data)
		);
	}

	subscribeLocalStorageToModel(model) {
		autorun(() =>
			Utils.storeDataToLocalStore(this.key, this.todos.map(todo => todo.toJson()))
		);
	}

	addTodo (title) {
		this.todos.push(new Todo(this, Utils.uuid(), title, false));
	}

	toggleAll (checked) {
		this.todos.forEach(
			todo => todo.completed = checked
		);
	}

	clearCompleted () {
		this.todos = this.todos.filter(
			todo => !todo.completed
		);
	}
}

export class Todo {
	constructor(store, id, title, completed) {
		this.store = store;
		extendObservable(this, { id, title, completed });
	}

	toggle() {
		this.completed = !this.completed;
	}

	destroy() {
		this.store.todos.remove(this);
	}

	setTitle(title) {
		this.title = title;
	}

	toJson() {
		return {
			id: this.id,
			title: this.title,
			completed: this.completed
		};
	}

	static fromJson(store, json) {
		return new Todo(store, json.id, json.title, json.completed);
	}
}
<|endoftext|>


<commit_before>var util = require('../util'),
  consts = require('../consts'),
  vl = require('vegalite'),
  isDimension = vl.field.isDimension;

module.exports = projections;

// TODO support other mode of projections generation
// powerset, chooseK, chooseKorLess are already included in the util

/**
 * fields
 * @param  {[type]} fields array of fields and query information
 * @return {[type]}        [description]
 */
function projections(fields, stats, opt) {
  opt = vl.schema.util.extend(opt||{}, consts.gen.projections);

  // First categorize field, selected, fieldsToAdd, and save indices
  var selected = [], fieldsToAdd = [], fieldSets = [],
    hasSelectedDimension = false,
    hasSelectedMeasure = false,
    indices = {};

  fields.forEach(function(field, index){
    //save indices for stable sort later
    indices[field.name] = index;

    if (field.selected) {
      selected.push(field);
      if (isDimension(field) || field.type ==='T') { // FIXME / HACK
        hasSelectedDimension = true;
      } else {
        hasSelectedMeasure = true;
      }
    } else if (field.selected !== false && !vl.field.isCount(field)) {
      if (vl.field.isDimension(field) &&
          vl.field.cardinality(field, stats, 15) > opt.maxCardinalityForAutoAddOrdinal) {
        return;
      }
      fieldsToAdd.push(field);
    }
  });

  fieldsToAdd.sort(compareFieldsToAdd(hasSelectedDimension, hasSelectedMeasure, indices));

  var setsToAdd = util.chooseKorLess(fieldsToAdd, 1);

  setsToAdd.forEach(function(setToAdd) {
    var fieldSet = selected.concat(setToAdd);
    if (fieldSet.length > 0) {
      if (opt.omitDotPlot && fieldSet.length === 1) return;
      fieldSets.push(fieldSet);
    }
  });

  fieldSets.forEach(function(fieldSet) {
      // always append projection's key to each projection returned, d3 style.
    fieldSet.key = projections.key(fieldSet);
  });

  return fieldSets;
}

var typeIsMeasureScore = {
  O: 0,
  T: 1,
  Q: 2
};

function compareFieldsToAdd(hasSelectedDimension, hasSelectedMeasure, indices) {
  return function(a, b){
    var aIsDim = isDimension(a), bIsDim = isDimension(b);
    // sort by type of the data
    if (a.type !== b.type) {
      if (!hasSelectedDimension) {
        return typeIsMeasureScore[a.type] - typeIsMeasureScore[b.type];
      } else if (!hasSelectedMeasure) {
        return typeIsMeasureScore[b.type] - typeIsMeasureScore[a.type];
      }
    }
    //make the sort stable
    return indices[a.name] - indices[b.name];
  };
}

projections.key = function(projection) {
  return projection.map(function(field) {
    return vl.field.isCount(field) ? 'count' : field.name;
  }).join(',');
};

<commit_msg>allow no maxCardinalityForAutoAddOrdinal<commit_after>var util = require('../util'),
  consts = require('../consts'),
  vl = require('vegalite'),
  isDimension = vl.field.isDimension;

module.exports = projections;

// TODO support other mode of projections generation
// powerset, chooseK, chooseKorLess are already included in the util

/**
 * fields
 * @param  {[type]} fields array of fields and query information
 * @return {[type]}        [description]
 */
function projections(fields, stats, opt) {
  opt = vl.schema.util.extend(opt||{}, consts.gen.projections);

  // First categorize field, selected, fieldsToAdd, and save indices
  var selected = [], fieldsToAdd = [], fieldSets = [],
    hasSelectedDimension = false,
    hasSelectedMeasure = false,
    indices = {};

  fields.forEach(function(field, index){
    //save indices for stable sort later
    indices[field.name] = index;

    if (field.selected) {
      selected.push(field);
      if (isDimension(field) || field.type ==='T') { // FIXME / HACK
        hasSelectedDimension = true;
      } else {
        hasSelectedMeasure = true;
      }
    } else if (field.selected !== false && !vl.field.isCount(field)) {
      if (vl.field.isDimension(field) &&
          !opt.maxCardinalityForAutoAddOrdinal &&
          vl.field.cardinality(field, stats, 15) > opt.maxCardinalityForAutoAddOrdinal
        ) {
        return;
      }
      fieldsToAdd.push(field);
    }
  });

  fieldsToAdd.sort(compareFieldsToAdd(hasSelectedDimension, hasSelectedMeasure, indices));

  var setsToAdd = util.chooseKorLess(fieldsToAdd, 1);

  setsToAdd.forEach(function(setToAdd) {
    var fieldSet = selected.concat(setToAdd);
    if (fieldSet.length > 0) {
      if (opt.omitDotPlot && fieldSet.length === 1) return;
      fieldSets.push(fieldSet);
    }
  });

  fieldSets.forEach(function(fieldSet) {
      // always append projection's key to each projection returned, d3 style.
    fieldSet.key = projections.key(fieldSet);
  });

  return fieldSets;
}

var typeIsMeasureScore = {
  O: 0,
  T: 1,
  Q: 2
};

function compareFieldsToAdd(hasSelectedDimension, hasSelectedMeasure, indices) {
  return function(a, b){
    var aIsDim = isDimension(a), bIsDim = isDimension(b);
    // sort by type of the data
    if (a.type !== b.type) {
      if (!hasSelectedDimension) {
        return typeIsMeasureScore[a.type] - typeIsMeasureScore[b.type];
      } else if (!hasSelectedMeasure) {
        return typeIsMeasureScore[b.type] - typeIsMeasureScore[a.type];
      }
    }
    //make the sort stable
    return indices[a.name] - indices[b.name];
  };
}

projections.key = function(projection) {
  return projection.map(function(field) {
    return vl.field.isCount(field) ? 'count' : field.name;
  }).join(',');
};

<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var megalomaniac;

    beforeEach(function () {
       megalomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(megalomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(megalomaniac.henchwoman).toBe("Harley");
      expect(megalomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var megalomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = megalomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date();
    var currentYear = (currentDate.getFullYear());
    var megalomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(megalomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var megalomaniac;
    beforeEach(function () {
      megalomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in megalomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in megalomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    megalomaniac.secretary = "Agent Smith";
    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    delete megalomaniac.henchman;
    expect("henchman" in megalomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
      function Circle(radius)
      {
        this.radius = radius;
      }

      var simpleCircle = new Circle(10);
      var colouredCircle = new Circle(5);
      colouredCircle.colour = "red";

      expect(simpleCircle.colour).toBe(FILL_ME_IN);
      expect(colouredCircle.colour).toBe(FILL_ME_IN);

      Circle.prototype.describe = function () {
        return "This circle has a radius of: " + this.radius;
      };

      expect(simpleCircle.describe()).toBe(FILL_ME_IN);
      expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>Solves the koans about about<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var megalomaniac;

    beforeEach(function () {
      megalomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(megalomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(megalomaniac.henchwoman).toBe("Harley");
      expect(megalomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var megalomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
            Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = megalomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date();
    var currentYear = (currentDate.getFullYear());
    var megalomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2015);
    expect(megalomaniac.calculateAge()).toBe(45);
  });

  describe("'in' keyword", function () {
    var megalomaniac;
    beforeEach(function () {
      megalomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in megalomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in megalomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in megalomaniac).toBe(false);

    megalomaniac.secretary = "Agent Smith";
    expect("secretary" in megalomaniac).toBe(true);

    delete megalomaniac.henchman;
    expect("henchman" in megalomaniac).toBe(false);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(undefined);
    expect(colouredCircle.colour).toBe("red");

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe("This circle has a radius of: 10");
    expect(colouredCircle.describe()).toBe("This circle has a radius of: 5");
  });
});
<|endoftext|>


<commit_before>"use strict";
/*eslint-disable no-invalid-this*/ // Because of the 'simple' class generation relying on lamda functions
/* MUST NOT BE MIGRATED TO ES6 BECAUSE USED IN A BROWSER */

/*eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1, 100, 10000] }]*/

function _noop () {}

/**
 * Simple class helper
 *
 * @param {Function} Constructor Constructor function
 * @param {Object} members Members dictionary
 * @param {Function} [Base] Base class
 * @return {Function} New class constructor
 * @private
 */
function _class (Constructor, members, Base) {
    var ResultConstructor;
    if (Base) {
        ResultConstructor = function () {
            Base.apply(this, arguments);
            Constructor.apply(this, arguments);
        };
        ResultConstructor.prototype = new Base();
    } else {
        ResultConstructor = function () {
            Constructor.apply(this, arguments);
        };
    }
    if (members) {
        Object.keys(members).forEach(function (memberName) {
            ResultConstructor.prototype[memberName] = members[memberName];
        });
    }
    return ResultConstructor;
}

/**
 * Part (Statement, Function, Branch) statistics
 *
 * @constructor
 * @class CoverageReport.PartStatistics
 */
var _PartStatistics = _class(_noop, {

    /** number of instances for this part */
    count: 0,

    /** number of tested instances */
    tested: 0,

    /** number of ignored instances */
    ignored: 0,

    /**
     * Increase tested or ignored count accordingly to what happened
     *
     * @param {Number} numberOfCall Number of calls extracted from the coverage report
     * @param {Object} partDefinition Part definition
     * Only skip (Boolean) is tested
     */
    _testedOrIgnored: function (numberOfCall, partDefinition) {
        if (numberOfCall > 0) {
            ++this.tested;
        } else if (partDefinition.skip) {
            ++this.ignored;
        }
    },

    /**
     * Common coverage processing
     *
     * @param {Number} numberOfCall Number of calls extracted from the coverage report
     * @param {Object} partDefinition Part definition
     */
    processCoverage: function (numberOfCall, partDefinition) {
        ++this.count;
        this._testedOrIgnored(numberOfCall, partDefinition);
    },

    /**
     * Adds information from another part statistics
     *
     * @param {CoverageReport.PartStatistics} partStatistics Statistics to add
     */
    add: function (partStatistics) {
        this.count += partStatistics.count;
        this.tested += partStatistics.tested;
        this.ignored += partStatistics.ignored;
    },

    // Generates percent value
    _toPercent: function (count, total, rounded) {
        if (rounded) {
            return Math.floor(100 * count / total);
        }
        return Math.floor(10000 * count / total) / 100;
    },

    /**
     * @param {Boolean} [rounded] Truncate decimals when true
     * @return {Number} Coverage ratio in percent
     */
    getCoverageRatio: function (rounded) {
        if (this.count === 0) {
            return 100;
        }
        return this._toPercent(this.tested + this.ignored, this.count, rounded);
    },

    /**
     * @param {Boolean} [rounded] Truncate decimals when true
     * @return {Number} Ignored ratio in percent
     */
    getIgnoredRatio: function (rounded) {
        if (this.count === 0) {
            return 0;
        }
        return this._toPercent(this.ignored, this.count, rounded);
    }

});

/**
 * Statement statistics
 *
 * @constructor
 * @class CoverageReport.StatementStatistics
 */
var _StatementStatistics = _class(_noop, null, _PartStatistics);

/**
 * Function statistics
 *
 * @constructor
 * @class CoverageReport.FunctionStatistics
 */
var _FunctionStatistics = _class(_noop, null, _PartStatistics);

/**
 * Branch statistics
 *
 * @constructor
 * @class CoverageReport.BranchStatistics
 */
var _BranchStatistics = _class(_noop, {

    /**
     * Branch-specific coverage processing
     *
     * @param {Number[]} numberOfCalls Number of calls extracted from the coverage report (one per branch)
     * @param {Object} branchDefinition Branch definition
     * locations array will used to fetch skip property of each branch
     */
    processCoverage: function (numberOfCalls, branchDefinition) {
        this.count += 2;
        this._testedOrIgnored(numberOfCalls[0], branchDefinition.locations[0]);
        this._testedOrIgnored(numberOfCalls[1], branchDefinition.locations[1]);
    }

}, _PartStatistics);

//region Region File statistics structure

/**
 * File statistics
 *
 * @param {String} name
 * @constructor
 */
var _File = _class(function (optionalName) {
    if (optionalName) {
        this.name = optionalName.replace(/\\/g, "/").split("src/")[1].split(".js")[0];
    }
    this.statements = new _StatementStatistics();
    this.functions = new _FunctionStatistics();
    this.branches = new _BranchStatistics();
}, {

    /** file name */
    name: "",

    /**
     * Statements statistics
     *
     * @type {CoverageReport.StatementStatistics}
     */
    statements: null,

    /**
     * Functions statistics
     *
     * @type {CoverageReport.FunctionStatistics}
     */
    functions: null,

    /**
     * Branches statistics
     *
     * @type {CoverageReport.BranchStatistics}
     */
    branches: null

});

/**
 * Process the coverage data and generate a consolidated report
 *
 * @param {Object} coverageData Data produced by istanbul
 * @constructor
 * @class CoverageReport
 */
var CoverageReport = _class(function (coverageData) {
    this._data = coverageData;
    this._compute();
}, {

    /** coverage data */
    _data: null,

    /** dictionary of coverage per file */
    _files: null,

    /**
     * Global coverage
     *
     * @type {CoverageReport.File}
     */
    _global: null,

    /**
     * Compute coverage for one file
     *
     * @param {String} fileName File name
     * @return {CoverageReport.File} Coverage for one file
     */
    _computeFileCoverage: function (fileName) {
        var result = new _File(fileName),
            fileData = this._data[fileName];
        [{
            type: "statements",
            data: "s",
            map: "statementMap"
        }, {
            type: "functions",
            data: "f",
            map: "fnMap"
        }, {
            type: "branches",
            data: "b",
            map: "branchMap"
        }].forEach(function (part) {
            var map = fileData[part.map],
                data = fileData[part.data],
                statistics = result[part.type],
                index = 1;
            while (undefined !== data[index]) {
                statistics.processCoverage(data[index], map[index]);
                ++index;
            }
        });
        return result;
    },

    /** Compute all coverages */
    _compute: function () {
        this._files = {};
        this._global = new _File();
        Object.keys(this._data).forEach(function (fileName) {
            var fileCoverage = this._computeFileCoverage(fileName);
            this._files[fileCoverage.name] = fileCoverage;
            this._global.statements.add(fileCoverage.statements);
            this._global.functions.add(fileCoverage.functions);
            this._global.branches.add(fileCoverage.branches);
        }, this);
    },

    /**
     * Get file coverage information
     *
     * @param {String} fileName Name of the file to obtain
     * @return {_File|undefined} Coverage information
     */
    get: function (fileName) {
        return this._files[fileName];
    },

    /**
     * Get consolidated coverage information
     *
     * @return {_File} Coverage information
     */
    getGlobal: function () {
        return this._global;
    }

});

module.exports = CoverageReport;
<commit_msg>removes -1 (#280)<commit_after>"use strict";
/*eslint-disable no-invalid-this*/ // Because of the 'simple' class generation relying on lamda functions
/* MUST NOT BE MIGRATED TO ES6 BECAUSE USED IN A BROWSER */

/*eslint no-magic-numbers: ["error", { "ignore": [0, 1, 100, 10000] }]*/

function _noop () {}

/**
 * Simple class helper
 *
 * @param {Function} Constructor Constructor function
 * @param {Object} members Members dictionary
 * @param {Function} [Base] Base class
 * @return {Function} New class constructor
 * @private
 */
function _class (Constructor, members, Base) {
    var ResultConstructor;
    if (Base) {
        ResultConstructor = function () {
            Base.apply(this, arguments);
            Constructor.apply(this, arguments);
        };
        ResultConstructor.prototype = new Base();
    } else {
        ResultConstructor = function () {
            Constructor.apply(this, arguments);
        };
    }
    if (members) {
        Object.keys(members).forEach(function (memberName) {
            ResultConstructor.prototype[memberName] = members[memberName];
        });
    }
    return ResultConstructor;
}

/**
 * Part (Statement, Function, Branch) statistics
 *
 * @constructor
 * @class CoverageReport.PartStatistics
 */
var _PartStatistics = _class(_noop, {

    /** number of instances for this part */
    count: 0,

    /** number of tested instances */
    tested: 0,

    /** number of ignored instances */
    ignored: 0,

    /**
     * Increase tested or ignored count accordingly to what happened
     *
     * @param {Number} numberOfCall Number of calls extracted from the coverage report
     * @param {Object} partDefinition Part definition
     * Only skip (Boolean) is tested
     */
    _testedOrIgnored: function (numberOfCall, partDefinition) {
        if (numberOfCall > 0) {
            ++this.tested;
        } else if (partDefinition.skip) {
            ++this.ignored;
        }
    },

    /**
     * Common coverage processing
     *
     * @param {Number} numberOfCall Number of calls extracted from the coverage report
     * @param {Object} partDefinition Part definition
     */
    processCoverage: function (numberOfCall, partDefinition) {
        ++this.count;
        this._testedOrIgnored(numberOfCall, partDefinition);
    },

    /**
     * Adds information from another part statistics
     *
     * @param {CoverageReport.PartStatistics} partStatistics Statistics to add
     */
    add: function (partStatistics) {
        this.count += partStatistics.count;
        this.tested += partStatistics.tested;
        this.ignored += partStatistics.ignored;
    },

    // Generates percent value
    _toPercent: function (count, total, rounded) {
        if (rounded) {
            return Math.floor(100 * count / total);
        }
        return Math.floor(10000 * count / total) / 100;
    },

    /**
     * @param {Boolean} [rounded] Truncate decimals when true
     * @return {Number} Coverage ratio in percent
     */
    getCoverageRatio: function (rounded) {
        if (this.count === 0) {
            return 100;
        }
        return this._toPercent(this.tested + this.ignored, this.count, rounded);
    },

    /**
     * @param {Boolean} [rounded] Truncate decimals when true
     * @return {Number} Ignored ratio in percent
     */
    getIgnoredRatio: function (rounded) {
        if (this.count === 0) {
            return 0;
        }
        return this._toPercent(this.ignored, this.count, rounded);
    }

});

/**
 * Statement statistics
 *
 * @constructor
 * @class CoverageReport.StatementStatistics
 */
var _StatementStatistics = _class(_noop, null, _PartStatistics);

/**
 * Function statistics
 *
 * @constructor
 * @class CoverageReport.FunctionStatistics
 */
var _FunctionStatistics = _class(_noop, null, _PartStatistics);

/**
 * Branch statistics
 *
 * @constructor
 * @class CoverageReport.BranchStatistics
 */
var _BranchStatistics = _class(_noop, {

    /**
     * Branch-specific coverage processing
     *
     * @param {Number[]} numberOfCalls Number of calls extracted from the coverage report (one per branch)
     * @param {Object} branchDefinition Branch definition
     * locations array will used to fetch skip property of each branch
     */
    processCoverage: function (numberOfCalls, branchDefinition) {
        this.count += 2;
        this._testedOrIgnored(numberOfCalls[0], branchDefinition.locations[0]);
        this._testedOrIgnored(numberOfCalls[1], branchDefinition.locations[1]);
    }

}, _PartStatistics);

//region Region File statistics structure

/**
 * File statistics
 *
 * @param {String} name
 * @constructor
 */
var _File = _class(function (optionalName) {
    if (optionalName) {
        this.name = optionalName.replace(/\\/g, "/").split("src/")[1].split(".js")[0];
    }
    this.statements = new _StatementStatistics();
    this.functions = new _FunctionStatistics();
    this.branches = new _BranchStatistics();
}, {

    /** file name */
    name: "",

    /**
     * Statements statistics
     *
     * @type {CoverageReport.StatementStatistics}
     */
    statements: null,

    /**
     * Functions statistics
     *
     * @type {CoverageReport.FunctionStatistics}
     */
    functions: null,

    /**
     * Branches statistics
     *
     * @type {CoverageReport.BranchStatistics}
     */
    branches: null

});

/**
 * Process the coverage data and generate a consolidated report
 *
 * @param {Object} coverageData Data produced by istanbul
 * @constructor
 * @class CoverageReport
 */
var CoverageReport = _class(function (coverageData) {
    this._data = coverageData;
    this._compute();
}, {

    /** coverage data */
    _data: null,

    /** dictionary of coverage per file */
    _files: null,

    /**
     * Global coverage
     *
     * @type {CoverageReport.File}
     */
    _global: null,

    /**
     * Compute coverage for one file
     *
     * @param {String} fileName File name
     * @return {CoverageReport.File} Coverage for one file
     */
    _computeFileCoverage: function (fileName) {
        var result = new _File(fileName),
            fileData = this._data[fileName];
        [{
            type: "statements",
            data: "s",
            map: "statementMap"
        }, {
            type: "functions",
            data: "f",
            map: "fnMap"
        }, {
            type: "branches",
            data: "b",
            map: "branchMap"
        }].forEach(function (part) {
            var map = fileData[part.map],
                data = fileData[part.data],
                statistics = result[part.type],
                index = 1;
            while (undefined !== data[index]) {
                statistics.processCoverage(data[index], map[index]);
                ++index;
            }
        });
        return result;
    },

    /** Compute all coverages */
    _compute: function () {
        this._files = {};
        this._global = new _File();
        Object.keys(this._data).forEach(function (fileName) {
            var fileCoverage = this._computeFileCoverage(fileName);
            this._files[fileCoverage.name] = fileCoverage;
            this._global.statements.add(fileCoverage.statements);
            this._global.functions.add(fileCoverage.functions);
            this._global.branches.add(fileCoverage.branches);
        }, this);
    },

    /**
     * Get file coverage information
     *
     * @param {String} fileName Name of the file to obtain
     * @return {_File|undefined} Coverage information
     */
    get: function (fileName) {
        return this._files[fileName];
    },

    /**
     * Get consolidated coverage information
     *
     * @return {_File} Coverage information
     */
    getGlobal: function () {
        return this._global;
    }

});

module.exports = CoverageReport;
<|endoftext|>


<commit_before>export function urlBuilder(property, value, separator) {
  if (value) {
    return `${property}${separator}${value}`;
  }

  return null;
}

export function locationBuilder(location) {
  const urlParts = [];

  if (Array.isArray(location)) {
    const arrParts = location.map(val => locationBuilder(val));
    urlParts.push(...arrParts);
  }

  if (typeof location === 'string' || typeof location === 'number') {
    urlParts.push(location);
  }

  if (typeof location === 'object' && location.lat && location.lng) {
    urlParts.push(`${location.lat},${location.lng}`);
  }

  return urlParts.join('%7C'); // |
}
<commit_msg>Add utils for checking and rendering different components<commit_after>export function urlBuilder(property, value, separator) {
  if (value) {
    return `${property}${separator}${value}`;
  }

  return null;
}

export function locationBuilder(location) {
  const urlParts = [];

  if (Array.isArray(location)) {
    const arrParts = location.map(val => locationBuilder(val));
    urlParts.push(...arrParts);
  }

  if (typeof location === 'string' || typeof location === 'number') {
    urlParts.push(location);
  }

  if (typeof location === 'object' && location.lat && location.lng) {
    urlParts.push(`${location.lat},${location.lng}`);
  }

  return urlParts.join('%7C'); // |
}

export function isStatelessComponent(component) {
  return (
    !component.render && !(component.prototype && component.prototype.render)
  );
}

export function isClassComponent(component) {
  return Boolean(
    component &&
      component.prototype.isReactComponent &&
      component.prototype.render
  );
}

export function renderStatelessComponent(component, props) {
  return component(props);
}

export function renderClassComponent(component, props) {
  return new component(props).render();
}
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Bain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>Fix number of brains<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>exports.init = function () {
    debugger
};
<commit_msg>Dropzone handlers<commit_after>var $ = require("/jquery");

exports.init = function () {
    var config = this._config;

    var $zone = $(config.ui.zone);
    var $previews = $(config.ui.previews);
    var $clickable = $(config.ui.clickable);

    var url = config.url;

    this.dz = new Dropzone($zone.get(0), {
        url: url || "/",
//        previewsContainer: $previews.get(0),
        clickable: $clickable.get(0)
    });

    $previews.hide();

    this.dz.on("success", function () {
        setTimeout(function() {
            $previews.fadeOut();
        }, 1000);
    });
};
<|endoftext|>