<commit_before>var WebSocket = require('ws');
var emitter   = require('./utils/emitter');
var moment    = require('moment');
var request   = require('request'); // github.com/mikeal/request

// Private
var Bots = {};

// Size of an object
Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

Object.getKeyByValue = function( obj, value ) {
    for( var prop in obj ) {
        if( obj.hasOwnProperty( prop ) ) {
        	console.log("PROP " + prop)
             if( obj[ prop ] === value )
                 return prop;
        }
    }
};

// Public
var self = module.exports = {

	size: function size() {
		return Object.size(Bots);
	},

	onlineUsers: function onlineUsers(appid) {

		if(typeof Bots[appid] === 'undefined')
			return false;

		var application = Bots[appid].application;

		request.post('https://slack.com/api/users.list', { json: true, form: { token: application.slack_api_token }}, function (error, response, body) {
			if (!error && response.statusCode == 200 && typeof body.ok !== "undefined" && body.ok == true) {
				return body.members;
			} else {
				return error;
			}
		});
	},

	addChannel: function addChannel(appid, code, name) {
		if(typeof Bots[appid] === 'undefined')
			return false;

		Bots[appid].channels["#" + name] = code;

		return Bots[appid].channels;
	},

	getChannelCode: function getChannelCode(appid, name) {
		if(typeof Bots[appid] === 'undefined')
			return false;

		return Bots[appid].channels["#" + name];
	},

	isConnected: function isConnected(appid) {
		if(typeof Bots[appid] === 'undefined')
			return false;
		return Bots[appid].isConnected;
	},

	connect: function connect(application) {

		var appid = application.id;

		console.log("Connecting to " + appid);

		if(typeof Bots[appid] === 'undefined' || Bots[appid].isConnected == false) {

			request.post('https://slack.com/api/rtm.start', { json: true, form: { token: application.slack_api_token, t: Date.now() }}, function (error, response, connection) {
				if (!error && response.statusCode == 200 && typeof connection.ok !== "undefined" && connection.ok == true) {

					Bots[appid]             = emitter;
					Bots[appid].websocket   = new WebSocket(connection.url);
					Bots[appid].application = application;
					Bots[appid].isConnected = false;
					Bots[appid].nick        = connection.self.id;
					Bots[appid].team        = connection.team.id;
					Bots[appid].teamDomain  = connection.team.domain;
					Bots[appid].bootedAt    = moment().utc().unix();
					Bots[appid].channels    = [];
					Bots[appid].errors      = [];

					console.log("Undefined");
					console.log("T: " + Object.size(Bots));

					// Read Channels
					for (var channel in connection.channels) {
						self.addChannel(appid, connection.channels[channel].id, connection.channels[channel].name);
					}

					// Socket Listner
					Bots[appid].websocket.addListener('open', function () {
						Bots[appid].isConnected = true;
						console.log(appid + " is online");
					});

					Bots[appid].websocket.addListener('close', function () {
						Bots[appid].isConnected = false;
						Bots[appid].removeAllListeners();
						console.log("conn closed");
					});

					// Websocket Events
					Bots[appid].websocket.addListener('message', function (data) {
						var message = JSON.parse(data);

						if(message.type == 'message' && message.channel.indexOf("C") == 0) {

							console.log("Channel message %j", message);
							Bots[appid].emit('message', message);

						} else if(message.type == 'message' && message.channel.indexOf("D") == 0) {

							console.log("Direct message %j", message);
							Bots[appid].emit('direct_message', message);

						} else if(typeof message.type !== 'undefined') {

							console.log("Other message %s %j", message.type, message);
							Bots[appid].emit(message.type, message);

						} else {

							console.log("Undefined message %j", message);

						}
					});

					Bots[appid].addListener('hello', function () {
						console.log(appid + " said hello");
					});

					Bots[appid].addListener('error', function (e) {
						console.log(appid + " had an error");
					});

					// Direct message
					Bots[appid].addListener('direct_message', function (message) {
						console.log("Direct message: %j", message);
						console.log("T: " + Object.size(Bots));

						// If command
						if(message.text.indexOf("!") == 0 && message.text.length > 1) {
							var command = message.text.substring(1, message.text.length);

							console.log("It's a command: " + command);

							if(command === "time") {
								self.say(appid, message.channel, "_It's now: *" + moment().utc().format() + "*._");
							} else if(command === "uptime") {
								var time = moment(Bots[appid].bootedAt, "X").utc();
								self.say(appid, message.channel, "_Uptime: *" + time.fromNow() + "* @ *" + time.format() + "*._");
							} else {
								// Command not valid!
								self.say(appid, message.channel, "_Sorry! Couldn't reconize the command: *" + command + "*._");
							}

						} else {
							// Reply
							self.say(appid, message.channel, "You said: _" + message.text + "_");
						}

					});

					return Bots[appid];
				}
			});

		} else {
			console.log("Already connected!");
			console.log("T: " + Object.size(Bots));

			return Bots[appid];
		}

	},

	say: function say(appid, channel, message) {
		if(typeof Bots[appid] === 'undefined') {
			return true;
		}

		var data = {
			"type":    "message",
			"channel": channel, //D... or C....
			"user":    Bots[appid].nick,
			"text":    message,
			"ts":      Date.now() + ".000000",
			"team":    Bots[appid].team
		};

		Bots[appid].websocket.send(JSON.stringify(data), function(error) {
			console.log("Error sending data to socket!");
		});
	},

	// Disconect one websocket
	disconnect: function disconnect(appid) {

		if(typeof Bots[appid] === 'undefined') {
			return true;
		}

		if(Bots[appid].isConnected == true) {
			Bots[appid].websocket.close();
		}

		return true;
	},

	// Disconect all webockets
	disconnectAll: function disconnectAll() {

		for (var appid in Bots) {
			this.disconnect(appid);
		}

		return true;
	}
};
<commit_msg>ignore first 2 messages of the socket<commit_after>var WebSocket = require('ws');
var emitter   = require('./utils/emitter');
var moment    = require('moment');
var request   = require('request'); // github.com/mikeal/request

// Private
var Bots = {};

// Size of an object
Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

Object.getKeyByValue = function( obj, value ) {
    for( var prop in obj ) {
        if( obj.hasOwnProperty( prop ) ) {
        	console.log("PROP " + prop)
             if( obj[ prop ] === value )
                 return prop;
        }
    }
};

// Public
var self = module.exports = {

	size: function size() {
		return Object.size(Bots);
	},

	onlineUsers: function onlineUsers(appid) {

		if(typeof Bots[appid] === 'undefined')
			return false;

		var application = Bots[appid].application;

		request.post('https://slack.com/api/users.list', { json: true, form: { token: application.slack_api_token }}, function (error, response, body) {
			if (!error && response.statusCode == 200 && typeof body.ok !== "undefined" && body.ok == true) {
				return body.members;
			} else {
				return error;
			}
		});
	},

	addChannel: function addChannel(appid, code, name) {
		if(typeof Bots[appid] === 'undefined')
			return false;

		Bots[appid].channels["#" + name] = code;

		return Bots[appid].channels;
	},

	getChannelCode: function getChannelCode(appid, name) {
		if(typeof Bots[appid] === 'undefined')
			return false;

		return Bots[appid].channels["#" + name];
	},

	isConnected: function isConnected(appid) {
		if(typeof Bots[appid] === 'undefined')
			return false;
		return Bots[appid].isConnected;
	},

	connect: function connect(application) {

		var appid = application.id;

		console.log("Connecting to " + appid);

		if(typeof Bots[appid] === 'undefined' || Bots[appid].isConnected == false) {

			request.post('https://slack.com/api/rtm.start', { json: true, form: { token: application.slack_api_token, t: Date.now() }}, function (error, response, connection) {
				if (!error && response.statusCode == 200 && typeof connection.ok !== "undefined" && connection.ok == true) {

					Bots[appid]             = emitter;
					Bots[appid].websocket   = new WebSocket(connection.url);
					Bots[appid].application = application;
					Bots[appid].isConnected = false;
					Bots[appid].msgCount    = 0;
					Bots[appid].nick        = connection.self.id;
					Bots[appid].team        = connection.team.id;
					Bots[appid].teamDomain  = connection.team.domain;
					Bots[appid].bootedAt    = moment().utc().unix();
					Bots[appid].channels    = [];
					Bots[appid].errors      = [];

					console.log("Undefined");
					console.log("T: " + Object.size(Bots));

					// Read Channels
					for (var channel in connection.channels) {
						self.addChannel(appid, connection.channels[channel].id, connection.channels[channel].name);
					}

					// Socket Listner
					Bots[appid].websocket.addListener('open', function () {
						Bots[appid].isConnected = true;
						console.log(appid + " is online");
					});

					Bots[appid].websocket.addListener('close', function () {
						Bots[appid].isConnected = false;
						Bots[appid].removeAllListeners();
						console.log("conn closed");
					});

					// Websocket Events
					Bots[appid].websocket.addListener('message', function (data) {
						var message = JSON.parse(data);

						// Gambiarra
						Bots[appid].msgCount++
						// Ignore first 2 messages: hello, last message
						if(Bots[appid].msgCount <= 2) return;

						if(message.type == 'message' && message.channel.indexOf("C") == 0) {

							console.log("Channel message %j", message);
							Bots[appid].emit('message', message);

						} else if(message.type == 'message' && message.channel.indexOf("D") == 0) {

							console.log("Direct message %j", message);
							Bots[appid].emit('direct_message', message);

						} else if(typeof message.type !== 'undefined') {

							console.log("Other message %s %j", message.type, message);
							Bots[appid].emit(message.type, message);

						} else {

							console.log("Undefined message %j", message);

						}
					});

					Bots[appid].addListener('hello', function () {
						console.log(appid + " said hello");
					});

					Bots[appid].addListener('error', function (e) {
						console.log(appid + " had an error");
					});

					// Direct message
					Bots[appid].addListener('direct_message', function (message) {

						// If command
						if(message.text.indexOf("!") == 0 && message.text.length > 1) {
							var command = message.text.substring(1, message.text.length);

							console.log("It's a command: " + command);

							if(command === "time") {
								self.say(appid, message.channel, "_It's now: *" + moment().utc().format() + "*._");
							} else if(command === "uptime") {
								var time = moment(Bots[appid].bootedAt, "X").utc();
								self.say(appid, message.channel, "_Uptime: *" + time.fromNow() + "* @ *" + time.format() + "*._");
							} else {
								// Command not valid!
								self.say(appid, message.channel, "_Sorry! Couldn't reconize the command: *" + command + "*._");
							}

						} else {
							// Reply
							self.say(appid, message.channel, "You said: _" + message.text + "_");
						}

					});

					return Bots[appid];
				}
			});

		} else {
			console.log("Already connected!");
			console.log("T: " + Object.size(Bots));

			return Bots[appid];
		}

	},

	say: function say(appid, channel, message) {
		if(typeof Bots[appid] === 'undefined') {
			return true;
		}

		var data = {
			"type":    "message",
			"channel": channel, //D... or C....
			"user":    Bots[appid].nick,
			"text":    message,
			"ts":      Date.now() + ".000000",
			"team":    Bots[appid].team
		};

		Bots[appid].websocket.send(JSON.stringify(data), function(error) {
			console.log("Error sending data to socket!");
		});
	},

	// Disconect one websocket
	disconnect: function disconnect(appid) {

		if(typeof Bots[appid] === 'undefined') {
			return true;
		}

		if(Bots[appid].isConnected == true) {
			Bots[appid].websocket.close();
		}

		return true;
	},

	// Disconect all webockets
	disconnectAll: function disconnectAll() {

		for (var appid in Bots) {
			this.disconnect(appid);
		}

		return true;
	}
};
<|endoftext|>


