<commit_before>(function($) {

	// default settings
	var settings = {
		background_color: '#003B62',
		position: 'top',
		content_class: 'messagebar-content-default',
		content_id: 'messagebar-content',
		shadow: true,
		message_types: {
			info: {barClass: 'messagebar-info', contentClass: 'messagebar-content-info'},
			error: {barClass: 'messagebar-error', contentClass: 'messagebar-content-error'},
		}
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Public API
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
	var api = {
		init: function(options) {
			// summary:
			//			create the message bar
			// options: Object
			//			Options used to configure the message bar
			//			background_color: String
			//					the background color of the message bar
			//			position: String
			//					the position of the message bar, either "top" or "bottom"
			//			content_class: String
			//					the CSS class to apply to the content of the message bar
			//			content_id: String
			//					the DOM id of the element that will contain the message bar content
			//			shadow: Boolean
			//					true to add a drop shadow to the message bar (only applied if position is "top")
			//			message_types: Object
			//					define message types and associate CSS classes for the bar and content elements when a message
			//					of a particular type is displayed. (see the default settings).
			return this.each(function() {
				console.log("messagebar#init -- invoked");

				var opts = $.extend({}, settings, options);

				var $this = $(this),
				data = $this.data('messagebar');

				if (!data) {
					// create the elements
					var bar = createBar(opts),
					content = createContent(opts),
					navigation = createNavigation(opts),
					upArrow = $('div', navigation).first(),
					downArrow = $('div', navigation).last();

					// add listeners
					bar.bind('click.messagebar', {plugin: $this}, handleMessageBarClick);
					upArrow.bind('click.messagebar', {plugin: $this}, handleNavigationUpClick);
					downArrow.bind('click.messagebar', {plugin: $this}, handleNavigationDownClick);

					// add to DOM
					$this.prepend(bar);
					bar.append(navigation).append(content);

					// initialize data
					$this.data('messagebar', {
						messages: [],
						index: 0,
						opts: opts,
						showing: false
					});
				}
			});
		},

		isShowing: function() {
			// summary:
			//			is the message bar being shown or not
			// return: Boolean
			//			true if the message bar is being shown, false if it is not
			var data = this.data('messagebar');
			if (data && typeof(data.showing) === 'boolean') {
				return data.showing;
			}
			return false;
		},

		show: function() {
			// summary:
			// 			show the message bar
			return this.each(function() {
				var data = $(this).data('messagebar');
			        bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last(),
				msgCount = data.messages.length;

				// always showing the most recent message so hide the 'up' arrow to start with
				toggleArrow(upArrow, true, true);

				// show the most recent message
				if (msgCount > 0) {
					// show the 'down' arrow when there are messages
					toggleArrow(downArrow, false, msgCount <= 1);

					displayMessage(data.messages[data.index], data.opts, this, bar, content);
				}
				else {
				        // hide the down arrow if there are no messages
					toggleArrow(downArrow, false, true);

					// reset the styles on the bar and content elements
					restoreBarStyle(this, data.opts);
					restoreContentStyle(this, data.opts);
					content.text('');
				}

				if (!data.showing) {
				        bar.fadeIn('fast');
				        data.showing = true;
				}
			});
		},

		hide: function(clearMessages) {
			// summary:
			// 			hide the message bar, optionally clear the messages
			// clearMessages: Boolean
			//			true to clear the messages, false otherwise
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar');

				// clear the messages
				if (clearMessages === true) {
					$this.messagebar('clearMessages');
				}

				if (data.showing) {
					$(".messagebar", this).fadeOut('fast');
					data.showing = false;
				}
			});
		},

		addMessage: function(message, type) {
			// summary:
			// 			add a message to the message bar
			// message: String
			//			the message to add
			// type: String
			//			the type of message (should be based on the 'message_types' defined during configuration)
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar');

				// the first message in the array is always the newest
				data.messages.unshift(createMessage(message, type));

				// change the index b/c we always want to view the most recent message
				data.index = 0;
			});
		},

		clearMessages: function() {
			// summary:
			//			clear the messages
			return this.each(function() {
				$(this).data('messagebar').messages.length = 0;
			});
		},

		showNext: function() {
			// summary:
			//			show the next message, if available
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar'),
				messages = data.messages,
				msgCount = messages.length,
				index = data.index,
				bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last();

				if (index < (msgCount - 1)) {
					// show up arrow
					toggleArrow(upArrow, true, false);

					// increment
					index += 1;

					// show the message
					displayMessage(messages[index], data.opts, this, bar, content);

					// update pointer
					data.index = index;

					// check to see if we're at the end
					if (index === (msgCount - 1)) {
						// hide the 'down'/'next' arrow
						toggleArrow(downArrow, false, true);
					}
				}
			});
		},

		showPrevious: function() {
			// summary:
			//			show the previous message, if available
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar'),
				messages = data.messages,
				msgCount = messages.length,
				index = data.index,
				bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last();

				if (index > 0) {
					// show down arrow
					toggleArrow(downArrow, false, false);

					// decrement
					index -= 1;

					// show the message
					displayMessage(messages[index], data.opts, this, bar, content);

					// update pointer
					data.index = index;

					// check to see if we're at the beginning
					if (index === 0) {
						// hide the 'up'/'previous' arrow
						toggleArrow(upArrow, true, true);
					}
				}
			});
		}
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Internal Methods
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
	var createBar = function(settings) {
		return setBarDefaultStyle($('
'), settings);
	};

	var setBarDefaultStyle = function(barEl, settings) {
		var classes = ['messagebar', 'messagebar-' + settings.position, settings.content_class];
		if (settings.shadow && settings.position == 'top') {
			classes.push('messagebar-shadow');
		}

		return barEl.attr('class', classes.join(' ')).css({"background-color": settings.background_color});
	};

	var restoreBarStyle = function(pluginEl, settings) {
		setBarDefaultStyle($('.messagebar', pluginEl), settings);
	};

	var createContent = function(settings) {
		return setContentDefaultStyle($("").attr('id', settings.content_id), settings);
	};

	var setContentDefaultStyle = function(contentEl, settings) {
		return contentEl.attr('class', 'messagebar-content ' + settings.content_class);
	};

	var restoreContentStyle = function(pluginEl, settings) {
		setContentDefaultStyle($('#' + settings.content_id, pluginEl), settings);
	};

	var createNavigation = function(settings) {
		var container = $('
');
		container.addClass("messagebar-navigation messagebar-navigation-" + settings.position);
		container.append('
').append('
');
		return container;
	};

	var createMessage = function(message, messageType) {
		return (function() {
			var msg = message,
			type = messageType;

			return {
				content: function() {
					return msg;
				},

				type: function() {
					return type;
				}
			};
		})();
	};

	var displayMessage = function(message, settings, jqPluginEl, jqBarEl, jqContentEl) {
		// summary:
		//			perform all the work to display a message
		// message: Object
		//			the message to display
		// settings: Object
		//			the plugin options/settings
		// jqPluginEl: jQuery element
		//			the element that the message bar plugin is attached to
		// jqBarEl: jQuery element
		//			the message bar element
		// jqContentEl: jQuery element
		//			the element that contains the content

		// lookup the config (from message_types)
		var msg_type_config  = settings.message_types[message.type()],
		// get the css class references for the bar and content elements
		barClass = msg_type_config.barClass,
		contentClass = msg_type_config.contentClass;

		// reset the styles on the bar and content elements
		restoreBarStyle(jqPluginEl, settings);
		restoreContentStyle(jqPluginEl, settings);

		jqBarEl.addClass(barClass);
		jqContentEl.addClass(contentClass).text(message.content());
	};

	var toggleArrow = function(arrow, up, hide) {
		// summary:
		//			hide or show an arrow
		// arrow: jQuery element
		// up: Boolean
		//			true if working with the up arrow, false if working with the down arrow
		// hide: Boolean
		//			true to hide the arrow, false to show it
		if (arrow) {
			var base = 'messagebar-arrow-' + (up ? 'up' : 'down');
			if (hide) {
				arrow.attr('class', base + ' ' + base + '-hidden');
			}
			else {
				arrow.attr('class', base);
			}
		}
	};

	var handleMessageBarClick = function(event) {
		var plugin = event.data.plugin;

		// hide the message bar
		$(plugin).messagebar('hide', true);
	};

	var handleNavigationUpClick = function(event) {
		event.stopPropagation();
		if ($(event.target).attr('class').match(/hidden/i)) {
			// if the arrow is 'hidden' then don't do anything
			return;
		}

		var plugin = event.data.plugin;
		$(plugin).messagebar('showPrevious');
	};

	var handleNavigationDownClick = function(event) {
		event.stopPropagation();
		if ($(event.target).attr('class').match(/hidden/i)) {
			// if the arrow is 'hidden' then don't do anything
			return;
		}
		var plugin = event.data.plugin;
		$(plugin).messagebar('showNext');
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Plugin Definition
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
    $.fn.messagebar = function(method) {

		// Method calling logic
		if ( api[method] ) {
			return api[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return api.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.messagebar' );
		}

    };
})(jQuery);<commit_msg>Edited lib/jquery.messagebar.js via Github, refactored the show/hide arrow stuff to make it a bit cleaner to use instead of having to know what the different flags were (just an internal plugin refactoring actually).<commit_after>(function($) {

	// default settings
	var settings = {
		background_color: '#003B62',
		position: 'top',
		content_class: 'messagebar-content-default',
		content_id: 'messagebar-content',
		shadow: true,
		message_types: {
			info: {barClass: 'messagebar-info', contentClass: 'messagebar-content-info'},
			error: {barClass: 'messagebar-error', contentClass: 'messagebar-content-error'},
		}
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Public API
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
	var api = {
		init: function(options) {
			// summary:
			//			create the message bar
			// options: Object
			//			Options used to configure the message bar
			//			background_color: String
			//					the background color of the message bar
			//			position: String
			//					the position of the message bar, either "top" or "bottom"
			//			content_class: String
			//					the CSS class to apply to the content of the message bar
			//			content_id: String
			//					the DOM id of the element that will contain the message bar content
			//			shadow: Boolean
			//					true to add a drop shadow to the message bar (only applied if position is "top")
			//			message_types: Object
			//					define message types and associate CSS classes for the bar and content elements when a message
			//					of a particular type is displayed. (see the default settings).
			return this.each(function() {
				console.log("messagebar#init -- invoked");

				var opts = $.extend({}, settings, options);

				var $this = $(this),
				data = $this.data('messagebar');

				if (!data) {
					// create the elements
					var bar = createBar(opts),
					content = createContent(opts),
					navigation = createNavigation(opts),
					upArrow = $('div', navigation).first(),
					downArrow = $('div', navigation).last();

					// add listeners
					bar.bind('click.messagebar', {plugin: $this}, handleMessageBarClick);
					upArrow.bind('click.messagebar', {plugin: $this}, handleNavigationUpClick);
					downArrow.bind('click.messagebar', {plugin: $this}, handleNavigationDownClick);

					// add to DOM
					$this.prepend(bar);
					bar.append(navigation).append(content);

					// initialize data
					$this.data('messagebar', {
						messages: [],
						index: 0,
						opts: opts,
						showing: false
					});
				}
			});
		},

		isShowing: function() {
			// summary:
			//			is the message bar being shown or not
			// return: Boolean
			//			true if the message bar is being shown, false if it is not
			var data = this.data('messagebar');
			if (data && typeof(data.showing) === 'boolean') {
				return data.showing;
			}
			return false;
		},

		show: function() {
			// summary:
			// 			show the message bar
			return this.each(function() {
				var data = $(this).data('messagebar');
				var bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last(),
				msgCount = data.messages.length;

				// always showing the most recent message so hide the 'up' arrow to start with
				hideArrow(upArrow);

				// show the most recent message
				if (msgCount > 0) {
					// show the 'down' arrow when there are messages
					(msgCount > 1 ? showArrow(downArrow) : hideArrow(downArrow));

					displayMessage(data.messages[data.index], data.opts, this, bar, content);
				}
				else {
					// hide the down arrow if there are no messages
					hideArrow(downArrow);

					// reset the styles on the bar and content elements
					restoreBarStyle(this, data.opts);
					restoreContentStyle(this, data.opts);
					content.text('');
				}

				if (!data.showing) {
					bar.fadeIn('fast');
					data.showing = true;
				}
			});
		},

		hide: function(clearMessages) {
			// summary:
			// 			hide the message bar, optionally clear the messages
			// clearMessages: Boolean
			//			true to clear the messages, false otherwise
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar');

				// clear the messages
				if (clearMessages === true) {
					$this.messagebar('clearMessages');
				}

				if (data.showing) {
					$(".messagebar", this).fadeOut('fast');
					data.showing = false;
				}
			});
		},

		addMessage: function(message, type) {
			// summary:
			// 			add a message to the message bar
			// message: String
			//			the message to add
			// type: String
			//			the type of message (should be based on the 'message_types' defined during configuration)
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar');

				// the first message in the array is always the newest
				data.messages.unshift(createMessage(message, type));

				// change the index b/c we always want to view the most recent message
				data.index = 0;
			});
		},

		clearMessages: function() {
			// summary:
			//			clear the messages
			return this.each(function() {
				$(this).data('messagebar').messages.length = 0;
			});
		},

		showNext: function() {
			// summary:
			//			show the next message, if available
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar'),
				messages = data.messages,
				msgCount = messages.length,
				index = data.index,
				bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last();

				if (index < (msgCount - 1)) {
					// show up arrow
					showArrow(upArrow);

					// increment
					index += 1;

					// show the message
					displayMessage(messages[index], data.opts, this, bar, content);

					// update pointer
					data.index = index;

					// check to see if we're at the end
					if (index === (msgCount - 1)) {
						// hide the 'down'/'next' arrow
						hideArrow(downArrow);
					}
				}
			});
		},

		showPrevious: function() {
			// summary:
			//			show the previous message, if available
			return this.each(function() {
				var $this = $(this),
				data = $this.data('messagebar'),
				messages = data.messages,
				msgCount = messages.length,
				index = data.index,
				bar = $('.messagebar', this),
				content = $('#' + data.opts.content_id, this),
				upArrow = $('.messagebar-navigation div', this).first(),
				downArrow = $('.messagebar-navigation div', this).last();

				if (index > 0) {
					// show down arrow
					showArrow(downArrow);

					// decrement
					index -= 1;

					// show the message
					displayMessage(messages[index], data.opts, this, bar, content);

					// update pointer
					data.index = index;

					// check to see if we're at the beginning
					if (index === 0) {
						// hide the 'up'/'previous' arrow
						hideArrow(upArrow);
					}
				}
			});
		}
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Internal Methods
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
	var createBar = function(settings) {
		return setBarDefaultStyle($('
'), settings);
	};

	var setBarDefaultStyle = function(barEl, settings) {
		var classes = ['messagebar', 'messagebar-' + settings.position, settings.content_class];
		if (settings.shadow && settings.position == 'top') {
			classes.push('messagebar-shadow');
		}

		return barEl.attr('class', classes.join(' ')).css({"background-color": settings.background_color});
	};

	var restoreBarStyle = function(pluginEl, settings) {
		setBarDefaultStyle($('.messagebar', pluginEl), settings);
	};

	var createContent = function(settings) {
		return setContentDefaultStyle($("").attr('id', settings.content_id), settings);
	};

	var setContentDefaultStyle = function(contentEl, settings) {
		return contentEl.attr('class', 'messagebar-content ' + settings.content_class);
	};

	var restoreContentStyle = function(pluginEl, settings) {
		setContentDefaultStyle($('#' + settings.content_id, pluginEl), settings);
	};

	var createNavigation = function(settings) {
		var container = $('
');
		container.addClass("messagebar-navigation messagebar-navigation-" + settings.position);
		container.append('
').append('
');
		return container;
	};

	var createMessage = function(message, messageType) {
		return (function() {
			var msg = message,
			type = messageType;

			return {
				content: function() {
					return msg;
				},

				type: function() {
					return type;
				}
			};
		})();
	};

	var displayMessage = function(message, settings, jqPluginEl, jqBarEl, jqContentEl) {
		// summary:
		//			perform all the work to display a message
		// message: Object
		//			the message to display
		// settings: Object
		//			the plugin options/settings
		// jqPluginEl: jQuery element
		//			the element that the message bar plugin is attached to
		// jqBarEl: jQuery element
		//			the message bar element
		// jqContentEl: jQuery element
		//			the element that contains the content

		// lookup the config (from message_types)
		var msg_type_config  = settings.message_types[message.type()],
		// get the css class references for the bar and content elements
		barClass = msg_type_config.barClass,
		contentClass = msg_type_config.contentClass;

		// reset the styles on the bar and content elements
		restoreBarStyle(jqPluginEl, settings);
		restoreContentStyle(jqPluginEl, settings);

		jqBarEl.addClass(barClass);
		jqContentEl.addClass(contentClass).text(message.content());
	};

	var _toggleArrow = function(arrow, up, hide) {
		// summary:
		//			hide or show an arrow
		// arrow: jQuery element
		// up: Boolean
		//			true if working with the up arrow, false if working with the down arrow
		// hide: Boolean
		//			true to hide the arrow, false to show it
		if (arrow) {
			var base = 'messagebar-arrow-' + (up ? 'up' : 'down');
			if (hide) {
				arrow.attr('class', base + ' ' + base + '-hidden');
			}
			else {
				arrow.attr('class', base);
			}
		}
	};

	var showArrow = function(arrow) {
		var isUpArrow = !!arrow.attr('class').match(/up/i);
		_toggleArrow(arrow, isUpArrow, false);
	};

	var hideArrow = function(arrow) {
		var isUpArrow = !!arrow.attr('class').match(/up/i);
		_toggleArrow(arrow, isUpArrow, true);
	};

	var handleMessageBarClick = function(event) {
		var plugin = event.data.plugin;

		// hide the message bar
		$(plugin).messagebar('hide', true);
	};

	var handleNavigationUpClick = function(event) {
		event.stopPropagation();
		if ($(event.target).attr('class').match(/hidden/i)) {
			// if the arrow is 'hidden' then don't do anything
			return;
		}

		var plugin = event.data.plugin;
		$(plugin).messagebar('showPrevious');
	};

	var handleNavigationDownClick = function(event) {
		event.stopPropagation();
		if ($(event.target).attr('class').match(/hidden/i)) {
			// if the arrow is 'hidden' then don't do anything
			return;
		}
		var plugin = event.data.plugin;
		$(plugin).messagebar('showNext');
	};

	/*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* Plugin Definition
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*/
    $.fn.messagebar = function(method) {

		// Method calling logic
		if ( api[method] ) {
			return api[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return api.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.messagebar' );
		}

    };
})(jQuery);<|endoftext|>


<commit_before>'use strict';
//GLOBALS
var mainContainer,
    boardContainer,
    board,
    boardId         = 'board',
    boardContainerID= 'boardCont',
    currentLvl      = 3, // 3 is the starting level
    tilesCounter    = 1, //Counter to hold the revealed answers
    levelBonus      = 5, //holds the points that will be added if the level succeeds
    cellSize        = 50,
    pointsForCorrectAnswer  = 10,
    wasLevelCleared         = true,
    minRowsSize     = 2,
    minCellsSize    = 2,
    initCellsSize   = 3,
    initRowsSize    = 3,
    maxRowsSize     = 6,
    maxCellsSize    = 6,
    boardPadding    = 60,
    answers         = '',
    trials          = 15, //how many trials user has
    score           = 0, //user score
    beforeHideCellsTimeout  = 2000,
    correctAnswerTimeout    = 600,
    board = null,
    popup = null;

var boardDimArray = [[2, 2], [2, 2], [3, 3], [4, 3], [4, 4], [5, 4], [5, 5], [6, 5], [6, 6]];

var MESSAGES = {
    levelLost: 'Sorry, you missed!\nTry again with less tiles!',
    tileSucess: 'You hit it right! Guess the next tile!',
    levelSuccess: 'Congratulations! You won another level.\nTry with more tiles!',
    guess: 'Guess the next tile!',
    gameOver: 'GAME OVER!\n Your score is: '
}

var ScoreBoardElement = function (imgURL, content, val) {
    this.imgURL = imgURL;
    this.content = content;
    this.val = val;
}

function getLvl() {
    return currentLvl;
}

function createBackground() {
    mainContainer = document.createElement('main');
    mainContainer.id = 'main-container';

    document.body.appendChild(mainContainer);
}

function createScoreBoard() {
    var scoreBoard = document.createElement('div');
    scoreBoard.id = 'score-board';
    mainContainer.appendChild(scoreBoard);
    var scoreBoardList = document.createElement('ul');
    scoreBoard.appendChild(scoreBoardList);

    var categories = [new ScoreBoardElement('', 'Tiles', getLvl()),
        new ScoreBoardElement('', 'Trials', trials),
        new ScoreBoardElement('', 'Score', score)];

    var categoriesSize = categories.length;
    for (var i = 0; i < categoriesSize; i++) {
        var li = document.createElement('li');
        li.className = 'score-board-element';
        li.innerText = categories[i].content;
        li.textContent = categories[i].content;
        scoreBoardList.appendChild(li);

        var sp = document.createElement('span');
        sp.className = 'score-board-value';
        sp.id = categories[i].content;
        sp.innerText = categories[i].val;
        sp.textContent = categories[i].val;
        li.appendChild(sp);
    }
}

function addPoints(tilePts, levelPts) {
    //increases the score by given amount of points passed as parameters
    levelPts = levelPts || 0;
    var scoreSpan = document.getElementById('Score');

    var score = scoreSpan.innerText || scoreSpan.textContent;
    score = parseInt(score) + parseInt(tilePts) + parseInt(levelPts);
    scoreSpan.innerText = score;
    scoreSpan.textContent = score;
}
function updateLevelBonus(direction) {
    switch (direction) {
        case 'down':
            if (levelBonus <= 5) { break; }
            else { levelBonus /= 2; }
            break;
        case 'up':
            levelBonus *= 2;
            break;
    }
}
function getUserClick(event) {
    // This function handles the player click
    var element = event.target;
    var selectedCellID = element.getAttribute('id');
    var isClicked = (element.getAttribute('data-is-clicked'))? true : false;
    if (element.getAttribute('data-is-true') && !isClicked) {
        var currLevel = getLvl();
        if (tilesCounter < currLevel) {
            element.setAttribute('data-is-clicked', 'true');
            tilesCounter++;
            addPoints(pointsForCorrectAnswer);
            element.setAttribute('data-is-true', 'false');

        } else if (tilesCounter == currLevel) {
            element.setAttribute('data-is-clicked', 'true');
            updateInfobox(MESSAGES.levelSuccess);
            wasLevelCleared = true;
            addPoints(pointsForCorrectAnswer, levelBonus);
            element.setAttribute('data-is-true', 'false');
            prepAndShowInfoForNextLvl();
            updateLevelBonus('up');
        }
    } else if(isClicked) {
        return;
    }else{
        element.classList.add('incorrectAnswer');
        setTimeout(function(){
            updateInfobox(MESSAGES.levelLost);
            wasLevelCleared = false;
            prepAndShowInfoForNextLvl();
        }, 500);
    }

}

function goToNextLvl() {
    if(trials) {
        //update trials in scoreboard
        trials--;
        document.getElementById('Trials').innerHTML = trials;

        //update Tiles in scoreboard
        document.getElementById('Tiles').innerHTML = getLvl();

        //clear counter
        tilesCounter = 1;

        //generate new board => Chech which is the current level and calc the board cells and rows
        var currLvl = getLvl();
        var board = (currLvl <= boardDimArray.length) ? (currLvl - 1) : (boardDimArray.length - 1);

        // Invokes "createBoard(cells, rows)" by giving in the correct number of cells and rows
        createBoard(boardDimArray[board][0], boardDimArray[board][1]);
    } else {
        //GAME OVER - no more trials. Function for displaying GAME OVER Screen here
        alert(MESSAGES.gameOver + score + '!');
    }
}

function updatePopupSize(width, height) {
    if(popup)  {
        width = width || board.offsetWidth;
        height = height || board.offsetHeight;

        popup.style.width = width + 'px';
        popup.style.height = height + 'px';
        popup.style.left = -(width/2) + 'px';
    }
}

function updateBoardAndPopupSizes(cells, rows) {
    var width = (cells * cellSize) + boardPadding;
    var height = (rows * cellSize) + boardPadding;
    board.style.width = width  + 'px';
    board.style.height = height + 'px';

    updatePopupSize(width, height);
}

function createBoard(cells, rows) {
    if (cells) {
        cells = ((cells) && (cells > minCellsSize)) ? ((cells < maxCellsSize) ? cells : maxCellsSize) : minCellsSize;
    } else {
        cells = initCellsSize;
    }
    if (rows) {
        rows = ((rows) && (rows > minRowsSize)) ? ((rows < maxRowsSize) ? rows : maxRowsSize) : minRowsSize;
    } else {
        rows = initRowsSize;
    }

    if (!board) {
        boardContainer = document.createElement('div');
        boardContainer.id = boardContainerID;
        mainContainer.appendChild(boardContainer);

        board = document.createElement('div');
        board.id = boardId;
        boardContainer.appendChild(board);
    }

    board.innerHTML = '';

    updateBoardAndPopupSizes(cells, rows);

    setTimeout(function () {
        for (var i = 1; i <= rows; i++) {
            var row = document.createElement('div');
            row.setAttribute('id', 'row' + i);
            row.className = 'row';
            for (var j = 1; j <= cells; j++) {
                var cell = document.createElement('div');
                cell.setAttribute('id', 'cell' + i + j);
                cell.className = 'cell';
                row.appendChild(cell);
            }
            board.appendChild(row);
        }
        assignCorrectAnswers(getLvl());
    }, correctAnswerTimeout);
}

function createInfoBox() {
    var infobox = document.createElement('div');
    infobox.id = 'infobox';
    mainContainer.appendChild(infobox);
}

function updateInfobox(occasion) {
    var infobox = document.getElementById('infobox');
    infobox.innerText = occasion;
    infobox.textContent = occasion;
}

function assignCorrectAnswers(level) {

    var assignedIndexes = [],
        selectedCells = [],
        cellsArray = document.getElementsByClassName('cell'),
        canContinue = true;

    var getRandomNumber = function () {
        return Math.floor(Math.random() * cellsArray.length)
    }

    for (var i = 0; i < level; i++) {
        canContinue = true;

        while (canContinue) {
            var randomCellIndex = getRandomNumber();
            if (assignedIndexes.indexOf(randomCellIndex) == -1) {
                var cellElement = cellsArray[randomCellIndex];
                selectedCells.push(cellElement);
                cellElement.setAttribute('data-is-true', 'true');
                assignedIndexes.push(randomCellIndex);
                canContinue = false;
            }
        }
    }

    answers = (answers != '') ? answers : '';
    answers = assignedIndexes.toString();

    //show the pattern to player
    for (var i = 0; i < selectedCells.length; i++) {
        selectedCells[i].classList.add('openAnswer');
    }

    //hide the pattern and assign onClick event listener
    setTimeout(function () {
        hidePattern(selectedCells);
    }, beforeHideCellsTimeout);
}

function hidePattern(selectedCellsPattern) {
    for (var i = 0; i < selectedCellsPattern.length; i++) {
        selectedCellsPattern[i].classList.remove('openAnswer');
    }

    for (var i = 0; i < document.getElementsByClassName('cell').length; i++) {
        document.getElementsByClassName('cell')[i].addEventListener('click', getUserClick.bind(this), false);
    }
    updateInfobox(MESSAGES.guess);
}

function closePopup() {
    popup.classList.remove('opened');
    goToNextLvl();
}

function updateCurrentLvl() {
    if (wasLevelCleared === true) {
        currentLvl++;
    } else if (currentLvl > 1) {
        currentLvl--;
    }
}

function prepAndShowInfoForNextLvl() {
    var msg = document.getElementById('infoDialogTxt');
    if(!popup) {
        popup = document.createElement('div');
        msg = document.createElement('span');
        msg.id = 'infoDialogTxt';

        popup.setAttribute('id', 'popup');
        popup.addEventListener('click', closePopup, false);
        boardContainer.appendChild(popup);
        popup.appendChild(msg);
    }

    updateCurrentLvl();

    var msgText = '';
    if(wasLevelCleared) {
        msgText += 'Points: +' + levelBonus + '<br />';
    }
    msgText += 'Next: ' + getLvl() + ' tiles';
    msg.innerHTML = msgText;

    popup.classList.add('opened');
    updatePopupSize();
}

createBackground();
createScoreBoard();
createBoard();
createInfoBox();<commit_msg>small fixes JSHint<commit_after>'use strict';
//GLOBALS
var mainContainer,
    boardContainer,
    board,
    boardId = 'board',
    boardContainerID = 'boardCont',
    currentLvl = 3, // 3 is the starting level
    tilesCounter = 1, //Counter to hold the revealed answers
    levelBonus = 5, //holds the points that will be added if the level succeeds
    cellSize = 50,
    pointsForCorrectAnswer = 10,
    wasLevelCleared = true,
    minRowsSize = 2,
    minCellsSize = 2,
    initCellsSize = 3,
    initRowsSize = 3,
    maxRowsSize = 6,
    maxCellsSize = 6,
    boardPadding = 60,
    answers = '',
    trials = 15, //how many trials user has
    score = 0, //user score
    beforeHideCellsTimeout = 2000,
    correctAnswerTimeout = 600,
    board = null,
    popup = null;

var boardDimArray = [[2, 2], [2, 2], [3, 3], [4, 3], [4, 4], [5, 4], [5, 5], [6, 5], [6, 6]];

var MESSAGES = {
    levelLost: 'Sorry, you missed!\nTry again with less tiles!',
    tileSucess: 'You hit it right! Guess the next tile!',
    levelSuccess: 'Congratulations! You won another level.\nTry with more tiles!',
    guess: 'Guess the next tile!',
    gameOver: 'GAME OVER!\n Your score is: '
};

var ScoreBoardElement = function (imgURL, content, val) {
    this.imgURL = imgURL;
    this.content = content;
    this.val = val;
};

function getLvl() {
    return currentLvl;
}

function createBackground() {
    mainContainer = document.createElement('main');
    mainContainer.id = 'main-container';

    document.body.appendChild(mainContainer);
}

function createScoreBoard() {
    var scoreBoard = document.createElement('div');
    scoreBoard.id = 'score-board';
    mainContainer.appendChild(scoreBoard);
    var scoreBoardList = document.createElement('ul');
    scoreBoard.appendChild(scoreBoardList);

    var categories = [new ScoreBoardElement('', 'Tiles', getLvl()),
        new ScoreBoardElement('', 'Trials', trials),
        new ScoreBoardElement('', 'Score', score)];

    var categoriesSize = categories.length;
    for (var i = 0; i < categoriesSize; i++) {
        var li = document.createElement('li');
        li.className = 'score-board-element';
        li.innerText = categories[i].content;
        li.textContent = categories[i].content;
        scoreBoardList.appendChild(li);

        var sp = document.createElement('span');
        sp.className = 'score-board-value';
        sp.id = categories[i].content;
        sp.innerText = categories[i].val;
        sp.textContent = categories[i].val;
        li.appendChild(sp);
    }
}

function addPoints(tilePts, levelPts) {
    //increases the score by given amount of points passed as parameters
    levelPts = levelPts || 0;
    var scoreSpan = document.getElementById('Score');

    var score = scoreSpan.innerText || scoreSpan.textContent;
    score = parseInt(score) + parseInt(tilePts) + parseInt(levelPts);
    scoreSpan.innerText = score;
    scoreSpan.textContent = score;
}
function updateLevelBonus(direction) {
    switch (direction) {
        case 'down':
            if (levelBonus <= 5) {
                break;
            } else { levelBonus /= 2; }
            break;
        case 'up':
            levelBonus *= 2;
            break;
    }
}
function getUserClick(event) {
    // This function handles the player click
    var element = event.target;
    // var selectedCellID = element.getAttribute('id');
    var isClicked = (element.getAttribute('data-is-clicked')) ? true : false;
    if (element.getAttribute('data-is-true') && !isClicked) {
        var currLevel = getLvl();
        if (tilesCounter < currLevel) {
            element.setAttribute('data-is-clicked', 'true');
            tilesCounter++;
            addPoints(pointsForCorrectAnswer);
            element.setAttribute('data-is-true', 'false');

        } else if (tilesCounter === currLevel) {
            element.setAttribute('data-is-clicked', 'true');
            updateInfobox(MESSAGES.levelSuccess);
            wasLevelCleared = true;
            addPoints(pointsForCorrectAnswer, levelBonus);
            element.setAttribute('data-is-true', 'false');
            prepAndShowInfoForNextLvl();
            updateLevelBonus('up');
        }
    } else if (isClicked) {
        return;
    } else {
        element.classList.add('incorrectAnswer');
        setTimeout(function () {
            updateInfobox(MESSAGES.levelLost);
            wasLevelCleared = false;
            prepAndShowInfoForNextLvl();
        }, 500);
    }

}

function goToNextLvl() {
    if (trials) {
        //update trials in scoreboard
        trials--;
        document.getElementById('Trials').innerHTML = trials;

        //update Tiles in scoreboard
        document.getElementById('Tiles').innerHTML = getLvl();

        //clear counter
        tilesCounter = 1;

        //generate new board => Chech which is the current level and calc the board cells and rows
        var currLvl = getLvl();
        var board = (currLvl <= boardDimArray.length) ? (currLvl - 1) : (boardDimArray.length - 1);

        // Invokes "createBoard(cells, rows)" by giving in the correct number of cells and rows
        createBoard(boardDimArray[board][0], boardDimArray[board][1]);
    } else {
        //GAME OVER - no more trials. Function for displaying GAME OVER Screen here
        alert(MESSAGES.gameOver + score + '!');
    }
}

function updatePopupSize(width, height) {
    if (popup) {
        width = width || board.offsetWidth;
        height = height || board.offsetHeight;

        popup.style.width = width + 'px';
        popup.style.height = height + 'px';
        popup.style.left = -(width / 2) + 'px';
    }
}

function updateBoardAndPopupSizes(cells, rows) {
    var width = (cells * cellSize) + boardPadding;
    var height = (rows * cellSize) + boardPadding;
    board.style.width = width + 'px';
    board.style.height = height + 'px';

    updatePopupSize(width, height);
}

function createBoard(cells, rows) {
    if (cells) {
        cells = ((cells) && (cells > minCellsSize)) ? ((cells < maxCellsSize) ? cells : maxCellsSize) : minCellsSize;
    } else {
        cells = initCellsSize;
    }
    if (rows) {
        rows = ((rows) && (rows > minRowsSize)) ? ((rows < maxRowsSize) ? rows : maxRowsSize) : minRowsSize;
    } else {
        rows = initRowsSize;
    }

    if (!board) {
        boardContainer = document.createElement('div');
        boardContainer.id = boardContainerID;
        mainContainer.appendChild(boardContainer);

        board = document.createElement('div');
        board.id = boardId;
        boardContainer.appendChild(board);
    }

    board.innerHTML = '';

    updateBoardAndPopupSizes(cells, rows);

    setTimeout(function () {
        for (var i = 1; i <= rows; i++) {
            var row = document.createElement('div');
            row.setAttribute('id', 'row' + i);
            row.className = 'row';
            for (var j = 1; j <= cells; j++) {
                var cell = document.createElement('div');
                cell.setAttribute('id', 'cell' + i + j);
                cell.className = 'cell';
                row.appendChild(cell);
            }
            board.appendChild(row);
        }
        assignCorrectAnswers(getLvl());
    }, correctAnswerTimeout);
}

function createInfoBox() {
    var infobox = document.createElement('div');
    infobox.id = 'infobox';
    mainContainer.appendChild(infobox);
}

function updateInfobox(occasion) {
    var infobox = document.getElementById('infobox');
    infobox.innerText = occasion;
    infobox.textContent = occasion;
}

function assignCorrectAnswers(level) {

    var assignedIndexes = [],
        selectedCells = [],
        cellsArray = document.getElementsByClassName('cell'),
        canContinue = true;

    var getRandomNumber = function () {
        return Math.floor(Math.random() * cellsArray.length);
    };

    for (var i = 0; i < level; i++) {
        canContinue = true;

        while (canContinue) {
            var randomCellIndex = getRandomNumber();
            if (assignedIndexes.indexOf(randomCellIndex) === -1) {
                var cellElement = cellsArray[randomCellIndex];
                selectedCells.push(cellElement);
                cellElement.setAttribute('data-is-true', 'true');
                assignedIndexes.push(randomCellIndex);
                canContinue = false;
            }
        }
    }

    answers = (answers !== '') ? answers : '';
    answers = assignedIndexes.toString();

    //show the pattern to player
    for (var j = 0; j < selectedCells.length; j++) {
        selectedCells[j].classList.add('openAnswer');
    }

    //hide the pattern and assign onClick event listener
    setTimeout(function () {
        hidePattern(selectedCells);
    }, beforeHideCellsTimeout);
}

function hidePattern(selectedCellsPattern) {
    for (var k = 0; k < selectedCellsPattern.length; k++) {
        selectedCellsPattern[k].classList.remove('openAnswer');
    }

    for (var i = 0; i < document.getElementsByClassName('cell').length; i++) {
        document.getElementsByClassName('cell')[i].addEventListener('click', getUserClick.bind(this), false);
    }
    updateInfobox(MESSAGES.guess);
}

function closePopup() {
    popup.classList.remove('opened');
    goToNextLvl();
}

function updateCurrentLvl() {
    if (wasLevelCleared === true) {
        currentLvl++;
    } else if (currentLvl > 1) {
        currentLvl--;
    }
}

function prepAndShowInfoForNextLvl() {
    var msg = document.getElementById('infoDialogTxt');
    if (!popup) {
        popup = document.createElement('div');
        msg = document.createElement('span');
        msg.id = 'infoDialogTxt';

        popup.setAttribute('id', 'popup');
        popup.addEventListener('click', closePopup, false);
        boardContainer.appendChild(popup);
        popup.appendChild(msg);
    }

    updateCurrentLvl();

    var msgText = '';
    if (wasLevelCleared) {
        msgText += 'Bonus Points: +' + levelBonus + '<br />';
    }
    msgText += 'Next: ' + getLvl() + ' tiles';
    msg.innerHTML = msgText;

    popup.classList.add('opened');
    updatePopupSize();
}

createBackground();
createScoreBoard();
createBoard();
createInfoBox();<|endoftext|>


<commit_before>var juice = require('juice');
var template = require('Template');

var Application = function Application() {
  this.actions = {};
  this.controllers = {};
}

exports.Application = Application;

Application.prototype.run = function(env) {
  // Dispatch the url

  var [ , url, format ] = env.PATH_INFO.match( /^(.*?)(?:\.(\w+))?$/ );
  env['juice.format'] = format;
  for (k in this.actions) {
    let info = this.actions[ k ] = this.buildAction( k, this.actions[ k ], env );

    let re = info.__matcher;

    var res = re(url);

    if (!res)
      continue;

    // We matched! dispatch to the action

    // We assume that re is infact a regexp, so res is an array of the form:
    //
    //  [ 'whole matched text', 'capture1', ... 'captureN' ]
    //
    //  We dont want the whole matched text.
    res.shift();

    return this.runAction(env, res, info);
  }

  // 404!
  return this.notFound(env);
}

Application.prototype.runAction = function(env, captures, action) {

  this.base = env['jsgi.url_scheme']
               + "://"
               + env.SERVER_NAME
               + ":"
               + env.SERVER_PORT
               + env.SCRIPT_NAME
               + "/";

  captures.unshift(env);

  var data = action.action.apply(this, captures);

  if (action.redirect) {
    var headers = new (juice.Utils.Headers);
    headers.location = this.urlFor(action.redirect);
    res = [
      302,
      headers,
      ""
    ];
  }

  // render the data in the appropriate way
  // note that if the format requested is json, this will supercede any redirect planned
  if (env['juice.format'] == "json") {
    res = [
      200,
      { contentType : 'application/json' },
      data.toSource()
    ];
  } else if (action.render) {
    var f = require('io').File( '/Users/dom/Documents/scratchpad/chores/templates/' + action.render );
    var tt = new Template();
    res = [
      200,
      { contentType : 'text/html' },
      tt.process( f.readWhole(), data )
    ];
  }

  return res;
}

/**
 * CSS for built in 404 and 500 error pages.
 */
Application.prototype.errorCss = [
'    * { margin: 0; padding: 0; }',
'    body { background: #eee; color: #000; font: 200 87.5%/1.5 "Lucida Grande", Calibri, sans-serif; }',
'    #overview { background: #79d108; border-bottom: 1.5em solid #90e71d; padding: 1.5em; }',
'    #details { padding: 1.5em; }',
'    h1 { font-size: 1.5em; font-weight: 200; line-height: 1; }',
'    dl { font-family: Consolas, monospace; margin-top: 1.5em; overflow: auto; }',
'    dt { clear: both; float: left; margin-right: 1em; text-align: right; width: 9em; }',
'    dd { float: left; }',
'    ol { font-family: Consolas, monospace; margin: 1.5em 0 1.5em 3em; }',
'    code { background: #a6f540; color: #000; font-family: Consolas, monospace; padding: 0.125em; }',
'    span { display: table-cell; }',
'    span:first-child { padding-right: 1em; text-align: right; }',
'    span:last-child { padding-left: 1em; }',
].join('\n');

Application.prototype.notFoundTemplate = <><![CDATA[<!DOCTYPE html>

  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <title>Page not found</title>

Page not found — 404

URL:

{url}

Method:

{env.REQUEST_METHOD}

Juice tried to match the URL {env.PATH_INFO} against the
    following patterns, but failed to find a match.

  for (k in this.actions) {
    content.body.div[1].ol.* +=
{k}
;
  }

  return [404, {}, "<!DOCTYPE html>\n" + content ];
}

Application.prototype.urlFor = function() {
  var url = Array.join(arguments, '/');
  url = url.replace(/\/+/g, '/')
           .replace(/^\//, '');

  return this.base + url;
}

Application.prototype.getAction = function( context, name ) {
  for ( [k,v] in Iterator( name.split( '.' ) ) ) {
    if ( v in context == false )
      throw new TypeError( name + " cannot be found in the controller" );
    context = context[ v ];
  }
  return context;
}

Application.prototype.buildAction = function( url, action, env ) {
  if ( typeof action == "function" || typeof action == "string" )
    action = { action : action };

  if ( typeof action.action == "string" )
    action.action = this.getAction( this.controllers, action.action );

  if ( "__matcher" in action && typeof action.__matcher != "function" )
    throw new TypeError( "action.__matcher is not a function" );

  if ( ! "__matcher" in action == false )
    action.__matcher = new RegExp( "^" + url + "$" );

  return action;
}
<commit_msg>Change 404 template to use TT rather than E4x<commit_after>var juice = require('juice');
var template = require('Template');

var Application = function Application() {
  this.actions = {};
  this.controllers = {};
}

exports.Application = Application;

Application.prototype.run = function(env) {
  // Dispatch the url

  var [ , url, format ] = env.PATH_INFO.match( /^(.*?)(?:\.(\w+))?$/ );
  env['juice.format'] = format;
  for (k in this.actions) {
    let info = this.actions[ k ] = this.buildAction( k, this.actions[ k ], env );

    let re = info.__matcher;

    var res = re(url);

    if (!res)
      continue;

    // We matched! dispatch to the action

    // We assume that re is infact a regexp, so res is an array of the form:
    //
    //  [ 'whole matched text', 'capture1', ... 'captureN' ]
    //
    //  We dont want the whole matched text.
    res.shift();

    return this.runAction(env, res, info);
  }

  // 404!
  return this.notFound(env);
}

Application.prototype.runAction = function(env, captures, action) {

  this.base = env['jsgi.url_scheme']
               + "://"
               + env.SERVER_NAME
               + ":"
               + env.SERVER_PORT
               + env.SCRIPT_NAME
               + "/";

  captures.unshift(env);

  var data = action.action.apply(this, captures);

  if (action.redirect) {
    var headers = new (juice.Utils.Headers);
    headers.location = this.urlFor(action.redirect);
    res = [
      302,
      headers,
      ""
    ];
  }

  // render the data in the appropriate way
  // note that if the format requested is json, this will supercede any redirect planned
  if (env['juice.format'] == "json") {
    res = [
      200,
      { contentType : 'application/json' },
      data.toSource()
    ];
  } else if (action.render) {
    var f = require('io').File( '/Users/dom/Documents/scratchpad/chores/templates/' + action.render );
    var tt = new Template();
    res = [
      200,
      { contentType : 'text/html' },
      tt.process( f.readWhole(), data )
    ];
  }

  return res;
}

/**
 * CSS for built in 404 and 500 error pages.
 */
Application.prototype.errorCss = [
'    * { margin: 0; padding: 0; }',
'    body { background: #eee; color: #000; font: 200 87.5%/1.5 "Lucida Grande", Calibri, sans-serif; }',
'    #overview { background: #79d108; border-bottom: 1.5em solid #90e71d; padding: 1.5em; }',
'    #details { padding: 1.5em; }',
'    h1 { font-size: 1.5em; font-weight: 200; line-height: 1; }',
'    dl { font-family: Consolas, monospace; margin-top: 1.5em; overflow: auto; }',
'    dt { clear: both; float: left; margin-right: 1em; text-align: right; width: 9em; }',
'    dd { float: left; }',
'    ol { font-family: Consolas, monospace; margin: 1.5em 0 1.5em 3em; }',
'    code { background: #a6f540; color: #000; font-family: Consolas, monospace; padding: 0.125em; }',
'    span { display: table-cell; }',
'    span:first-child { padding-right: 1em; text-align: right; }',
'    span:last-child { padding-left: 1em; }',
].join('\n');

/**
 * Template to render when no actions match
 */
Application.prototype.notFoundTemplate = <><![CDATA[<!DOCTYPE html>

  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <title>Page not found</title>

Page not found — 404

URL:

[% url %]

Method:

[%env.REQUEST_METHOD%]

Juice tried to match the URL [% env.PATH_INFO %] against the
    following patterns, but failed to find a match.

[% FOREACH k IN actions %]

[% k.key %]

[% END -%]

]]></> + "";

Application.prototype.notFound = function(env) {

  var url = env['jsgi.url_scheme']
          + "://"
          + env.SERVER_NAME
          + ":"
          + env.SERVER_PORT
          + env.SCRIPT_NAME
          + env.PATH_INFO;

  var tt = new Template();
  return [
    404,
    { contentType : 'text/html' },
    tt.process(
      this.notFoundTemplate,
      { url: url,
        actions: this.actions,
        env: env,
        css: this.errorCss
      }
    )
  ];

}

Application.prototype.urlFor = function() {
  var url = Array.join(arguments, '/');
  url = url.replace(/\/+/g, '/')
           .replace(/^\//, '');

  return this.base + url;
}

Application.prototype.getAction = function( context, name ) {
  for ( [k,v] in Iterator( name.split( '.' ) ) ) {
    if ( v in context == false )
      throw new TypeError( name + " cannot be found in the controller" );
    context = context[ v ];
  }
  return context;
}

Application.prototype.buildAction = function( url, action, env ) {
  if ( typeof action == "function" || typeof action == "string" )
    action = { action : action };

  if ( typeof action.action == "string" )
    action.action = this.getAction( this.controllers, action.action );

  if ( "__matcher" in action && typeof action.__matcher != "function" )
    throw new TypeError( "action.__matcher is not a function" );

  if ( ! "__matcher" in action == false )
    action.__matcher = new RegExp( "^" + url + "$" );

  return action;
}
<|endoftext|>


<commit_before>"use strict";
var EventDispatcher = require('../events/event-dispatcher'),
    loader = require('../loader/loader'),
    environments = require('../environments/environments'),
    inject = require('../inject/inject'),
    path = require('path'),
    fs = require('fs'),
    _ = require('lodash');

var Launcher = EventDispatcher.define({

    constructor: function () {
        this.cachedRequire = [];

    },

    launch: function (config) {

        this.loadOptions(config)

        this.loadEnvironments();

        this.loadFiles();

        this.loadInjector();

        this.fireEvent('appolo-launched');
    },

    loadOptions:function(config){

        var defaults = {
            paths:['config', 'server'],
            root : process.cwd(),
            environment : (process.env.NODE_ENV || 'development'),
            bootStrapClassId :'appolo-bootstrap',
            version: require('../../package.json').version
        }

        this._options = _.extend(defaults ,config || {});

        return this._options;
    },

    loadFiles:function(){
        var loadPaths = _.union(this._options.paths, environments.paths);

        //load env files
        loader(this._options.root,loadPaths,function(filePath){
            require(filePath);
            this.cachedRequire.push(filePath);
        }.bind(this));
    },

    loadEnvironments: function () {
        var allPath = path.join(this._options.root, 'config/environments/all'),
            environmentPath = path.join(this._options.root, 'config/environments/', this._options.environment + '.js'),
            all = require(allPath),
            environment = require(environmentPath);

        this.cachedRequire.push(allPath);
        this.cachedRequire.push(environmentPath);

        //add current env config to appolo env
        _.extend(environments, all, environment || {});

        //save evn name
        environments.type = this._options.environment;

        //add root
        environments.rootDir = this._options.root;

        inject.addObject('environment', environments);
        inject.addObject('env', environments);
    },

    loadInjector: function () {
        var definitions = {},
            injectPath = path.join(this._options.root, 'config/inject');

        if (fs.existsSync(injectPath)) {

            loader(this._options.root,path.join('config', 'inject'),function(filePath){
                _.extend(definitions, require(filePath));
                this.cachedRequire.push(filePath);
            }.bind(this));
        }

        //load inject
        inject.initialize({
            definitions: definitions,
            root: this._options.root
        });

        this.loadBootStrap();

    },

    loadBootStrap:function(){
        var bootstrapDef = inject.getDefinition(this._options.bootStrapClassId);

        if(bootstrapDef){
            var bootstrap = inject.getObject(this._options.bootStrapClassId);

            bootstrap.initialize();
        }

    },

    reset:function(){
        _.forEach(this.cachedRequire,function(filePath){
            delete require.cache[filePath];
        });
        this.cachedRequire.length = 0;
        this._options = null;
        _.forEach(environments,function(value,key){
            delete environments[key];
        });

        inject.reset();

        process.removeAllListeners();
    }
});

module.exports = new Launcher();<commit_msg>new appolo<commit_after>"use strict";
var EventDispatcher = require('../events/event-dispatcher'),
    loader = require('../loader/loader'),
    environments = require('../environments/environments'),
    inject = require('../inject/inject'),
    path = require('path'),
    fs = require('fs'),
    _ = require('lodash');

var Launcher = EventDispatcher.define({

    constructor: function () {
        this.cachedRequire = [];

    },

    launch: function (config) {

        this.loadOptions(config)

        this.loadEnvironments();

        this.loadFiles();

        this.loadInjector();

        this.fireEvent('appolo-launched');
    },

    loadOptions:function(config){

        var defaults = {
            paths:['config', 'server'],
            root : process.cwd(),
            environment : (process.env.NODE_ENV || 'development'),
            bootStrapClassId :'appolo-bootstrap',
            version: require(path.join(process.cwd(),'package.json')).version
        }

        this._options = _.extend(defaults ,config || {});

        return this._options;
    },

    loadFiles:function(){
        var loadPaths = _.union(this._options.paths, environments.paths);

        //load env files
        loader(this._options.root,loadPaths,function(filePath){
            require(filePath);
            this.cachedRequire.push(filePath);
        }.bind(this));
    },

    loadEnvironments: function () {
        var allPath = path.join(this._options.root, 'config/environments/all'),
            environmentPath = path.join(this._options.root, 'config/environments/', this._options.environment + '.js'),
            all = require(allPath),
            environment = require(environmentPath);

        this.cachedRequire.push(allPath);
        this.cachedRequire.push(environmentPath);

        //add current env config to appolo env
        _.extend(environments, all, environment || {});

        //save evn name
        environments.type = this._options.environment;

        //add root
        environments.rootDir = this._options.root;

        inject.addObject('environment', environments);
        inject.addObject('env', environments);
    },

    loadInjector: function () {
        var definitions = {},
            injectPath = path.join(this._options.root, 'config/inject');

        if (fs.existsSync(injectPath)) {

            loader(this._options.root,path.join('config', 'inject'),function(filePath){
                _.extend(definitions, require(filePath));
                this.cachedRequire.push(filePath);
            }.bind(this));
        }

        //load inject
        inject.initialize({
            definitions: definitions,
            root: this._options.root
        });

        this.loadBootStrap();

    },

    loadBootStrap:function(){
        var bootstrapDef = inject.getDefinition(this._options.bootStrapClassId);

        if(bootstrapDef){
            var bootstrap = inject.getObject(this._options.bootStrapClassId);

            bootstrap.initialize();
        }

    },

    reset:function(){
        _.forEach(this.cachedRequire,function(filePath){
            delete require.cache[filePath];
        });
        this.cachedRequire.length = 0;
        this._options = null;
        _.forEach(environments,function(value,key){
            delete environments[key];
        });

        inject.reset();

        process.removeAllListeners();
    }
});

module.exports = new Launcher();<|endoftext|>


<commit_before>'use strict';

var livereload = require('livereload'),
    connectLr = require('connect-livereload-safe');

module.exports = function(lingon, config) {

  // add script tag injection middleware to the express server
  lingon.one('serverConfigure', function() {

    config = config || {};
    config.port = config.port || 35729;

    // inject browser script tag
    lingon.server.use(connectLr({
      port: config.port
    }));
  });

  // start the livereload server
  lingon.one('serverStarted', function() {

    var server;

    // set livereload to watch the source dir
    config.watchDir = config.watchDir || process.cwd() + '/' + lingon.config.sourcePath;

    // add extensions for livereload to watch
    config.exts = config.exts || lingon.config.directiveFileTypes.concat(Object.keys(lingon.config.extensionRewrites));

    server = livereload.createServer(config);

    server.watch(config.watchDir);

    lingon.log('Livereload is listening on port ' + config.port);
  });
};<commit_msg>catch port in use error<commit_after>'use strict';

var livereload = require('livereload');
var connectLr = require('connect-livereload-safe');

module.exports = function(lingon, config) {

  // add script tag injection middleware to the express server
  lingon.one('serverConfigure', function() {

    config = config || {};
    config.port = config.port || 35729;

    // inject browser script tag
    lingon.server.use(connectLr({
      port: config.port
    }));

    process.on('uncaughtException', function(error) {
      if(error.code == 'EADDRINUSE') {
        lingon.log.error('Port ' + config.port + ' is already in use, lingon-livereload could not start!');
        lingon.log.info('[Info] Try changing the port in your lingon-livereload config');
        process.exit();
      }
    });
  });

  // start the livereload server
  lingon.one('serverStarted', function() {

    var server;

    // set livereload to watch the source dir
    config.watchDir = config.watchDir || process.cwd() + '/' + lingon.config.sourcePath;

    // add extensions for livereload to watch
    config.exts = config.exts || lingon.config.directiveFileTypes.concat(Object.keys(lingon.config.extensionRewrites));

    server = livereload.createServer(config);

    server.watch(config.watchDir);

    lingon.log('Livereload is listening on port ' + config.port);
  });
};<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var glob = require('glob')
var mkdirp = require('mkdirp')
var tmp = require('tmp')
var checkSyntaxError = require('syntax-error')
var syntaxError = false
var Cucumber = require.main.require('cucumber/lib/cucumber')
var configuration
var formatters
var tempTestFolder = tmp.dirSync({ unsafeCleanup: true })
var tempLogFile = tmp.fileSync({ unsafeCleanup: true })
var featuresResult = Cucumber.Runtime.FeaturesResult()
var scenarioResult
var runtime
var currentStep
var client
var prevTime

tmp.setGracefulCleanup()

function bootstrap (options) {
  var done = false

  var configurationArgs = [options.featureFiles]
  configuration = Cucumber.Cli.Configuration({
    source: true,
    snippets: true,
    colors: true,
    format: ['pretty', 'json:' + tempLogFile.name]
  }, configurationArgs)

  formatters = configuration.getFormatters()
  runtime = Cucumber(getFeatureSources(options), getSupportCodeInitializer(options))

  if (syntaxError) {
    return
  }

  runtime.getFeatures().getFeatures().asyncForEach(function (feature, nextFeature) {
    var backgroundSteps = []

    createTestFile(feature, options)

    if (feature.hasBackground()) {
      feature.getBackground().getSteps().forEach(function (step) {
        step.execute = getStepExecutor(step)
        if (step.execute) backgroundSteps.push(step)
      })
    }

    feature.instructVisitorToVisitScenarios({
      visitScenario: function (scenario, nextScenario) {
        var steps = []
        scenario.getSteps().forEach(function (step) {
          step.execute = getStepExecutor(step)
          if (step.execute) steps.push(step)
        })
        discoverScenario(feature, scenario, backgroundSteps.concat(steps), options)
        nextScenario()
      }
    }, nextFeature)
  }, function () {
    done = true
  })

  while (!done) {}

  patchNighwatchTestSuite()
  patchNighwatchTestCase()
  patchNighwatchAsyncTree()
  patchNighwatchReporter()

  return tempTestFolder.name
}

bootstrap.features = {}

function patchNighwatchTestSuite () {
  var TestSuite = require.main.require('nightwatch/lib/runner/testsuite')
  var origSetupClient = TestSuite.prototype.setupClient

  TestSuite.prototype.setupClient = function () {
    var result = origSetupClient.call(this)
    client = this.client.get()
    return result
  }
}

function patchNighwatchTestCase () {
  var TestCase = require.main.require('nightwatch/lib/runner/testcase')
  var origRun = TestCase.prototype.run

  TestCase.prototype.run = function () {
    return origRun.call(this)
      .then(function (testResults) {
        logScenarioResult()
        return testResults
      })
  }
}

function patchNighwatchAsyncTree () {
  var AsyncTree = require.main.require('nightwatch/lib/core/queue').instance()
  var origRunCommand = AsyncTree.runCommand
  var origAppend = AsyncTree.append

  AsyncTree.runCommand = function (node, done) {
    return origRunCommand.call(this, node, function () {
      if (node.step && node.step.lastNode === node) {
        var lastResult = client.results.tests.length && client.results.tests[client.results.tests.length - 1]
        var failure = lastResult && lastResult.failure
        logStepResult(node.step, failure ? Cucumber.Status.FAILED : Cucumber.Status.PASSED)
      }
      done()
    })
  }

  AsyncTree.append = function (nodeName, command, context, args, stackTrace) {
    var result = origAppend.call(this, nodeName, command, context, args, stackTrace)
    var node = this.currentNode.children[this.currentNode.children.length - 1]

    node.step = currentStep
    if (node.parent.step) node.step = node.parent.step
    if (node.step) node.step.lastNode = node

    return result
  }
}

function patchNighwatchReporter () {
  console.log('#0')
  var Reporter = require.main.require('nightwatch/lib/runner/reporter')
  var origSave = Reporter.prototype.save

  Reporter.prototype.save = function () {
    console.log('#1')
    logFeaturesResult()
    console.log('#2')
    logAfterFeatures(runtime.getFeatures().getFeatures())
    console.log('#3')
    try {
      this.globalResults.cucumber = JSON.parse(fs.readFileSync(tempLogFile.name, 'utf8'))
      console.log('#4')
    } catch (err) {
      console.log('#4X')
      console.err('Cannot reald cucumber json formatter output form ' + tempLogFile.name)
    }
    console.log('#5')
    return origSave.call(this)
  }
}

function broadcastEvent (event) {
  formatters.forEach(function (formatter) {
    formatter.hear(event, function () {})
  })
}

function logAfterFeatures (features) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURES_EVENT_NAME, { features: features })
  broadcastEvent(event.replicateAsPostEvent())
}

function logFeaturesResult () {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURES_RESULT_EVENT_NAME, { featuresResult: featuresResult })
  broadcastEvent(event)
}

function logBeforeFeature (feature) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURE_EVENT_NAME, { feature: feature })
  broadcastEvent(event.replicateAsPreEvent())
  prevTime = time()
}

function logBackground (background) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.BACKGROUND_EVENT_NAME, { background: background })
  broadcastEvent(event.replicateAsPreEvent())
}

function logBeforeScenario (scenario) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.SCENARIO_EVENT_NAME, { scenario: scenario })
  scenarioResult = Cucumber.Runtime.ScenarioResult(scenario)
  broadcastEvent(event.replicateAsPreEvent())
}

