<commit_before>/* Handles interaction between view and model
 */

/// requires
var Player = require("./players"),
	settings = require("./settings"),
	Turn = require("./turn");

/// object
function Controller(board, view) {
	/// public variables
	this.board = board;
	this.view = view;

	// the turn that this client is taking right now
	this.currentTurn = null;

	// the direction the player has chosen to kick the puck
	this.kickDirection = null;

	// an object containing all the event listeners that have been applied to
	// the current state, as well as handlers that are called when they occur
	this.listeners = {};

	// whether or not a message is currently being displayed in the UI
	this.messageShowing = false;

	// an array containing the valid positions the puck can be kicked to
	this.puckTrajectory = null;

	// the actor that is currently highlighted by the UI
	this.selectedActor = null;

	// an object containing all of the possible events in the game, held under
	// the UI state that they should be
	this.states = {
		// events that all states should be subscribed to regardless of UI state
		"global": {
			"close message": function () {
				this.messageShowing = false;
			},

			"message": function (data) {
				this.view.message(data);
				this.messageShowing = true;
			},

			"window resize": function () {
				this.clearUIState();
				this.view.display.resizeBoard();

				if (this.messageShowing) {
					this.view.resizeMessage();
				}

				// resize dialog windows
				this.view.resizeDialogsWindows();
			}
		},

		// when the player is placing the puck...
		"placing puck": {
			"click tile": function (data) {
				var pos = data.element.data("position"),
					self = this,
					tile = this.board.tile(pos);

				if (this.validPuckPositions.indexOf(tile) >= 0) {
					this.board.placePuck(pos);
					this.view.display.createPuck(settings.animationSpeed);

					setTimeout(function () {
						self.view.display.clearPuckGhost();
					}, settings.animationSpeed);

					this.view.events.listenToPuckEvents();
					this.emit("placed puck");
					this.setUIState("playing round");

					// record puck placement
					this.currentTurn.recordMove(this.board.puck, null, pos);
				}
			},

			"destroy state": function () {
				this.view.display.enableActorMouseEvents();
			},

			"init state": function () {
				this.validPuckPositions = this.board.getValidPuckPositions();
				this.view.display.disableActorMouseEvents();

				this.emit("message", {
					life: "placed puck",
					message: "Place the puck."
				});

				this.currentTurn = new Turn(this, this.board.settings.owner);
				this.currentTurn.recordMove("Begin round", null, null);
				this.view.showTurnState(this.board.settings.owner);
			},

			"mouse enter tile": function (data) {
				var pos = data.element.data("position"),
					tile = this.board.tile(pos),
					validPos = this.validPuckPositions.indexOf(tile) >= 0;

				if (tile.type !== "wall" && !validPos) {
					this.view.display.highlightTile(tile, false);
				}

				if (validPos) {
					this.view.display.showPuckGhost(pos);
				}
			},

			"mouse exit tile": function () {
				this.view.display.clearPuckGhost();
				this.view.display.unhighlightTile();
			}
		},

		// after the player has placed the puck and is actually playing a round
		"playing round": {
			"click actor": function (data) {
				var actor = this.board.actors[data.element.data("actor")];

				// if the actor that has been clicked on is the currently
				// selected actor, don't do anything
				if (actor === this.selectedActor) {
					this.clearUIState();
					return false;
				}

				this.clearUIState();

				// prevent the player from moving actors that do not belong to
				// them
				if (actor.owner !== this.board.settings.owner) {
					return false;
				}

				// display the clicked actor as selected
				this.selectActor(actor);
			},

			"click puck": function () {
				this.selectPuck();
			},

			"click tile": function (data) {
				var actor,
					index,
					oldPos,
					pos = data.element.data("position"),
					tile = this.view.display.tiles[pos.x][pos.y];

				// if the tile is clicked and it is a valid move, have the
				// selected actor move to that tile
				if (tile.validMove) {
					actor = this.selectedActor;
					index = this.selectedActorIndex;
					oldPos = {
						x: actor.x,
						y: actor.y
					};

					// clear the UI
					this.clearUIState();

					// move the actor in the model
					actor.move(this.board.tiles[pos.x][pos.y]);

					// move the actor in the view
					this.view.display.moveActor(index, function () {
						// and record this move in the current turn once the
						// move is done rendering
						this.currentTurn.recordMove(actor, oldPos, pos);
					}.bind(this));
				} else if (tile.validKickDirection) {
					this.clearUIState();

					this.kickDirection = tile;
					this.projectKickTrajectory();
				} else if (tile.validKick) {
					oldPos = {
						x: this.board.puck.x,
						y: this.board.puck.y
					};

					this.kickPuck(this.board.tiles[pos.x][pos.y], function () {
						this.currentTurn.recordMove(this.board.puck,
							oldPos, pos);
					}.bind(this));

					this.clearUIState();
				} else {
					this.clearUIState();
				}
			},

			// when this client finishes making a turn, send the turn data to
			// the server -- err, that is, do nothing for now, until the server
			// is implemented
			//TODO: check turn.js:finish (this is non-emulated player move)
			"finish turn": function (turn, scored) {
				// get the turn data in serialized form, ready to be passed to
				// the server
				// var turnData = turn.serialize();

				// pass the turn data to the server

				// and store this turn on the turns list
				this.turns.push(turn);

				// now that we've saved this turn, it is no longer current, so
				// create a new one and pass control of the board to the other
				// player
				this.currentTurn = new Turn(this, Player.Two);
				this.board.settings.owner = Player.Two;
				this.view.showTurnState(Player.Two);

				// if this turn ended by a player scoring, we need to reset the
				// board to allow for a new round to start, and we need to
				// update the score on the screen
				if (scored) {
					var score = this.turns.slice(-1)[0].score();

					// display updated scores
					this.view.updateScore(score);

					// is game won
					if(Math.max(score.player1, score.player2) >= settings.game.scoreToWin) {
						setTimeout(function () {
							this.setUIState('game inactive');
							this.emit('game won', score);
						}.bind(this));
					}else{
						// reset the board
						// this.reset();
					}
				}
			},

			// create a new turn from the data that has been (ostensibly)
			// received from the server
			//TODO: check turn.js:finish (this is emulated server move)
			"receive turn": function (data, scored) {
				var turn = new Turn(this, Player.Two);
				turn.deserialize(data);

				// ordinarily we would want to call turn.display to render the
				// turn to this client, now that it's just been received from
				// the server -- however, because we're faking it and allowing
				// both players to make turns from this one client, it will have
				// already been displayed in the UI, and so there's no reason to
				// try to show it again

				// turn.display();

				this.turns.push(turn);

				// create a new turn and allow the other player to move
				this.currentTurn = new Turn(this, Player.One);
				this.board.settings.owner = Player.One;
				this.view.showTurnState(Player.One);

				// if this turn ended by a player scoring, we need to reset the
				// board to allow for a new round to start, and we need to
				// update the score on the screen
				if (scored) {
					var score = this.turns.slice(-1)[0].score();

					// display updated scores
					this.view.updateScore(score);

					// is game won
					if(Math.max(score.player1, score.player2) >= settings.game.scoreToWin) {
						setTimeout(function () {
							this.setUIState('game inactive');
							this.emit('game won', score);
						}.bind(this));
					}else{
						// reset the board
						this.reset();
					}
				}
			},

			"mouse enter tile": function (data) {
				var pos = data.element.data("position"),
					tile = this.view.display.tiles[pos.x][pos.y];

				if (tile.validMove ||
					tile.validKickDirection ||
					tile.validKick) {

					this.view.display.highlightTile(tile, true);
				}
			},

			"mouse exit tile": function () {
				this.view.display.unhighlightTile();
			},

			"redo": function () {
				// if the current turn is not our turn, don't try to redo it
				if (this.currentTurn.owner !== this.board.settings.owner) {
					return;
				}

				this.currentTurn.redoMove();
			},

			"undo": function () {
				// if the current turn is not our turn, don't try to undo it
				if (this.currentTurn.owner !== this.board.settings.owner) {
					return;
				}

				this.currentTurn.undoMove();
			}
		},

		// state when game is not active
		// for example game finished or not started
		"game inactive": {
			"game won": function (scores) {
				this.view.gameWon(scores);
			},

			"click new game": function () {
				this.view.newGameClicked();
				this.reset();
			},

			"click mode 2p local": function () {
				this.view.hideWelcomeWindow();
				setTimeout(function () {
					this.setUIState("placing puck");
				}.bind(this));
			}
		}
	};

	// an array containing all of the turns that have taken place so far, both
	// turns that this client has made as well as all turns received from the
	// server -- the length of this array represents the amount of turns so far
	this.turns = [];
}

/// public functions
Controller.prototype = {
	addListener: function (eventName, callback) {
		var listener;

		callback = callback.bind(this);

		// if there is no callback we may be being passed an object full of
		// listeners; if so, iterate through them and add each one individually
		if (!callback) {
			for (listener in eventName) {
				this.addListener(listener, eventName[listener]);
			}

			return;
		}

		// add a single event listener to the list without overriding any other
		// event listeners
		if (this.listeners[eventName]) {
			this.listeners[eventName].push(callback);
		} else {
			this.listeners[eventName] = [callback];
		}

		return callback;
	},

	setUIState: function (stateName) {
		var eventName;

		// destroy the old state so we can build the new one
		this.emit("destroy state");
		this.clearListeners();
		this.clearUIState();

		// apply all global listeners, the ones that should apply to all states
		for (eventName in this.states.global) {
			this.addListener(eventName, this.states.global[eventName]);
		}

		// and add the listeners that are specific to this state
		for (eventName in this.states[stateName]) {
			this.addListener(eventName, this.states[stateName][eventName]);
		}

		this.emit("init state");
	},

	clearListeners: function () {
		this.listeners = {};
	},

	clearUIState: function () {
		this.view.display.deselectActor(this.selectedActorIndex);
		this.view.display.clearKickDirections();
		this.view.display.clearKickTrajectory();
		this.view.display.unhighlightTile();

		this.puckSelected = false;
		this.selectedActor = null;
		this.kickDirection = null;
		this.puckTrajectory = null;
	},

	emit: function (eventName) {
		var i;

		if (!this.listeners[eventName]) {
			return;
		}

		for (i = 0; i < this.listeners[eventName].length; i++) {
			this.listeners[eventName][i].apply(this,
				Array.prototype.slice.apply(arguments).slice(1));
		}
	},

	kickPuck: function (target, callback) {
		var trajectory = this.puckTrajectory
			.splice(0, this.puckTrajectory.indexOf(target) + 1);

		this.board.puck.kick(trajectory[trajectory.length - 1]);
		this.view.display.showKick(trajectory, callback);
	},

	projectKickTrajectory: function () {
		this.puckTrajectory = this.board.puck.calculateTrajectory(
			this.kickDirection);

		// if we have only one available move on selected trajectory
		// then don't show single dot, just move there
		if(this.puckTrajectory.length == 1) {
			this.kickPuck(this.puckTrajectory[0], function () {
				//this.currentTurn.recordMove(this.board.puck, oldPos, pos); //TODO recordMove when "undo system" will me made
			});
			return;
		}

		this.view.display.showKickTrajectory(this.puckTrajectory);
	},

	removeListener: function (eventName, callback) {
		var index,
			listeners = this.listeners[eventName];

		if (listeners) {
			index = listeners.indexOf(callback);

			if (index > -1) {
				listeners.splice(index, 1);
			}
		}
	},

	// reset the board after finishing a round
	reset: function () {
		setTimeout(function () {
			this.board.clear();
			this.view.display.clear();

			this.board.placeActors(window.globalVariables
				.mockServerResponse.actors);

			this.view.reshowGame();
			this.view.events.listenToActorEvents();
			this.setUIState("placing puck");
		}.bind(this));
	},

	// select an actor and cause the available positions to move to be shown
	selectActor: function (actor) {
		this.selectedActor = actor;
		this.selectedActorIndex = this.board.actors.indexOf(actor);

		this.view.display.selectActor(this.selectedActor);
	},

	selectPuck: function () {
		if (this.puckSelected) {
			this.clearUIState();
			return;
		}

		this.clearUIState();

		this.puckSelected = true;
		this.view.display.showKickDirections(this.board.puck
			.kickDirections(this.board.settings.owner));
	}
};

