<commit_before> // Design Basic Game Solo Challenge

// This is a solo challenge

// Your mission description: Sink all of your enemies ships before they sink yours!
// Overall mission:
// Goals: Find enemy ships on the grid and sink them before the computer finds and
//        sinks all of your ships
// Characters: You will have a number of ships positioned on a grid; the computer
//             playing as the enemey will have the same
// Objects: Computer Players (CP) grid; players grid
//          CP collection of ships; your collection of ships
// Functions: attack a square
//            determine if there was a hit and report it
//            update grids to show hits and misses
//            get user input
//            check to see if a ship is sunk
//            check to see if anyone has won
// Pseudocode
// Create "fleet" objects
//    Each fleet consists of ships with a size and a health (same number)
//       :battleship 5
//       :destroyer  4
//       :cruiser    3
//       :submarine  2
// Randomly fill two grids with "ships"
//    1. Starting with the battleship, randomly place ship in grid
//       a. grid is an array of arrays
//       b. all spaces initialized as EMPTY_SPACE for water/meaning empty
//       c. randomly generate two numbers for the starting position of the ship
//       d. check if the ship can fit horizontally or vertically without going
//          out of bounds of the array grid
//       e. (for additional ships) check that ship will not intersect a ship
//          already placed in the array grid
//       f. place the ship by changing the array values to "B" for example, to
//       g. indicate the ship type
//       h. iterate through fleet until all ships have been succesfully placed
//          by returning to "c."
// Display grids (with update)
//    1. Call a function to display an empty enemy grid and your own filled grid
//       a. iterate through enemy array grid; on initial display it will be empty
//          but on subsequent rounds it will display an "X" for where you have made
//          a hit and an "O" for where you missed.
//    2. Call the above function but with player info so that it will show the locations
//       of your ships as well as hit and miss data
// Get User attack
//  ** Check for valid input!!!
//    1. prompt user for a grid position to attack
//    2. check if that space is occupied by an enemy ship
//       a. IF it is, THEN replace that element in the enemy grid with an "X"
//       b. ELSE place an "O" in that space on the enemy grid
//    3. check if ship is sunk
//       a. IF yes, let the user know, ELSE continue as normal
//          i. if YES THEN check if all ship have been sunk. If true, you win!
//             unless of course it is all of your ships that have been sunk
// Get computer attack
//    1. generate two random numbers
//    2. check the element in the grid at the above location
//       a. check through the same steps in Get User Attack to update the player's
//          board and to see if the computer won.
//

// Initial Code
GRID_SIZE = 9; // size of the playing area
X_AXIS = 0; // defines the index to be used for the x axis values
Y_AXIS = 1; // defines the index to be used for the y axis values
TOP_LABEL = [" ",1,2,3,4,5,6,7,8]; // sets labels for top row of grid
SIDE_LABEL = [' ', 'A','B','C','D','E','F','G','H']; // labels for side of grid
SPACER = "    "; // sets the horizontal spacer that makes it look pretty
VSPCER = "\n \n"; // set the vertical spacer that makes it look pretty
EMPTY_SPACE = " "; // sets the value to be used for empty spaces in the grid
HIT_X = "X"; //sets the value to be used for a "hit" on a ship
MISS = "O"; //set the value to be used for a missed shot

// returns two random values in an array. These values are guaranteed
// to be within the playing space of the game grid
function posXY(){
	var pos_x = Math.floor(Math.random() * (GRID_SIZE-1)) + 1;
	var pos_y = Math.floor(Math.random() * (GRID_SIZE-1)) + 1;
	return [pos_x, pos_y];
}

// Define a fleet object
function Fleet() {
	this.battleship = { size: 5, health: 5, sym: "B"};
	this.destroyer = { size: 4, health: 4, sym: "D"};
	this.cruiser = { size: 3, health: 3, sym: "C"};
	this.submarine = { size: 2, health: 2, sym: "S"};
	this.isHit = function(ship) {
		ship.health -= 1;
		return ship.health;
	}
}

// creates an array of arrays whose dimensions are size x size
function createArray(size) {
	arr = new Array(size);
	for (var i = 0; i < size; i++){
		arr[i] = new Array(size);
	}

	return arr;
}

// mainly a debugging tool for diplaying a row at a time
function show_row(arr){
	for (var i = 0; i < arr.length; i++){
		process.stdout.write("i: " + arr[i] + "\t");
	}
	console.log("");
}

// debugging tool for displaying all ships in fleet and size values
function showObjectProp(fleet){
	console.log(fleet)
	for (var key in fleet){
		if (fleet.hasOwnProperty(key)){
			if (key != "isHit") console.log(key + " : " + fleet[key].size);
		}
	}
}

//  populates an square matrix array of GRID_SIZE x GRID_SIZE dimension
function Grid() {
	this.grid = createArray(GRID_SIZE);
	for (var i = 0; i < GRID_SIZE; i++){
		if (i == 0) {
			this.grid[i] = TOP_LABEL;
			continue;
		}
		for (var j = 0; j < GRID_SIZE; j++){
			if (j == 0){
				this.grid[i][j] = SIDE_LABEL[i];
			} else {
			this.grid[i][j] = EMPTY_SPACE;
			}
		}
	}
	return this.grid;
}

// Shows the playing grid of either the player or the computer
// The computers grid (when enemy == true) does not display the
// locations of the enemy ships
function displayGrid(grid, enemy) {
	if (enemy) {
		console.log("\t <** Enemy Grid **>");
	} else console.log("\t <** Player Grid **>");
	for (var i = 0; i < GRID_SIZE; i++){
		for (var j = 0; j < GRID_SIZE; j++){
			if ((!enemy)||(i == 0)||(j == 0)) {
				process.stdout.write(grid[i][j] + SPACER);
			} else {
				if ((grid[i][j] != SPACER)||  // create a function to quickly check all of this
					(grid[i][j] != HIT_X)||
					(grid[i][j] != MISS)) {
					process.stdout.write(EMPTY_SPACE + SPACER);
				} else {
					process.stdout.write(grid[i][j] + SPACER);
				}
			}
		}
		process.stdout.write(VSPCER);
	}
}

// ------------------------------------------------------------------------
/* Functions below handle placing and validating locations of fleet ships */
// ------------------------------------------------------------------------

// Checks if there is enough horizontal room in grid to place ship and also
// makes sure that another ship is not in the way
function fitsHorizontal(x, y, size, grid){
	console.log("x : " + x + "\t size : " + size + " space : " + (GRID_SIZE - x) + "   t/f : " + ((GRID_SIZE - x) > size) );
	var doesFit = ((GRID_SIZE - x) > size);
	if (doesFit) {
		for (var i = 0; i < size; i++){
			if (grid[y][x+i] != EMPTY_SPACE) doesFit = false;
		}
	}
	return doesFit;
}

// Checks if there is enough vertical room in grid to place ship and also
// makes sure that another ship is not in the way
function fitsVertical(x, y, size, grid){
	console.log("y : " + y + "\t size : " + size + " space : " + (GRID_SIZE - y) + "   t/f : " + ((GRID_SIZE - y) > size) );
	var doesFit = ((GRID_SIZE - y) > size);
	if (doesFit) {
		for (var i = 0; i < size; i++){
			if (grid[y+i][x] != EMPTY_SPACE) doesFit = false;
		}
	}
	return doesFit;
}

// finds a valid position for each ship on the grid
function findValidPosition(shipsize, grid){
	loc = posXY();      // I am cheating by letting these two variables exist beyond
	horizontal = false; // of this method.  Bad practice, but a quick solution ;)
	if (fitsHorizontal(loc[X_AXIS], loc[Y_AXIS],shipsize, grid)) {
		horizontal = true;
		return [loc, horizontal];
	} else if (fitsVertical(loc[X_AXIS], loc[Y_AXIS], shipsize, grid)){
		horizontal = false;
		return [loc, horizontal];
	} else return [false];
}

// places the symbols for each ship in its location on the grid
function putShipOnGrid(pos, ship, hor, grid){
	if (hor){
		for (var i = 0; i < ship.size; i++){
			grid[pos[Y_AXIS]][pos[X_AXIS]+i] = ship.sym;
		}
	} else {
		for (var i = 0; i < ship.size; i++){
			grid[pos[Y_AXIS]+i][pos[X_AXIS]] = ship.sym;
		}
	}
}

// master function which iterates over all ships in a fleet, placing them
// in valid positions on the playing grid
function placeShips(fleet, grid){
	for (var key in fleet){
		if (fleet.hasOwnProperty(key)){
			if (key != "isHit") {
				while (!findValidPosition(fleet[key].size, grid)[0]){}
				console.log(key + " : " + fleet[key].size); //debugging line
				console.log("posXY : " + loc[0] + ", " + loc[1] + " is horizontal? " + horizontal);
				putShipOnGrid(loc, fleet[key], horizontal, grid);
			}
		}
	}
}

// Functions below are for gameplay

function checkHit(pos, grid){
	var row = pos[Y_AXIS];
	var column = pos[X_AXIS];
	if ((grid[row][column] != EMPTY_SPACE)&&
	    (grid[row][column] != HIT_X)&&
	    (grid[row][column] != MISS)) {
		return true;
	} else return false;
}

function updateFleet(letter, fleet) {
	switch (letter) {
		case "B":
			fleet.isHit(fleet.battleship);
			console.log("Battleship health: " + fleet.battleship.health);
			break;
		case "C":
			fleet.isHit(fleet.cruiser);
			console.log("Cruiser health: " + fleet.cruiser.health);
			break;
		case "D":
			fleet.isHit(fleet.destroyer);
			console.log("Destroyer health: " + fleet.destroyer.health);
			break;
		case "S":
			fleet.isHit(fleet.submarine);
			console.log("Submarine health: " + fleet.submarine.health);
			break;
	}
}