function logScenarioResult () {
  featuresResult.witnessScenarioResult(scenarioResult)
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.SCENARIO_RESULT_EVENT_NAME, { scenarioResult: scenarioResult })
  broadcastEvent(event)
}

function logStepResult (step, status) {
  var stepResult = Cucumber.Runtime.StepResult({
    step: step,
    stepDefinition: step.stepDefinitions[0],
    duration: durationInNanoseconds(prevTime),
    status: status,
    failureException: '',
    attachments: []
  })
  scenarioResult.witnessStepResult(stepResult)
  featuresResult.witnessStepResult(stepResult)
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.STEP_RESULT_EVENT_NAME, { stepResult: stepResult })
  broadcastEvent(event)
  prevTime = time()
}

function time () {
  if (typeof process !== 'undefined' && process.hrtime) {
    return process.hrtime()
  } else {
    return new Date().getTime()
  }
}

function durationInNanoseconds (start) {
  if (typeof process !== 'undefined' && process.hrtime) {
    var duration = process.hrtime(start)
    return duration[0] * 1e9 + duration[1]
  } else {
    return (new Date().getTime() - start) * 1e6
  }
}

function getFeatureSources (options) {
  var featureSources = []

  glob.sync(options.featureFiles + '/**/*.feature').forEach(function (file) {
    featureSources.push([path.resolve(process.cwd(), file), fs.readFileSync(file)])
  })

  return featureSources
}