/// exports
module.exports = Controller;<commit_msg>Reset game for new game fixes<commit_after>/* Handles interaction between view and model
 */

/// requires
var Player = require("./players"),
	settings = require("./settings"),
	Turn = require("./turn");

/// object
function Controller(board, view) {
	/// public variables
	this.board = board;
	this.view = view;

	// the turn that this client is taking right now
	this.currentTurn = null;

	// the direction the player has chosen to kick the puck
	this.kickDirection = null;

	// an object containing all the event listeners that have been applied to
	// the current state, as well as handlers that are called when they occur
	this.listeners = {};

	// whether or not a message is currently being displayed in the UI
	this.messageShowing = false;

	// an array containing the valid positions the puck can be kicked to
	this.puckTrajectory = null;

	// the actor that is currently highlighted by the UI
	this.selectedActor = null;

	// an object containing all of the possible events in the game, held under
	// the UI state that they should be
	this.states = {
		// events that all states should be subscribed to regardless of UI state
		"global": {
			"close message": function () {
				this.messageShowing = false;
			},

			"message": function (data) {
				this.view.message(data);
				this.messageShowing = true;
			},

			"window resize": function () {
				this.clearUIState();
				this.view.display.resizeBoard();

				if (this.messageShowing) {
					this.view.resizeMessage();
				}

				// resize dialog windows
				this.view.resizeDialogsWindows();
			}
		},

		// when the player is placing the puck...
		"placing puck": {
			"click tile": function (data) {
				var pos = data.element.data("position"),
					self = this,
					tile = this.board.tile(pos);

				if (this.validPuckPositions.indexOf(tile) >= 0) {
					this.board.placePuck(pos);
					this.view.display.createPuck(settings.animationSpeed);

					setTimeout(function () {
						self.view.display.clearPuckGhost();
					}, settings.animationSpeed);

					this.view.events.listenToPuckEvents();
					this.emit("placed puck");
					this.setUIState("playing round");

					// record puck placement
					this.currentTurn.recordMove(this.board.puck, null, pos);
				}
			},

			"destroy state": function () {
				this.view.display.enableActorMouseEvents();
			},

			"init state": function () {
				this.validPuckPositions = this.board.getValidPuckPositions();
				this.view.display.disableActorMouseEvents();

				this.emit("message", {
					life: "placed puck",
					message: "Place the puck."
				});

				this.currentTurn = new Turn(this, this.board.settings.owner);
				this.currentTurn.recordMove("Begin round", null, null);
				this.view.showTurnState(this.board.settings.owner);
			},

			"mouse enter tile": function (data) {
				var pos = data.element.data("position"),
					tile = this.board.tile(pos),
					validPos = this.validPuckPositions.indexOf(tile) >= 0;

				if (tile.type !== "wall" && !validPos) {
					this.view.display.highlightTile(tile, false);
				}

				if (validPos) {
					this.view.display.showPuckGhost(pos);
				}
			},

			"mouse exit tile": function () {
				this.view.display.clearPuckGhost();
				this.view.display.unhighlightTile();
			}
		},

		// after the player has placed the puck and is actually playing a round
		"playing round": {
			"click actor": function (data) {
				var actor = this.board.actors[data.element.data("actor")];

				// if the actor that has been clicked on is the currently
				// selected actor, don't do anything
				if (actor === this.selectedActor) {
					this.clearUIState();
					return false;
				}

				this.clearUIState();

				// prevent the player from moving actors that do not belong to
				// them
				if (actor.owner !== this.board.settings.owner) {
					return false;
				}

				// display the clicked actor as selected
				this.selectActor(actor);
			},

			"click puck": function () {
				this.selectPuck();
			},

			"click tile": function (data) {
				var actor,
					index,
					oldPos,
					pos = data.element.data("position"),
					tile = this.view.display.tiles[pos.x][pos.y];

				// if the tile is clicked and it is a valid move, have the
				// selected actor move to that tile
				if (tile.validMove) {
					actor = this.selectedActor;
					index = this.selectedActorIndex;
					oldPos = {
						x: actor.x,
						y: actor.y
					};

					// clear the UI
					this.clearUIState();

					// move the actor in the model
					actor.move(this.board.tiles[pos.x][pos.y]);

					// move the actor in the view
					this.view.display.moveActor(index, function () {
						// and record this move in the current turn once the
						// move is done rendering
						this.currentTurn.recordMove(actor, oldPos, pos);
					}.bind(this));
				} else if (tile.validKickDirection) {
					this.clearUIState();

					this.kickDirection = tile;
					this.projectKickTrajectory();
				} else if (tile.validKick) {
					oldPos = {
						x: this.board.puck.x,
						y: this.board.puck.y
					};

					this.kickPuck(this.board.tiles[pos.x][pos.y], function () {
						this.currentTurn.recordMove(this.board.puck,
							oldPos, pos);
					}.bind(this));

					this.clearUIState();
				} else {
					this.clearUIState();
				}
			},

			// when this client finishes making a turn, send the turn data to
			// the server -- err, that is, do nothing for now, until the server
			// is implemented
			//TODO: check turn.js:finish (this is non-emulated player move)
			"finish turn": function (turn, scored) {
				// get the turn data in serialized form, ready to be passed to
				// the server
				// var turnData = turn.serialize();

				// pass the turn data to the server

				// and store this turn on the turns list
				this.turns.push(turn);

				// now that we've saved this turn, it is no longer current, so
				// create a new one and pass control of the board to the other
				// player
				this.currentTurn = new Turn(this, Player.Two);
				this.board.settings.owner = Player.Two;
				this.view.showTurnState(Player.Two);

				// if this turn ended by a player scoring, we need to reset the
				// board to allow for a new round to start, and we need to
				// update the score on the screen
				if (scored) {
					var score = this.turns.slice(-1)[0].score();

					// display updated scores
					this.view.updateScore(score);

					// is game won
					if(Math.max(score.player1, score.player2) >= settings.game.scoreToWin) {
						setTimeout(function () {
							this.setUIState('game inactive');
							this.emit('game won', score);
						}.bind(this));
					}else{
						// reset the board
						// this.reset();
					}
				}
			},

			// create a new turn from the data that has been (ostensibly)
			// received from the server
			//TODO: check turn.js:finish (this is emulated server move)
			"receive turn": function (data, scored) {
				var turn = new Turn(this, Player.Two);
				turn.deserialize(data);

				// ordinarily we would want to call turn.display to render the
				// turn to this client, now that it's just been received from
				// the server -- however, because we're faking it and allowing
				// both players to make turns from this one client, it will have
				// already been displayed in the UI, and so there's no reason to
				// try to show it again

				// turn.display();

				this.turns.push(turn);

				// create a new turn and allow the other player to move
				this.currentTurn = new Turn(this, Player.One);
				this.board.settings.owner = Player.One;
				this.view.showTurnState(Player.One);

				// if this turn ended by a player scoring, we need to reset the
				// board to allow for a new round to start, and we need to
				// update the score on the screen
				if (scored) {
					var score = this.turns.slice(-1)[0].score();

					// display updated scores
					this.view.updateScore(score);

					// is game won
					if(Math.max(score.player1, score.player2) >= settings.game.scoreToWin) {
						setTimeout(function () {
							this.setUIState('game inactive');
							this.emit('game won', score);
						}.bind(this));
					}else{
						// reset the board
						this.reset();
					}
				}
			},

			"mouse enter tile": function (data) {
				var pos = data.element.data("position"),
					tile = this.view.display.tiles[pos.x][pos.y];

				if (tile.validMove ||
					tile.validKickDirection ||
					tile.validKick) {

					this.view.display.highlightTile(tile, true);
				}
			},

			"mouse exit tile": function () {
				this.view.display.unhighlightTile();
			},

			"redo": function () {
				// if the current turn is not our turn, don't try to redo it
				if (this.currentTurn.owner !== this.board.settings.owner) {
					return;
				}

				this.currentTurn.redoMove();
			},

			"undo": function () {
				// if the current turn is not our turn, don't try to undo it
				if (this.currentTurn.owner !== this.board.settings.owner) {
					return;
				}

				this.currentTurn.undoMove();
			}
		},

		// state when game is not active
		// for example game finished or not started
		"game inactive": {
			"game won": function (scores) {
				this.view.gameWon(scores);
			},

			"click new game": function () {
				this.view.newGameClicked();
			},

			"click mode 2p local": function () {
				this.view.hideWelcomeWindow();
				this.resetGame();
				/*setTimeout(function () {
					this.setUIState("placing puck");
				}.bind(this));*/
			}
		}
	};

	// an array containing all of the turns that have taken place so far, both
	// turns that this client has made as well as all turns received from the
	// server -- the length of this array represents the amount of turns so far
	this.turns = [];
}