function updateGame(fleet, grid, enemy){
	// get firing data
	if (enemy) {
		var pos = posXY();
	} else {
		var pos = posXY(); // real version would get user input
	}
	console.log("row : " + pos[Y_AXIS] + "\t col : " + pos[X_AXIS]);
	if (checkHit(pos, grid)) {
		value_at_pos = grid[pos[Y_AXIS]][pos[X_AXIS]];
		updateFleet(value_at_pos, fleet);
		grid[pos[Y_AXIS]][pos[X_AXIS]] = "X";
	} else grid[pos[Y_AXIS]][pos[X_AXIS]] = "O";
	return grid;
}

// Code below is for getting user input from the console.
// would require fitting all of the game play functions within
// the structure of the callbacks in order to work because
// of the asynchronous nature of JS execution.  The code you
// see in here is just sample/test code put in during my futile
// trouble shooting of this issue.
function getPlayerInput() {
	var readline = require('readline');

	var rl = readline.createInterface({
	  input: process.stdin,
	  output: process.stdout
	});

	rl.question("What do you think of Node.js? ", function(answer) {
	  // TODO: Log the answer in a database
	  process.stdin.pause();
	  console.log("Thank you for your valuable feedback:", answer);

	  rl.close();
	});

}
	// var readline = require('readline');
	// var rl = readline.createInterface(process.stdin, process.stdout);
	// rl.setPrompt("Target Coordinates [x, y] : ");
	// rl.prompt();
	// rl.on('line', function(line){
	// 	if (line === "exit") rl.close();
	// 	return line;
	// 	//rl.prompt();
	// }).on('close', function(){
	// 	process.exit(0);

// Driver Code
console.log("Numbers: " + posXY());
var myFleet = new Fleet();
console.log("show health: " + myFleet.battleship.health);
console.log("show hit: " + myFleet.isHit(myFleet.battleship));
var enemyFleet = new Fleet();
console.log("show enemy : " + enemyFleet.battleship.health);
myGrid = new Grid();
displayGrid(myGrid);
placeShips(myFleet, myGrid);
displayGrid(myGrid);
enemyGrid = new Grid();
placeShips(enemyFleet, enemyGrid);
displayGrid(enemyGrid, true);
showObjectProp(myFleet);
myGrid = updateGame(myFleet, myGrid, false);
displayGrid(myGrid);

// Refactored Code

// Reflection
// What was the most difficult part of this challenge?

What did you learn about creating objects and functions that interact with one another?

	Wow!  I really miss not being able to creat classes!  It isn't terribly difficult to
	do, but a lot of data is getting passed around between functions.

Did you learn about any new built-in methods you could use in your refactored solution?
If so, what were they and how do they work?

	I kind of gave up on finding built-in methods to fix issues after looking at some of
	JS api.  Really, the logic is pretty straight forward and refactoring in my case,
	to do seriously, would amount to reworking the whole thing and creating classes.  But,
	JS doesn't do classes, so maybe restructure to avoid passing so much data around
	between functions.

How can you access and manipulate properties of objects?
//
//
//
//
//
//
//<commit_msg>Finish reflection for 7.8<commit_after> // Design Basic Game Solo Challenge

// This is a solo challenge

// Your mission description: Sink all of your enemies ships before they sink yours!
// Overall mission:
// Goals: Find enemy ships on the grid and sink them before the computer finds and
//        sinks all of your ships
// Characters: You will have a number of ships positioned on a grid; the computer
//             playing as the enemey will have the same
// Objects: Computer Players (CP) grid; players grid
//          CP collection of ships; your collection of ships
// Functions: attack a square
//            determine if there was a hit and report it
//            update grids to show hits and misses
//            get user input
//            check to see if a ship is sunk
//            check to see if anyone has won
// Pseudocode
// Create "fleet" objects
//    Each fleet consists of ships with a size and a health (same number)
//       :battleship 5
//       :destroyer  4
//       :cruiser    3
//       :submarine  2
// Randomly fill two grids with "ships"
//    1. Starting with the battleship, randomly place ship in grid
//       a. grid is an array of arrays
//       b. all spaces initialized as EMPTY_SPACE for water/meaning empty
//       c. randomly generate two numbers for the starting position of the ship
//       d. check if the ship can fit horizontally or vertically without going
//          out of bounds of the array grid
//       e. (for additional ships) check that ship will not intersect a ship
//          already placed in the array grid
//       f. place the ship by changing the array values to "B" for example, to
//       g. indicate the ship type
//       h. iterate through fleet until all ships have been succesfully placed
//          by returning to "c."
// Display grids (with update)
//    1. Call a function to display an empty enemy grid and your own filled grid
//       a. iterate through enemy array grid; on initial display it will be empty
//          but on subsequent rounds it will display an "X" for where you have made
//          a hit and an "O" for where you missed.
//    2. Call the above function but with player info so that it will show the locations
//       of your ships as well as hit and miss data
// Get User attack
//  ** Check for valid input!!!
//    1. prompt user for a grid position to attack
//    2. check if that space is occupied by an enemy ship
//       a. IF it is, THEN replace that element in the enemy grid with an "X"
//       b. ELSE place an "O" in that space on the enemy grid
//    3. check if ship is sunk
//       a. IF yes, let the user know, ELSE continue as normal
//          i. if YES THEN check if all ship have been sunk. If true, you win!
//             unless of course it is all of your ships that have been sunk
// Get computer attack
//    1. generate two random numbers
//    2. check the element in the grid at the above location
//       a. check through the same steps in Get User Attack to update the player's
//          board and to see if the computer won.
//

// Initial Code
GRID_SIZE = 9; // size of the playing area
X_AXIS = 0; // defines the index to be used for the x axis values
Y_AXIS = 1; // defines the index to be used for the y axis values
TOP_LABEL = [" ",1,2,3,4,5,6,7,8]; // sets labels for top row of grid
SIDE_LABEL = [' ', 'A','B','C','D','E','F','G','H']; // labels for side of grid
SPACER = "    "; // sets the horizontal spacer that makes it look pretty
VSPCER = "\n \n"; // set the vertical spacer that makes it look pretty
EMPTY_SPACE = " "; // sets the value to be used for empty spaces in the grid
HIT_X = "X"; //sets the value to be used for a "hit" on a ship
MISS = "O"; //set the value to be used for a missed shot

// returns two random values in an array. These values are guaranteed
// to be within the playing space of the game grid
function posXY(){
	var pos_x = Math.floor(Math.random() * (GRID_SIZE-1)) + 1;
	var pos_y = Math.floor(Math.random() * (GRID_SIZE-1)) + 1;
	return [pos_x, pos_y];
}

// Define a fleet object
function Fleet() {
	this.battleship = { size: 5, health: 5, sym: "B"};
	this.destroyer = { size: 4, health: 4, sym: "D"};
	this.cruiser = { size: 3, health: 3, sym: "C"};
	this.submarine = { size: 2, health: 2, sym: "S"};
	this.isHit = function(ship) {
		ship.health -= 1;
		return ship.health;
	}
}

// creates an array of arrays whose dimensions are size x size
function createArray(size) {
	arr = new Array(size);
	for (var i = 0; i < size; i++){
		arr[i] = new Array(size);
	}

	return arr;
}

// mainly a debugging tool for diplaying a row at a time
function show_row(arr){
	for (var i = 0; i < arr.length; i++){
		process.stdout.write("i: " + arr[i] + "\t");
	}
	console.log("");
}

// debugging tool for displaying all ships in fleet and size values
function showObjectProp(fleet){
	console.log(fleet)
	for (var key in fleet){
		if (fleet.hasOwnProperty(key)){
			if (key != "isHit") console.log(key + " : " + fleet[key].size);
		}
	}
}

//  populates an square matrix array of GRID_SIZE x GRID_SIZE dimension
function Grid() {
	this.grid = createArray(GRID_SIZE);
	for (var i = 0; i < GRID_SIZE; i++){
		if (i == 0) {
			this.grid[i] = TOP_LABEL;
			continue;
		}
		for (var j = 0; j < GRID_SIZE; j++){
			if (j == 0){
				this.grid[i][j] = SIDE_LABEL[i];
			} else {
			this.grid[i][j] = EMPTY_SPACE;
			}
		}
	}
	return this.grid;
}

// Shows the playing grid of either the player or the computer
// The computers grid (when enemy == true) does not display the
// locations of the enemy ships
function displayGrid(grid, enemy) {
	if (enemy) {
		console.log("\t <** Enemy Grid **>");
	} else console.log("\t <** Player Grid **>");
	for (var i = 0; i < GRID_SIZE; i++){
		for (var j = 0; j < GRID_SIZE; j++){
			if ((!enemy)||(i == 0)||(j == 0)) {
				process.stdout.write(grid[i][j] + SPACER);
			} else {
				if ((grid[i][j] != SPACER)||  // create a function to quickly check all of this
					(grid[i][j] != HIT_X)||
					(grid[i][j] != MISS)) {
					process.stdout.write(EMPTY_SPACE + SPACER);
				} else {
					process.stdout.write(grid[i][j] + SPACER);
				}
			}
		}
		process.stdout.write(VSPCER);
	}
}

// ------------------------------------------------------------------------
/* Functions below handle placing and validating locations of fleet ships */
// ------------------------------------------------------------------------

// Checks if there is enough horizontal room in grid to place ship and also
// makes sure that another ship is not in the way
function fitsHorizontal(x, y, size, grid){
	console.log("x : " + x + "\t size : " + size + " space : " + (GRID_SIZE - x) + "   t/f : " + ((GRID_SIZE - x) > size) );
	var doesFit = ((GRID_SIZE - x) > size);
	if (doesFit) {
		for (var i = 0; i < size; i++){
			if (grid[y][x+i] != EMPTY_SPACE) doesFit = false;
		}
	}
	return doesFit;
}