function getSupportCodeInitializer (options) {
  return function () {
    var files = []
    var supportCodeHelper = this

    glob.sync(options.stepDefinitions + '/**/*.js').forEach(function (file) {
      files.push(path.resolve(process.cwd(), file))
    })

    files.forEach(function (file) {
      var initializer
      var src = fs.readFileSync(file)
      var err = checkSyntaxError(src, file)

      if (err) {
        console.error(err)
        syntaxError = true
        return
      }

      initializer = require(file)

      if (typeof (initializer) === 'function') {
        initializer.call(supportCodeHelper)
      }
    })
  }
}

function getStepExecutor (step) {
  step.stepDefinitions = runtime.getSupportCodeLibrary().lookupStepDefinitionsByName(step.getName())

  return function (context, callback) {
    if (!step.stepDefinitions || !step.stepDefinitions.length) return logStepResult(step, Cucumber.Status.UNDEFINED)
    if (step.stepDefinitions.length > 1) return logStepResult(step, Cucumber.Status.AMBIGUOUS)
    step.stepDefinitions[0].invoke(step, context, {getAttachments: function () {}}, 60000, callback)
  }
}

function getFeatureTags (feature) {
  return feature.getTags().map(function (tag) {
    return tag.getName().replace(/^@/, '')
  })
}