/// public functions
Controller.prototype = {
	addListener: function (eventName, callback) {
		var listener;

		callback = callback.bind(this);

		// if there is no callback we may be being passed an object full of
		// listeners; if so, iterate through them and add each one individually
		if (!callback) {
			for (listener in eventName) {
				this.addListener(listener, eventName[listener]);
			}

			return;
		}

		// add a single event listener to the list without overriding any other
		// event listeners
		if (this.listeners[eventName]) {
			this.listeners[eventName].push(callback);
		} else {
			this.listeners[eventName] = [callback];
		}

		return callback;
	},

	setUIState: function (stateName) {
		var eventName;

		// destroy the old state so we can build the new one
		this.emit("destroy state");
		this.clearListeners();
		this.clearUIState();

		// apply all global listeners, the ones that should apply to all states
		for (eventName in this.states.global) {
			this.addListener(eventName, this.states.global[eventName]);
		}

		// and add the listeners that are specific to this state
		for (eventName in this.states[stateName]) {
			this.addListener(eventName, this.states[stateName][eventName]);
		}

		this.emit("init state");
	},

	clearListeners: function () {
		this.listeners = {};
	},

	clearUIState: function () {
		this.view.display.deselectActor(this.selectedActorIndex);
		this.view.display.clearKickDirections();
		this.view.display.clearKickTrajectory();
		this.view.display.unhighlightTile();

		this.puckSelected = false;
		this.selectedActor = null;
		this.kickDirection = null;
		this.puckTrajectory = null;
	},

	emit: function (eventName) {
		var i;

		if (!this.listeners[eventName]) {
			return;
		}

		for (i = 0; i < this.listeners[eventName].length; i++) {
			this.listeners[eventName][i].apply(this,
				Array.prototype.slice.apply(arguments).slice(1));
		}
	},

	kickPuck: function (target, callback) {
		var trajectory = this.puckTrajectory
			.splice(0, this.puckTrajectory.indexOf(target) + 1);

		this.board.puck.kick(trajectory[trajectory.length - 1]);
		this.view.display.showKick(trajectory, callback);
	},

	projectKickTrajectory: function () {
		this.puckTrajectory = this.board.puck.calculateTrajectory(
			this.kickDirection);

		// if we have only one available move on selected trajectory
		// then don't show single dot, just move there
		if(this.puckTrajectory.length == 1) {
			this.kickPuck(this.puckTrajectory[0], function () {
				//this.currentTurn.recordMove(this.board.puck, oldPos, pos); //TODO recordMove when "undo system" will me made
			});
			return;
		}

		this.view.display.showKickTrajectory(this.puckTrajectory);
	},

	removeListener: function (eventName, callback) {
		var index,
			listeners = this.listeners[eventName];

		if (listeners) {
			index = listeners.indexOf(callback);

			if (index > -1) {
				listeners.splice(index, 1);
			}
		}
	},

	// reset the board after finishing a round
	reset: function () {
		setTimeout(function () {
			this.board.clear();
			this.view.display.clear();

			this.board.placeActors(window.globalVariables
				.mockServerResponse.actors);

			this.view.reshowGame();
			this.view.events.listenToActorEvents();
			this.setUIState("placing puck");
		}.bind(this));
	},

	// reset the game after one of player won
	resetGame: function () {
		// clear turns of previous game
		this.turns = [];

		// clear displayed score
		var scores = {};
		scores[Player.One] = '0';
		scores[Player.Two] = '0';
		this.view.updateScore(scores);

		// new round for new clean game
		this.reset();
	},

	// select an actor and cause the available positions to move to be shown
	selectActor: function (actor) {
		this.selectedActor = actor;
		this.selectedActorIndex = this.board.actors.indexOf(actor);

		this.view.display.selectActor(this.selectedActor);
	},

	selectPuck: function () {
		if (this.puckSelected) {
			this.clearUIState();
			return;
		}

		this.clearUIState();

		this.puckSelected = true;
		this.view.display.showKickDirections(this.board.puck
			.kickDirections(this.board.settings.owner));
	}
};

/// exports
module.exports = Controller;<|endoftext|>


<commit_before>/**
 * Util functions
 */
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var libxmljs = require('libxslt').libxmljs;

exports.md5 = function(str) {
	return crypto.createHash('md5').update(str).digest('hex');
};

exports.sanitizeJSONString = function(json_str) {
	var tmp = json_str.split('\n');
	// HACK: Remove first "<?xml..." line manually for non-xml outputs
	if (json_str.indexOf('<?xml') == 0) {
		tmp.splice(0, 1);
	}
	//Remove newlines
	json_str = tmp.join(' ');
	return json_str;
};

exports.deleteFolderRecursive = function deleteFolderRecursive(path) {
	if (fs.existsSync(path)) {
		fs.readdirSync(path).forEach(function(file, index) {
			var curPath = path + "/" + file;
			if (fs.statSync(curPath).isDirectory()) { // recurse
				deleteFolderRecursive(curPath);
			} else { // delete file
				fs.unlinkSync(curPath);
			}
		});
		fs.rmdirSync(path);
	}
};

/**********************
 * Utility Methods
 **********************/

/**
 * To String
 */
exports.toParamsString = function(params) {
	var result = [];
	var prefix = '@';
	var value = '';

	for (var prop in params) {
		prefix = (prop !== 'userId') ? '@' : '@@';
		value = params[prop];

		if(prop === 'tableName' || prop === 'mode')
			if(value !== 'DEFAULT')
				value = '\'' + params[prop] + '\'';

		result.push(prefix + prop + '=' + value);
	}

	return result.join(', ');;
};

/**
 * Get Catalog object from XML (from getXMLData)
 */
exports.parseCatalog = function(xml, callback) {
	var xmlDoc = libxmljs.parseXml(xml); // Sync func

	if(!xmlDoc)
		return callback({message: "Error: Parsing XML"});

	var catalog = {
		dbId: xmlDoc.root().attr("dbId").value(),
		lang: xmlDoc.root().attr("lang").value(),
		Table_Schema: xmlDoc.root().attr("Table_Schema").value(),
		Table_Name: xmlDoc.root().attr("Table_Name").value(),
		mode: xmlDoc.root().attr("mode").value(),
		controlType: xmlDoc.root().attr("controlType").value()
	};

	var fileTemplate = xmlDoc.root().attr("fileTemplate");
	if(fileTemplate)
		catalog.fileTemplate = fileTemplate.value();

	callback(null, catalog);
};

/**
 * Get Filename Location from Catalog
 */
exports.getFilename = function(config, params, catalog, callback) {
	var sLocation = path.join(
		config.ui.guis[params.output].cache,
		catalog.dbId,
		catalog.lang,
		catalog.Table_Schema,
		catalog.Table_Name,
		catalog.mode
	);

	var sFileName = path.join(sLocation, catalog.controlType + '.js');

	// ToDo: Use fs.Async functions?
	if(fs.existsSync(sFileName) && params.rebuild !== '1') {
		//console.info('# PanaxJS - Existing file: ' + sFileName);
		callback(null, true, sFileName);
	} else {
		if(fs.existsSync(sFileName)) {
			fs.unlinkSync(sFileName);
			//console.info('# PanaxJS - Deleted file: ' + sFileName);
		}
		if(!fs.existsSync(sLocation)) {
			mkdirp(sLocation);
			//console.info('# PanaxJS - Mkdirp folder: ' + sLocation);
		}

		//console.info('# PanaxJS - Missing file: ' + sFileName);
		callback(null, false, sFileName);
	}
};

/**
 * Get Results object from XML (from persist)
 */
exports.parseResults = function(xml, callback) {
	var xmlDoc = libxmljs.parseXml(xml); // Sync func

	if(!xmlDoc)
		return callback({message: "Error: Parsing XML"});

	var results = [];

	xmlDoc.root().childNodes().forEach(function (resultNode) {
		var result_attrs = resultNode.attrs();
		var result = {};
		for(var i=0;i<result_attrs.length;i++) {
			result[result_attrs[i].name()] = result_attrs[i].value();
		}
		result.fields = [];
		resultNode.childNodes().forEach(function (fieldNode) {
			var field_attrs = fieldNode.attrs();
			var field = {};
			for(var i=0;i<field_attrs.length;i++) {
				field[field_attrs[i].name()] = field_attrs[i].value();
			}
			if(fieldNode.text()) {
				field.value = fieldNode.text();
			}
			result.fields.push(field);
		});
		results.push(result);
	});

	callback(null, results);
};<commit_msg>refactor(global): rename catalog -> metadata<commit_after>/**
 * Util functions
 */
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var libxmljs = require('libxslt').libxmljs;

exports.md5 = function(str) {
	return crypto.createHash('md5').update(str).digest('hex');
};

exports.sanitizeJSONString = function(json_str) {
	var tmp = json_str.split('\n');
	// HACK: Remove first "<?xml..." line manually for non-xml outputs
	if (json_str.indexOf('<?xml') == 0) {
		tmp.splice(0, 1);
	}
	//Remove newlines
	json_str = tmp.join(' ');
	return json_str;
};

exports.deleteFolderRecursive = function deleteFolderRecursive(path) {
	if (fs.existsSync(path)) {
		fs.readdirSync(path).forEach(function(file, index) {
			var curPath = path + "/" + file;
			if (fs.statSync(curPath).isDirectory()) { // recurse
				deleteFolderRecursive(curPath);
			} else { // delete file
				fs.unlinkSync(curPath);
			}
		});
		fs.rmdirSync(path);
	}
};

/**********************
 * Utility Methods
 **********************/

/**
 * To String
 */
exports.toParamsString = function(params) {
	var result = [];
	var prefix = '@';
	var value = '';

	for (var prop in params) {
		prefix = (prop !== 'userId') ? '@' : '@@';
		value = params[prop];

		if(prop === 'tableName' || prop === 'mode')
			if(value !== 'DEFAULT')
				value = '\'' + params[prop] + '\'';

		result.push(prefix + prop + '=' + value);
	}

	return result.join(', ');;
};

/**
 * Get Entity's Metadata object from XML (from getXMLData)
 */
exports.parseMetadata = function(xml, callback) {
	var xmlDoc = libxmljs.parseXml(xml); // Sync func

	if(!xmlDoc)
		return callback({message: "Error: Parsing XML"});

	var metadata = {
		dbId: xmlDoc.root().attr("dbId").value(),
		lang: xmlDoc.root().attr("lang").value(),
		Table_Schema: xmlDoc.root().attr("Table_Schema").value(),
		Table_Name: xmlDoc.root().attr("Table_Name").value(),
		mode: xmlDoc.root().attr("mode").value(),
		controlType: xmlDoc.root().attr("controlType").value()
	};

	var fileTemplate = xmlDoc.root().attr("fileTemplate");
	if(fileTemplate)
		metadata.fileTemplate = fileTemplate.value();

	callback(null, metadata);
};

/**
 * Get Filename Location from Metadata
 */