// Checks if there is enough vertical room in grid to place ship and also
// makes sure that another ship is not in the way
function fitsVertical(x, y, size, grid){
	console.log("y : " + y + "\t size : " + size + " space : " + (GRID_SIZE - y) + "   t/f : " + ((GRID_SIZE - y) > size) );
	var doesFit = ((GRID_SIZE - y) > size);
	if (doesFit) {
		for (var i = 0; i < size; i++){
			if (grid[y+i][x] != EMPTY_SPACE) doesFit = false;
		}
	}
	return doesFit;
}

// finds a valid position for each ship on the grid
function findValidPosition(shipsize, grid){
	loc = posXY();      // I am cheating by letting these two variables exist beyond
	horizontal = false; // of this method.  Bad practice, but a quick solution ;)
	if (fitsHorizontal(loc[X_AXIS], loc[Y_AXIS],shipsize, grid)) {
		horizontal = true;
		return [loc, horizontal];
	} else if (fitsVertical(loc[X_AXIS], loc[Y_AXIS], shipsize, grid)){
		horizontal = false;
		return [loc, horizontal];
	} else return [false];
}

// places the symbols for each ship in its location on the grid
function putShipOnGrid(pos, ship, hor, grid){
	if (hor){
		for (var i = 0; i < ship.size; i++){
			grid[pos[Y_AXIS]][pos[X_AXIS]+i] = ship.sym;
		}
	} else {
		for (var i = 0; i < ship.size; i++){
			grid[pos[Y_AXIS]+i][pos[X_AXIS]] = ship.sym;
		}
	}
}

// master function which iterates over all ships in a fleet, placing them
// in valid positions on the playing grid
function placeShips(fleet, grid){
	for (var key in fleet){
		if (fleet.hasOwnProperty(key)){
			if (key != "isHit") {
				while (!findValidPosition(fleet[key].size, grid)[0]){}
				console.log(key + " : " + fleet[key].size); //debugging line
				console.log("posXY : " + loc[0] + ", " + loc[1] + " is horizontal? " + horizontal);
				putShipOnGrid(loc, fleet[key], horizontal, grid);
			}
		}
	}
}

// Functions below are for gameplay

function checkHit(pos, grid){
	var row = pos[Y_AXIS];
	var column = pos[X_AXIS];
	if ((grid[row][column] != EMPTY_SPACE)&&
	    (grid[row][column] != HIT_X)&&
	    (grid[row][column] != MISS)) {
		return true;
	} else return false;
}

function updateFleet(letter, fleet) {
	switch (letter) {
		case "B":
			fleet.isHit(fleet.battleship);
			console.log("Battleship health: " + fleet.battleship.health);
			break;
		case "C":
			fleet.isHit(fleet.cruiser);
			console.log("Cruiser health: " + fleet.cruiser.health);
			break;
		case "D":
			fleet.isHit(fleet.destroyer);
			console.log("Destroyer health: " + fleet.destroyer.health);
			break;
		case "S":
			fleet.isHit(fleet.submarine);
			console.log("Submarine health: " + fleet.submarine.health);
			break;
	}
}

function updateGame(fleet, grid, enemy){
	// get firing data
	if (enemy) {
		var pos = posXY();
	} else {
		var pos = posXY(); // real version would get user input
	}
	console.log("row : " + pos[Y_AXIS] + "\t col : " + pos[X_AXIS]);
	if (checkHit(pos, grid)) {
		value_at_pos = grid[pos[Y_AXIS]][pos[X_AXIS]];
		updateFleet(value_at_pos, fleet);
		grid[pos[Y_AXIS]][pos[X_AXIS]] = "X";
	} else grid[pos[Y_AXIS]][pos[X_AXIS]] = "O";
	return grid;
}

// Code below is for getting user input from the console.
// would require fitting all of the game play functions within
// the structure of the callbacks in order to work because
// of the asynchronous nature of JS execution.  The code you
// see in here is just sample/test code put in during my futile
// trouble shooting of this issue.
function getPlayerInput() {
	var readline = require('readline');

	var rl = readline.createInterface({
	  input: process.stdin,
	  output: process.stdout
	});

	rl.question("What do you think of Node.js? ", function(answer) {
	  // TODO: Log the answer in a database
	  process.stdin.pause();
	  console.log("Thank you for your valuable feedback:", answer);

	  rl.close();
	});

}
	// var readline = require('readline');
	// var rl = readline.createInterface(process.stdin, process.stdout);
	// rl.setPrompt("Target Coordinates [x, y] : ");
	// rl.prompt();
	// rl.on('line', function(line){
	// 	if (line === "exit") rl.close();
	// 	return line;
	// 	//rl.prompt();
	// }).on('close', function(){
	// 	process.exit(0);

// Driver Code
console.log("Numbers: " + posXY());
var myFleet = new Fleet();
console.log("show health: " + myFleet.battleship.health);
console.log("show hit: " + myFleet.isHit(myFleet.battleship));
var enemyFleet = new Fleet();
console.log("show enemy : " + enemyFleet.battleship.health);
myGrid = new Grid();
displayGrid(myGrid);
placeShips(myFleet, myGrid);
displayGrid(myGrid);
enemyGrid = new Grid();
placeShips(enemyFleet, enemyGrid);
displayGrid(enemyGrid, true);
showObjectProp(myFleet);
myGrid = updateGame(myFleet, myGrid, false);
displayGrid(myGrid);

// Refactored Code

// Reflection
// What was the most difficult part of this challenge?

/*
What did you learn about creating objects and functions that interact with one another?

	Wow!  I really miss not being able to creat classes!  It isn't terribly difficult to
	do, but a lot of data is getting passed around between functions.

Did you learn about any new built-in methods you could use in your refactored solution?
If so, what were they and how do they work?

	I kind of gave up on finding built-in methods to fix issues after looking at some of
	JS api.  Really, the logic is pretty straight forward and refactoring in my case,
	to do seriously, would amount to reworking the whole thing and creating classes.  But,
	JS doesn't do classes, so maybe restructure to avoid passing so much data around
	between functions.

How can you access and manipulate properties of objects?

	You can use dot or bracket notation to access object properties.  You can iterate through
	an object's properties using "for (var key in obj)" loop to cycle through properties,
	although you should include a check for obj.hasOwnProperty in order to avoid capturing
	any properties that might belong to the object Prototype.  You can use functions or direct
	expressions to alter the values of properties of an object.
*/<|endoftext|>


<commit_before>/**
 * @module ol/renderer/webgl-new/PointsLayer
 */
import LayerRenderer from '../Layer';
import WebGLBuffer from '../../webgl/Buffer';
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl';
import WebGLContext, {DefaultAttrib, DefaultUniform} from '../../webgl/Context';
import WebGLVertex from "../../webgl/Vertex";
import WebGLFragment from "../../webgl/Fragment";
import GeometryType from "../../geom/GeometryType";

const VERTEX_SHADER = `
  precision mediump float;
  attribute vec2 a_position;
  attribute vec2 a_texCoord;
  attribute float a_rotateWithView;
  attribute vec2 a_offsets;

  uniform mat4 u_projectionMatrix;
  uniform mat4 u_offsetScaleMatrix;
  uniform mat4 u_offsetRotateMatrix;

  varying vec2 v_texCoord;

  void main(void) {
    mat4 offsetMatrix = u_offsetScaleMatrix;
    if (a_rotateWithView == 1.0) {
      offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;
    }
    vec4 offsets = offsetMatrix * vec4(a_offsets, 0.0, 0.0);
    gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
    v_texCoord = a_texCoord;
  }`;

const FRAGMENT_SHADER = `
  precision mediump float;
  uniform float u_opacity;

  varying vec2 v_texCoord;

  void main(void) {
    gl_FragColor.rgb = vec3(1.0, 1.0, 1.0);
    float alpha = u_opacity;
    if (alpha == 0.0) {
      discard;
    }
    gl_FragColor.a = alpha;
  }`;

/**
 * @classdesc
 * Webgl vector renderer optimized for points.
 * All features will be rendered as points.
 * @api
 */
class WebGLPointsLayerRenderer extends LayerRenderer {

  /**
   * @param {import("../../layer/Vector.js").default} vectorLayer Vector layer.
   */
  constructor(vectorLayer) {
    super(vectorLayer);

    this.element_ = document.createElement('canvas');

    this.context_ = new WebGLContext(this.element_);

    this.sourceRevision_ = -1;

    this.verticesBuffer_ = new WebGLBuffer([], DYNAMIC_DRAW);
    this.indicesBuffer_ = new WebGLBuffer([], DYNAMIC_DRAW);

    const vertexShader = new WebGLVertex(VERTEX_SHADER);
    const fragmentShader = new WebGLFragment(FRAGMENT_SHADER);
    const program = this.context_.getProgram(fragmentShader, vertexShader);
    this.context_.useProgram(program);
  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    super.disposeInternal();
  }

  /**
   * @inheritDoc
   */
  composeFrame(frameState) {
    this.context_.prepareDraw();
    this.context_.applyFrameState(frameState);
    this.context_.setUniformFloatValue(DefaultUniform.OPACITY, this.getLayer().getOpacity());
    this.context_.drawElements(0, this.indicesBuffer_.getArray().length);
  }

  /**
   * @inheritDoc
   */
  prepareFrame(frameState) {
    const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
    const vectorSource = /** @type {import("../../source/Vector.js").default} */ (vectorLayer.getSource());

    if (this.sourceRevision_ < vectorSource.getRevision()) {
      this.sourceRevision_ = vectorSource.getRevision();

      const viewState = frameState.viewState;
      const projection = viewState.projection;
      const resolution = viewState.resolution;

      // loop on features to fill the buffer
      vectorSource.loadFeatures([-Infinity, -Infinity, Infinity, Infinity], resolution, projection);
      vectorSource.forEachFeature((feature) => {
        if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
          return;
        }
        const geom = /** @type {import("../../geom/Point").default} */ (feature.getGeometry());
        const x = geom.getCoordinates()[0], y = geom.getCoordinates()[1], size = 20;
        let stride = 4;
        let baseIndex = this.verticesBuffer_.getArray().length / stride;

        this.verticesBuffer_.getArray().push(
          x, y, -size / 2, -size / 2,
          x, y, +size / 2, -size / 2,
          x, y, +size / 2, +size / 2,
          x, y, -size / 2, +size / 2,
        );
        this.indicesBuffer_.getArray().push(
          baseIndex, baseIndex + 1, baseIndex + 3,
          baseIndex + 1, baseIndex + 2, baseIndex + 3
        );
      });

      // write new data
      this.context_.bindBuffer(ARRAY_BUFFER, this.verticesBuffer_);
      this.context_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);