function discoverScenario (feature, scenario, steps, options) {
  var tags
  var scenarioName
  var example

  if (!feature.discovered) {
    feature.discovered = {
      before: function () {
        logBeforeFeature(feature)
        if (feature.hasBackground()) logBackground(feature.getBackground())
      },
      after: function (browser) {
        if (options.closeSession === 'afterFeature') {
          browser.end()
        }
      },
      beforeEach: options.beforeScenario,
      afterEach: options.afterScenario
    }

    bootstrap.features[feature.getName()] = feature.discovered

    tags = getFeatureTags(feature)

    if (tags.length) {
      feature.discovered['@tags'] = tags
    }
  }

  if (scenario.getScenarioOutlineLine()) {
    if (!feature.discovered.firstOutlineRow) {
      feature.discovered.firstOutlineRow = scenario.getLine()
      example = 1
    } else {
      example = 1 + scenario.getLine() - feature.discovered.firstOutlineRow
    }
  }

  if (example) {
    scenarioName = scenario.getName() + ' #' + example
  } else {
    scenarioName = scenario.getName()
  }

  feature.discovered[scenarioName] = function (browser) {
    logBeforeScenario(scenario)

    steps.forEach(function (step) {
      currentStep = step
      if (options.beforeStep) options.beforeStep(browser)
      step.execute(browser, function (result) {
        if (result.getStatus() === Cucumber.Status.FAILED) {
          console.log(result.getFailureException())
        }
      })
      currentStep = null
      if (options.afterStep) options.afterStep(browser)
    })

    if (options.closeSession === 'afterScenario') {
      browser.end()
    }
  }
}