<commit_before>var puzzle1Grid = [
        [7, 8, 9],
        [4, 5, 6],
        [1, 2, 3],
    ],
    puzzle1Processor = {
        U: function (x, y) {
            y++;

            return {
                x: x,
                y: (y > 2) ? 2 : y
            };
        },
        D: function (x, y) {
            y--;

            return {
                x: x,
                y: (y < 0) ? 0 : y
            };
        },
        L: function (x, y) {
            x--;

            return {
                x: (x < 0) ? 0 : x,
                y: y
            };
        },
        R: function (x, y) {
            x++;

            return {
                x: (x > 2) ? 2 : x,
                y: y
            };
        }
    },
    /*

    Bounds detection on this shape:

        1
      2 3 4
    5 6 7 8 9
      A B C
        D

    Maybe a better way? This is rough but it works.

    */
    puzzle2Grid = [
        [null, null, 13, null, null],
        [null, 10, 11, 12, null],
        [5, 6, 7, 8, 9],
        [null, 2, 3, 4, null],
        [null, null, 1, null, null]
    ],
    puzzle2Lookup = [
        [4, 2],
        [3, 1],
        [3, 2],
        [3, 3],
        [2, 0],
        [2, 1],
        [2, 2],
        [2, 3],
        [2, 4],
        [1, 1],
        [1, 2],
        [1, 3],
        [0, 2]
    ],
    puzzle2Processor = {
        U: function (x, y) {
            if (y !== 2 && !(Math.abs(x) === 1 && y === 1) && Math.abs(x) !== 2) {
                y++;
            }

            return {
                x: x,
                y: y
            };
        },
        D: function (x, y) {
            if (y !== -2 && !(Math.abs(x) === 1 && y === -1) && Math.abs(x) !== 2) {
                y--;
            }

            return {
                x: x,
                y: y
            };
        },
        L: function (x, y) {
            if (x !== -2 && !(Math.abs(y) === 1 && x === -1) && Math.abs(y) !== 2) {
                x--;
            }

            return {
                x: x,
                y: y
            };
        },
        R: function (x, y) {
            if (x !== 2 && !(Math.abs(y) === 1 && x === 1) && Math.abs(y) !== 2) {
                x++;
            }

            return {
                x: x,
                y: y
            };
        }
    };

function calculateNumberPuzzle1(startingNumber, set) {
    // Calculate the X/Y for the location (we're flipping the Y since our numbers don't start at the origin)
    var x = (startingNumber - 1) % 3,
        y = Math.floor(Math.abs((startingNumber - 9)) / 3);

    set.forEach(function (direction) {
        var shifted = puzzle1Processor[direction](x, y);
        x = shifted.x;
        y = shifted.y;
    }, this);

    return puzzle1Grid[y][x];
}

function calculateNumberPuzzle2(startingNumber, set) {
    var x = puzzle2Lookup[startingNumber - 1][1] - 2,
        y = puzzle2Lookup[startingNumber - 1][0] - 2;

    set.forEach(function (direction) {
        var shifted = puzzle2Processor[direction](x, y);
        x = shifted.x;
        y = shifted.y;
    }, this);

    return puzzle2Grid[y + 2][x + 2];
}

function puzzleProcessor(inputs, calculator) {
    var location = 5,
        finalNumber = '';

    for (var i = 0; i < inputs.length; i++) {
        location = calculator(location, inputs[i]);

        finalNumber += location.toString(16);
    }

    return finalNumber;
}