      let bytesPerFloat = Float32Array.BYTES_PER_ELEMENT;
      this.context_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * 4, 0);
      this.context_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * 4, bytesPerFloat * 2);
    }

    return true;
  }
}

export default WebGLPointsLayerRenderer;
<commit_msg>Added texcoord in default shader<commit_after>/**
 * @module ol/renderer/webgl-new/PointsLayer
 */
import LayerRenderer from '../Layer';
import WebGLBuffer from '../../webgl/Buffer';
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl';
import WebGLContext, {DefaultAttrib, DefaultUniform} from '../../webgl/Context';
import WebGLVertex from "../../webgl/Vertex";
import WebGLFragment from "../../webgl/Fragment";
import GeometryType from "../../geom/GeometryType";

const VERTEX_SHADER = `
  precision mediump float;
  attribute vec2 a_position;
  attribute vec2 a_texCoord;
  attribute float a_rotateWithView;
  attribute vec2 a_offsets;

  uniform mat4 u_projectionMatrix;
  uniform mat4 u_offsetScaleMatrix;
  uniform mat4 u_offsetRotateMatrix;

  varying vec2 v_texCoord;

  void main(void) {
    mat4 offsetMatrix = u_offsetScaleMatrix;
    if (a_rotateWithView == 1.0) {
      offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;
    }
    vec4 offsets = offsetMatrix * vec4(a_offsets, 0.0, 0.0);
    gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
    v_texCoord = a_texCoord;
  }`;

const FRAGMENT_SHADER = `
  precision mediump float;
  uniform float u_opacity;

  varying vec2 v_texCoord;

  void main(void) {
    gl_FragColor.rgb = vec3(1.0, 1.0, 1.0);
    float alpha = u_opacity;
    if (alpha == 0.0) {
      discard;
    }
    gl_FragColor.a = alpha;
  }`;

/**
 * @classdesc
 * Webgl vector renderer optimized for points.
 * All features will be rendered as points.
 * @api
 */
class WebGLPointsLayerRenderer extends LayerRenderer {

  /**
   * @param {import("../../layer/Vector.js").default} vectorLayer Vector layer.
   */
  constructor(vectorLayer) {
    super(vectorLayer);

    this.element_ = document.createElement('canvas');

    this.context_ = new WebGLContext(this.element_);

    this.sourceRevision_ = -1;

    this.verticesBuffer_ = new WebGLBuffer([], DYNAMIC_DRAW);
    this.indicesBuffer_ = new WebGLBuffer([], DYNAMIC_DRAW);

    const vertexShader = new WebGLVertex(VERTEX_SHADER);
    const fragmentShader = new WebGLFragment(FRAGMENT_SHADER);
    const program = this.context_.getProgram(fragmentShader, vertexShader);
    this.context_.useProgram(program);
  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    super.disposeInternal();
  }

  /**
   * @inheritDoc
   */
  composeFrame(frameState) {
    this.context_.prepareDraw();
    this.context_.applyFrameState(frameState);
    this.context_.setUniformFloatValue(DefaultUniform.OPACITY, this.getLayer().getOpacity());
    this.context_.drawElements(0, this.indicesBuffer_.getArray().length);
  }

  /**
   * @inheritDoc
   */
  prepareFrame(frameState) {
    const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
    const vectorSource = /** @type {import("../../source/Vector.js").default} */ (vectorLayer.getSource());

    if (this.sourceRevision_ < vectorSource.getRevision()) {
      this.sourceRevision_ = vectorSource.getRevision();

      const viewState = frameState.viewState;
      const projection = viewState.projection;
      const resolution = viewState.resolution;

      // loop on features to fill the buffer
      vectorSource.loadFeatures([-Infinity, -Infinity, Infinity, Infinity], resolution, projection);
      vectorSource.forEachFeature((feature) => {
        if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
          return;
        }
        const geom = /** @type {import("../../geom/Point").default} */ (feature.getGeometry());
        const x = geom.getCoordinates()[0], y = geom.getCoordinates()[1], size = 20;
        let stride = 6;
        let baseIndex = this.verticesBuffer_.getArray().length / stride;

        this.verticesBuffer_.getArray().push(
          x, y, -size / 2, -size / 2, 0, 0,
          x, y, +size / 2, -size / 2, 1, 0,
          x, y, +size / 2, +size / 2, 1, 1,
          x, y, -size / 2, +size / 2, 0, 1,
        );
        this.indicesBuffer_.getArray().push(
          baseIndex, baseIndex + 1, baseIndex + 3,
          baseIndex + 1, baseIndex + 2, baseIndex + 3
        );
      });

      // write new data
      this.context_.bindBuffer(ARRAY_BUFFER, this.verticesBuffer_);
      this.context_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);

      let bytesPerFloat = Float32Array.BYTES_PER_ELEMENT;
      this.context_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * 6, 0);
      this.context_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * 6, bytesPerFloat * 2);
      this.context_.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * 6, bytesPerFloat * 4);
    }

    return true;
  }
}

export default WebGLPointsLayerRenderer;
<|endoftext|>


<commit_before>var defaultOptions = {
    state: {
        name: null,
        selector: null,
        element: null,
        tmpl: 'layout'
    }
};

/**
 * Define state options
 *
 * @private
*/
function defOptions (options, data) {
    var stateOptions = {};

    for (var option in defaultOptions.state) {
        stateOptions[option] = options[option] || data[option] || defaultOptions.state[option];
    }

    return stateOptions;
}

/**
 * Activate a state.
 *
 * @public
 * @param {object} The error object.
 * @param {object} The data object.
*/
module.exports = function activateState (scope, inst, _options, data, next) {

    // merge default options
    var options = defOptions(_options, data);

    // state must exist
    var state = (inst._args.states || {})[options.name];
    if (!state) {
        return next(new Error('View.state: State "' + options.name + '" not found.'));
    }

    // activate state elements
    state.forEach(function (config) {

        // call other states
        if (config.states) {
            var nextFn = function () {};
            config.states.forEach(function (stateName) {
                activateState.call(inst, { _: { name: stateName }}, data, nextFn);
            });
        }

        var selector = config.sel || options.selector;
        // handle element config
        var element = config.element || options.element;
        if (element && !selector) {
            selector = "[data-element='" + element + "']";
        }

        // return with error if state has no selector
        if (selector) {
            selector = typeof selector !== 'string' ? selector : (document).querySelectorAll(selector);

            // manipulate classes
            if (config.add || config.toggle || config.rm) {
                manipulateClasses(selector, config);
            }

            // manipulate attributes
            if (config.attr || config.rmAttr) {
                manipulateAttributes(selector, config);
            }

            // manipulate properties
            if (config.prop) {
                manipulateProperties(selector, config);
            }
        }
    });

    next(null, data);
};

/**
 * Manipulate css classes (add, rm, toggle).
 *
 * @private
*/
function manipulateClasses (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate classes
    for (var i = 0; i < elms.length; ++i) {

        // remove classes
        if (state.rm) {
            elms[i].classList.remove.apply(elms[i].classList, state.rm);
        }

        // add classes
        if (state.add) {
            elms[i].classList.add.apply(elms[i].classList, state.add);
        }

        // toggle classes
        if (state.toggle) {
            elms[i].classList.toggle.apply(elms[i].classList, state.toggle);
        }
    }
}

/**
 * Manipulate element attributes (attr, rmAttr).
 *
 * @private
*/
function manipulateAttributes (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate attributes
    for (var i = 0; i < elms.length; ++i) {

        // set attribute
        if (state.attr) {
            state.attr.forEach(function (attribute) {
                if (typeof attribute.name !== 'undefined' && typeof attribute.value !== 'undefined')
                elms[i].setAttribute(attribute.name, attribute.value);
            });
        }

        // remove attribute
        if (state.rmAttr) {
            state.setAttribute.forEach(function (attribute) {
                elms[i].removeAttribute(attribute);
            });
        }
    }
}

/**
 * Manipulate element properties (prop).
 *
 * @private
*/
function manipulateProperties (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate properties
    for (var i = 0; i < elms.length; ++i) {

        // set prop
        if (state.prop) {
            for (var prop in state.prop) {
                if (!state.prop.hasOwnProperty(prop)) {
                    continue
                }

                elms[i][prop] = state.prop[prop];
            }
        }
    }
}
<commit_msg>read states config from instance directly<commit_after>var defaultOptions = {
    state: {
        name: null,
        selector: null,
        element: null,
        tmpl: 'layout'
    }
};

/**
 * Define state options
 *
 * @private
*/
function defOptions (options, data) {
    var stateOptions = {};

    for (var option in defaultOptions.state) {
        stateOptions[option] = options[option] || data[option] || defaultOptions.state[option];
    }

    return stateOptions;
}