function createTestFile (feature, options) {
  var selfPath = __filename.split(path.sep).join('/')
  var testFileSource = 'module.exports = require("' + selfPath + '").features["' + feature.getName() + '"]'
  var testFilePath = path.join(tempTestFolder.name, path.relative(options.featureFiles, feature.getUri())).replace(/\.[^/.]+$/, '.js')

  mkdirp.sync(path.dirname(testFilePath))
  fs.writeFileSync(testFilePath, testFileSource)
}

module.exports = bootstrap
<commit_msg>  Try to fix travis tests #6<commit_after>var fs = require('fs')
var path = require('path')
var glob = require('glob')
var mkdirp = require('mkdirp')
var tmp = require('tmp')
var checkSyntaxError = require('syntax-error')
var syntaxError = false
var Cucumber = require.main.require('cucumber/lib/cucumber')
var configuration
var formatters
var tempTestFolder = tmp.dirSync({ unsafeCleanup: true })
var tempLogFile = tmp.fileSync({ unsafeCleanup: true })
var featuresResult = Cucumber.Runtime.FeaturesResult()
var scenarioResult
var runtime
var currentStep
var client
var prevTime

tmp.setGracefulCleanup()

function bootstrap (options) {
  var done = false

  var configurationArgs = [options.featureFiles]
  configuration = Cucumber.Cli.Configuration({
    source: true,
    snippets: true,
    colors: true,
    format: ['pretty', 'json:' + tempLogFile.name]
  }, configurationArgs)

  formatters = configuration.getFormatters()
  runtime = Cucumber(getFeatureSources(options), getSupportCodeInitializer(options))

  if (syntaxError) {
    return
  }

  runtime.getFeatures().getFeatures().asyncForEach(function (feature, nextFeature) {
    var backgroundSteps = []

    createTestFile(feature, options)

    if (feature.hasBackground()) {
      feature.getBackground().getSteps().forEach(function (step) {
        step.execute = getStepExecutor(step)
        if (step.execute) backgroundSteps.push(step)
      })
    }

    feature.instructVisitorToVisitScenarios({
      visitScenario: function (scenario, nextScenario) {
        var steps = []
        scenario.getSteps().forEach(function (step) {
          step.execute = getStepExecutor(step)
          if (step.execute) steps.push(step)
        })
        discoverScenario(feature, scenario, backgroundSteps.concat(steps), options)
        nextScenario()
      }
    }, nextFeature)
  }, function () {
    done = true
  })

  while (!done) {}

  patchNighwatchTestSuite()
  patchNighwatchTestCase()
  patchNighwatchAsyncTree()
  patchNighwatchReporter()

  return tempTestFolder.name
}