module.exports = function () {
    console.log('---DAY 02-----------------');

    var rawInput1 = 'RLRDDRLLDLRLUDDULLDRUUULDDLRLUDDDLDRRDUDDDLLURDDDLDDDRDURUDRDRRULUUDUDDRRRLRRRRRLRULRLLRULDRUUDRLRRURDDRLRULDLDULLLRULURRUULLRLLDDDDLLDURRUDLDLURDRDRDLUUUDDRDUUDDULLUURRDRLDDULURRRUDLLULULDLLURURUDRRRRUDRLRDLRRLDDRDDLULDLLLURURDUDRRRRUULURLRDULDRLUDRRUDDUULDURUDLDDURRRDLULLUUDRLLDUUDLDRUDDRLLLLLLDUDUDDLRDLRRDRUDDRRRLLRRDLLRLDDURUURRRDDLDUULLDLDLRURDLLLDDRUUDRUDDDDULRLLDUULRUULLLULURRRLLULDLDUDLDLURUDUDULLDLLUUDRRDRLUURURURURDLURUUDLDRLUDDUUDULDULULLLDLDDULLULLDULRRDRULLURRRULLDDDULULURLRDURLLURUDDULLRUDLRURURRDRDUULDRUUDURDURDDLRDUUULDUUDRDURURDRRRURLLDDLLLURURULULUDLRDLDRDRURLRLULRDLU',
        rawInput2 = 'UDLDURRULDRDDLDUULUDLDUULUURDDRUDRURRRUDRURLLDDRURLDLRDUUURDLLULURDDUDDDRRRURLLDLDLULRDULRLULDLUUDLLRLDLRUUULDDUURDLDDRRDLURLDUDDRURDRRURDURRRLUULURDDLRDLDRRRLDUDRLRLLRLDDUULDURUUULLLRRRRRRRDRRRDRLUULDLDDLULDRDUDLLUDRRUDRUUDULRLUURDDDDRRUUDLURULLLURDULUURDRDDURULRUDRRDLRDUUUUUDDDRDRDDRUDRDDDRLRUUDRDRDDDLUDRDRLDRDDRULURDRLDRUDUDRUULRLLUDRDRLLLLDUDRRLLURDLLLDRRUDDUDRLRLDUDRLURRUUULURDDRUURRLDRLRRRUUDLULDDDRDLDUUURLLUULDDRRUDLDDRUDUDUURURDDRDULLLLLULRRRDLRRRDDDLURDDDDLUULLLRDDURRRRLURRLDDLRUULULRDRDDDDLDUUUUUUDRRULUUUDD',
        rawInput3 = 'UURDRRUDLURRDDDLUDLRDURUDURDLLLLRDLRLRDDRDRDUUULRDLLDLULULRDUDDRRUUDURULDLUDLRDRUDLDDULLLDDRDLLDULLLURLLRDDLDRDULRRDDULRDURLLRUDRLRRLUDURLDRDLDLRLLLURLRRURDLDURDLUDULRDULLLDRDDRDLDRDULUULURDRRRLDRRUULULLDDRRLDLRUURLRUURLURRLLULUUULRLLDDUDDLRLDUURURUDLRDLURRLLURUDLDLLUDDUULUUUDDDURDLRRDDDLDRUDRLRURUUDULDDLUUDDULLDDRRDDRRRUDUDUDLDLURLDRDLLLLDURDURLRLLLUUDLRRRRUDUDDLDLRUURRLRRLUURRLUDUDRRRRRRRLDUDDRUDDLUDLRDDDRLDUULDRDRRDLDRURDLDRULRLRLUDRDLRRUURUUUUDLDUUULLLRRRRRDLRRURDDLLLLUULDLLRULLUDLLDLLUDLRLRRLRURDDRRL',
        rawInput4 = 'URDRDLLRDDDLLLDDLURLRURUURRRLUURURDURRLLUDURRLRLDLUURDLULRRDRUDDLULDLDRLDLRLRRLLLDDDUDDDLRURURRLLDRRRURUDLRDDLLDULDDLDRLUUUDRRRULDUULRDDDLRRLLURDDURLULRDUDURRLLDLLRLDUDDRRDDLRLLLDUDRLUURRLLDULRLDLUUUUUDULUDLULUDDUURRURLDLDRRLDLRRUDUDRRDLDUDDLULLDLLRDRURDRDRRLDDDDRDDRLLDDDLLUDRURLURDRRRRRUDDDUDUDDRDUUDRRUDUDRLULDDURULUURUUUURDRULRLRULLDDRRRUULRRRRURUDLDLRDLLDRLURLRUULLURDUDULRRURLRLLRRLLLURULRRRLDDUULLUUULRRDRULUUUUDRDRRDLRURLRLLRLRRRDRDRLDLUURUURULLDLULRRLRRDRULRRLLLDDURULLDLDLDLUUURDLDLUUDULRLLUDDRRDLLDLDLDURLUURRDDRRURDRLUDRLUUUDLDULDLUDRLDUDDLLRUDULLLLLDRRLLUULLUUURRDDUURDLLRDDLRLLU',
        rawInput5 = 'LDUDRRDLUUDDRLLUUULURLDUDLUDLRLDRURLULRLLDDLRRUUUDDDDRDULDDUUDLRUULDRULLRDRUDDURLDUUURRUDUDRDRDURRDLURRRDRLDLRRRLLLRLURUURRDLLRDLDDLLRDUDDRDUULRULRRURLUDDUDDDUULLUURDULDULLLLRUUUDDRRRLDDDLDLRRDRDRDLUULRLULDRULDLRDRRUDULUDLLUDUULRDLRRUUDDLLDUDDRULURRLULDLDRRULDDRUUDDLURDLRDRLULRRLURRULDUURDLUDLLDRLDULLULDLLRDRDLLLUDLRULLRLDRDDDLDDDLRULDLULLRUUURRLLDUURRLRLDUUULDUURDURRULULRUUURULLLRULLURDDLDRLLRDULLUDLDRRRLLLLDUULRRLDURDURDULULDUURLDUDRLRURRDLUUULURRUDRUUUDRUR';

    // TEST DATA
    // rawInput1 = 'ULL';
    // rawInput2 = 'RRDDD';
    // rawInput3 = 'LURDL';
    // rawInput4 = 'UUUUD';

    var splitInput1 = rawInput1.split(''),
        splitInput2 = rawInput2.split(''),
        splitInput3 = rawInput3.split(''),
        splitInput4 = rawInput4.split(''),
        splitInput5 = rawInput5.split(''),
        inputs = [splitInput1, splitInput2, splitInput3, splitInput4, splitInput5];

    // TEST DATA
    // inputs = [splitInput1, splitInput2, splitInput3, splitInput4];

    // Puzzle 1
    var puzzle1Answer = puzzleProcessor(inputs, calculateNumberPuzzle1);
    // Should be 18843
    console.log('--- Puzzle 1 - Answer: ' + puzzle1Answer + '.');

    // Puzzle 2
    var puzzle2Answer = puzzleProcessor(inputs, calculateNumberPuzzle2);
    // Should be 67BB9
    console.log('--- Puzzle 2 - Answer: ' + puzzle2Answer.toUpperCase() + '.');
};<commit_msg>Removed extra comments<commit_after>var puzzle1Grid = [
        [7, 8, 9],
        [4, 5, 6],
        [1, 2, 3],
    ],
    puzzle1Processor = {
        U: function (x, y) {
            y++;

            return {
                x: x,
                y: (y > 2) ? 2 : y
            };
        },
        D: function (x, y) {
            y--;

            return {
                x: x,
                y: (y < 0) ? 0 : y
            };
        },
        L: function (x, y) {
            x--;

            return {
                x: (x < 0) ? 0 : x,
                y: y
            };
        },
        R: function (x, y) {
            x++;

            return {
                x: (x > 2) ? 2 : x,
                y: y
            };
        }
    },
    puzzle2Grid = [
        [null, null, 13, null, null],
        [null, 10, 11, 12, null],
        [5, 6, 7, 8, 9],
        [null, 2, 3, 4, null],
        [null, null, 1, null, null]
    ],
    puzzle2Lookup = [
        [4, 2],
        [3, 1],
        [3, 2],
        [3, 3],
        [2, 0],
        [2, 1],
        [2, 2],
        [2, 3],
        [2, 4],
        [1, 1],
        [1, 2],
        [1, 3],
        [0, 2]
    ],
    puzzle2Processor = {
        U: function (x, y) {
            if (y !== 2 && !(Math.abs(x) === 1 && y === 1) && Math.abs(x) !== 2) {
                y++;
            }

            return {
                x: x,
                y: y
            };
        },
        D: function (x, y) {
            if (y !== -2 && !(Math.abs(x) === 1 && y === -1) && Math.abs(x) !== 2) {
                y--;
            }

            return {
                x: x,
                y: y
            };
        },
        L: function (x, y) {
            if (x !== -2 && !(Math.abs(y) === 1 && x === -1) && Math.abs(y) !== 2) {
                x--;
            }

            return {
                x: x,
                y: y
            };
        },
        R: function (x, y) {
            if (x !== 2 && !(Math.abs(y) === 1 && x === 1) && Math.abs(y) !== 2) {
                x++;
            }

            return {
                x: x,
                y: y
            };
        }
    };

function calculateNumberPuzzle1(startingNumber, set) {
    // Calculate the X/Y for the location (we're flipping the Y since our numbers don't start at the origin)
    var x = (startingNumber - 1) % 3,
        y = Math.floor(Math.abs((startingNumber - 9)) / 3);

    set.forEach(function (direction) {
        var shifted = puzzle1Processor[direction](x, y);
        x = shifted.x;
        y = shifted.y;
    }, this);

    return puzzle1Grid[y][x];
}

function calculateNumberPuzzle2(startingNumber, set) {
    var x = puzzle2Lookup[startingNumber - 1][1] - 2,
        y = puzzle2Lookup[startingNumber - 1][0] - 2;

    set.forEach(function (direction) {
        var shifted = puzzle2Processor[direction](x, y);
        x = shifted.x;
        y = shifted.y;
    }, this);

    return puzzle2Grid[y + 2][x + 2];
}

function puzzleProcessor(inputs, calculator) {
    var location = 5,
        finalNumber = '';

    for (var i = 0; i < inputs.length; i++) {
        location = calculator(location, inputs[i]);

        finalNumber += location.toString(16);
    }

    return finalNumber;
}

module.exports = function () {
    console.log('---DAY 02-----------------');

    var rawInput1 = 'RLRDDRLLDLRLUDDULLDRUUULDDLRLUDDDLDRRDUDDDLLURDDDLDDDRDURUDRDRRULUUDUDDRRRLRRRRRLRULRLLRULDRUUDRLRRURDDRLRULDLDULLLRULURRUULLRLLDDDDLLDURRUDLDLURDRDRDLUUUDDRDUUDDULLUURRDRLDDULURRRUDLLULULDLLURURUDRRRRUDRLRDLRRLDDRDDLULDLLLURURDUDRRRRUULURLRDULDRLUDRRUDDUULDURUDLDDURRRDLULLUUDRLLDUUDLDRUDDRLLLLLLDUDUDDLRDLRRDRUDDRRRLLRRDLLRLDDURUURRRDDLDUULLDLDLRURDLLLDDRUUDRUDDDDULRLLDUULRUULLLULURRRLLULDLDUDLDLURUDUDULLDLLUUDRRDRLUURURURURDLURUUDLDRLUDDUUDULDULULLLDLDDULLULLDULRRDRULLURRRULLDDDULULURLRDURLLURUDDULLRUDLRURURRDRDUULDRUUDURDURDDLRDUUULDUUDRDURURDRRRURLLDDLLLURURULULUDLRDLDRDRURLRLULRDLU',
        rawInput2 = 'UDLDURRULDRDDLDUULUDLDUULUURDDRUDRURRRUDRURLLDDRURLDLRDUUURDLLULURDDUDDDRRRURLLDLDLULRDULRLULDLUUDLLRLDLRUUULDDUURDLDDRRDLURLDUDDRURDRRURDURRRLUULURDDLRDLDRRRLDUDRLRLLRLDDUULDURUUULLLRRRRRRRDRRRDRLUULDLDDLULDRDUDLLUDRRUDRUUDULRLUURDDDDRRUUDLURULLLURDULUURDRDDURULRUDRRDLRDUUUUUDDDRDRDDRUDRDDDRLRUUDRDRDDDLUDRDRLDRDDRULURDRLDRUDUDRUULRLLUDRDRLLLLDUDRRLLURDLLLDRRUDDUDRLRLDUDRLURRUUULURDDRUURRLDRLRRRUUDLULDDDRDLDUUURLLUULDDRRUDLDDRUDUDUURURDDRDULLLLLULRRRDLRRRDDDLURDDDDLUULLLRDDURRRRLURRLDDLRUULULRDRDDDDLDUUUUUUDRRULUUUDD',
        rawInput3 = 'UURDRRUDLURRDDDLUDLRDURUDURDLLLLRDLRLRDDRDRDUUULRDLLDLULULRDUDDRRUUDURULDLUDLRDRUDLDDULLLDDRDLLDULLLURLLRDDLDRDULRRDDULRDURLLRUDRLRRLUDURLDRDLDLRLLLURLRRURDLDURDLUDULRDULLLDRDDRDLDRDULUULURDRRRLDRRUULULLDDRRLDLRUURLRUURLURRLLULUUULRLLDDUDDLRLDUURURUDLRDLURRLLURUDLDLLUDDUULUUUDDDURDLRRDDDLDRUDRLRURUUDULDDLUUDDULLDDRRDDRRRUDUDUDLDLURLDRDLLLLDURDURLRLLLUUDLRRRRUDUDDLDLRUURRLRRLUURRLUDUDRRRRRRRLDUDDRUDDLUDLRDDDRLDUULDRDRRDLDRURDLDRULRLRLUDRDLRRUURUUUUDLDUUULLLRRRRRDLRRURDDLLLLUULDLLRULLUDLLDLLUDLRLRRLRURDDRRL',
        rawInput4 = 'URDRDLLRDDDLLLDDLURLRURUURRRLUURURDURRLLUDURRLRLDLUURDLULRRDRUDDLULDLDRLDLRLRRLLLDDDUDDDLRURURRLLDRRRURUDLRDDLLDULDDLDRLUUUDRRRULDUULRDDDLRRLLURDDURLULRDUDURRLLDLLRLDUDDRRDDLRLLLDUDRLUURRLLDULRLDLUUUUUDULUDLULUDDUURRURLDLDRRLDLRRUDUDRRDLDUDDLULLDLLRDRURDRDRRLDDDDRDDRLLDDDLLUDRURLURDRRRRRUDDDUDUDDRDUUDRRUDUDRLULDDURULUURUUUURDRULRLRULLDDRRRUULRRRRURUDLDLRDLLDRLURLRUULLURDUDULRRURLRLLRRLLLURULRRRLDDUULLUUULRRDRULUUUUDRDRRDLRURLRLLRLRRRDRDRLDLUURUURULLDLULRRLRRDRULRRLLLDDURULLDLDLDLUUURDLDLUUDULRLLUDDRRDLLDLDLDURLUURRDDRRURDRLUDRLUUUDLDULDLUDRLDUDDLLRUDULLLLLDRRLLUULLUUURRDDUURDLLRDDLRLLU',
        rawInput5 = 'LDUDRRDLUUDDRLLUUULURLDUDLUDLRLDRURLULRLLDDLRRUUUDDDDRDULDDUUDLRUULDRULLRDRUDDURLDUUURRUDUDRDRDURRDLURRRDRLDLRRRLLLRLURUURRDLLRDLDDLLRDUDDRDUULRULRRURLUDDUDDDUULLUURDULDULLLLRUUUDDRRRLDDDLDLRRDRDRDLUULRLULDRULDLRDRRUDULUDLLUDUULRDLRRUUDDLLDUDDRULURRLULDLDRRULDDRUUDDLURDLRDRLULRRLURRULDUURDLUDLLDRLDULLULDLLRDRDLLLUDLRULLRLDRDDDLDDDLRULDLULLRUUURRLLDUURRLRLDUUULDUURDURRULULRUUURULLLRULLURDDLDRLLRDULLUDLDRRRLLLLDUULRRLDURDURDULULDUURLDUDRLRURRDLUUULURRUDRUUUDRUR';

    // TEST DATA
    // rawInput1 = 'ULL';
    // rawInput2 = 'RRDDD';
    // rawInput3 = 'LURDL';
    // rawInput4 = 'UUUUD';

    var splitInput1 = rawInput1.split(''),
        splitInput2 = rawInput2.split(''),
        splitInput3 = rawInput3.split(''),
        splitInput4 = rawInput4.split(''),
        splitInput5 = rawInput5.split(''),
        inputs = [splitInput1, splitInput2, splitInput3, splitInput4, splitInput5];

    // TEST DATA
    // inputs = [splitInput1, splitInput2, splitInput3, splitInput4];

    // Puzzle 1
    var puzzle1Answer = puzzleProcessor(inputs, calculateNumberPuzzle1);
    // Should be 18843
    console.log('--- Puzzle 1 - Answer: ' + puzzle1Answer + '.');

    // Puzzle 2
    var puzzle2Answer = puzzleProcessor(inputs, calculateNumberPuzzle2);
    // Should be 67BB9
    console.log('--- Puzzle 2 - Answer: ' + puzzle2Answer.toUpperCase() + '.');
};<|endoftext|>