/**
 * Activate a state.
 *
 * @public
 * @param {object} The error object.
 * @param {object} The data object.
*/
module.exports = function activateState (scope, inst, _options, data, next) {

    // merge default options
    var options = defOptions(_options, data);

    // state must exist
    var state = (inst.states || {})[options.name];
    if (!state) {
        return next(new Error('View.state: State "' + options.name + '" not found.'));
    }

    // activate state elements
    state.forEach(function (config) {

        // call other states
        if (config.states) {
            var nextFn = function () {};
            config.states.forEach(function (stateName) {
                activateState.call(inst, { _: { name: stateName }}, data, nextFn);
            });
        }

        var selector = config.sel || options.selector;
        // handle element config
        var element = config.element || options.element;
        if (element && !selector) {
            selector = "[data-element='" + element + "']";
        }

        // return with error if state has no selector
        if (selector) {
            selector = typeof selector !== 'string' ? selector : (document).querySelectorAll(selector);

            // manipulate classes
            if (config.add || config.toggle || config.rm) {
                manipulateClasses(selector, config);
            }

            // manipulate attributes
            if (config.attr || config.rmAttr) {
                manipulateAttributes(selector, config);
            }

            // manipulate properties
            if (config.prop) {
                manipulateProperties(selector, config);
            }
        }
    });

    next(null, data);
};

/**
 * Manipulate css classes (add, rm, toggle).
 *
 * @private
*/
function manipulateClasses (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate classes
    for (var i = 0; i < elms.length; ++i) {

        // remove classes
        if (state.rm) {
            elms[i].classList.remove.apply(elms[i].classList, state.rm);
        }

        // add classes
        if (state.add) {
            elms[i].classList.add.apply(elms[i].classList, state.add);
        }

        // toggle classes
        if (state.toggle) {
            elms[i].classList.toggle.apply(elms[i].classList, state.toggle);
        }
    }
}

/**
 * Manipulate element attributes (attr, rmAttr).
 *
 * @private
*/
function manipulateAttributes (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate attributes
    for (var i = 0; i < elms.length; ++i) {

        // set attribute
        if (state.attr) {
            state.attr.forEach(function (attribute) {
                if (typeof attribute.name !== 'undefined' && typeof attribute.value !== 'undefined')
                elms[i].setAttribute(attribute.name, attribute.value);
            });
        }

        // remove attribute
        if (state.rmAttr) {
            state.setAttribute.forEach(function (attribute) {
                elms[i].removeAttribute(attribute);
            });
        }
    }
}

/**
 * Manipulate element properties (prop).
 *
 * @private
*/
function manipulateProperties (elms, state) {

    if (!(elms instanceof NodeList)) {
        elms = [elms];
    }

    // manipulate properties
    for (var i = 0; i < elms.length; ++i) {

        // set prop
        if (state.prop) {
            for (var prop in state.prop) {
                if (!state.prop.hasOwnProperty(prop)) {
                    continue
                }

                elms[i][prop] = state.prop[prop];
            }
        }
    }
}
<|endoftext|>


<commit_before>//post-spots.js

module.exports = function(db) {
  return function(req, res) {
    var spots = db.collection('spots');
    spots.insert(req.body, function(err, result) {
      if(err) {
        res.status(500).json{(
          code: "dbError",
          err: err
        )};
      } else {
        console.log("Created Spot: ", result);
        res.json(result);
      }
    });
  }
};
<commit_msg>Update post-spots.js<commit_after>//post-spots.js

module.exports = function(db) {
  return function(req, res) {
    var spots = db.collection('spots');
    spots.insert(req.body, function(err, result) {
      if(err) {
        res.status(500).json{(
          code: "DbError",
          err: err
        )};
      } else {
        console.log("Created Spot: ", result);
        res.json(result);
      }
    });
  }
};
<|endoftext|>


<commit_before>/**
 * Collapsible - jQuery Plugin
 *
 * This plugin enables the management of
 * collapsibles on the page with cookie support.
 *
 * Copyright (c) 2010 John Snyder (snyderplace.com)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 */