bootstrap.features = {}

function patchNighwatchTestSuite () {
  var TestSuite = require.main.require('nightwatch/lib/runner/testsuite')
  var origSetupClient = TestSuite.prototype.setupClient

  TestSuite.prototype.setupClient = function () {
    var result = origSetupClient.call(this)
    client = this.client.get()
    return result
  }
}

function patchNighwatchTestCase () {
  var TestCase = require.main.require('nightwatch/lib/runner/testcase')
  var origRun = TestCase.prototype.run

  TestCase.prototype.run = function () {
    return origRun.call(this)
      .then(function (testResults) {
        logScenarioResult()
        return testResults
      })
  }
}

function patchNighwatchAsyncTree () {
  var AsyncTree = require.main.require('nightwatch/lib/core/queue').instance()
  var origRunCommand = AsyncTree.runCommand
  var origAppend = AsyncTree.append

  AsyncTree.runCommand = function (node, done) {
    return origRunCommand.call(this, node, function () {
      if (node.step && node.step.lastNode === node) {
        var lastResult = client.results.tests.length && client.results.tests[client.results.tests.length - 1]
        var failure = lastResult && lastResult.failure
        logStepResult(node.step, failure ? Cucumber.Status.FAILED : Cucumber.Status.PASSED)
      }
      done()
    })
  }

  AsyncTree.append = function (nodeName, command, context, args, stackTrace) {
    var result = origAppend.call(this, nodeName, command, context, args, stackTrace)
    var node = this.currentNode.children[this.currentNode.children.length - 1]

    node.step = currentStep
    if (node.parent.step) node.step = node.parent.step
    if (node.step) node.step.lastNode = node

    return result
  }
}