exports.getFilename = function(config, params, metadata, callback) {
	var sLocation = path.join(
		config.ui.guis[params.output].cache,
		metadata.dbId,
		metadata.lang,
		metadata.Table_Schema,
		metadata.Table_Name,
		metadata.mode
	);

	var sFileName = path.join(sLocation, metadata.controlType + '.js');

	// ToDo: Use fs.Async functions?
	if(fs.existsSync(sFileName) && params.rebuild !== '1') {
		//console.info('# PanaxJS - Existing file: ' + sFileName);
		callback(null, true, sFileName);
	} else {
		if(fs.existsSync(sFileName)) {
			fs.unlinkSync(sFileName);
			//console.info('# PanaxJS - Deleted file: ' + sFileName);
		}
		if(!fs.existsSync(sLocation)) {
			mkdirp(sLocation);
			//console.info('# PanaxJS - Mkdirp folder: ' + sLocation);
		}

		//console.info('# PanaxJS - Missing file: ' + sFileName);
		callback(null, false, sFileName);
	}
};

/**
 * Get Results object from XML (from persist)
 */
exports.parseResults = function(xml, callback) {
	var xmlDoc = libxmljs.parseXml(xml); // Sync func

	if(!xmlDoc)
		return callback({message: "Error: Parsing XML"});

	var results = [];

	xmlDoc.root().childNodes().forEach(function (resultNode) {
		var result_attrs = resultNode.attrs();
		var result = {};
		for(var i=0;i<result_attrs.length;i++) {
			result[result_attrs[i].name()] = result_attrs[i].value();
		}
		result.fields = [];
		resultNode.childNodes().forEach(function (fieldNode) {
			var field_attrs = fieldNode.attrs();
			var field = {};
			for(var i=0;i<field_attrs.length;i++) {
				field[field_attrs[i].name()] = field_attrs[i].value();
			}
			if(fieldNode.text()) {
				field.value = fieldNode.text();
			}
			result.fields.push(field);
		});
		results.push(result);
	});

	callback(null, results);
};<|endoftext|>


<commit_before>(function () {

  'use strict';

  /* istanbul ignore next */
  var angular = window.angular ? window.angular : 'undefined' !== typeof require ? require('angular') : undefined;
  var c3 = window.c3 ? window.c3 : 'undefined' !== typeof require ? require('c3') : undefined;

  function angularChartController($scope, $element, $timeout, angularChartWatcher) {
    console.log('init');
    var baseConfiguration = {};
    var configuration;

    addIdentifier();
    angularChartWatcher.init($scope);
    updateCallback();

    // register callbacks after first digest cycle
    $timeout(function() {
      angularChartWatcher.registerChartCallback(updateCallback);
      angularChartWatcher.registerDataCallback(updateCallback);
    });

    function updateCallback() {
      configuration = baseConfiguration;
      applyData();
      applyChartOptions();
      generateChart();
    }

    // add unique identifier for each chart
    //
    function addIdentifier() {
      $scope.dataAttributeChartID = 'chartid' + Math.floor(Math.random() * 1000000001);
      angular.element($element).attr('id', $scope.dataAttributeChartID);
      baseConfiguration.bindto = '#' + $scope.dataAttributeChartID;
    }

    function applyData() {
      if ($scope.options.data) {
        configuration.data = {
          json: $scope.options.data
        };
      }
    }

    function applyChartOptions() {
      // TODO replace with angular 1.4.0 angular.merge for deep copy
      angular.extend(
        configuration,
        $scope.options.chart
      );
    }

    function generateChart() {
      console.log('draw', configuration);
      window.onresize = null;
      c3.generate(configuration);
    }

  }

  angular
    .module('angularChart')
    .controller('angularChartController', angularChartController);

})();
<commit_msg>add destroy watcher<commit_after>(function () {

  'use strict';

  /* istanbul ignore next */
  var angular = window.angular ? window.angular : 'undefined' !== typeof require ? require('angular') : undefined;
  var c3 = window.c3 ? window.c3 : 'undefined' !== typeof require ? require('c3') : undefined;

  function angularChartController($scope, $element, $timeout, angularChartWatcher) {
    console.log('init');
    var baseConfiguration = {};
    var configuration;
    var chart;

    addIdentifier();
    angularChartWatcher.init($scope);
    updateCallback();
    registerDestroyListener();

    // register callbacks after first digest cycle
    $timeout(function() {
      angularChartWatcher.registerChartCallback(updateCallback);
      angularChartWatcher.registerDataCallback(updateCallback);
    });

    function updateCallback() {
      configuration = baseConfiguration;
      applyData();
      applyChartOptions();
      generateChart();
    }

    // add unique identifier for each chart
    //
    function addIdentifier() {
      $scope.dataAttributeChartID = 'chartid' + Math.floor(Math.random() * 1000000001);
      angular.element($element).attr('id', $scope.dataAttributeChartID);
      baseConfiguration.bindto = '#' + $scope.dataAttributeChartID;
    }

    function applyData() {
      if ($scope.options.data) {
        configuration.data = {
          json: $scope.options.data
        };
      }
    }

    function applyChartOptions() {
      // TODO replace with angular 1.4.0 angular.merge for deep copy
      angular.extend(
        configuration,
        $scope.options.chart
      );
    }

    function generateChart() {
      console.log('draw', configuration);
      window.onresize = null;
      chart = c3.generate(configuration);
    }

    function registerDestroyListener() {
      $scope.$on('$destroy', function () {
        chart.destroy();
        $element.remove();
      });
    }

  }

  angular
    .module('angularChart')
    .controller('angularChartController', angularChartController);

})();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

exports.guessTabWidth = function(source) {
  var counts = []; // Sparse array.
  var lastIndent = 0;

  source.split("\n").forEach(function(line) {
    var indent = /^\s*/.exec(line)[0].length;
    var diff = Math.abs(indent - lastIndent);
    counts[diff] = ~~counts[diff] + 1;
    lastIndent = indent;
  });

  var maxCount = -1;
  var result = 2;

  for (var tabWidth = 1;
       tabWidth < counts.length;
       tabWidth += 1) {
    if (tabWidth in counts &&
        counts[tabWidth] > maxCount) {
      maxCount = counts[tabWidth];
      result = tabWidth;
    }
  }

  return result;
};

exports.defaults = function(obj) {
  var len = arguments.length;
  var extension;

  for (var i = 1; i < len; ++i) {
    if ((extension = arguments[i])) {
      for (var key in extension) {
        if (obj[key] === undefined) {
          obj[key] = extension[key];
        }
      }
    }
  }

  return obj;
};<commit_msg>Use hasOwnProperty when setting defaults<commit_after>/**
 * Copyright (c) 2013, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var hasOwn = Object.prototype.hasOwnProperty;

exports.guessTabWidth = function(source) {
  var counts = []; // Sparse array.
  var lastIndent = 0;

  source.split("\n").forEach(function(line) {
    var indent = /^\s*/.exec(line)[0].length;
    var diff = Math.abs(indent - lastIndent);
    counts[diff] = ~~counts[diff] + 1;
    lastIndent = indent;
  });

  var maxCount = -1;
  var result = 2;

  for (var tabWidth = 1;
       tabWidth < counts.length;
       tabWidth += 1) {
    if (tabWidth in counts &&
        counts[tabWidth] > maxCount) {
      maxCount = counts[tabWidth];
      result = tabWidth;
    }
  }

  return result;
};

exports.defaults = function(obj) {
  var len = arguments.length;
  var extension;

  for (var i = 1; i < len; ++i) {
    if ((extension = arguments[i])) {
      for (var key in extension) {
        if (hasOwn.call(extension, key) && !hasOwn.call(obj, key)) {
          obj[key] = extension[key];
        }
      }
    }
  }

  return obj;
};<|endoftext|>