<commit_before>let CACHE_NAME = 'order-splitter-cache-%%GULP_INJECT_VERSION%%';
let urlsToCache = ['/', '/main.js'];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function(cache) {
      console.log('Opened cache');
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('activate', function(event) {
  let cacheWhiteList = [CACHE_NAME];
  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(
        keyList.filter(function(key) {
          return cacheWhiteList.indexOf(key) === -1;
        }).map(function(key) {
          return caches.delete(key);
        })
      );
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      // Cache hit - return response
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});
<commit_msg>Update service worker URLs to cache<commit_after>let CACHE_NAME = 'order-splitter-cache-%%GULP_INJECT_VERSION%%';
let urlsToCache = ['/', '/styles.css', '/all.min.js'];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function(cache) {
      console.log('Opened cache');
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('activate', function(event) {
  let cacheWhiteList = [CACHE_NAME];
  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(
        keyList.filter(function(key) {
          return cacheWhiteList.indexOf(key) === -1;
        }).map(function(key) {
          return caches.delete(key);
        })
      );
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      // Cache hit - return response
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});
<|endoftext|>


<commit_before>(function(){
  'use strict';

  var serviceApiEndpoint = 'https://customerdataservicedemo.azurewebsites.net/api/';
  var customerQuery = 'customer/';
  var orderQuery = 'order/'
  var customer = {};

  // The Office initialize function must be run each time a new page is loaded
  Office.initialize = function(reason){
    jQuery(document).ready(function(){
      app.initialize();

        if ($.fn.Pivot) {
          $('.ms-Pivot').Pivot();
        }

      displayItemDetails();
    });
  };

  function customerLookupCallback(result) {

   if (result.length > 0) {
      customer.lastName = result[0].LastName;
      customer.firstName = result[0].FirstName;
      customer.email = result[0].Email;
      customer.companyName = result[0].CompanyName;
      customer.customerId = result[0].CustomerId;

      $('#company').text(customer.companyName);
      $('#lastName').text(customer.lastName);
      $('#firstName').text(customer.firstName);
      $('#number').text(customer.customerId);

      getOrders(customer.customerId);
   }
  }

  function getCustomer(email) {

    $.ajax(
        {
            type: "GET",
            dataType: "jsonp",
            url: serviceApiEndpoint + customerQuery + email + "/true/",
            contentType: "text/javascript",
            success: customerLookupCallback
        });
  }

  function makeCell(text)
  {
    var cell = $('

');
    var span = $('').text(text);
    span.appendTo(cell);

    return cell;
  }

  function orderLookupCallback(result) {
    var orders = result;

    orders.forEach(function(element) {

    var row = $('

');

    makeCell(element.CustomerId).appendTo(row);
    makeCell(element.PurchaseDate).appendTo(row);
    makeCell(element.InvoiceDate).appendTo(row);
    makeCell(element.TotalAmount).appendTo(row);

    row.appendTo($('#orders'));

    }, this);

  }

  function getOrders(customerId) {
    $.ajax(
        {
            type: "GET",
            dataType: "jsonp",
            url: serviceApiEndpoint + orderQuery + customerId + "/",
            contentType: "text/javascript",
            success: orderLookupCallback
        });
  }

  // Displays the "Subject" and "From" fields, based on the current mail item
  function displayItemDetails(){
    var item = Office.cast.item.toItemRead(Office.context.mailbox.item);

    //jQuery('#subject').text(item.subject);

    var from;
    if (item.itemType === Office.MailboxEnums.ItemType.Message) {
      from = Office.cast.item.toMessageRead(item).from;
    } else if (item.itemType === Office.MailboxEnums.ItemType.Appointment) {
      from = Office.cast.item.toAppointmentRead(item).organizer;
    }

    if (from) {

      getCustomer(from.emailAddress);

      // jQuery('#from').text(from.displayName);
      // jQuery('#from').click(function(){
      //   app.showNotification(from.displayName, from.emailAddress);
      // });
    }
  }
})();
<commit_msg>Added check for unrecognised customer<commit_after>(function(){
  'use strict';

  var serviceApiEndpoint = 'https://customerdataservicedemo.azurewebsites.net/api/';
  var customerQuery = 'customer/';
  var orderQuery = 'order/'
  var customer = {};

  // The Office initialize function must be run each time a new page is loaded
  Office.initialize = function(reason){
    jQuery(document).ready(function(){
      app.initialize();

        if ($.fn.Pivot) {
          $('.ms-Pivot').Pivot();
        }

      displayItemDetails();
    });
  };

  function customerLookupCallback(result) {

   if (result.length > 0) {
      customer.lastName = result[0].LastName;
      customer.firstName = result[0].FirstName;
      customer.email = result[0].Email;
      customer.companyName = result[0].CompanyName;
      customer.customerId = result[0].CustomerId;

      $('#company').text(customer.companyName);
      $('#lastName').text(customer.lastName);
      $('#firstName').text(customer.firstName);
      $('#number').text(customer.customerId);

      getOrders(customer.customerId);
   }
   else
   {
      $('#company').text('Email address not recognised. Do you want to add this customer to CRM?');
   }
  }

  function getCustomer(email) {

    $.ajax(
        {
            type: "GET",
            dataType: "jsonp",
            url: serviceApiEndpoint + customerQuery + email + "/true/",
            contentType: "text/javascript",
            success: customerLookupCallback
        });
  }

  function makeCell(text)
  {
    var cell = $('

');
    var span = $('').text(text);
    span.appendTo(cell);

    return cell;
  }

  function orderLookupCallback(result) {
    var orders = result;

    orders.forEach(function(element) {

    var row = $('

');

    makeCell(element.CustomerId).appendTo(row);
    makeCell(element.PurchaseDate).appendTo(row);
    makeCell(element.InvoiceDate).appendTo(row);
    makeCell(element.TotalAmount).appendTo(row);

    row.appendTo($('#orders'));

    }, this);

  }

  function getOrders(customerId) {
    $.ajax(
        {
            type: "GET",
            dataType: "jsonp",
            url: serviceApiEndpoint + orderQuery + customerId + "/",
            contentType: "text/javascript",
            success: orderLookupCallback
        });
  }

  // Displays the "Subject" and "From" fields, based on the current mail item
  function displayItemDetails(){
    var item = Office.cast.item.toItemRead(Office.context.mailbox.item);

    //jQuery('#subject').text(item.subject);

    var from;
    if (item.itemType === Office.MailboxEnums.ItemType.Message) {
      from = Office.cast.item.toMessageRead(item).from;
    } else if (item.itemType === Office.MailboxEnums.ItemType.Appointment) {
      from = Office.cast.item.toAppointmentRead(item).organizer;
    }

    if (from) {

      getCustomer(from.emailAddress);

      // jQuery('#from').text(from.displayName);
      // jQuery('#from').click(function(){
      //   app.showNotification(from.displayName, from.emailAddress);
      // });
    }
  }
})();
<|endoftext|>


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

var QIssue = FOAM({
    model_: 'Model',
    extendsModel: 'GeneratedQIssue',

    name: 'QIssue',

    tableProperties:
    [
      'starred',
      'id',
      'app',
      'priority',
      'milestone',
      'iteration',
      'releaseBlock',
      'category',
      'status',
      'owner',
      'summary',
      'OS',
      'updated'
    ],

    properties: [
        {
          model_: 'IntegerProperty',
          name: 'id',
          shortName: 'i',
          label: 'ID',
          required: true,
          tableWidth: '48px',
          tableFormatter: function(value, row, table) {
            var id = table.nextID();

            table.on('mouseover', function(e) {
              table.browser.preview(e, value);
            }, id);

            return '
' + value + '
';
          }
        },
        {
          model_: 'StringProperty',
          name: 'priority',
          shortName: 'p',
          aliases: ['pr', 'pri', 'prior'],
          tableLabel: 'Priority',
          tableWidth: '60px',
          compareProperty: function(p1, p2) {
            var priorities = ['Low', 'Medium', 'High', 'Critical'];
            var r = priorities.indexOf(p1) - priorities.indexOf(p2);
            return r === 0 ? 0 : r < 0 ? -1 : 1;
          },
          required: true
        },
        {
          model_: 'StringProperty',
          name: 'app',
          tableWidth: '60px'
        },
        {
            name: 'milestone',
            shortName: 'm',
            aliases: ['mstone'],
            tableLabel: 'M',
            type: 'Integer',
            tableWidth: '40px',
            defaultValue: ''
        },
        {
            name: 'iteration',
            shortName: 'it',
            aliases: ['iter'],
            type: 'String',
            tableWidth: '69px'
        },
        {
            name: 'releaseBlock',
            shortName: 'rb',
            aliases: ['rBlock', 'release'],
            type: 'String',
            tableWidth: '103px',
            defaultValue: ''
        },
        {
            name: 'category',
            shortName: 'c',
            aliases: ['cat', 'cr'],
            label: 'Cr',
            tableWidth: '87px',
            type: 'String',
            defaultValue: ''
        },
        {
            name: 'status',
            shortName: 's',
            aliases: ['stat'],
            type: 'String',
            tableWidth: '58px',
            defaultValue: ''
        },
        {
            name: 'owner',
            shortName: 'o',
            tableWidth: '181px',
            type: 'String'
        },
        {
            name: 'summary',
            shortName: 'su',
            label: 'Summary + Labels',
            type: 'String',
            tableWidth: '100%',
            tableFormatter: function(value, row) {
              return value +
                QIssue.LABELS.tableFormatter(row.labels, row);
            }
        },
        {
            name: 'labels',
            shortName: 'l',
            aliases: ['label'],
            type: 'String',
            view: 'QIssueLabelsView',
            tableFormatter: function(value, row) {
              var sb = [];
              //              var a = value.split(', ');
              var a = value;
              for ( var i = 0 ; i < a.length ; i++ ) {
                // The the column is already being shown, then exclude it's label
                if ( row.model_.tableProperties.indexOf(labelToProperty[a[i].split('-')[0]]) == -1 ) {
                  sb.push(' ');
                  sb.push(a[i]);
                  sb.push('');
                }
              }
              return sb.join('');
            },
            postSet: function(a) {
              for ( var i = 0 ; i < a.length ; i++ ) {
                for ( var key in labelToProperty ) {
                  if ( a[i].substring(0, key.length) == key ) {
                    var prop = labelToProperty[key];
                    var val = a[i].substring(key.length+1).intern();
                    // ???: Should be treated as last value or an array?
                    this[prop] = val;
//                  this[prop].push(val);
                    a.splice(i,1);
                    i--;
                    break;
                  }
                }
              }
            }
        },
        {
            name: 'OS',
            tableWidth: '61px',
            type: 'String'
        },
        {
         model_: 'DateTimeProperty',
         name: 'updated',
         shortName: 'mod',
         mode: 'read-write',
         required: true,
         tableWidth: '100',
         valueFactory: function() { return new Date(); }
      },
      {
         model_: 'BooleanProperty',
         name: 'starred',
         tableLabel: '',
         tableFormatter: function(val, obj, tableView) {
           var temp = obj.clone();
           var view = ImageBooleanView.create({
               trueImage: 'data:image/gif;base64,R0lGODlhDwAPAMQfAF9h4RYVnZeQJC0u0lRQU42R6P/7Fv74L05NrRkZxi4tW52XXv71D8nAIWxnjnRxr3NuMJKOluXbBe7kCa2x7UFD1vPoB77D8Jqe6n6B5tvTUr62BMrP8lJPh1xbuv///yH5BAEAAB8ALAAAAAAPAA8AAAWD4CeOWQKMaDpESepi3tFlLgpExlK9RT9ohkYi08N8KhWP8nEwMBwIDyJRSTgO2CaDYcBOCAlMgtDYmhmTDSFQ+HAqgbLZIlAMLqiKw7m1EAYuFQsGEhITEwItKBc/EgIEAhINAUYkCBIQAQMBEGonIwAKa21iCgo7IxQDFRQjF1VtHyEAOw==', //'images/star_on.gif',
               falseImage: 'data:image/gif;base64,R0lGODlhDwAPALMPAP///8zj++r7/7vb/rHW/tPt/9Lk+qzT/rbY/sHh/8Te/N7q+Nzy/7nY/djn+f///yH5BAEAAA8ALAAAAAAPAA8AAARg8MkZjpo4k0KyNwlQBB42MICAfEF7APDRBsYzIEkewGKeDI1DgUckMg6GTdFIqC0QgyUgQVhgGkOi4OBBCJYdzILAywIGNcoOgCAQvowBRpE4kgzCQgPjQCAcEwsNTRIRADs=', //'images/star_off.gif',
               value: temp.propertyValue('starred')
             });

           temp.addPropertyListener('starred', function() {
             tableView.browser.IssueDAO.put(temp);
           });

           tableView.addChild(view);

           return view.toHTML();
         },
         view: {
           // TODO: make it so that initialized objects can be used as factories
           create: function() {
             return ImageBooleanView.create({
               trueImage: 'images/star_on.gif',
               falseImage: 'images/star_off.gif'
             });
           }
         },
         tableWidth: '20',
         help: 'Whether the authenticated user has starred this issue.'
      },
      {
         model_: 'IntegerProperty',
         name: 'stars',
         help: 'Number of stars this issue has.'
      }
    ],

    methods: {
      createPreviewView: function() {
        return QIssuePreviewView.create({ model: QIssue });
      }
    }
});

QIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return ('' + v).length ? v : '----';
    };
  }
});

var QIssueComment = FOAM({
  model_: 'Model',
  name: 'QIssueComment',
  extendsModel: 'IssueComment',

  properties: [
    {
      name: 'author',
      view: 'QIssueCommentAuthorView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'updates',
      view: 'QIssueCommentUpdateView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'published',
      view: 'RelativeDateTimeFieldView'
    }
  ]
});

var QUser = FOAM({
  model_: 'Model',
  name: 'QUser',
  extendsModel: 'User',

  properties: [
    {
      model_: 'StringProperty',
      name: 'email'
    },
    {
      name: 'projects',
      postSet: function(newValue) {
        if ( this.preferredProjects.length == 0 ) {
          this.preferredProjects = newValue.map(function(p) { return p.name; });
        }
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'preferredProjects'
    },
  ]
});
<commit_msg>Crbug: Fixed 'milestone' field.  Changed widths of some table columns.<commit_after>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var labelToProperty = {
  App:          'app',
  Priority:     'priority',
  Milestone:    'milestone',
  Cr:           'category',
  Iteration:    'iteration',
  ReleaseBlock: 'releaseBlock',
  OS:           'OS'
};

var QIssue = FOAM({
    model_: 'Model',
    extendsModel: 'GeneratedQIssue',

    name: 'QIssue',

    tableProperties:
    [
      'starred',
      'id',
      'app',
      'priority',
      'milestone',
      'iteration',
      'releaseBlock',
      'category',
      'status',
      'owner',
      'summary',
      'OS',
      'updated'
    ],

    properties: [
        {
          model_: 'IntegerProperty',
          name: 'id',
          shortName: 'i',
          label: 'ID',
          required: true,
          tableWidth: '48px',
          tableFormatter: function(value, row, table) {
            var id = table.nextID();

            table.on('mouseover', function(e) {
              table.browser.preview(e, value);
            }, id);

            return '
' + value + '
';
          }
        },
        {
          model_: 'StringProperty',
          name: 'priority',
          shortName: 'p',
          aliases: ['pr', 'pri', 'prior'],
          tableLabel: 'Priority',
          tableWidth: '60px',
          compareProperty: function(p1, p2) {
            var priorities = ['Low', 'Medium', 'High', 'Critical'];
            var r = priorities.indexOf(p1) - priorities.indexOf(p2);
            return r === 0 ? 0 : r < 0 ? -1 : 1;
          },
          required: true
        },
        {
          model_: 'StringProperty',
          name: 'app',
          tableWidth: '70px'
        },
        {
            name: 'milestone',
            shortName: 'm',
            aliases: ['mstone'],
            tableLabel: 'M',
            type: 'Integer',
            tableWidth: '70px',
            defaultValue: ''
        },
        {
            name: 'iteration',
            shortName: 'it',
            aliases: ['iter'],
            type: 'String',
            tableWidth: '69px'
        },
        {
            name: 'releaseBlock',
            shortName: 'rb',
            aliases: ['rBlock', 'release'],
            type: 'String',
            tableWidth: '103px',
            defaultValue: ''
        },
        {
            name: 'category',
            shortName: 'c',
            aliases: ['cat', 'cr'],
            label: 'Cr',
            tableWidth: '87px',
            type: 'String',
            defaultValue: ''
        },
        {
            name: 'status',
            shortName: 's',
            aliases: ['stat'],
            type: 'String',
            tableWidth: '58px',
            defaultValue: ''
        },
        {
            name: 'owner',
            shortName: 'o',
            tableWidth: '181px',
            type: 'String'
        },
        {
            name: 'summary',
            shortName: 'su',
            label: 'Summary + Labels',
            type: 'String',
            tableWidth: '100%',
            tableFormatter: function(value, row) {
              return value +
                QIssue.LABELS.tableFormatter(row.labels, row);
            }
        },
        {
            name: 'labels',
            shortName: 'l',
            aliases: ['label'],
            type: 'String',
            view: 'QIssueLabelsView',
            tableFormatter: function(value, row) {
              var sb = [];
              //              var a = value.split(', ');
              var a = value;
              for ( var i = 0 ; i < a.length ; i++ ) {
                // The the column is already being shown, then exclude it's label
                if ( row.model_.tableProperties.indexOf(labelToProperty[a[i].split('-')[0]]) == -1 ) {
                  sb.push(' ');
                  sb.push(a[i]);
                  sb.push('');
                }
              }
              return sb.join('');
            },
            postSet: function(a) {
              for ( var i = 0 ; i < a.length ; i++ ) {
                for ( var key in labelToProperty ) {
                  if ( a[i].substring(0, key.length) == key ) {
                    var prop = labelToProperty[key];
                    var val = a[i].substring(key.length+1).intern();
                    // ???: Should be treated as last value or an array?
                    this[prop] = val;
//                  this[prop].push(val);
                    a.splice(i,1);
                    i--;
                    break;
                  }
                }
              }
            }
        },
        {
            name: 'OS',
            tableWidth: '61px',
            type: 'String'
        },
        {
         model_: 'DateTimeProperty',
         name: 'updated',
         shortName: 'mod',
         mode: 'read-write',
         required: true,
         tableWidth: '100',
         valueFactory: function() { return new Date(); }
      },
      {
         model_: 'BooleanProperty',
         name: 'starred',
         tableLabel: '',
         tableFormatter: function(val, obj, tableView) {
           var temp = obj.clone();
           var view = ImageBooleanView.create({
               trueImage: 'data:image/gif;base64,R0lGODlhDwAPAMQfAF9h4RYVnZeQJC0u0lRQU42R6P/7Fv74L05NrRkZxi4tW52XXv71D8nAIWxnjnRxr3NuMJKOluXbBe7kCa2x7UFD1vPoB77D8Jqe6n6B5tvTUr62BMrP8lJPh1xbuv///yH5BAEAAB8ALAAAAAAPAA8AAAWD4CeOWQKMaDpESepi3tFlLgpExlK9RT9ohkYi08N8KhWP8nEwMBwIDyJRSTgO2CaDYcBOCAlMgtDYmhmTDSFQ+HAqgbLZIlAMLqiKw7m1EAYuFQsGEhITEwItKBc/EgIEAhINAUYkCBIQAQMBEGonIwAKa21iCgo7IxQDFRQjF1VtHyEAOw==', //'images/star_on.gif',
               falseImage: 'data:image/gif;base64,R0lGODlhDwAPALMPAP///8zj++r7/7vb/rHW/tPt/9Lk+qzT/rbY/sHh/8Te/N7q+Nzy/7nY/djn+f///yH5BAEAAA8ALAAAAAAPAA8AAARg8MkZjpo4k0KyNwlQBB42MICAfEF7APDRBsYzIEkewGKeDI1DgUckMg6GTdFIqC0QgyUgQVhgGkOi4OBBCJYdzILAywIGNcoOgCAQvowBRpE4kgzCQgPjQCAcEwsNTRIRADs=', //'images/star_off.gif',
               value: temp.propertyValue('starred')
             });

           temp.addPropertyListener('starred', function() {
             tableView.browser.IssueDAO.put(temp);
           });

           tableView.addChild(view);

           return view.toHTML();
         },
         view: {
           // TODO: make it so that initialized objects can be used as factories
           create: function() {
             return ImageBooleanView.create({
               trueImage: 'images/star_on.gif',
               falseImage: 'images/star_off.gif'
             });
           }
         },
         tableWidth: '20',
         help: 'Whether the authenticated user has starred this issue.'
      },
      {
         model_: 'IntegerProperty',
         name: 'stars',
         help: 'Number of stars this issue has.'
      }
    ],

    methods: {
      createPreviewView: function() {
        return QIssuePreviewView.create({ model: QIssue });
      }
    }
});

QIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return ('' + v).length ? v : '----';
    };
  }
});