function patchNighwatchReporter () {
  console.log('#0')
  var Reporter = require.main.require('nightwatch/lib/runner/reporter')
  var origSave = Reporter.prototype.save

  Reporter.prototype.save = function () {
    console.log('#1')
    logFeaturesResult()
    console.log('#2')
    logAfterFeatures(runtime.getFeatures().getFeatures())
    console.log('#3')
    try {
      this.globalResults.cucumber = JSON.parse(fs.readFileSync(tempLogFile.name, 'utf8'))
      console.log('#4')
    } catch (err) {
      console.log('#4X')
      console.error('Cannot reald cucumber json formatter output form ' + tempLogFile.name)
      console.error(err)
    }
    console.log('#5')
    return origSave.call(this)
  }
}

function broadcastEvent (event) {
  formatters.forEach(function (formatter) {
    formatter.hear(event, function () {})
  })
}

function logAfterFeatures (features) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURES_EVENT_NAME, { features: features })
  broadcastEvent(event.replicateAsPostEvent())
}

function logFeaturesResult () {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURES_RESULT_EVENT_NAME, { featuresResult: featuresResult })
  broadcastEvent(event)
}

function logBeforeFeature (feature) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.FEATURE_EVENT_NAME, { feature: feature })
  broadcastEvent(event.replicateAsPreEvent())
  prevTime = time()
}

function logBackground (background) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.BACKGROUND_EVENT_NAME, { background: background })
  broadcastEvent(event.replicateAsPreEvent())
}

function logBeforeScenario (scenario) {
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.SCENARIO_EVENT_NAME, { scenario: scenario })
  scenarioResult = Cucumber.Runtime.ScenarioResult(scenario)
  broadcastEvent(event.replicateAsPreEvent())
}

function logScenarioResult () {
  featuresResult.witnessScenarioResult(scenarioResult)
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.SCENARIO_RESULT_EVENT_NAME, { scenarioResult: scenarioResult })
  broadcastEvent(event)
}

function logStepResult (step, status) {
  var stepResult = Cucumber.Runtime.StepResult({
    step: step,
    stepDefinition: step.stepDefinitions[0],
    duration: durationInNanoseconds(prevTime),
    status: status,
    failureException: '',
    attachments: []
  })
  scenarioResult.witnessStepResult(stepResult)
  featuresResult.witnessStepResult(stepResult)
  var event = Cucumber.Runtime.AstTreeWalker.Event(Cucumber.Runtime.AstTreeWalker.STEP_RESULT_EVENT_NAME, { stepResult: stepResult })
  broadcastEvent(event)
  prevTime = time()
}

function time () {
  if (typeof process !== 'undefined' && process.hrtime) {
    return process.hrtime()
  } else {
    return new Date().getTime()
  }
}

function durationInNanoseconds (start) {
  if (typeof process !== 'undefined' && process.hrtime) {
    var duration = process.hrtime(start)
    return duration[0] * 1e9 + duration[1]
  } else {
    return (new Date().getTime() - start) * 1e6
  }
}

function getFeatureSources (options) {
  var featureSources = []

  glob.sync(options.featureFiles + '/**/*.feature').forEach(function (file) {
    featureSources.push([path.resolve(process.cwd(), file), fs.readFileSync(file)])
  })

  return featureSources
}

function getSupportCodeInitializer (options) {
  return function () {
    var files = []
    var supportCodeHelper = this

    glob.sync(options.stepDefinitions + '/**/*.js').forEach(function (file) {
      files.push(path.resolve(process.cwd(), file))
    })

    files.forEach(function (file) {
      var initializer
      var src = fs.readFileSync(file)
      var err = checkSyntaxError(src, file)

      if (err) {
        console.error(err)
        syntaxError = true
        return
      }

      initializer = require(file)

      if (typeof (initializer) === 'function') {
        initializer.call(supportCodeHelper)
      }
    })
  }
}

function getStepExecutor (step) {
  step.stepDefinitions = runtime.getSupportCodeLibrary().lookupStepDefinitionsByName(step.getName())

  return function (context, callback) {
    if (!step.stepDefinitions || !step.stepDefinitions.length) return logStepResult(step, Cucumber.Status.UNDEFINED)
    if (step.stepDefinitions.length > 1) return logStepResult(step, Cucumber.Status.AMBIGUOUS)
    step.stepDefinitions[0].invoke(step, context, {getAttachments: function () {}}, 60000, callback)
  }
}

function getFeatureTags (feature) {
  return feature.getTags().map(function (tag) {
    return tag.getName().replace(/^@/, '')
  })
}

function discoverScenario (feature, scenario, steps, options) {
  var tags
  var scenarioName
  var example

  if (!feature.discovered) {
    feature.discovered = {
      before: function () {
        logBeforeFeature(feature)
        if (feature.hasBackground()) logBackground(feature.getBackground())
      },
      after: function (browser) {
        if (options.closeSession === 'afterFeature') {
          browser.end()
        }
      },
      beforeEach: options.beforeScenario,
      afterEach: options.afterScenario
    }

    bootstrap.features[feature.getName()] = feature.discovered

    tags = getFeatureTags(feature)

    if (tags.length) {
      feature.discovered['@tags'] = tags
    }
  }

  if (scenario.getScenarioOutlineLine()) {
    if (!feature.discovered.firstOutlineRow) {
      feature.discovered.firstOutlineRow = scenario.getLine()
      example = 1
    } else {
      example = 1 + scenario.getLine() - feature.discovered.firstOutlineRow
    }
  }

  if (example) {
    scenarioName = scenario.getName() + ' #' + example
  } else {
    scenarioName = scenario.getName()
  }

  feature.discovered[scenarioName] = function (browser) {
    logBeforeScenario(scenario)

    steps.forEach(function (step) {
      currentStep = step
      if (options.beforeStep) options.beforeStep(browser)
      step.execute(browser, function (result) {
        if (result.getStatus() === Cucumber.Status.FAILED) {
          console.log(result.getFailureException())
        }
      })
      currentStep = null
      if (options.afterStep) options.afterStep(browser)
    })

    if (options.closeSession === 'afterScenario') {
      browser.end()
    }
  }
}