<commit_before>var DayPlanner = function() {
	var menu;

	var openedItemHeight = 200; // px
	var minItemInterval = 5; // min

	var startTime = "00:00";

	// set height according to duration (1 minute = 1px)
	var resetItemsHeight = function() {
		var items = document.querySelectorAll('.item');
		for (var i = 0; i < items.length; i++) {
			resizeItem(items[i], getItemDuration(items[i]));
		}
	};

	var resizeItem = function(item, height) {
		item.style.height = height + "px";
	};

	var getOpenedItem = function() {
		return document.getElementById("menu").parentNode;
	};

	var showMenu = function(item) {
		item.appendChild(menu);
		menu.style.display = "block";

		refreshMenu();
	};

	var refreshMenu = function() {
		var openedItem = getOpenedItem();

		// refresh change item name input
		document.getElementById("name-input").value = getItemName(openedItem);

		// refresh duration input
		document.getElementById("duration-input").value = getItemDuration(openedItem);
	};

	var getItemDuration = function(item) {
		return item.querySelector(".duration").innerHTML.trim() * 1;
	};

	var getItemName = function(item) {
		return item.querySelector(".item-name").innerHTML.trim();
	};

	var hideMenu = function() {
		document.getElementById("menu").outerHTML = "";
	};

	var calculateTimes = function() {
		var items = document.querySelectorAll('.item');

		var previousTime = startTime;
		for (var i = 0; i < items.length; i++) {
			items[i].querySelector(".time").innerHTML = Time.minutesToTime(Time.timeToMinutes(previousTime) + getItemDuration(items[i]));
			previousTime = Time.minutesToTime(getItemDuration(items[i]) + Time.timeToMinutes(previousTime));
		}
	};

	var init = function() {
		// initialize first time in items start/end times
		document.getElementById('start-time').innerHTML = startTime;

		var items = document.querySelectorAll('.content');
		// items init
		for (var i = 0; i < items.length; i++) {
			// add onclick to display options
			items[i].onclick = function() {
				clickOnItem(this.parentNode);
			};
		}

		// set height according to duration (1 minute = 1px)
		resetItemsHeight();

		// calculates start/end times of items
		calculateTimes();

		//initialize menu
		menuInit();
	};

	var menuInit = function() {
		menu = document.getElementById('menu');

		// add button init
		var addButton = document.getElementById("add-item");
		addButton.onclick = function() {
			// add default item behind selected item
			var defaultItem = document.getElementById("default-item").children[0];
			defaultItem = defaultItem.cloneNode(true);

			var itemNode = getOpenedItem();
			var newItem = itemNode.parentNode.insertBefore(defaultItem, itemNode.nextSibling);

			// add onclick event on newly created item
			newItem.querySelector(".content").onclick = function() {
				clickOnItem(this.parentNode);
			};

			// opens menu on newly created item
			clickOnItem(newItem);
			// recalculate times
			calculateTimes();
		};

		// delete button init
		var deleteButton = document.getElementById("delete-item");
		deleteButton.onclick = function() {
			// delete current item
			getOpenedItem().outerHTML = "";

			// recalculate times
			calculateTimes();
		};

		// duration buttons
		var durationInput = document.getElementById("duration-input");
		var changeDurationInput = function(amount) {
			if (Lib.isNumber(durationInput.value)) {
				durationInput.value = durationInput.value * 1 + amount;
			} else {
				durationInput.value = getItemDuration(getOpenedItem());
			}
		};

		var plusButton = document.getElementById("duration-plus");
		plusButton.onclick = function() {
			changeDurationInput(10);
		};

		var minusButton = document.getElementById("duration-minus");
		minusButton.onclick = function() {
			changeDurationInput(-10);
		};

		//hide menu button
		var hideMenuButton = document.getElementById("hide-menu");
		hideMenuButton.onclick = function() {
			resetItemsHeight();
			hideMenu();
		};

		// save button
		var saveButton = document.getElementById("save");
		saveButton.onclick = function() {
			// resizes item height according to input value
			if (Lib.isNumber(durationInput.value) && durationInput.value >= minItemInterval) {
				getOpenedItem().querySelector(".duration").innerHTML = durationInput.value;
			}

			// changes name of item
			var nameInput = document.getElementById("name-input");
			getOpenedItem().querySelector(".item-name").innerHTML = nameInput.value;

			hideMenu();
			resetItemsHeight();
			calculateTimes();
		};
	};

	var clickOnItem = function(item) {
		resetItemsHeight();
		resizeItem(item, openedItemHeight);
		showMenu(item);
	};

	return {
		init: init
	};
}();
<commit_msg>changed item duration is now saved instantly after the change and items start/end times are recalculated in real time<commit_after>var DayPlanner = function() {
	var menu;

	var openedItemHeight = 200; // px
	var minItemInterval = 1; // min
	var maxItemInterval = 120; // min

	var startTime = "00:00";

	// set height according to duration (1 minute = 1px)
	var resetItemsHeight = function() {
		var items = document.querySelectorAll('.item');
		for (var i = 0; i < items.length; i++) {
			resizeItem(items[i], getItemDuration(items[i]));
		}
	};

	var resizeItem = function(item, height) {
		item.style.height = height + "px";
	};

	var getOpenedItem = function() {
		return document.getElementById("menu").parentNode;
	};

	var showMenu = function(item) {
		item.appendChild(menu);
		menu.style.display = "block";

		refreshMenu();
	};

	var refreshMenu = function() {
		var openedItem = getOpenedItem();

		// refresh change item name input
		document.getElementById("name-input").value = getItemName(openedItem);

		// refresh duration input
		document.getElementById("duration-input").value = getItemDuration(openedItem);
	};

	var getItemDuration = function(item) {
		return item.querySelector(".duration").innerHTML.trim() * 1;
	};

	var getItemName = function(item) {
		return item.querySelector(".item-name").innerHTML.trim();
	};

	var hideMenu = function() {
		document.getElementById("menu").outerHTML = "";
	};

	var calculateTimes = function() {
		var items = document.querySelectorAll('.item');

		var previousTime = startTime;
		for (var i = 0; i < items.length; i++) {
			items[i].querySelector(".time").innerHTML = Time.minutesToTime(Time.timeToMinutes(previousTime) + getItemDuration(items[i]));
			previousTime = Time.minutesToTime(getItemDuration(items[i]) + Time.timeToMinutes(previousTime));
		}
	};

	var init = function() {
		// initialize first time in items start/end times
		document.getElementById('start-time').innerHTML = startTime;

		var items = document.querySelectorAll('.content');
		// items init
		for (var i = 0; i < items.length; i++) {
			// add onclick to display options
			items[i].onclick = function() {
				clickOnItem(this.parentNode);
			};
		}

		// set height according to duration (1 minute = 1px)
		resetItemsHeight();

		// calculates start/end times of items
		calculateTimes();

		//initialize menu
		menuInit();
	};

	var menuInit = function() {
		menu = document.getElementById('menu');

		// add button init
		var addButton = document.getElementById("add-item");
		addButton.onclick = function() {
			// add default item behind selected item
			var defaultItem = document.getElementById("default-item").children[0];
			defaultItem = defaultItem.cloneNode(true);

			var itemNode = getOpenedItem();
			var newItem = itemNode.parentNode.insertBefore(defaultItem, itemNode.nextSibling);

			// add onclick event on newly created item
			newItem.querySelector(".content").onclick = function() {
				clickOnItem(this.parentNode);
			};

			// opens menu on newly created item
			clickOnItem(newItem);
			// recalculate times
			calculateTimes();
		};

		// delete button init
		var deleteButton = document.getElementById("delete-item");
		deleteButton.onclick = function() {
			// delete current item
			getOpenedItem().outerHTML = "";

			// recalculate times
			calculateTimes();
		};

		// duration buttons
		var addDuration = function(amount) {
			var durationInput = document.getElementById("duration-input");

			amount = amount * 1 + durationInput.value * 1;
			if (amount < minItemInterval) {
				amount = minItemInterval;
			} else if (amount > maxItemInterval) {
				amount = maxItemInterval;
			}

			getOpenedItem().querySelector(".duration").innerHTML = amount;
			durationInput.value = amount;

			calculateTimes();
		};

		var changeDuration = function(amount) {
			if (Lib.isNumber(amount) && amount >= minItemInterval && amount <= maxItemInterval) {
				getOpenedItem().querySelector(".duration").innerHTML = amount;
				calculateTimes();
			}
		};

		var durationInput = document.getElementById("duration-input");
		durationInput.oninput = function() {
			changeDuration(this.value);
		};

		var plusButton = document.getElementById("duration-plus");
		plusButton.onclick = function() {
			addDuration(10);
		};

		var minusButton = document.getElementById("duration-minus");
		minusButton.onclick = function() {
			addDuration(-10);
		};

		//hide menu button
		var hideMenuButton = document.getElementById("hide-menu");
		hideMenuButton.onclick = function() {
			resetItemsHeight();
			hideMenu();
		};

		// save button
		var saveButton = document.getElementById("save");
		saveButton.onclick = function() {

			// changes name of item
			var nameInput = document.getElementById("name-input");
			getOpenedItem().querySelector(".item-name").innerHTML = nameInput.value;

			hideMenu();
			resetItemsHeight();
			calculateTimes();
		};
	};

	var clickOnItem = function(item) {
		resetItemsHeight();
		resizeItem(item, openedItemHeight);
		showMenu(item);
	};

	return {
		init: init
	};
}();
<|endoftext|>


<commit_before>'use strict';

var cheerio = require('cheerio');
var fs = require('fs');
var tokens = require('./login/tokens');
var util = require('util');

// Open the sessions database
var Datastore = require('nedb');
var sessionDB = new Datastore({filename: './db/sessions.db', autoload: true});

// Automatically compact the DB every 5 minutes
sessionDB.persistence.setAutocompactionInterval(300000);

var config = require('./config').getConfig();
var filteredConfig = require('./config').getFilteredConfig();

exports.authCheck = function (req, res, next) {
    if (!config.login.enabled) {
        return next();
    }

    var allowed = (req.user !== undefined) ? req.user.allowed : false;
    var provider = (req.user !== undefined) ? req.user.provider : 'none';
    var providerAllowed = (provider !== 'none') ? config.login[provider].enabled : false;

    if (req.query.key || req.cookies.socketToken) {
        tokens.find({token: req.query.key || req.cookies.socketToken}, function (err, token) {
            if (err) throw err;
            if (token) next();
            else {
                // Ensure we delete the existing cookie so that it doesn't become poisoned
                // and cause an infinite login loop.
                res.clearCookie('socketToken');
                res.clearCookie('connect.sid');
                req.session.returnTo = req.url;
                res.redirect('/login');
            }
        });
    } else if (req.isAuthenticated() && allowed && providerAllowed) {
        // Create token
        tokens.findOrCreate({provider: provider, id: req.user.id}, function(err, token) {
            if (err) throw err;

            // To set a cookie on localhost, domain must be "null"
            var domain = config.host === 'localhost'
                ? null
                : '.' + config.host;
            res.cookie('socketToken', token, {domain: domain});
            next();
        });
    } else {
        req.session.returnTo = req.url;
        res.redirect('/login');
    }
};

exports.findSession = function(params, cb) {
    params = params || {};
    sessionDB.findOne(params, function (err, doc) {
        if (err) cb(err);
        else cb(null, doc);
    });
};

exports.injectScripts = function (pathOrHtml, resourceType, opts, cb) {
    // Graphics only pass the path to the html file.
    // Panels and dialogs pass a cached HTML string.
    if (resourceType === 'graphic') {
        fs.readFile(pathOrHtml, inject);
    } else {
        inject(null, pathOrHtml);
    }

    function inject(err, html) {
        var $ = cheerio.load(html);

        // Everything needs the shims and config
        var scripts = [
            '<script src="/components/observe-shim/lib/observe-shim.js"></script>',
            '<script src="/shims/WeakMap.js"></script>',
            '<script>window.ncgConfig = ' + JSON.stringify(filteredConfig) + ';</script>'
        ];

        var styles = [];

        if (resourceType === 'panel' || resourceType === 'dialog') {
            if (opts.standalone) {
                // load the API
                scripts.push('<script src="/nodecg-api.js"></script>');
            }
            else {
                // Panels and dialogs can grab the API from the dashboard
                scripts.push('<script>window.NodeCG = window.top.NodeCG</script>');
            }

            // Both panels and dialogs need the main default style framework
            scripts.push('<link rel="import" href="/dashboard/style/nodecg-styles.html">');

            if (opts.standalone) {
                // load the socket
                scripts.push('<script src="/components/cn-jsurl/url.min.js"></script>');
                scripts.push("<script>var url = new Url; window.token = url.query.key || Cookies.get('socketToken'); if (window.token) { window.socket = io.connect('//' + window.ncgConfig.baseURL + '/', { query: 'token=' + window.token }); } else { window.socket = io.connect('//' + window.ncgConfig.baseURL + '/'); }</script>");
            }
            else {
                // They both also need to reference the dashboard window's socket, rather than make their own
                scripts.push('<script>window.socket = window.top.socket;</script>');
            }

            // Likewise, they both need the contentWindow portion of the iframeResizer.
            // We put this at the start and make it async so it loads ASAP.
            scripts.unshift('<script async src="/components/iframe-resizer/js/iframeResizer.contentWindow.min.js">' +
                '</script>');

            // Panels need the default panel styles and the dialog_opener
            if (resourceType === 'panel') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/panel.css">');
                scripts.push('<script async src="/dashboard/dialog_opener.js"></script>');
            }

            // Dialogs need the default dialog styles and the dialog_helper
            else if (resourceType === 'dialog') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/dialog.css">');
                scripts.push('<script async src="/dashboard/dialog_helper.js"></script>');
            }
        }

        else if (resourceType === 'graphic') {
            // Graphics need to create their own socket
            scripts.push('<script src="/socket.io/socket.io.js"></script>');

            // If login security is enabled, graphics must provide a valid token when they connect to the socket
            // They also need cookies-js and a helper to manage URL query strings
            var socketScript;
            if (config.login.enabled) {
                scripts.push('<script src="/components/cookies-js/dist/cookies.min.js"></script>');
                scripts.push('<script src="/login/QueryString.js"></script>');
                socketScript =
                    '<script>\n' +
                    'window.token = qs["key"] || Cookies.get("socketToken");\n' +
                    'window.socket = io.connect("//%s/",{query: "token=" + window.token});\n' +
                    '</script>';
            } else {
                socketScript = '<script>window.socket = io.connect("//%s/");</script>';
            }
            scripts.push(util.format(socketScript, filteredConfig.baseURL));

            // Graphics must include the API script themselves before attempting to make an instance of it
            scripts.push('<script src="/nodecg-api.js"></script>');
        }

        else {
            throw new Error('Invalid resourceType "' + resourceType + '"');
        }

        // Inject a small script to create a NodeCG API instance, if requested.
        if (opts.createApiInstance) {
            var partialBundle = {
                name: opts.createApiInstance.name,
                config: opts.createApiInstance.config
            };

            scripts.push(
                util.format('<script>window.nodecg = new NodeCG(%s, window.socket);</script>',
                    JSON.stringify(partialBundle))
            );
        }

        // Inject the scripts required for singleInstance behavior, if requested.
        if (opts.singleInstance) {
            scripts.push('<script src="/instance/client_heart.js"></script>');
        }

        scripts = scripts.join('\n');

        // Put our scripts before their first script or HTML import.
        // If they have no scripts or imports, put our scripts at the end of <body>.
        var theirScriptsAndImports = $('script, link[rel="import"]');
        if (theirScriptsAndImports.length > 0) {
            theirScriptsAndImports.first().before(scripts);
        } else {
            $('body').append(scripts);
        }

        // Inject the needed stylesheets, if any.
        // If there are <script> tags in the head, inject before them.
        // Otherwise, add at the end of the <head>.
        if (styles.length > 0) {
            styles = styles.join('\n');

            var headScripts = $('head').find('script');
            if (headScripts.length > 0) {
                headScripts.first().before(styles);
            } else {
                $('head').append(styles);
            }
        }

        cb($.html());
    }
};