var QIssueComment = FOAM({
  model_: 'Model',
  name: 'QIssueComment',
  extendsModel: 'IssueComment',

  properties: [
    {
      name: 'author',
      view: 'QIssueCommentAuthorView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'updates',
      view: 'QIssueCommentUpdateView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'published',
      view: 'RelativeDateTimeFieldView'
    }
  ]
});

var QUser = FOAM({
  model_: 'Model',
  name: 'QUser',
  extendsModel: 'User',

  properties: [
    {
      model_: 'StringProperty',
      name: 'email'
    },
    {
      name: 'projects',
      postSet: function(newValue) {
        if ( this.preferredProjects.length == 0 ) {
          this.preferredProjects = newValue.map(function(p) { return p.name; });
        }
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'preferredProjects'
    },
  ]
});
<|endoftext|>


<commit_before>// This file is in ES5 syntax to allow for older versions of Node.js

var path = require('path')
var fs = require('fs')
var javascript_time_ago = require('javascript-time-ago').default

fs.readdirSync(path.resolve(__dirname, 'locale')).forEach(function(filename)
{
	var locale_path = path.resolve(__dirname, 'locale', filename)
	var stats = fs.statSync(locale_path)
	if (stats.isDirectory())
	{
		javascript_time_ago.locale(require(locale_path))
	}
})<commit_msg>misc refactoring<commit_after>// This file is in ES5 syntax to allow for older versions of Node.js

var path = require('path')
var fs = require('fs')
var javascript_time_ago = require('javascript-time-ago').default

fs.readdirSync(path.resolve(__dirname, 'locale')).forEach(function(filename)
{
	var locale_path = path.resolve(__dirname, 'locale', filename)
	if (fs.statSync(locale_path).isDirectory())
	{
		javascript_time_ago.locale(require(locale_path))
	}
})<|endoftext|>


<commit_before>/**
 * Function: WebSocketClient
 *
 * The WebSocketClient object is used to create an object for simplifying
 * WebSocketClient requests.
 *
 *      env.WebSocketClient = new this.WebSocketClient();
 *      env.WebSocketClient.connect('ws://localhost:9992/',
 *                     'echo-protocol',
 *                      function(connection) {
 *           env.connection = connection;
 *           env.connection.send('command', _this);
 *      });
 *
 * Parameters:
 *
 *   baseUrl - the baseUrl of all your WebSocketClient calls
 *
 * Returns:
 *
 *   returns a WebSocketClient object a connect() function, sendAndVerify(),
 *   and sendWithCallback()
 */
if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define(['jquery', 'websocket', './Write'],
       function (jquery, WebSocket, Write, undefined) {
  var writeObj = new Write();
  var write = writeObj.func;

  var WebSocketClient = function (cfg) {
    if (typeof cfg.url == 'string') {
      this.url = cfg.url;
    }
    if (typeof cfg.type == 'string') {
      this.type = cfg.type;
    }
  };
  WebSocketClient.prototype = {
    url: undefined,
    type: undefined
  };

  WebSocketClient.prototype.connect = function (onComplete) {
    var client = new WebSocket.client();
    var _this = this;

    client.on('connectFailed', function (error) {
      write('[WebSocketClient]: Connect Error: ' + error.toString());
    });

    client.on('connect', function (connection) {
      write('[WebSocketClient]: connected');
      var test = {
        command: '',
        callbacks: {
          onMessage: undefined,
          onError: undefined
        },
        obj: undefined,
        autoVerify: false
      }; // ASYNC ?

      connection.on('error', function (error) {
        write("[WebSocketClient]: Connection Error: " + error.toString());
      });

      connection.on('close', function () {
        write('[WebSocketClient]: Connection Closed');
      });

      connection.on('message', function (message) {
        if (test.autoVerify === true) {
          console.log('test.result:'+test.result);
          test.obj.assertFailAnd(test.result, undefined, 'sendAndVerify result (second param) undefined');
          var msg = JSON.parse(message.utf8Data);
          //msg = msg.replace(/["]/g,'');
          //test.obj.assert(msg, _this.messages[test.command]);

          if (message.type === 'utf8') {
            write("[WebSocketClient]: Received Response: " + msg);

            if (test.result !== undefined) {
              //console.log('expected response: ', _this.messages[test.command]);
              //console.log('actual response: ', message.utf8Data);
              if (typeof test.result === 'string') {
                // if the test command is a string, it's probably json, lets compare it directly in that case
                test.obj.assert(test.result, message.utf8Data, 'tried to compare json strings');
              } else {
                test.obj.assert(test.result,
                              msg, 'stringified JSON vs msg object');
              }
            } else {
              test.obj.result(false, 'WebSocketClient: no result set to auto verify');
            }
          }
        } else {
          test.callbacks.onMessage(message);
        }
      });

      // helper function for tests to verify the command and mark test
      // complete if the verification is successful against the test
      // data passed in during the instantiation in the controller.
      connection.sendAndVerify = function (command, result, testObj) {
        test.command = command;
        test.result = result;
        test.autoVerify = true;
        test.obj = testObj;
        connection.sendUTF(command);
      };
      // another helper function to assist with an async test that doesn't
      // want to use auto-verify. You can do your verification in the
      // callback methods you specify
      connection.sendWithCallback = function (command, onMessage, onError) {
        test.command = command;
        test.autoVerify = false;
        test.callbacks.onMessage= onMessage;
        test.callbacks.onError = onError;
        connection.sendUTF(command);
      };

      onComplete(connection); // connection established, return
                              // modified connection object to test suite.
    });

    client.connect(this.url, this.type);
  };

  return WebSocketClient;
});<commit_msg>slightly imrpoved message reporting<commit_after>/**
 * Function: WebSocketClient
 *
 * The WebSocketClient object is used to create an object for simplifying
 * WebSocketClient requests.
 *
 *      env.WebSocketClient = new this.WebSocketClient();
 *      env.WebSocketClient.connect('ws://localhost:9992/',
 *                     'echo-protocol',
 *                      function(connection) {
 *           env.connection = connection;
 *           env.connection.send('command', _this);
 *      });
 *
 * Parameters:
 *
 *   baseUrl - the baseUrl of all your WebSocketClient calls
 *
 * Returns:
 *
 *   returns a WebSocketClient object a connect() function, sendAndVerify(),
 *   and sendWithCallback()
 */
if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define(['jquery', 'websocket', './Write'],
       function (jquery, WebSocket, Write, undefined) {
  var writeObj = new Write();
  var write = writeObj.func;

  var WebSocketClient = function (cfg) {
    if (typeof cfg.url == 'string') {
      this.url = cfg.url;
    }
    if (typeof cfg.type == 'string') {
      this.type = cfg.type;
    }
  };
  WebSocketClient.prototype = {
    url: undefined,
    type: undefined
  };

  WebSocketClient.prototype.connect = function (onComplete) {
    var client = new WebSocket.client();
    var _this = this;

    client.on('connectFailed', function (error) {
      write('[WebSocketClient]: Connect Error: ' + error.toString());
    });

    client.on('connect', function (connection) {
      write('[WebSocketClient]: connected');
      var test = {
        command: '',
        callbacks: {
          onMessage: undefined,
          onError: undefined
        },
        obj: undefined,
        autoVerify: false
      }; // ASYNC ?

      connection.on('error', function (error) {
        write("[WebSocketClient]: Connection Error: " + error.toString());
      });

      connection.on('close', function () {
        write('[WebSocketClient]: Connection Closed');
      });

      connection.on('message', function (message) {
        if (test.autoVerify === true) {
          //console.log('test.result:'+test.result);
          test.obj.assertFailAnd(test.result, undefined, 'sendAndVerify result (second param) undefined');
          var msg = JSON.parse(message.utf8Data);
          //msg = msg.replace(/["]/g,'');
          //test.obj.assert(msg, _this.messages[test.command]);

          if (message.type === 'utf8') {
            write("[WebSocketClient]: Received Response: " + message.utf8Data);

            if (test.result !== undefined) {
              //console.log('expected response: ', _this.messages[test.command]);
              //console.log('actual response: ', message.utf8Data);
              if (typeof test.result === 'string') {
                // if the test command is a string, it's probably json, lets compare it directly in that case
                test.obj.assert(test.result, message.utf8Data, 'tried to compare json strings');
              } else {
                //console.log('MSG: ', msg);
                //console.log('RES: ', test.result);
                test.obj.assert(test.result,
                              msg, 'obj vs msg object');
              }
            } else {
              test.obj.result(false, 'WebSocketClient: no result set to auto verify');
            }
          }
        } else {
          test.callbacks.onMessage(message);
        }
      });

      // helper function for tests to verify the command and mark test
      // complete if the verification is successful against the test
      // data passed in during the instantiation in the controller.
      connection.sendAndVerify = function (command, result, testObj) {
        test.command = command;
        test.result = result;
        test.autoVerify = true;
        test.obj = testObj;
        connection.sendUTF(command);
      };
      // another helper function to assist with an async test that doesn't
      // want to use auto-verify. You can do your verification in the
      // callback methods you specify
      connection.sendWithCallback = function (command, onMessage, onError) {
        test.command = command;
        test.autoVerify = false;
        test.callbacks.onMessage= onMessage;
        test.callbacks.onError = onError;
        connection.sendUTF(command);
      };

      onComplete(connection); // connection established, return
                              // modified connection object to test suite.
    });

    client.connect(this.url, this.type);
  };

  return WebSocketClient;
});<|endoftext|>


<commit_before>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');
var filters = require('./torque_filters');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this._icons = {};
    this._filters = filters(this._canvas);
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._style = null;
    this._gradients = {};

    this._forcePoints = false;
  }

  torque.extend(PointRenderer.prototype, torque.Event, {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
      var img_names = this._shader.getImageURLs();
      this._preloadIcons(img_names);
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var self = this;
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);
      if(this._style === null || this._style !== st){
        this._style = st;
      }

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      var img_name = this._qualifyURL(st["marker-file"] || st["point-file"]);
      if (img_name && this._icons.itemsToLoad <= 0) {
          var img = this._icons[img_name];
          img.w = st['marker-width'] || img.width;
          img.h = st['marker-width'] || st['marker-height'];
          cartocss.renderSprite(ctx, img, st);
      }
      else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }

      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }

      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },
    _qualifyURL: function(url) {
      if (typeof this.options.qualifyURL !== "undefined"){
        return this.options.qualifyURL(url);
      }
      else{
        var a = document.createElement('a');
        a.href = url;
        return a.href;
      }
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if (!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if (blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if (activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if (c) {
           var sp = sprites[c];
           if (sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1);
             var y = tileMax - tile.y[posIdx]; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }

      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    },
    _preloadIcons: function(img_names){
      var self = this;
      this._icons = {};
      if (img_names.length > 0 && !this._forcePoints){
        for (var i = 0; i<img_names.length; i++){
          var new_img = this._createImage();
          this._icons[this._qualifyURL(img_names[i])] = null;
          if (typeof self._icons.itemsToLoad === 'undefined'){
            this._icons.itemsToLoad = img_names.length;
          }
          var filtered = self._shader.getLayers().some(function(layer){return typeof layer.shader["image-filters"] !== "undefined"});
          if (filtered){
            new_img.crossOrigin = 'Anonymous';
          }
          new_img.onload = function(e){
            self._icons[this.src] = this;
            if (Object.keys(self._icons).length === img_names.length + 1){
              self._icons.itemsToLoad--;
              if (self._icons.itemsToLoad <= 0){
                self.clearSpriteCache();
                self.fire("allIconsLoaded");
              }
            }
          };
          new_img.onerror = function(){
            self._forcePoints = true;
            self.clearSpriteCache();
            if(filtered){
              console.info("Only CORS-enabled, or same domain image-files can be used in combination with image-filters");
            }
            console.error("Couldn't get marker-file " + this.src);
          };
          this.itemsToLoad++;
          new_img.src = img_names[i];
        }
      }

  },
  applyFilters: function(){
    if(this._style){
      if(this._style['image-filters']){
        function gradientKey(imf){
          var hash = ""
          for(var i = 0; i < imf.args.length; i++){
            var rgb = imf.args[i].rgb;
            hash += rgb[0] + ":" + rgb[1] + ":" + rgb[2];
          }
          return hash;
        }
        var gradient = this._gradients[gradientKey(this._style['image-filters'])];
        if(!gradient){
          function componentToHex(c) {
            var hex = c.toString(16);
            return hex.length == 1 ? "0" + hex : hex;
          }

          function rgbToHex(r, g, b) {
            return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
          }
          gradient = {};
          var colorize = this._style['image-filters'].args;

          var increment = 1/colorize.length;
          for (var i = 0; i < colorize.length; i++){
            var key = increment * i + increment;
            var rgb = colorize[i].rgb;
            var formattedColor = rgbToHex(rgb[0], rgb[1], rgb[2]);
            gradient[key] = formattedColor;
          }
          this._gradients[gradientKey(this._style['image-filters'])] = gradient;
        }
        this._filters.gradient(gradient);
        this._filters.draw();
      }
    }
  }
});

  // exports public api
module.exports = PointRenderer;
<commit_msg>adds half the resolution size to x and y positions<commit_after>var torque = require('../');
var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');
var filters = require('./torque_filters');

  var TAU = Math.PI * 2;
  var DEFAULT_CARTOCSS = [
    '#layer {',
    '  marker-fill: #662506;',
    '  marker-width: 4;',
    '  [value > 1] { marker-fill: #FEE391; }',
    '  [value > 2] { marker-fill: #FEC44F; }',
    '  [value > 3] { marker-fill: #FE9929; }',
    '  [value > 4] { marker-fill: #EC7014; }',
    '  [value > 5] { marker-fill: #CC4C02; }',
    '  [value > 6] { marker-fill: #993404; }',
    '  [value > 7] { marker-fill: #662506; }',
    '}'
  ].join('\n');

  var COMP_OP_TO_CANVAS = {
    "src": 'source-over',
    "src-over": 'source-over',
    "dst-over": 'destination-over',
    "src-in": 'source-in',
    "dst-in": 'destination-in',
    "src-out": 'source-out',
    "dst-out": 'destination-out',
    "src-atop": 'source-atop',
    "dst-atop": 'destination-atop',
    "xor": 'xor',
    "darken": 'darken',
    "lighten": 'lighten'
  }

  function compop2canvas(compop) {
    return COMP_OP_TO_CANVAS[compop] || compop;
  }

  //
  // this renderer just render points depending of the value
  //
  function PointRenderer(canvas, options) {
    if (!canvas) {
      throw new Error("canvas can't be undefined");
    }
    this.options = options;
    this._canvas = canvas;
    this._ctx = canvas.getContext('2d');
    this._sprites = []; // sprites per layer
    this._shader = null;
    this._icons = {};
    this._filters = filters(this._canvas);
    this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
    this.TILE_SIZE = 256;
    this._style = null;
    this._gradients = {};

    this._forcePoints = false;
  }

  torque.extend(PointRenderer.prototype, torque.Event, {

    clearCanvas: function() {
      var canvas = this._canvas;
      var color = this._Map['-torque-clear-color']
      // shortcut for the default value
      if (color  === "rgba(255, 255, 255, 0)" || !color) {
        this._canvas.width = this._canvas.width;
      } else {
        var ctx = this._ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        var compop = this._Map['comp-op']
        ctx.globalCompositeOperation = compop2canvas(compop);
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }
    },

    setCanvas: function(canvas) {
      this._canvas = canvas;
      this._ctx = canvas.getContext('2d');
    },

    //
    // sets the cartocss style to render stuff
    //
    setCartoCSS: function(cartocss) {
      // clean sprites
      this.setShader(new carto.RendererJS().render(cartocss));
    },

    setShader: function(shader) {
      // clean sprites
      this._sprites = [];
      this._shader = shader;
      this._Map = this._shader.getDefault().getStyle({}, { zoom: 0 });
      var img_names = this._shader.getImageURLs();
      this._preloadIcons(img_names);
    },

    clearSpriteCache: function() {
      this._sprites = [];
    },

    //
    // generate sprite based on cartocss style
    //
    generateSprite: function(shader, value, shaderVars) {
      var self = this;
      var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
      var st = shader.getStyle({
        value: value
      }, shaderVars);
      if(this._style === null || this._style !== st){
        this._style = st;
      }

      var pointSize = st['marker-width'];
      if (!pointSize) {
        return null;
      }

      if (st['marker-opacity'] === 0 && !st['marker-line-opacity']) {
        return null;
      }

      var canvas = this._createCanvas();
      // take into account the exterior ring to calculate the size
      var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
      var ctx = canvas.getContext('2d');
      var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
      ctx.translate(w/2, w/2);

      var img_name = this._qualifyURL(st["marker-file"] || st["point-file"]);
      if (img_name && this._icons.itemsToLoad <= 0) {
          var img = this._icons[img_name];
          img.w = st['marker-width'] || img.width;
          img.h = st['marker-width'] || st['marker-height'];
          cartocss.renderSprite(ctx, img, st);
      }
      else {
        var mt = st['marker-type'];
        if (mt && mt === 'rectangle') {
          cartocss.renderRectangle(ctx, st);
        } else {
          cartocss.renderPoint(ctx, st);
        }
      }
      prof.end(true);
      if (torque.flags.sprites_to_images) {
        var i = this._createImage();
        i.src = canvas.toDataURL();
        return i;
      }

      return canvas;
    },

    //
    // renders all the layers (and frames for each layer) from cartocss
    //
    renderTile: function(tile, key) {
      var prof = Profiler.metric('torque.renderer.point.renderLayers').start();
      var layers = this._shader.getLayers();
      for(var i = 0, n = layers.length; i < n; ++i ) {
        var layer = layers[i];
        if (layer.name() !== "Map") {
          var sprites = this._sprites[i] || (this._sprites[i] = {});
          // frames for each layer
          for(var fr = 0; fr < layer.frames().length; ++fr) {
            var frame = layer.frames()[fr];
            var fr_sprites = sprites[frame] || (sprites[frame] = []);
            this._renderTile(tile, key - frame, frame, fr_sprites, layer);
          }
        }
      }

      prof.end(true);
    },

    _createCanvas: function() {
      return this.options.canvasClass
        ? new this.options.canvasClass()
        : document.createElement('canvas');
    },

    _createImage: function() {
      return this.options.imageClass
        ? new this.options.imageClass()
        : new Image();
    },
    _qualifyURL: function(url) {
      if (typeof this.options.qualifyURL !== "undefined"){
        return this.options.qualifyURL(url);
      }
      else{
        var a = document.createElement('a');
        a.href = url;
        return a.href;
      }
    },

    //
    // renders a tile in the canvas for key defined in
    // the torque tile
    //
    _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
      if (!this._canvas) return;

      var prof = Profiler.metric('torque.renderer.point.renderTile').start();
      var ctx = this._ctx;
      var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
      if (blendMode) {
        ctx.globalCompositeOperation = blendMode;
      }
      if (this.options.cumulative && key > tile.maxDate) {
        //TODO: precache because this tile is not going to change
        key = tile.maxDate;
      }
      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
      var activePixels = tile.timeCount[key];
      if (activePixels) {
        var pixelIndex = tile.timeIndex[key];
        for(var p = 0; p < activePixels; ++p) {
          var posIdx = tile.renderDataPos[pixelIndex + p];
          var c = tile.renderData[pixelIndex + p];
          if (c) {
           var sp = sprites[c];
           if (sp === undefined) {
             sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
           }
           if (sp) {
             var x = tile.x[posIdx]- (sp.width >> 1) + this.options.resolution/2;
             var y = tileMax - tile.y[posIdx] + this.options.resolution/2; // flip mercator
             ctx.drawImage(sp, x, y - (sp.height >> 1));
           }
          }
        }
      }

      prof.end(true);
    },

    setBlendMode: function(b) {
      this.options.blendmode = b;
    },

    /**
     * get active points for a step in active zoom
     * returns a list of bounding boxes [[sw, ne] , [], []] where ne is a {lat: .., lon: ...} obj
     * empty list if there is no active pixels
     */
    getActivePointsBBox: function(tile, step) {
      var positions = [];
      var mercator = new torque.Mercator();

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx]; // flip mercator
         positions.push(mercator.tilePixelBBox(
           tile.coord.x,
           tile.coord.y,
           tile.coord.z,
           x, y
         ));
        }
      }
      return positions;
    },

    // return the value for x, y (tile coordinates)
    // null for no value
    getValueFor: function(tile, step, px, py) {
      var mercator = new torque.Mercator();
      var res = this.options.resolution;
      var res2 = res >> 1;

      var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1);
      //this.renderer.renderTile(tile, this.key, pos.x, pos.y);
      var activePixels = tile.timeCount[step];
      var pixelIndex = tile.timeIndex[step];
      for(var p = 0; p < activePixels; ++p) {
        var posIdx = tile.renderDataPos[pixelIndex + p];
        var c = tile.renderData[pixelIndex + p];
        if (c) {
         var x = tile.x[posIdx];
         var y = tileMax - tile.y[posIdx];
         var dx = px + res2 - x;
         var dy = py + res2 - y;
         if (dx >= 0 && dx < res && dy >= 0 && dy < res) {
           return {
             value: c,
             bbox: mercator.tilePixelBBox(
               tile.coord.x,
               tile.coord.y,
               tile.coord.z,
               x - res2, y - res2, res
             )
           }
         }
        }
      }
      return null;
    },
    _preloadIcons: function(img_names){
      var self = this;
      this._icons = {};
      if (img_names.length > 0 && !this._forcePoints){
        for (var i = 0; i<img_names.length; i++){
          var new_img = this._createImage();
          this._icons[this._qualifyURL(img_names[i])] = null;
          if (typeof self._icons.itemsToLoad === 'undefined'){
            this._icons.itemsToLoad = img_names.length;
          }
          var filtered = self._shader.getLayers().some(function(layer){return typeof layer.shader["image-filters"] !== "undefined"});
          if (filtered){
            new_img.crossOrigin = 'Anonymous';
          }
          new_img.onload = function(e){
            self._icons[this.src] = this;
            if (Object.keys(self._icons).length === img_names.length + 1){
              self._icons.itemsToLoad--;
              if (self._icons.itemsToLoad <= 0){
                self.clearSpriteCache();
                self.fire("allIconsLoaded");
              }
            }
          };
          new_img.onerror = function(){
            self._forcePoints = true;
            self.clearSpriteCache();
            if(filtered){
              console.info("Only CORS-enabled, or same domain image-files can be used in combination with image-filters");
            }
            console.error("Couldn't get marker-file " + this.src);
          };
          this.itemsToLoad++;
          new_img.src = img_names[i];
        }
      }

  },
  applyFilters: function(){
    if(this._style){
      if(this._style['image-filters']){
        function gradientKey(imf){
          var hash = ""
          for(var i = 0; i < imf.args.length; i++){
            var rgb = imf.args[i].rgb;
            hash += rgb[0] + ":" + rgb[1] + ":" + rgb[2];
          }
          return hash;
        }
        var gradient = this._gradients[gradientKey(this._style['image-filters'])];
        if(!gradient){
          function componentToHex(c) {
            var hex = c.toString(16);
            return hex.length == 1 ? "0" + hex : hex;
          }

          function rgbToHex(r, g, b) {
            return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
          }
          gradient = {};
          var colorize = this._style['image-filters'].args;

          var increment = 1/colorize.length;
          for (var i = 0; i < colorize.length; i++){
            var key = increment * i + increment;
            var rgb = colorize[i].rgb;
            var formattedColor = rgbToHex(rgb[0], rgb[1], rgb[2]);
            gradient[key] = formattedColor;
          }
          this._gradients[gradientKey(this._style['image-filters'])] = gradient;
        }
        this._filters.gradient(gradient);
        this._filters.draw();
      }
    }
  }
});

  // exports public api
module.exports = PointRenderer;
<|endoftext|>