function createTestFile (feature, options) {
  var selfPath = __filename.split(path.sep).join('/')
  var testFileSource = 'module.exports = require("' + selfPath + '").features["' + feature.getName() + '"]'
  var testFilePath = path.join(tempTestFolder.name, path.relative(options.featureFiles, feature.getUri())).replace(/\.[^/.]+$/, '.js')

  mkdirp.sync(path.dirname(testFilePath))
  fs.writeFileSync(testFilePath, testFileSource)
}

module.exports = bootstrap
<|endoftext|>


<commit_before>/**
 * Core dependencies.
 */

var fs = require('fs');

/**
 * External dependencies.
 */

var AssertionError = require('assertion-error');

/**
 * Return an exit code expectation.
 *
 * @param {Number} expected exit code.
 * @returns {Function}
 * @api public
 */

exports.code = function(code) {
  return function(result) {
    if (code !== result.code) {
      return error(result, 'Expected exit code: "' + code + '", actual: "' + result.code + '"');
    }
  };
};

/**
 * Return no timeout expectation.
 *
 * @returns {Function}
 * @api public
 */

exports.time = function() {
  return function(result) {
    if (result.killed) {
      return error(result, 'Command execution terminated (timeout)');
    }
  };
};

/**
 * Return a stderr expectation.
 *
 * @param {String|RegExp} expected string or regular express to match
 * @returns {Function}
 * @api public
 */

exports.stderr = function(expected) {
  return function(result) {
    var msg = 'Expected stderr to match "' + expected + '". Actual: "' + result.stderr + '"';
    return assertOut(result.stderr, expected, result, msg);
  };
};

/**
 * Return a stdout expectation.
 *
 * @param {String|RegExp} expected string or regular express to match
 * @returns {Function}
 * @api public
 */

exports.stdout = function(expected) {
  return function(result) {
    var msg = 'Expected stdout to match "' + expected + '". Actual: "' + result.stdout + '"';
    return assertOut(result.stdout, expected, result, msg);
  };
};

/**
 * Verify that a `path` exists.
 *
 * @param {String} path
 * @returns {Function}
 * @api public
 */

exports.exists = function(path) {
  return function(result) {
    if (fs.existsSync(path) !== true) {
      return error(result, 'Expected "' + path + '" to exist.');
    }
  };
};

/**
 * Verify that `path`'s data matches `data`.
 *
 * @param {String} path
 * @param {String|RegExp} data
 * @returns {Function}
 * @api public
 */

exports.match = function(path, data) {
  return function(result) {
    var contents = fs.readFileSync(path, { encoding: 'utf8' });
    var statement = data instanceof RegExp
      ? data.test(contents)
      : data === contents;

    if (statement !== true) {
      return error(result, 'Expected "' + path + '" to match "' + data + '", but it was: "' + contents + '"');
    }
  };
};

/**
 * Assert stdout or stderr.
 *
 * @param {Mixed} actual
 * @param {Mixed} expected
 * @param {Result} result
 * @param {String} error message
 * @returns {AssertionError|null}
 * @api private
 */

function assertOut(actual, expected, result, message) {
  var statement = expected instanceof RegExp
    ? expected.test(actual)
    : expected === actual;

  if (statement !== true) {
    return error(result, message);
  }
}

/**
 * Create and return a new `AssertionError`.
 * It will assign the given `result` to it, it will also prepend the executed command
 * to the error message.
 *
 * Assertion error is a constructor for test and validation frameworks that implements
 * standardized Assertion Error specification.
 *
 * For more info go visit https://github.com/chaijs/assertion-error
 *
 * @param {Result} result
 * @param {String} error message
 * @returns {AssertionError}
 * @api private
 */

function error(result, message) {
  var error = new AssertionError('`' + result.cmd + '`: ' + message);
  error.result = result;
  return error;
}
<commit_msg>Make JSHint happy<commit_after>/**
 * Core dependencies.
 */

var fs = require('fs');

/**
 * External dependencies.
 */

var AssertionError = require('assertion-error');

/**
 * Return an exit code expectation.
 *
 * @param {Number} expected exit code.
 * @returns {Function}
 * @api public
 */

exports.code = function(code) {
  return function(result) {
    if (code !== result.code) {
      return error(result, 'Expected exit code: "' + code + '", actual: "' + result.code + '"');
    }
  };
};

/**
 * Return no timeout expectation.
 *
 * @returns {Function}
 * @api public
 */

exports.time = function() {
  return function(result) {
    if (result.killed) {
      return error(result, 'Command execution terminated (timeout)');
    }
  };
};

/**
 * Return a stderr expectation.
 *
 * @param {String|RegExp} expected string or regular express to match
 * @returns {Function}
 * @api public
 */

exports.stderr = function(expected) {
  return function(result) {
    var msg = 'Expected stderr to match "' + expected + '". Actual: "' + result.stderr + '"';
    return assertOut(result.stderr, expected, result, msg);
  };
};

/**
 * Return a stdout expectation.
 *
 * @param {String|RegExp} expected string or regular express to match
 * @returns {Function}
 * @api public
 */

exports.stdout = function(expected) {
  return function(result) {
    var msg = 'Expected stdout to match "' + expected + '". Actual: "' + result.stdout + '"';
    return assertOut(result.stdout, expected, result, msg);
  };
};

/**
 * Verify that a `path` exists.
 *
 * @param {String} path
 * @returns {Function}
 * @api public
 */

exports.exists = function(path) {
  return function(result) {
    if (fs.existsSync(path) !== true) {
      return error(result, 'Expected "' + path + '" to exist.');
    }
  };
};

/**
 * Verify that `path`'s data matches `data`.
 *
 * @param {String} path
 * @param {String|RegExp} data
 * @returns {Function}
 * @api public
 */

exports.match = function(path, data) {
  return function(result) {
    var contents = fs.readFileSync(path, { encoding: 'utf8' });
    var statement = data instanceof RegExp
      ? data.test(contents)
      : data === contents;

    if (statement !== true) {
      return error(result, 'Expected "' + path + '" to match "' + data + '", but it was: "' + contents + '"');
    }
  };
};

/**
 * Assert stdout or stderr.
 *
 * @param {Mixed} actual
 * @param {Mixed} expected
 * @param {Result} result
 * @param {String} error message
 * @returns {AssertionError|null}
 * @api private
 */

function assertOut(actual, expected, result, message) {
  var statement = expected instanceof RegExp
    ? expected.test(actual)
    : expected === actual;

  if (statement !== true) {
    return error(result, message);
  }
}

/**
 * Create and return a new `AssertionError`.
 * It will assign the given `result` to it, it will also prepend the executed command
 * to the error message.
 *
 * Assertion error is a constructor for test and validation frameworks that implements
 * standardized Assertion Error specification.
 *
 * For more info go visit https://github.com/chaijs/assertion-error
 *
 * @param {Result} result
 * @param {String} error message
 * @returns {AssertionError}
 * @api private
 */

function error(result, message) {
  var err = new AssertionError('`' + result.cmd + '`: ' + message);
  err.result = result;
  return err;
}
<|endoftext|>


<commit_before>window.addEventListener('message', function (event) {
	// if (originWhitelist.includes(event.origin)) {
	if (event.origin) {
		const action = event && event.data && event.data.action;
		msg(`HTML5 message received: ${action}`);
		return handleMessage({ event, action });
	} else {
		msg(`[ERROR: postMessage missing event.origin]`);
	}
});

function handleMessage(params = {}) {
	msg(`handleMessage params:`);
	msgObjectProps(params);

	const { event, action } = params;

	if (!(event && action)) {
		let err = `params event and action are required.`;
		msg(`handleMessage error: ${err}`)
		console.error(ReferenceError(err));
		return false;
	}

	const extensionId = event.origin.split("//")[1];
	if (!validExtensionId(extensionId)) {
		// don't respond to unexpected origins
		return false;
	}

	msg(`Confirmed message from valid extension ${extensionId}`);

	switch(action) {
		case 'ENCRYPT':
			auth_sign(event.data.data, respondToAction);
			break;
		case 'DECRYPT':
			// perform auth_decrypt()
			break;
		default:
			// unhandled action
			break;
	}

}

function respondToAction(data) {
	chrome.runtime.sendMessage(extensionId, { ok_sig: data },
		response => {
			if (!response.success) {
				msg(`sendMessage response failed:`);
				msg(JSON.stringify(response));
			} else {
				msg(`SUCCESS`);
			}
		});
}

const originWhitelist = [
	'https://'
];

function validExtensionId(str) {
	const re = /^[A-Za-z]{32}$/;
	const matchArr = str.match(re);
	return (matchArr && matchArr.length);
}

function msgObjectProps(obj) {
	if (typeof obj === 'object') {
		for (var k in obj) {
			msg(`> ${k}: ${JSON.stringify(obj[k])}`);
		}
	} else {
		msg(`[value]: ${obj}`);
	}
}
<commit_msg>Fix respondToAction<commit_after>window.addEventListener('message', function (event) {
	// if (originWhitelist.includes(event.origin)) {
	if (event.origin) {
		const action = event && event.data && event.data.action;
		msg(`HTML5 message received: ${action}`);
		return handleMessage({ event, action });
	} else {
		msg(`[ERROR: postMessage missing event.origin]`);
	}
});

function handleMessage(params = {}) {
	msg(`handleMessage params:`);
	msgObjectProps(params);

	const { event, action } = params;

	if (!(event && action)) {
		let err = `params event and action are required.`;
		msg(`handleMessage error: ${err}`)
		console.error(ReferenceError(err));
		return false;
	}

	const extensionId = event.origin.split("//")[1];
	if (!validExtensionId(extensionId)) {
		// don't respond to unexpected origins
		return false;
	}

	msg(`Confirmed message from valid extension ${extensionId}`);

	switch(action) {
		case 'ENCRYPT':
			auth_sign(event.data.data, data => respondToAction({
				extensionId
				ok_sig: data
			}));
			break;
		case 'DECRYPT':
			// perform auth_decrypt()
			break;
		default:
			// unhandled action
			break;
	}

}

function respondToAction(params = {}) {
	msg(`Responding to extension`);
	msgObjectProps(params);

	const { extensionId, ok_sig } = params;
	chrome.runtime.sendMessage(extensionId, { ok_sig },
		response => {
			if (!response.success) {
				msg(`sendMessage response failed:`);
				msg(JSON.stringify(response));
			} else {
				msg(`SUCCESS`);
			}
		});
}

const originWhitelist = [
	'https://'
];

function validExtensionId(str) {
	const re = /^[A-Za-z]{32}$/;
	const matchArr = str.match(re);
	return (matchArr && matchArr.length);
}

function msgObjectProps(obj) {
	if (typeof obj === 'object') {
		for (var k in obj) {
			msg(`> ${k}: ${JSON.stringify(obj[k])}`);
		}
	} else {
		msg(`[value]: ${obj}`);
	}
}
<|endoftext|>