exports.versionCompare = function (v1, v2, options) {
    var lexicographical = options && options.lexicographical;
    var zeroExtend = options && options.zeroExtend;
    var v1parts = v1.split('.');
    var v2parts = v2.split('.');

    function isValidPart(x) { return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); }
    if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { return NaN; }
    if (zeroExtend) {
        while (v1parts.length < v2parts.length) v1parts.push('0');
        while (v2parts.length < v1parts.length) v2parts.push('0');
    }
    if (!lexicographical) {
        v1parts = v1parts.map(Number);
        v2parts = v2parts.map(Number);
    }
    for (var i = 0; i < v1parts.length; ++i) {
        if (v2parts.length === i) { return 1; }
        if (v1parts[i] === v2parts[i]) { continue; }
        else if (v1parts[i] > v2parts[i]) { return 1; }
        else { return -1; }
    }
    if (v1parts.length !== v2parts.length) { return -1; }
    return 0;
};

module.exports = exports;
<commit_msg>Load all required scripts for properly connecting to socket.io.<commit_after>'use strict';

var cheerio = require('cheerio');
var fs = require('fs');
var tokens = require('./login/tokens');
var util = require('util');

// Open the sessions database
var Datastore = require('nedb');
var sessionDB = new Datastore({filename: './db/sessions.db', autoload: true});

// Automatically compact the DB every 5 minutes
sessionDB.persistence.setAutocompactionInterval(300000);

var config = require('./config').getConfig();
var filteredConfig = require('./config').getFilteredConfig();

exports.authCheck = function (req, res, next) {
    if (!config.login.enabled) {
        return next();
    }

    var allowed = (req.user !== undefined) ? req.user.allowed : false;
    var provider = (req.user !== undefined) ? req.user.provider : 'none';
    var providerAllowed = (provider !== 'none') ? config.login[provider].enabled : false;

    if (req.query.key || req.cookies.socketToken) {
        tokens.find({token: req.query.key || req.cookies.socketToken}, function (err, token) {
            if (err) throw err;
            if (token) next();
            else {
                // Ensure we delete the existing cookie so that it doesn't become poisoned
                // and cause an infinite login loop.
                res.clearCookie('socketToken');
                res.clearCookie('connect.sid');
                req.session.returnTo = req.url;
                res.redirect('/login');
            }
        });
    } else if (req.isAuthenticated() && allowed && providerAllowed) {
        // Create token
        tokens.findOrCreate({provider: provider, id: req.user.id}, function(err, token) {
            if (err) throw err;

            // To set a cookie on localhost, domain must be "null"
            var domain = config.host === 'localhost'
                ? null
                : '.' + config.host;
            res.cookie('socketToken', token, {domain: domain});
            next();
        });
    } else {
        req.session.returnTo = req.url;
        res.redirect('/login');
    }
};

exports.findSession = function(params, cb) {
    params = params || {};
    sessionDB.findOne(params, function (err, doc) {
        if (err) cb(err);
        else cb(null, doc);
    });
};

exports.injectScripts = function (pathOrHtml, resourceType, opts, cb) {
    // Graphics only pass the path to the html file.
    // Panels and dialogs pass a cached HTML string.
    if (resourceType === 'graphic') {
        fs.readFile(pathOrHtml, inject);
    } else {
        inject(null, pathOrHtml);
    }

    function inject(err, html) {
        var $ = cheerio.load(html);

        // Everything needs the shims and config
        var scripts = [
            '<script src="/components/observe-shim/lib/observe-shim.js"></script>',
            '<script src="/shims/WeakMap.js"></script>',
            '<script>window.ncgConfig = ' + JSON.stringify(filteredConfig) + ';</script>'
        ];

        var styles = [];

        if (resourceType === 'panel' || resourceType === 'dialog') {
            if (opts.standalone) {
                // load the API
                scripts.push('<script src="/nodecg-api.js"></script>');
            }
            else {
                // Panels and dialogs can grab the API from the dashboard
                scripts.push('<script>window.NodeCG = window.top.NodeCG</script>');
            }

            // Both panels and dialogs need the main default style framework
            scripts.push('<link rel="import" href="/dashboard/style/nodecg-styles.html">');

            if (opts.standalone) {
                // load the socket
                scripts.push('<script src="/components/cookies-js/dist/cookies.min.js"></script>');
                scripts.push('<script src="/components/cn-jsurl/url.min.js"></script>');
                scripts.push('<script src="/socket.io/socket.io.js"></script>');
                scripts.push("<script>var url = new Url; window.token = url.query.key || Cookies.get('socketToken'); if (window.token) { window.socket = io.connect('//' + window.ncgConfig.baseURL + '/', { query: 'token=' + window.token }); } else { window.socket = io.connect('//' + window.ncgConfig.baseURL + '/'); }</script>");
            }
            else {
                // They both also need to reference the dashboard window's socket, rather than make their own
                scripts.push('<script>window.socket = window.top.socket;</script>');
            }

            // Likewise, they both need the contentWindow portion of the iframeResizer.
            // We put this at the start and make it async so it loads ASAP.
            scripts.unshift('<script async src="/components/iframe-resizer/js/iframeResizer.contentWindow.min.js">' +
                '</script>');

            // Panels need the default panel styles and the dialog_opener
            if (resourceType === 'panel') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/panel.css">');
                scripts.push('<script async src="/dashboard/dialog_opener.js"></script>');
            }

            // Dialogs need the default dialog styles and the dialog_helper
            else if (resourceType === 'dialog') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/dialog.css">');
                scripts.push('<script async src="/dashboard/dialog_helper.js"></script>');
            }
        }

        else if (resourceType === 'graphic') {
            // Graphics need to create their own socket
            scripts.push('<script src="/socket.io/socket.io.js"></script>');

            // If login security is enabled, graphics must provide a valid token when they connect to the socket
            // They also need cookies-js and a helper to manage URL query strings
            var socketScript;
            if (config.login.enabled) {
                scripts.push('<script src="/components/cookies-js/dist/cookies.min.js"></script>');
                scripts.push('<script src="/login/QueryString.js"></script>');
                socketScript =
                    '<script>\n' +
                    'window.token = qs["key"] || Cookies.get("socketToken");\n' +
                    'window.socket = io.connect("//%s/",{query: "token=" + window.token});\n' +
                    '</script>';
            } else {
                socketScript = '<script>window.socket = io.connect("//%s/");</script>';
            }
            scripts.push(util.format(socketScript, filteredConfig.baseURL));

            // Graphics must include the API script themselves before attempting to make an instance of it
            scripts.push('<script src="/nodecg-api.js"></script>');
        }

        else {
            throw new Error('Invalid resourceType "' + resourceType + '"');
        }

        // Inject a small script to create a NodeCG API instance, if requested.
        if (opts.createApiInstance) {
            var partialBundle = {
                name: opts.createApiInstance.name,
                config: opts.createApiInstance.config
            };

            scripts.push(
                util.format('<script>window.nodecg = new NodeCG(%s, window.socket);</script>',
                    JSON.stringify(partialBundle))
            );
        }

        // Inject the scripts required for singleInstance behavior, if requested.
        if (opts.singleInstance) {
            scripts.push('<script src="/instance/client_heart.js"></script>');
        }

        scripts = scripts.join('\n');

        // Put our scripts before their first script or HTML import.
        // If they have no scripts or imports, put our scripts at the end of <body>.
        var theirScriptsAndImports = $('script, link[rel="import"]');
        if (theirScriptsAndImports.length > 0) {
            theirScriptsAndImports.first().before(scripts);
        } else {
            $('body').append(scripts);
        }

        // Inject the needed stylesheets, if any.
        // If there are <script> tags in the head, inject before them.
        // Otherwise, add at the end of the <head>.
        if (styles.length > 0) {
            styles = styles.join('\n');

            var headScripts = $('head').find('script');
            if (headScripts.length > 0) {
                headScripts.first().before(styles);
            } else {
                $('head').append(styles);
            }
        }

        cb($.html());
    }
};

exports.versionCompare = function (v1, v2, options) {
    var lexicographical = options && options.lexicographical;
    var zeroExtend = options && options.zeroExtend;
    var v1parts = v1.split('.');
    var v2parts = v2.split('.');

    function isValidPart(x) { return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); }
    if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { return NaN; }
    if (zeroExtend) {
        while (v1parts.length < v2parts.length) v1parts.push('0');
        while (v2parts.length < v1parts.length) v2parts.push('0');
    }
    if (!lexicographical) {
        v1parts = v1parts.map(Number);
        v2parts = v2parts.map(Number);
    }
    for (var i = 0; i < v1parts.length; ++i) {
        if (v2parts.length === i) { return 1; }
        if (v1parts[i] === v2parts[i]) { continue; }
        else if (v1parts[i] > v2parts[i]) { return 1; }
        else { return -1; }
    }
    if (v1parts.length !== v2parts.length) { return -1; }
    return 0;
};