(function($) {
	$.fn.collapsible = function(cmd, arg) {
		if (typeof cmd == 'string') {
			$.fn.collapsible.dispatcher[cmd](this, arg);
		} else {
			$.fn.collapsible.dispatcher['_create'](this, cmd);
		}
	};

	$.fn.collapsible.dispatcher = {
		_create : function(obj, arg) {
			createCollapsable(obj, arg);
		}
	};

	function createCollapsable(obj, options) {
		// build main options before element iteration
		var opts = $.extend({}, $.fn.collapsible.defaults, options);
		// store any opened default values to set cookie later
		var opened = new Array();

		// iterate and reformat each matched element
		obj.each(function() {
			var $this = $(this);
			$this.data('collapsible-opts', opts);

			//lets bind it to mouseenter
			if (opts.bind == 'mouseenter') {
				$this.bind('mouseenter', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to mouseover
			if (opts.bind == 'mouseover') {
				$this.bind('mouseover',function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to click
			if (opts.bind == 'click') {
				$this.bind('click', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to dblclick
			if (opts.bind == 'dblclick') {
				$this.bind('dblclick', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets initialize the collapsibles
			//get the id for this element
			id = $this.attr('id');
			//do we use cookies
			if (!useCookies(opts)) { //no just open the defaults
				//is this collapsible in the default open array?
				dOpenIndex = inDefaultOpen(id, opts);
				if (dOpenIndex === false) { //no, close it
					$this.addClass(opts.cssClose); //append the close class
					$this.next().hide();
				} else { //yes open it
					$this.addClass(opts.cssOpen); //append the open class
					$this.next().show();
					opened.push(id);
				}
			} else { //we can use cookies, let do so
				//has a cookie been set, this overrides default open
				if (issetCookie(opts)) {
					cookieIndex = inCookie(id, opts);
					if (cookieIndex === false) {
						$this.addClass(opts.cssClose);//append the close class
						$this.next().hide();
					} else {
						$this.addClass(opts.cssOpen);//append the open class
						$this.next().show();
						opened.push(id);
					}
				} else { //a cookie hasn't been set open defaults, add them to opened array
					dOpenIndex = inDefaultOpen(id, opts);
					if (dOpenIndex === false) {
						$this.addClass(opts.cssClose);//append the close class
						$this.next().hide();
					} else {
						$this.addClass(opts.cssOpen);//append the open class
						$this.next().show();
						opened.push(id);
					}
				}
			}
		});
		//now that the loop is done, lets set the cookie
		if (opened.length > 0 && useCookies(opts)) {
			setCookie(opened.toString(), opts);
		} else {
			setCookie('', opts);
		}
		return obj;
	};
	//Toggle a collapsible on an event
	function toggle($this, opts)
	{
		// open a closed item
		if ($this.hasClass(opts.cssClose)) {
			$this.removeClass(opts.cssClose).addClass(opts.cssOpen);
			$this.next().slideDown(opts.speed);
			//do cookies if plugin available
			if (useCookies(opts)) {
				// split the cookieOpen string by ","
				id = $this.attr('id');
				appendCookie(id, opts);
			}
			//return false; //skipped this element
		} else {
			//give the proper class to the heading
			$this.addClass(opts.cssClose).removeClass(opts.cssOpen);
			//still here, close an open item
			$this.next().slideUp(opts.speed); //no animation as its a page load initalization
			//return false; //just incase its a link, lets not let it fire off
			//do cookies if plugin available
			if (useCookies(opts)) {
				// split the cookieOpen string by ","
				id = $this.attr('id');
				unsetCookieId(id, opts);
			}
		}
		return false;
	}
	//do we use cookies
	function useCookies(opts)
	{
		//return false if cookie plugin not present or if a cookie name is not provided
		if (!$.cookie || opts.cookieName == '') {
			return false;
		}
		//we can use cookies
		return true;
	}
	//append a collapsible to the cookie
	function appendCookie(value, opts)
	{
		//check if cookie plugin available and cookiename is set
		if (!useCookies(opts)) {
			return false;
		}
		//does a cookie already exist
		if (!issetCookie(opts)) {
			//no lets set one
			setCookie(value, opts);
			return true;
		}
		//cookie already exists, is this collapsible already set?
		if (inCookie(value, opts)) { //yes, quit here
			return true;
		}
		//still here, we have a cookie and need to append our collapsible
		//get the cookie
		cookie = $.cookie(opts.cookieName);
		//unescape it
		cookie = unescape(cookie);
		//turn it into an array
		cookieArray = cookie.split(',');
		//add it to list
		cookieArray.push(value);
		//save it
		setCookie(cookieArray.toString(), opts);
		return true;
	}
	//unset a collapsible from the cookie
	function unsetCookieId(value, opts)
	{
		//check if cookie plugin available and cookiename is set
		if (!useCookies(opts)) {
			return false;
		}
		//if its not there we don't need to remove from it
		if (!issetCookie(opts)) { //quit here, don't have a cookie
			return true;
		}
		//we have a cookie, is this collapsible in it
		cookieIndex = inCookie(value, opts);
		if (cookieIndex === false) { //not in the cookie quit here
			return true;
		}
		//still here get the cookie
		cookie = $.cookie(opts.cookieName);
		//unescape it
		cookie = unescape(cookie);
		//turn it into an array
		cookieArray = cookie.split(',');
		//lets pop it out of the array
		cookieArray.splice(cookieIndex, 1);
		setCookie(cookieArray.toString(), opts);
	}
	//set a cookie
	function setCookie(value, opts)
	{
		//can use the cookie plugin
		if (!useCookies(opts)) { //no, quit here
			return false;
		}
		//cookie plugin is available, lets set the cookie
		$.cookie(opts.cookieName, value, opts.cookieOptions);
	}
	//check if a collapsible is in the cookie
	function inCookie(value, opts)
	{
		//can use the cookie plugin
		if (!useCookies(opts)) {
			return false;
		}
		//if its not there we don't need to remove from it
		if (!issetCookie(opts)) { //quit here, don't have a cookie
			return false;
		}
		//unescape it
		cookie = unescape($.cookie(opts.cookieName));
		//turn it into an array
		cookieArray = cookie.split(',');
		//get the index of the collapsible if in the cookie array
		cookieIndex = $.inArray(value, cookieArray);
		//is this value in the cookie arrray
		if (cookieIndex == -1) { //no, quit here
			return false;
		}
		//yes, return the index
		return cookieIndex;
	}
	//check if a cookie is set
	function issetCookie(opts)
	{
		//can we use the cookie plugin
		if (!useCookies(opts)) { //no, quit here
			return false;
		}
		//is the cookie set
		if ($.cookie(opts.cookieName) == null) { //no, quit here
			return false;
		}
		//the cookie is set and we can use the cookie plugin
		return true;
	}
	//check if a collapsible is in the list of collapsibles to be opened by default
	function inDefaultOpen(id, opts)
	{
		//get the array of open collapsibles
		defaultOpen = getDefaultOpen(opts);
		//is it in the default open array
		index = $.inArray(id, defaultOpen);
		if (index == -1) { //nope, quit here
			return false;
		}
		//it is a default open item, return its index
		return index;
	}
	//get the default open collapsibles and return array
	function getDefaultOpen(opts)
	{
		//initialize an empty array
		defaultOpen = new Array();
		//if there is a list, lets split it into an array
		if (opts.defaultOpen != '') {
			defaultOpen = opts.defaultOpen.split(',');
		}
		//return the default open array
		return defaultOpen;
	}

	// settings
	$.fn.collapsible.defaults = {
		cssClose: 'collapse-close', //class you want to assign to a closed collapsible header
		cssOpen: 'collapse-open', //class you want to assign an opened collapsible header
		cookieName: 'collapsible', //name of the cookie you want to set for this collapsible
		cookieOptions: { //cookie options, see cookie plugin for details
			path: '/',
			expires: 7,
			domain: '',
			secure: ''
		},
		defaultOpen: '', //comma seperated list of header ids that you want opened by default
		speed: 300, //speed of the slide effect
		bind: 'click' //event to bind to, supports click, dblclick, mouseover and mouseenter
	};
})(jQuery);<commit_msg>saver ad loader for opts in object<commit_after>/**
 * Collapsible - jQuery Plugin
 *
 * This plugin enables the management of
 * collapsibles on the page with cookie support.
 *
 * Copyright (c) 2010 John Snyder (snyderplace.com)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 */
(function($) {
	$.fn.collapsible = function(cmd, arg) {
		if (typeof cmd == 'string') {
			$.fn.collapsible.dispatcher[cmd](this, arg);
		} else {
			$.fn.collapsible.dispatcher['_create'](this, cmd);
		}
	};

	$.fn.collapsible.dispatcher = {
		_create : function(obj, arg) {
			createCollapsable(obj, arg);
		}
	};

	function createCollapsable(obj, options) {
		// build main options before element iteration
		var opts = $.extend({}, $.fn.collapsible.defaults, options);
		// store any opened default values to set cookie later
		var opened = new Array();

		// iterate and reformat each matched element
		obj.each(function() {
			var $this = $(this);
			saveOpts($this, opts);

			//lets bind it to mouseenter
			if (opts.bind == 'mouseenter') {
				$this.bind('mouseenter', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to mouseover
			if (opts.bind == 'mouseover') {
				$this.bind('mouseover',function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to click
			if (opts.bind == 'click') {
				$this.bind('click', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets bind it to dblclick
			if (opts.bind == 'dblclick') {
				$this.bind('dblclick', function(e) {
					e.preventDefault(); //stop links from firing
					toggle($this, opts); //toggle open/close
				});
			}

			//lets initialize the collapsibles
			//get the id for this element
			id = $this.attr('id');
			//do we use cookies
			if (!useCookies(opts)) { //no just open the defaults
				//is this collapsible in the default open array?
				dOpenIndex = inDefaultOpen(id, opts);
				if (dOpenIndex === false) { //no, close it
					$this.addClass(opts.cssClose); //append the close class
					$this.next().hide();
				} else { //yes open it
					$this.addClass(opts.cssOpen); //append the open class
					$this.next().show();
					opened.push(id);
				}
			} else { //we can use cookies, let do so
				//has a cookie been set, this overrides default open
				if (issetCookie(opts)) {
					cookieIndex = inCookie(id, opts);
					if (cookieIndex === false) {
						$this.addClass(opts.cssClose);//append the close class
						$this.next().hide();
					} else {
						$this.addClass(opts.cssOpen);//append the open class
						$this.next().show();
						opened.push(id);
					}
				} else { //a cookie hasn't been set open defaults, add them to opened array
					dOpenIndex = inDefaultOpen(id, opts);
					if (dOpenIndex === false) {
						$this.addClass(opts.cssClose);//append the close class
						$this.next().hide();
					} else {
						$this.addClass(opts.cssOpen);//append the open class
						$this.next().show();
						opened.push(id);
					}
				}
			}
		});
		//now that the loop is done, lets set the cookie
		if (opened.length > 0 && useCookies(opts)) {
			setCookie(opened.toString(), opts);
		} else {
			setCookie('', opts);
		}
		return obj;
	};
	// Load opts from object
	function loadOpts($this) {
		return $this.data('collapsible-opts');
	}
	// Save opts into object
	function saveOpts($this, opts) {
		return $this.data('collapsible-opts', opts);
	}
	//Toggle a collapsible on an event
	function toggle($this, opts)
	{
		// open a closed item
		if ($this.hasClass(opts.cssClose)) {
			$this.removeClass(opts.cssClose).addClass(opts.cssOpen);
			$this.next().slideDown(opts.speed);
			//do cookies if plugin available
			if (useCookies(opts)) {
				// split the cookieOpen string by ","
				id = $this.attr('id');
				appendCookie(id, opts);
			}
			//return false; //skipped this element
		} else {
			//give the proper class to the heading
			$this.addClass(opts.cssClose).removeClass(opts.cssOpen);
			//still here, close an open item
			$this.next().slideUp(opts.speed); //no animation as its a page load initalization
			//return false; //just incase its a link, lets not let it fire off
			//do cookies if plugin available
			if (useCookies(opts)) {
				// split the cookieOpen string by ","
				id = $this.attr('id');
				unsetCookieId(id, opts);
			}
		}
		return false;
	}
	//do we use cookies
	function useCookies(opts)
	{
		//return false if cookie plugin not present or if a cookie name is not provided
		if (!$.cookie || opts.cookieName == '') {
			return false;
		}
		//we can use cookies
		return true;
	}
	//append a collapsible to the cookie
	function appendCookie(value, opts)
	{
		//check if cookie plugin available and cookiename is set
		if (!useCookies(opts)) {
			return false;
		}
		//does a cookie already exist
		if (!issetCookie(opts)) {
			//no lets set one
			setCookie(value, opts);
			return true;
		}
		//cookie already exists, is this collapsible already set?
		if (inCookie(value, opts)) { //yes, quit here
			return true;
		}
		//still here, we have a cookie and need to append our collapsible
		//get the cookie
		cookie = $.cookie(opts.cookieName);
		//unescape it
		cookie = unescape(cookie);
		//turn it into an array
		cookieArray = cookie.split(',');
		//add it to list
		cookieArray.push(value);
		//save it
		setCookie(cookieArray.toString(), opts);
		return true;
	}
	//unset a collapsible from the cookie
	function unsetCookieId(value, opts)
	{
		//check if cookie plugin available and cookiename is set
		if (!useCookies(opts)) {
			return false;
		}
		//if its not there we don't need to remove from it
		if (!issetCookie(opts)) { //quit here, don't have a cookie
			return true;
		}
		//we have a cookie, is this collapsible in it
		cookieIndex = inCookie(value, opts);
		if (cookieIndex === false) { //not in the cookie quit here
			return true;
		}
		//still here get the cookie
		cookie = $.cookie(opts.cookieName);
		//unescape it
		cookie = unescape(cookie);
		//turn it into an array
		cookieArray = cookie.split(',');
		//lets pop it out of the array
		cookieArray.splice(cookieIndex, 1);
		setCookie(cookieArray.toString(), opts);
	}
	//set a cookie
	function setCookie(value, opts)
	{
		//can use the cookie plugin
		if (!useCookies(opts)) { //no, quit here
			return false;
		}
		//cookie plugin is available, lets set the cookie
		$.cookie(opts.cookieName, value, opts.cookieOptions);
	}
	//check if a collapsible is in the cookie
	function inCookie(value, opts)
	{
		//can use the cookie plugin
		if (!useCookies(opts)) {
			return false;
		}
		//if its not there we don't need to remove from it
		if (!issetCookie(opts)) { //quit here, don't have a cookie
			return false;
		}
		//unescape it
		cookie = unescape($.cookie(opts.cookieName));
		//turn it into an array
		cookieArray = cookie.split(',');
		//get the index of the collapsible if in the cookie array
		cookieIndex = $.inArray(value, cookieArray);
		//is this value in the cookie arrray
		if (cookieIndex == -1) { //no, quit here
			return false;
		}
		//yes, return the index
		return cookieIndex;
	}
	//check if a cookie is set
	function issetCookie(opts)
	{
		//can we use the cookie plugin
		if (!useCookies(opts)) { //no, quit here
			return false;
		}
		//is the cookie set
		if ($.cookie(opts.cookieName) == null) { //no, quit here
			return false;
		}
		//the cookie is set and we can use the cookie plugin
		return true;
	}
	//check if a collapsible is in the list of collapsibles to be opened by default
	function inDefaultOpen(id, opts)
	{
		//get the array of open collapsibles
		defaultOpen = getDefaultOpen(opts);
		//is it in the default open array
		index = $.inArray(id, defaultOpen);
		if (index == -1) { //nope, quit here
			return false;
		}
		//it is a default open item, return its index
		return index;
	}
	//get the default open collapsibles and return array
	function getDefaultOpen(opts)
	{
		//initialize an empty array
		defaultOpen = new Array();
		//if there is a list, lets split it into an array
		if (opts.defaultOpen != '') {
			defaultOpen = opts.defaultOpen.split(',');
		}
		//return the default open array
		return defaultOpen;
	}

	// settings
	$.fn.collapsible.defaults = {
		cssClose: 'collapse-close', //class you want to assign to a closed collapsible header
		cssOpen: 'collapse-open', //class you want to assign an opened collapsible header
		cookieName: 'collapsible', //name of the cookie you want to set for this collapsible
		cookieOptions: { //cookie options, see cookie plugin for details
			path: '/',
			expires: 7,
			domain: '',
			secure: ''
		},
		defaultOpen: '', //comma seperated list of header ids that you want opened by default
		speed: 300, //speed of the slide effect
		bind: 'click' //event to bind to, supports click, dblclick, mouseover and mouseenter
	};
})(jQuery);<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react'
import _ from 'lodash'
import {Link} from 'react-router'

class AlertsTable extends Component {
  constructor(props) {
    super(props)

    this.state = {
      searchTerm: '',
      filteredAlerts: this.props.alerts,
      sortDirection: null,
      sortKey: null,
    }

    this.filterAlerts = ::this.filterAlerts
    this.changeSort = ::this.changeSort
    this.sortableClasses = ::this.sortableClasses
    this.sort = ::this.sort
  }

  componentWillReceiveProps(newProps) {
    this.filterAlerts(this.state.searchTerm, newProps.alerts)
  }

  filterAlerts(searchTerm, newAlerts) {
    const alerts = newAlerts || this.props.alerts
    const filterText = searchTerm.toLowerCase()
    const filteredAlerts = alerts.filter(h => {
      if (h.host === null || h.name === null || h.level === null) {
        return false
      }

      return (
        h.name.toLowerCase().includes(filterText) ||
        h.host.toLowerCase().includes(filterText) ||
        h.level.toLowerCase().includes(filterText)
      )
    })
    this.setState({searchTerm, filteredAlerts})
  }

  changeSort(key) {
    // if we're using the key, reverse order; otherwise, set it with ascending
    if (this.state.sortKey === key) {
      const reverseDirection = this.state.sortDirection === 'asc'
        ? 'desc'
        : 'asc'
      this.setState({sortDirection: reverseDirection})
    } else {
      this.setState({sortKey: key, sortDirection: 'asc'})
    }
  }

  sortableClasses(key) {
    if (this.state.sortKey === key) {
      if (this.state.sortDirection === 'asc') {
        return 'sortable-header sorting-ascending'
      }
      return 'sortable-header sorting-descending'
    }
    return 'sortable-header'
  }

  sort(alerts, key, direction) {
    switch (direction) {
      case 'asc':
        return _.sortBy(alerts, e => e[key])
      case 'desc':
        return _.sortBy(alerts, e => e[key]).reverse()
      default:
        return alerts
    }
  }

  renderTable() {
    const {source: {id}} = this.props
    const alerts = this.sort(
      this.state.filteredAlerts,
      this.state.sortKey,
      this.state.sortDirection
    )
    return this.props.alerts.length
      ?

               this.changeSort('name')}
                className={this.sortableClasses('name')}
              >
                Name

               this.changeSort('level')}
                className={this.sortableClasses('level')}
              >
                Level

               this.changeSort('time')}
                className={this.sortableClasses('time')}
              >
                Time

               this.changeSort('host')}
                className={this.sortableClasses('host')}
              >
                Host

               this.changeSort('value')}
                className={this.sortableClasses('value')}
              >
                Value

            {alerts.map(({name, level, time, host, value}) => {
              return (
                <tr key={`${name}-${level}-${time}-${host}-${value}`}>
                  {name}
                  <td className={`monotype alert-level-${level.toLowerCase()}`}>
                    {level}

                    {new Date(Number(time)).toISOString()}

                    <Link to={`/sources/${id}/hosts/${host}`}>
                      {host}
                    </Link>

                  {value}

              )
            })}

      : this.renderTableEmpty()
  }

  renderTableEmpty() {
    const {source: {id}, shouldNotBeFilterable} = this.props

    return shouldNotBeFilterable
      ?

            Learn how to configure your first Rule in

            the Getting Started guide

      :

            There are no Alerts to display

            Try changing the Time Range or
            <Link
              style={{marginLeft: '10px'}}
              to={`/sources/${id}/alert-rules/new`}
              className="btn btn-primary btn-sm"
            >
              Create an Alert Rule
            </Link>

  }

  render() {
    const {
      shouldNotBeFilterable,
      limit,
      onGetMoreAlerts,
      isAlertsMaxedOut,
      alertsCount,
    } = this.props

    return shouldNotBeFilterable
      ?

          {this.renderTable()}
          {limit
            ? <button
                className="btn btn-xs btn-primary"
                onClick={onGetMoreAlerts}
                disabled={isAlertsMaxedOut}
              >
                {isAlertsMaxedOut
                  ? `All ${alertsCount} alerts displayed`
                  : 'Get More'}
              </button>
            : null}

      :

{this.props.alerts.length} Alerts

            {this.props.alerts.length
              ? <SearchBar onSearch={this.filterAlerts} />
              : null}

            {this.renderTable()}

  }
}

class SearchBar extends Component {
  constructor(props) {
    super(props)

    this.state = {
      searchTerm: '',
    }

    this.handleSearch = ::this.handleSearch
    this.handleChange = ::this.handleChange
  }

  componentWillMount() {
    const waitPeriod = 300
    this.handleSearch = _.debounce(this.handleSearch, waitPeriod)
  }

  handleSearch() {
    this.props.onSearch(this.state.searchTerm)
  }

  handleChange(e) {
    this.setState({searchTerm: e.target.value}, this.handleSearch)
  }

  render() {
    return (

        <input
          type="text"
          className="form-control"
          placeholder="Filter Alerts by Name..."
          onChange={this.handleChange}
          value={this.state.searchTerm}
        />

    )
  }
}

const {arrayOf, bool, func, number, shape, string} = PropTypes

AlertsTable.propTypes = {
  alerts: arrayOf(
    shape({
      name: string,
      time: string,
      value: string,
      host: string,
      level: string,
    })
  ),
  source: shape({
    id: string.isRequired,
    name: string.isRequired,
  }).isRequired,
  shouldNotBeFilterable: bool,
  limit: number,
  onGetMoreAlerts: func,
  isAlertsMaxedOut: bool,
  alertsCount: number,
}

SearchBar.propTypes = {
  onSearch: func.isRequired,
}

export default AlertsTable
<commit_msg>Only show Get More button if there are alerts<commit_after>import React, {Component, PropTypes} from 'react'
import _ from 'lodash'
import {Link} from 'react-router'

class AlertsTable extends Component {
  constructor(props) {
    super(props)

    this.state = {
      searchTerm: '',
      filteredAlerts: this.props.alerts,
      sortDirection: null,
      sortKey: null,
    }

    this.filterAlerts = ::this.filterAlerts
    this.changeSort = ::this.changeSort
    this.sortableClasses = ::this.sortableClasses
    this.sort = ::this.sort
  }

  componentWillReceiveProps(newProps) {
    this.filterAlerts(this.state.searchTerm, newProps.alerts)
  }

  filterAlerts(searchTerm, newAlerts) {
    const alerts = newAlerts || this.props.alerts
    const filterText = searchTerm.toLowerCase()
    const filteredAlerts = alerts.filter(h => {
      if (h.host === null || h.name === null || h.level === null) {
        return false
      }

      return (
        h.name.toLowerCase().includes(filterText) ||
        h.host.toLowerCase().includes(filterText) ||
        h.level.toLowerCase().includes(filterText)
      )
    })
    this.setState({searchTerm, filteredAlerts})
  }

  changeSort(key) {
    // if we're using the key, reverse order; otherwise, set it with ascending
    if (this.state.sortKey === key) {
      const reverseDirection = this.state.sortDirection === 'asc'
        ? 'desc'
        : 'asc'
      this.setState({sortDirection: reverseDirection})
    } else {
      this.setState({sortKey: key, sortDirection: 'asc'})
    }
  }

  sortableClasses(key) {
    if (this.state.sortKey === key) {
      if (this.state.sortDirection === 'asc') {
        return 'sortable-header sorting-ascending'
      }
      return 'sortable-header sorting-descending'
    }
    return 'sortable-header'
  }

  sort(alerts, key, direction) {
    switch (direction) {
      case 'asc':
        return _.sortBy(alerts, e => e[key])
      case 'desc':
        return _.sortBy(alerts, e => e[key]).reverse()
      default:
        return alerts
    }
  }

  renderTable() {
    const {source: {id}} = this.props
    const alerts = this.sort(
      this.state.filteredAlerts,
      this.state.sortKey,
      this.state.sortDirection
    )
    return this.props.alerts.length
      ?

               this.changeSort('name')}
                className={this.sortableClasses('name')}
              >
                Name

               this.changeSort('level')}
                className={this.sortableClasses('level')}
              >
                Level

               this.changeSort('time')}
                className={this.sortableClasses('time')}
              >
                Time

               this.changeSort('host')}
                className={this.sortableClasses('host')}
              >
                Host

               this.changeSort('value')}
                className={this.sortableClasses('value')}
              >
                Value

            {alerts.map(({name, level, time, host, value}) => {
              return (
                <tr key={`${name}-${level}-${time}-${host}-${value}`}>
                  {name}
                  <td className={`monotype alert-level-${level.toLowerCase()}`}>
                    {level}

                    {new Date(Number(time)).toISOString()}

                    <Link to={`/sources/${id}/hosts/${host}`}>
                      {host}
                    </Link>

                  {value}

              )
            })}

      : this.renderTableEmpty()
  }

  renderTableEmpty() {
    const {source: {id}, shouldNotBeFilterable} = this.props

    return shouldNotBeFilterable
      ?

            Learn how to configure your first Rule in

            the Getting Started guide

      :

            There are no Alerts to display

            Try changing the Time Range or
            <Link
              style={{marginLeft: '10px'}}
              to={`/sources/${id}/alert-rules/new`}
              className="btn btn-primary btn-sm"
            >
              Create an Alert Rule
            </Link>

  }

  render() {
    const {
      shouldNotBeFilterable,
      limit,
      onGetMoreAlerts,
      isAlertsMaxedOut,
      alertsCount,
    } = this.props

    return shouldNotBeFilterable
      ?

          {this.renderTable()}
          {limit && alertsCount
            ? <button
                className="btn btn-xs btn-primary"
                onClick={onGetMoreAlerts}
                disabled={isAlertsMaxedOut}
              >
                {isAlertsMaxedOut
                  ? `All ${alertsCount} alerts displayed`
                  : 'Get More'}
              </button>
            : null}

      :

{this.props.alerts.length} Alerts

            {this.props.alerts.length
              ? <SearchBar onSearch={this.filterAlerts} />
              : null}

            {this.renderTable()}

  }
}

class SearchBar extends Component {
  constructor(props) {
    super(props)

    this.state = {
      searchTerm: '',
    }

    this.handleSearch = ::this.handleSearch
    this.handleChange = ::this.handleChange
  }

  componentWillMount() {
    const waitPeriod = 300
    this.handleSearch = _.debounce(this.handleSearch, waitPeriod)
  }

  handleSearch() {
    this.props.onSearch(this.state.searchTerm)
  }

  handleChange(e) {
    this.setState({searchTerm: e.target.value}, this.handleSearch)
  }

  render() {
    return (

        <input
          type="text"
          className="form-control"
          placeholder="Filter Alerts by Name..."
          onChange={this.handleChange}
          value={this.state.searchTerm}
        />

    )
  }
}

const {arrayOf, bool, func, number, shape, string} = PropTypes

AlertsTable.propTypes = {
  alerts: arrayOf(
    shape({
      name: string,
      time: string,
      value: string,
      host: string,
      level: string,
    })
  ),
  source: shape({
    id: string.isRequired,
    name: string.isRequired,
  }).isRequired,
  shouldNotBeFilterable: bool,
  limit: number,
  onGetMoreAlerts: func,
  isAlertsMaxedOut: bool,
  alertsCount: number,
}

SearchBar.propTypes = {
  onSearch: func.isRequired,
}

export default AlertsTable
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Legend Agar.io Extension Tempory Edition
// @namespace    Legend Agar.io
// @version      2.2
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        http://agar.io/*
// @match        https://talky.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==
// Legend Mod by Jimboy3100
/*MIT License
Copyright (c) [2017] [The Legend Mod]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// Check location
//if (location.host === "agar.io" && location.pathname === "/") {
//    location.href = "http://agar.io/ogario" + location.hash;
//   return;
//}

// Inject script
if (location.host == "agar.io" && location.pathname == "/") {
	location.href = "http://agar.io/legendmod" + window.location.search + location.hash;
	window.stop();
	document.documentElement.innerHTML = "";
	GM_xmlhttpRequest({
		method : "GET",
		url : "https://jimboy3100.github.io/v3/legendmodv3.html",
		onload : function(e) {
			document.open();
			document.write(e.responseText);
			document.close();
		}
	});
}
// Inject Chat Talky.io Userscript
if (location.host == "talky.io") {

	(function() {
    var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    link.href = 'https://jimboy3100.github.io/banners/icon32croped.ico.gif';
    document.getElementsByTagName('head')[0].appendChild(link);
	})();

	document.title="Legend Mod - Talky";

    var url2 = window.location.href;
    var gamename = getParameterByName("name", url2);
    var IPAgario = getParameterByName("ip", url2);

    setTimeout(function() {
        document.getElementsByClassName('_26dP_7FWLFRnvW8hs-AIzR')[0].remove();
        document.getElementsByClassName('_26dP_7FWLFRnvW8hs-AIzR')[0].remove();
        document.getElementsByClassName('_26dP_7FWLFRnvW8hs-AIzR')[0].remove();
    }, 4100);

    setTimeout(function() {
        document.getElementById('skip').click();
        document.getElementsByClassName('TalkyButton__text')[0].click();

    }, 3500);
    setTimeout(function() {
        document.getElementsByClassName('_1U4l9qYTHl6ExTsW9IvwnO')[1].value = gamename;
        //Legend Mod Copy Agar.io Token

		if (IPAgario.length==6){
		document.getElementsByClassName('message message-info message-full-width')[0].before("[Talky.io]: Legend Mod. Server: " + "http://agar.io/#" + IPAgario + " . [PARTY] (Password rooms are different than Public)");}
		else{
		document.getElementsByClassName('message message-info message-full-width')[0].before("[Talky.io]: Legend Mod. Server: " + "http://agar.io/?sip=" + IPAgario + " . (Password rooms are different than Public)");}

        document.getElementsByClassName('_1U4l9qYTHl6ExTsW9IvwnO')[1].value = gamename;
        document.getElementsByClassName('message message-info message-full-width')[0].style.visibility = 'hidden';
        document.getElementsByClassName('Box _3-HLfCQ5QT5fuKgw4tvBkP')[0].remove();
        document.getElementsByClassName('-ZMXacQm9s80kTx3I-A47')[0].remove();

    }, 4000);
}
//runs only if play.google.com is a popup, doesnt if directly joined
if (location.host == "play.google.com") {
	window.close();
}

setTimeout(function() {
	    // Inject Chat to text userscript
    (function() {
        'use strict';

        function pre_loop() {
            if (!document.getElementById("message-box")) {
                setTimeout(pre_loop, 4000);
                console.log("VoiceDeOChat:wait for Legend load");
                return;
            }
            return initialize();
        }
        return pre_loop();

        function initialize() {
            var lang_hash = {
                "default": "default",
                "ja": "日本語",
                "en-US": "English",
                "en-US": "Ελληνικά",
                "zh-CN": "简体中文",
                "zh-TW": "繁體中文",
                "ko": "한국어"
            };
            var cfg = {};
            cfg.prefix = GM_getValue("prefix", "🎤");
            cfg.lang = GM_getValue("lang", "default");
            cfg.unpause = GM_getValue("unpause", false);
            console.log("load prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            $("#message-box").mousedown(function() {
                return false;
            });
            $(".team-top-menu").mousedown(function() {
                return false;
            });
            $("#message-menu").append('X');
            $(".chatbox-hide").click(function() {
                $("#message-box").css("display", "none");
                if (cfg.unpause && $("#pause-hud").css("display") == "block") {
                    var code = 82; // 'R'
                    $(document).trigger(jQuery.Event('keydown', {
                        keyCode: code,
                        which: code
                    }));
                }
            });
            $("#message-menu").append('C');
            $(".chatbox-clear").click(function() {
                $("#message").val("");
            });
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new window.SpeechRecognition();
            if (cfg.lang !== "default") {
                recognition.lang = cfg.lang;
            }
            console.log("cfg.lang/recognition.lang=" + cfg.lang + "/" + recognition.lang);
            recognition.addEventListener('result', function(event) {
                var text_to = event.results.item(0).item(0).transcript;
                var text_pre = $("#message").val();
                if (text_pre === "") {
                    text_to = cfg.prefix + text_to;
                } else {
                    text_to = text_pre + " " + text_to;
                }
                $("#message").val(text_to);
            }, false);
            recognition.addEventListener('end', function(event) {
                fn_recognition_end();
            }, false);
            $("#message-menu").append('🎤');
            $(".voice-start").click(function() {
                fn_recognition_start();
            });

            function fn_recognition_start() {
                $("#voice-config").css("display", "none");
                $(".voice-start").css("background-color", "green");
                recognition.start();
            }

            function fn_recognition_end() {
                $(".voice-start").css("background-color", "");
            }
            $("#og-options").append('

');
            $("#voice-config").append('
Voice
');
            $("#voice-config").append('Voice-Prefix:<input type="text" id="voice-prefix" style="width:4em; float:none;" value="' + cfg.prefix + '"/>');

            function fn_lang_make() {
                $("#voice-config").append('Voice-lang:<select id="voice-lang"/></select>');
                for (var code in lang_hash) {
                    var desc = lang_hash[code];
                    var selected = (code === cfg.lang) ? ' selected' : '';
                    $("#voice-lang").append('<option value="' + code + '"' + selected + '>' + desc + '</option>');
                }
            }
            fn_lang_make();
            $("#voice-config").append('<input type="checkbox" id="voice-unpause"' + (cfg.unpause ? ' checked' : '') + '/>UnPause');

            var observ_obj = $("#og-settings");
            var observ_cur = observ_obj.css("display");
            var observer = new MutationObserver(function(mutations) {
                var observ_pre = observ_cur;
                var observ_new = observ_obj.css("display");
                observ_cur = observ_new;
                if (observ_new == "none" && observ_pre == "block") {
                    fn_config_save();
                }
            });
            observer.observe(observ_obj[0], {
                attributes: true,
                attributeFilter: ['style']
            });

            function fn_config_save() {
                cfg.prefix = $("#voice-prefix").val();
                GM_setValue("prefix", cfg.prefix);
                cfg.lang = $("#voice-lang").val();
                GM_setValue("lang", cfg.lang);
                if (cfg.lang !== "default") {
                    recognition.lang = cfg.lang;
                }
                cfg.unpause = $("#voice-unpause").prop('checked');
                GM_setValue("unpause", cfg.unpause);
                console.log("saved prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            }
        }
    })();
}, 5000);
//End of Legend Mod

<commit_msg>Update legendmodv3.user.js<commit_after>// ==UserScript==
// @name         Legend Agar.io Extension Tempory Edition
// @namespace    Legend Agar.io
// @version      2.2
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        http://agar.io/*
// @match        https://talky.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @connect      jimboy3100.github.io
// @grant        GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==
// Legend Mod by Jimboy3100
/*MIT License
Copyright (c) [2017] [The Legend Mod]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// Check location
if (location.host === "agar.io" && location.pathname === "/") {

// Inject script
window.stop();
document.documentElement.innerHTML = "";
GM_xmlhttpRequest({
    method : "GET",
    url : "https://jimboy3100.github.io/v3/",
    onload : function(e) {
        document.open();
        document.write(e.responseText);
        document.close();
    }
});
}
<|endoftext|>