module.exports = exports;
<|endoftext|>


<commit_before>/**
 * Compare two arrays
 * @TODO Add flag for strict comparison
 */
Array.prototype.equals = Array.prototype.compare = function equals(array) {
  if (!Array.isArray(array) || this.length !== array.length) {
    return false;
  }
  for (var i = 0; i < this.length; i++) {
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
      // recurse into the nested arrays
      if (!this[i].equals(array[i])) {
        return false;
      }
    } else if (this[i] !== array[i]) {
      return false;
    }
  }
  return true;
};

/**
 *
 */
Array.prototype.toObject = function toObject() {
  var object = {};
  for (var i = 0; i < this.length; ++i) {
    if (this[i] !== undefined) {
      object[i] = this[i];
    }
  }
  return object;
};

Array.prototype.shuffle = function shuffle() {
  var counter = this.length,
    temp, index;

  // While there are elements in the array
  while (counter--) {
    // Pick a random index
    index = (Math.random() * counter) | 0;

    // And swap the last element with it
    temp = this[counter];
    this[counter] = this[index];
    this[index] = temp;
  }

  return this;
};

Array.prototype.unique = function() {
  var a = this.slice(0);
  for (var i = 0; i < a.length; ++i) {
    for (var j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j])
        a.splice(j--, 1);
    }
  }
  return a;
};

Array.prototype.merge = function(array) {
  if (!Array.isArray(array)) {
    return false;
  }
  Array.prototype.push.apply(this, array);
  return this.unique();
};

Array.prototype.query = function query(queryObject) {
    return this;
};<commit_msg>clean up lib<commit_after>Array.prototype.equals = Array.prototype.compare = function equals(array) {
  if (!Array.isArray(array) || this.length !== array.length) {
    return false;
  }
  for (var i = 0; i < this.length; i++) {
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
      // recurse into the nested arrays
      if (!this[i].equals(array[i])) {
        return false;
      }
    } else if (this[i] !== array[i]) {
      return false;
    }
  }
  return true;
};

Array.prototype.toObject = function toObject() {
  var object = {};
  for (var i = 0; i < this.length; ++i) {
    if (this[i] !== undefined) {
      object[i] = this[i];
    }
  }
  return object;
};

Array.prototype.shuffle = function shuffle() {
  var counter = this.length,
    temp, index;

  // While there are elements in the array
  while (counter--) {
    // Pick a random index
    index = (Math.random() * counter) | 0;

    // And swap the last element with it
    temp = this[counter];
    this[counter] = this[index];
    this[index] = temp;
  }

  return this;
};

Array.prototype.unique = function() {
  var a = this.slice(0);
  for (var i = 0; i < a.length; ++i) {
    for (var j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j])
        a.splice(j--, 1);
    }
  }
  return a;
};

Array.prototype.merge = function(array) {
  if (!Array.isArray(array)) {
    return false;
  }
  Array.prototype.push.apply(this, array);
  return this.unique();
};<|endoftext|>


<commit_before>import React from 'react';
import { Switch } from 'react-router';
import { Route, Link } from 'react-router-dom';
import About from './About';
import NotFound from './NotFound';
import Posts from '../containers/Posts';

export default () => {
  return (

<Link to="/">Home</Link>

<Link to="/about">About</Link>

      <Switch>
        <Route exact path="/" components={Posts}/>
        <Route exact path="/about" component={About}/>
        <Route component={NotFound}/>
      </Switch>

  );
};
<commit_msg>Add redux<commit_after>import React from 'react';
import { Switch } from 'react-router';
import { Route, Link } from 'react-router-dom';
import About from './About';
import NotFound from './NotFound';
import Posts from '../containers/Posts';

export default () => {
  return (

<Link to="/">Home</Link>

<Link to="/about">About</Link>

      <Switch>
        <Route exact path="/" component={Posts}/>
        <Route exact path="/about" component={About}/>
        <Route component={NotFound}/>
      </Switch>

  );
};
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var path = require('path');
var join = path.join;
var extname = path.extname;
var dirname = path.dirname;
var basename = path.basename;
var relative = path.relative;
var util = require('util');
var colors = require('colors/safe');
var debug = require('debug')('gulp-cmd');

// The work cwd
var cwd = process.cwd();

// Set debug color use 6
debug.color = 6;

/**
 * Parse package form vinyl
 * @param vinyl
 * @param wwwroot
 * @returns {object}
 */
function parsePackage(vinyl, wwwroot){
  var relative = vinyl.relative;

  // vinyl not in base dir, user wwwroot
  if (isRelative(relative)) {
    relative = path.relative(wwwroot, vinyl.path);
    // vinyl not in wwwroot, throw error
    if (isRelative(relative)) {
      throwError('file: %s is out of bound of wwwroot: %s.', normalize(vinyl.path), normalize(wwwroot));
    }

    // reset relative
    relative = path.join('/', relative);
  }

  var dir = normalize(dirname(relative));
  var filename = basename(relative);
  var SPLITRE = /\/((?:\d+\.){2}\d+)(?:\/|$)/;
  var match = dir.split(SPLITRE);

  return {
    name: match[0] || '',
    version: match[1] || '',
    file: match[2] ? match[2] + '/' + filename : filename
  }
}

/**
 * Simple template
 * ```
 * var tpl = '{{name}}/{{version}}';
 * util.template(tpl, {name:'base', version: '1.0.0'});
 * ```
 */

function template(format, data){
  if (!is.string(format)) return '';

  return format.replace(/{{([a-z]*)}}/gi, function (all, match){
    return data[match] || '';
  });
}

/**
 * Create a plugin
 * @param name
 * @param transport
 * @returns {Function}
 */

function plugin(name, transport){
  return function (vinyl, options){
    // debug
    debug('load plugin: %s', colors.green(name));
    // debug
    debug('read file: %s', colors.magenta(pathFromCwd(vinyl.path)));

    vinyl = transport(vinyl, options);

    return vinyl;
  };
}

var PATHS_RE = /^([^/:]+)(\/.+)$/;
var VARS_RE = /{([^{]+)}/g;

/**
 * Parse alias
 * @param id
 * @param alias
 * @returns {*}
 */

function parseAlias(id, alias){
  alias = alias || {};

  return alias && is.string(alias[id]) ? alias[id] : id;
}

/**
 * Parse paths
 * @param id
 * @param paths
 * @returns {*}
 */

function parsePaths(id, paths){
  var match;

  paths = paths || {};

  if (paths && (match = id.match(PATHS_RE)) && is.string(paths[match[1]])) {
    id = paths[match[1]] + match[2];
  }

  return id;
}

/**
 * Parse vars
 * @param id
 * @param vars
 * @returns {*}
 */

function parseVars(id, vars){
  vars = vars || {};

  if (vars && id.indexOf('{') > -1) {
    id = id.replace(VARS_RE, function (match, key){
      return is.string(vars[key]) ? vars[key] : match;
    });
  }

  return id;
}

/**
 * Normalize path
 * @param path
 * @returns {string}
 */

function normalize(path){
  path = path.replace(/\\+/g, '/');
  path = path.replace(/([^:/])\/+\//g, '$1/');
  path = path.replace(/(:)?\/{2,}/, '$1//');

  return path;
}

/**
 * Resolve a `relative` path base on `base` path
 * @param relative
 * @param vinyl
 * @param wwwroot
 * @returns {string}
 */

function resolve(relative, vinyl, wwwroot){
  var base;
  var absolute;

  // debug
  debug('resolve path: %s', colors.magenta(normalize(relative)));

  // resolve
  if (isRelative(relative)) {
    base = dirname(vinyl.path);
    absolute = join(base, relative);

    // out of base, use wwwroot
    if (isOutBound(absolute, base)) {
      base = wwwroot;
      absolute = join(base, relative);

      // out of wwwroot
      if (isOutBound(absolute, base)) {
        throwError('file: %s is out of bound of wwwroot: %s.', normalize(absolute), normalize(base));
      }
    }
  } else if (isAbsolute(relative)) {
    base = wwwroot;
    absolute = join(base, relative.substring(1));
  } else {
    base = join(vinyl.cwd, vinyl.base);
    absolute = join(base, relative);
  }

  // debug
  debug('of base path: %s', colors.magenta(pathFromCwd(base)));
  debug('to: %s', colors.magenta(pathFromCwd(absolute)));

  return absolute;
}

/**
 * Hide .js if exists
 * @param path
 * @returns {*}
 */

function hideExt(path){
  return extname(path) === '.js' ? path.replace(/\.js$/, '') : path;
}

/**
 * Add .js if not exists
 * @param path
 * @returns {*}
 */

function addExt(path){
  return extname(path) === '.js' ? path : (path + '.js');
}

/**
 * Test path is relative path or not
 * @param path
 * @returns {boolean}
 */

function isRelative(path){
  return /^\.{1,2}[\\/]/.test(path);
}

/**
 * Test path is absolute path or not
 * @param path
 * @returns {boolean}
 */

function isAbsolute(path){
  return /^[\\/](?:[^\\/]+|$)/.test(path);
}

/**
 * Test path is local path or not
 * @param path
 * @returns {boolean}
 */

function isLocal(path){
  return !/^https?:\/\/|^\/\//.test(path) && !/^data:/.test(path);
}

/**
 * Test path is out of bound of base
 * @param path
 * @param base
 * @returns {boolean}
 */

function isOutBound(path, base){
  return /(?:^|[\\\/])\.\.(?:[\\\/]|$)/.test(relative(base, path));
}

/**
 * Get relative path from cwd
 * @param path
 * @returns {string}
 */

function pathFromCwd(path){
  return normalize(relative(cwd, path)) || './';
}

/**
 * Plugin error
 */

function throwError(){
  var slice = [].slice;
  var message = util.format
    .apply(null, slice.call(arguments));

  throw new Error(message);
}

/**
 * Node extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */

function extend(){
  var target = arguments[0] || {};
  var i = 1;
  var length = arguments.length;
  var deep = false;
  var options, name, src, copy, copy_is_array, clone;

  // handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !is.fn(target)) {
    target = {};
  }

  for (; i < length; i++) {
    // only deal with non-null/undefined values
    options = arguments[i];

    if (options !== null) {
      if (typeof options === 'string') {
        options = options.split('');
      }

      // extend the base object
      for (name in options) {
        if (options.hasOwnProperty(name)) {
          src = target[name];
          copy = options[name];

          // prevent never-ending loop
          if (target === copy) {
            continue;
          }

          // recurse if we're merging plain objects or arrays
          if (deep && copy && (is.hash(copy) || (copy_is_array = Array.isArray(copy)))) {
            if (copy_is_array) {
              copy_is_array = false;
              clone = src && Array.isArray(src) ? src : [];
            } else {
              clone = src && is.hash(src) ? src : {};
            }

            // never move original objects, clone them
            target[name] = extend(deep, clone, copy);

            // don't bring in undefined values
          } else if (typeof copy !== 'undefined') {
            target[name] = copy;
          }
        }
      }
    }
  }

  // return the modified object
  return target;
}

/**
 * Wrap module
 * @param id
 * @param deps
 * @param code
 * @returns {string}
 */

function wrapModule(id, deps, code){
  // header and footer template string
  var headerTpl = 'define({{id}}, {{deps}}, function(require, exports, module){';
  var footerTpl = '});\n\n';

  if (Buffer.isBuffer(code)) code = code.toString();

  // debug
  debug('compile module: %s', colors.magenta(id));

  id = JSON.stringify(id);
  deps = JSON.stringify(deps);

  return template(headerTpl, { id: id, deps: deps })
    + '\n' + code + '\n' + footerTpl;
}

/**
 * Exports module.
 */

module.exports.cwd = cwd;
module.exports.template = template;
module.exports.parsePackage = parsePackage;
module.exports.plugin = plugin;
module.exports.normalize = normalize;
module.exports.parseAlias = parseAlias;
module.exports.parsePaths = parsePaths;
module.exports.parseVars = parseVars;
module.exports.hideExt = hideExt;
module.exports.addExt = addExt;
module.exports.isRelative = isRelative;
module.exports.isAbsolute = isAbsolute;
module.exports.isLocal = isLocal;
module.exports.isOutBound = isOutBound;
module.exports.resolve = resolve;
module.exports.pathFromCwd = pathFromCwd;
module.exports.throwError = throwError;
module.exports.extend = extend;
module.exports.colors = colors;
module.exports.debug = debug;
module.exports.wrapModule = wrapModule;
<commit_msg>bug fixed<commit_after>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var path = require('path');
var join = path.join;
var extname = path.extname;
var dirname = path.dirname;
var basename = path.basename;
var relative = path.relative;
var util = require('util');
var colors = require('colors/safe');
var debug = require('debug')('gulp-cmd');

// The work cwd
var cwd = process.cwd();

// Set debug color use 6
debug.color = 6;

/**
 * Parse package form vinyl
 * @param vinyl
 * @param wwwroot
 * @returns {object}
 */
function parsePackage(vinyl, wwwroot){
  var relative = vinyl.relative;

  // vinyl not in base dir, user wwwroot
  if (isRelative(relative)) {
    relative = path.relative(wwwroot, vinyl.path);
    // vinyl not in wwwroot, throw error
    if (isRelative(relative)) {
      throwError('file: %s is out of bound of wwwroot: %s.', normalize(vinyl.path), normalize(wwwroot));
    }

    // reset relative
    relative = path.join('/', relative);
  }

  var dir = normalize(dirname(relative));
  var filename = basename(relative);
  var SPLITRE = /\/((?:\d+\.){2}\d+)(?:\/|$)/;
  var match = dir.split(SPLITRE);

  return {
    name: match[0] || '',
    version: match[1] || '',
    file: match[2] ? match[2] + '/' + filename : filename
  }
}

/**
 * Simple template
 * ```
 * var tpl = '{{name}}/{{version}}';
 * util.template(tpl, {name:'base', version: '1.0.0'});
 * ```
 */

function template(format, data){
  if (!is.string(format)) return '';

  return format.replace(/{{([a-z]*)}}/gi, function (all, match){
    return data[match] || '';
  });
}

/**
 * Create a plugin
 * @param name
 * @param transport
 * @returns {Function}
 */

function plugin(name, transport){
  return function (vinyl, options){
    // debug
    debug('load plugin: %s', colors.green(name));
    // debug
    debug('read file: %s', colors.magenta(pathFromCwd(vinyl.path)));

    vinyl = transport(vinyl, options);

    return vinyl;
  };
}

var PATHS_RE = /^([^/:]+)(\/.+)$/;
var VARS_RE = /{([^{]+)}/g;

/**
 * Parse alias
 * @param id
 * @param alias
 * @returns {*}
 */

function parseAlias(id, alias){
  alias = alias || {};

  return alias && is.string(alias[id]) ? alias[id] : id;
}

/**
 * Parse paths
 * @param id
 * @param paths
 * @returns {*}
 */

function parsePaths(id, paths){
  var match;

  paths = paths || {};

  if (paths && (match = id.match(PATHS_RE)) && is.string(paths[match[1]])) {
    id = paths[match[1]] + match[2];
  }

  return id;
}

/**
 * Parse vars
 * @param id
 * @param vars
 * @returns {*}
 */

function parseVars(id, vars){
  vars = vars || {};

  if (vars && id.indexOf('{') > -1) {
    id = id.replace(VARS_RE, function (match, key){
      return is.string(vars[key]) ? vars[key] : match;
    });
  }

  return id;
}

/**
 * Normalize path
 * @param path
 * @returns {string}
 */

function normalize(path){
  path = path.replace(/\\+/g, '/');
  path = path.replace(/([^:/])\/+\//g, '$1/');
  path = path.replace(/(:)?\/{2,}/, '$1//');

  return path;
}

/**
 * Resolve a `relative` path base on `base` path
 * @param relative
 * @param vinyl
 * @param wwwroot
 * @returns {string}
 */

function resolve(relative, vinyl, wwwroot){
  var base;
  var absolute;

  // debug
  debug('resolve path: %s', colors.magenta(normalize(relative)));

  // resolve
  if (isRelative(relative)) {
    base = dirname(vinyl.path);
    absolute = join(base, relative);

    // out of base, use wwwroot
    if (isOutBound(absolute, wwwroot)) {
      throwError('file: %s is out of bound of wwwroot: %s.', normalize(absolute), normalize(wwwroot));
    }
  } else if (isAbsolute(relative)) {
    base = wwwroot;
    absolute = join(base, relative.substring(1));
  } else {
    base = join(vinyl.cwd, vinyl.base);
    absolute = join(base, relative);
  }

  // debug
  debug('of base path: %s', colors.magenta(pathFromCwd(base)));
  debug('to: %s', colors.magenta(pathFromCwd(absolute)));

  return absolute;
}

/**
 * Hide .js if exists
 * @param path
 * @returns {*}
 */

function hideExt(path){
  return extname(path) === '.js' ? path.replace(/\.js$/, '') : path;
}

/**
 * Add .js if not exists
 * @param path
 * @returns {*}
 */

function addExt(path){
  return extname(path) === '.js' ? path : (path + '.js');
}

/**
 * Test path is relative path or not
 * @param path
 * @returns {boolean}
 */

function isRelative(path){
  return /^\.{1,2}[\\/]/.test(path);
}

/**
 * Test path is absolute path or not
 * @param path
 * @returns {boolean}
 */

function isAbsolute(path){
  return /^[\\/](?:[^\\/]+|$)/.test(path);
}

/**
 * Test path is local path or not
 * @param path
 * @returns {boolean}
 */

function isLocal(path){
  return !/^https?:\/\/|^\/\//.test(path) && !/^data:/.test(path);
}

/**
 * Test path is out of bound of base
 * @param path
 * @param base
 * @returns {boolean}
 */

function isOutBound(path, base){
  return /(?:^|[\\\/])\.\.(?:[\\\/]|$)/.test(relative(base, path));
}

/**
 * Get relative path from cwd
 * @param path
 * @returns {string}
 */

function pathFromCwd(path){
  return normalize(relative(cwd, path)) || './';
}

/**
 * Plugin error
 */

function throwError(){
  var slice = [].slice;
  var message = util.format
    .apply(null, slice.call(arguments));

  throw new Error(message);
}

/**
 * Node extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */

function extend(){
  var target = arguments[0] || {};
  var i = 1;
  var length = arguments.length;
  var deep = false;
  var options, name, src, copy, copy_is_array, clone;

  // handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !is.fn(target)) {
    target = {};
  }

  for (; i < length; i++) {
    // only deal with non-null/undefined values
    options = arguments[i];

    if (options !== null) {
      if (typeof options === 'string') {
        options = options.split('');
      }

      // extend the base object
      for (name in options) {
        if (options.hasOwnProperty(name)) {
          src = target[name];
          copy = options[name];

          // prevent never-ending loop
          if (target === copy) {
            continue;
          }

          // recurse if we're merging plain objects or arrays
          if (deep && copy && (is.hash(copy) || (copy_is_array = Array.isArray(copy)))) {
            if (copy_is_array) {
              copy_is_array = false;
              clone = src && Array.isArray(src) ? src : [];
            } else {
              clone = src && is.hash(src) ? src : {};
            }

            // never move original objects, clone them
            target[name] = extend(deep, clone, copy);

            // don't bring in undefined values
          } else if (typeof copy !== 'undefined') {
            target[name] = copy;
          }
        }
      }
    }
  }

  // return the modified object
  return target;
}

/**
 * Wrap module
 * @param id
 * @param deps
 * @param code
 * @returns {string}
 */

function wrapModule(id, deps, code){
  // header and footer template string
  var headerTpl = 'define({{id}}, {{deps}}, function(require, exports, module){';
  var footerTpl = '});\n\n';

  if (Buffer.isBuffer(code)) code = code.toString();

  // debug
  debug('compile module: %s', colors.magenta(id));

  id = JSON.stringify(id);
  deps = JSON.stringify(deps);

  return template(headerTpl, { id: id, deps: deps })
    + '\n' + code + '\n' + footerTpl;
}

/**
 * Exports module.
 */

module.exports.cwd = cwd;
module.exports.template = template;
module.exports.parsePackage = parsePackage;
module.exports.plugin = plugin;
module.exports.normalize = normalize;
module.exports.parseAlias = parseAlias;
module.exports.parsePaths = parsePaths;
module.exports.parseVars = parseVars;
module.exports.hideExt = hideExt;
module.exports.addExt = addExt;
module.exports.isRelative = isRelative;
module.exports.isAbsolute = isAbsolute;
module.exports.isLocal = isLocal;
module.exports.isOutBound = isOutBound;
module.exports.resolve = resolve;
module.exports.pathFromCwd = pathFromCwd;
module.exports.throwError = throwError;
module.exports.extend = extend;
module.exports.colors = colors;
module.exports.debug = debug;
module.exports.wrapModule = wrapModule;
<|endoftext|>