<commit_before>//Translated from grid.rb using babyruby2js
'use strict';

var main = require('./main');

/** @class A generic grid - a Goban owns a grid
 *  public read-only attribute: gsize, yx
 */
function Grid(gsize) {
    if (gsize === undefined) gsize = 19;
    this.gsize = gsize;
    // We keep extra "border" cells around the real board.
    // Idea is to avoid to have to check i,j against gsize in many places.
    // Having a real item (BORDER) on the way helps to detect bugs.
    this.yx = Array.new(gsize + 2, function () {
        return Array.new(gsize + 2, main.BORDER);
    });
}
module.exports = Grid;

Grid.COLOR_NAMES = ['black', 'white'];
Grid.EMPTY_CHAR = '+';
Grid.DAME_CHAR = '?';
Grid.STONE_CHARS = '@O';
Grid.DEAD_CHARS = '&#';
Grid.TERRITORY_CHARS = '-:';
Grid.COLOR_CHARS = Grid.STONE_CHARS + Grid.DEAD_CHARS + Grid.TERRITORY_CHARS + Grid.DAME_CHAR + Grid.EMPTY_CHAR;
Grid.CIRCULAR_COLOR_CHARS = Grid.DAME_CHAR + Grid.EMPTY_CHAR + Grid.COLOR_CHARS;
Grid.ZONE_CODE = 100; // used for zones (100, 101, etc.); must be > COLOR_CHARS.length

// Possible values of a color (beside BLACK & WHITE)
Grid.EMPTY_COLOR = -1; // this is same as EMPTY, conveniently
Grid.DAME_COLOR = -2; // index of ? in above string; 2 from the end of the string
Grid.DEAD_COLOR = 2; // 2 and 3
Grid.TERRITORY_COLOR = 4; // 4 and 5

// Converts a "territory" character into an owner score (-1= black, +1= white)
// dame, empty, live*2, dead*2, terr*2
Grid.territory2owner = [0,0, -1,+1, +1,-1, -1,+1];
// Converts potential territory number to a char (-1, -0.5, 0, +0.5, +1) -> char
Grid.territory2char = '-\'?.:';

Grid.prototype.copy = function (sourceGrid) {
    if (sourceGrid.gsize !== this.gsize) {
        throw new Error('Cannot copy between different sized grids');
    }
    var srcYx = sourceGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = srcYx[j][i];
        }
    }
    return this;
};

/** Converts from goban grid (stones) to simple grid (colors)
 *  @param {Goban} goban - not modified
 *  @return {Grid} the grid (this)
 */
Grid.prototype.initFromGoban = function (goban) {
    var sourceGrid = goban.grid;
    if (sourceGrid.gsize !== this.gsize) {
        throw new Error('Cannot copy between different sized grids');
    }
    var srcYx = sourceGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = srcYx[j][i].color;
        }
    }
    return this;
};

// Returns the "character" used to represent a stone in text style
Grid.colorToChar = function (color) {
    if (color >= Grid.ZONE_CODE) {
        return String.fromCharCode(('A'.charCodeAt() + color - Grid.ZONE_CODE));
    }
    if (color < Grid.DAME_COLOR || color >= Grid.COLOR_CHARS.length) {
        throw new Error('Invalid color ' + color);
    }
    if (color < 0) color += Grid.COLOR_CHARS.length;
    return Grid.COLOR_CHARS[color];
};

// Returns the name of the color/player (e.g. "black")
Grid.colorName = function (color) { // TODO remove me or?
    return Grid.COLOR_NAMES[color];
};

Grid.charToColor = function (char) {
    return Grid.CIRCULAR_COLOR_CHARS.indexOf(char) + Grid.DAME_COLOR;
};

Grid.prototype.toText = function (block) {
    return this.toTextExt(true, '\n', block);
};

Grid.prototype.toLine = function (block) {
    return this.toTextExt(false, ',', block);
};

// Receives a block of code and calls it for each vertex.
// The block should return a string representation.
// This method returns the concatenated string showing the grid.
Grid.prototype.toTextExt = function (withLabels, endOfRow, block) {
    var yx = new Grid(this.gsize).yx;
    var maxlen = 1, i, j, val;
    for (j = this.gsize; j >= 1; j--) {
        for (i = 1; i <= this.gsize; i++) {
            val = block(this.yx[j][i]);
            if (val === null) {
                val = '';
            }
            yx[j][i] = val;
            if (val.length > maxlen) {
                maxlen = val.length;
            }
        }
    }
    var numChar = maxlen;
    var white = '          ';
    var s = '';
    for (j = this.gsize; j >= 1; j--) {
        if (withLabels) {
            s += '%2d'.format(j) + ' ';
        }
        for (i = 1; i <= this.gsize; i++) {
            val = yx[j][i];
            if (val.length < numChar) {
                val = white.substr(1, numChar - val.length) + val;
            }
            s += val;
        }
        s += endOfRow;
    }
    if (withLabels) {
        s += '   ';
        for (i = 1; i <= this.gsize; i++) {
            s += white.substr(1, numChar - 1) + Grid.xLabel(i);
        }
        s += '\n';
    }
    if (endOfRow !== '\n') {
        return s.chop();
    }
    return s;
};

Grid.prototype.toString = function () {
    var s = '';
    for (var j = this.gsize; j >= 1; j--) {
        for (var i = 1; i <= this.gsize; i++) {
            s += Grid.colorToChar(this.yx[j][i]);
        }
        s += '\n';
    }
    return s;
};

// Returns a text "image" of the grid. See also copy? method.
// Image is upside-down to help compare with a copy paste from console log.
// So last row (j==gsize) comes first in image
Grid.prototype.image = function () {
    if (main.instanceOf(Object, this.yx[1][1])) {
        return this.toLine(function (s) {
            return Grid.colorToChar(s.color);
        });
    } else {
        return this.toLine(function (c) {
            return Grid.colorToChar(c);
        });
    }
};

// Watch out our images are upside-down on purpose (to help copy paste from screen)
// So last row (j==gsize) comes first in image
Grid.prototype.loadImage = function (image) {
    var rows = image.split(/\"|,/);
    if (rows.length !== this.gsize) {
        throw new Error('Invalid image: ' + rows.length + ' rows instead of ' + this.gsize);
    }
    for (var j = this.gsize; j >= 1; j--) {
        var row = rows[this.gsize - j];
        if (row.length !== this.gsize) {
            throw new Error('Invalid image: row ' + row);
        }
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = Grid.charToColor(row[i - 1]);
        }
    }
};

var COLUMNS = 'abcdefghjklmnopqrstuvwxyz'; // NB: "i" is skipped

// Parses a move like "c12" into 3,12
Grid.move2xy = function (move) {
    var i = COLUMNS.indexOf(move[0]) + 1;
    var j = parseInt(move.substr(1, 2));
    if (!i || isNaN(j)) throw new Error('Illegal move parsed: ' + move);
    return [i, j];
};

// Builds a string representation of a move (3,12->"c12")
Grid.xy2move = function (i, j) {
    return COLUMNS[i - 1] + j;
};

// Converts a numeric X coordinate in a letter (e.g 3->c)
Grid.xLabel = function (i) {
    return COLUMNS[i - 1];
};
<commit_msg>Comment<commit_after>//Translated from grid.rb using babyruby2js
'use strict';

var main = require('./main');

/** @class A generic grid - a Goban owns a grid
 *  public read-only attribute: gsize, yx
 */
function Grid(gsize) {
    if (gsize === undefined) gsize = 19;
    this.gsize = gsize;
    // We keep extra "border" cells around the real board.
    // Idea is to avoid to have to check i,j against gsize in many places.
    // Having a real item (BORDER) on the way helps to detect bugs.
    this.yx = Array.new(gsize + 2, function () {
        return Array.new(gsize + 2, main.BORDER);
    });
}
module.exports = Grid;

Grid.COLOR_NAMES = ['black', 'white'];
Grid.EMPTY_CHAR = '+';
Grid.DAME_CHAR = '?';
Grid.STONE_CHARS = '@O';
Grid.DEAD_CHARS = '&#';
Grid.TERRITORY_CHARS = '-:';
Grid.COLOR_CHARS = Grid.STONE_CHARS + Grid.DEAD_CHARS + Grid.TERRITORY_CHARS + Grid.DAME_CHAR + Grid.EMPTY_CHAR;
Grid.CIRCULAR_COLOR_CHARS = Grid.DAME_CHAR + Grid.EMPTY_CHAR + Grid.COLOR_CHARS;
Grid.ZONE_CODE = 100; // used for zones (100, 101, etc.); must be > COLOR_CHARS.length

// Possible values of a color (beside BLACK & WHITE)
Grid.EMPTY_COLOR = -1; // this is same as EMPTY, conveniently
Grid.DAME_COLOR = -2; // index of ? in above string; 2 from the end of the string
Grid.DEAD_COLOR = 2; // 2 and 3
Grid.TERRITORY_COLOR = 4; // 4 and 5

// Converts a "territory" character into an owner score (-1= black, +1= white)
// dame,empty, liveB,liveW deadB,deadW, terrB,terrW
Grid.territory2owner = [0,0, -1,+1, +1,-1, -1,+1];
// Converts potential territory number to a char (-1, -0.5, 0, +0.5, +1) -> char
Grid.territory2char = '-\'?.:';

Grid.prototype.copy = function (sourceGrid) {
    if (sourceGrid.gsize !== this.gsize) {
        throw new Error('Cannot copy between different sized grids');
    }
    var srcYx = sourceGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = srcYx[j][i];
        }
    }
    return this;
};

/** Converts from goban grid (stones) to simple grid (colors)
 *  @param {Goban} goban - not modified
 *  @return {Grid} the grid (this)
 */
Grid.prototype.initFromGoban = function (goban) {
    var sourceGrid = goban.grid;
    if (sourceGrid.gsize !== this.gsize) {
        throw new Error('Cannot copy between different sized grids');
    }
    var srcYx = sourceGrid.yx;
    for (var j = 1; j <= this.gsize; j++) {
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = srcYx[j][i].color;
        }
    }
    return this;
};

// Returns the "character" used to represent a stone in text style
Grid.colorToChar = function (color) {
    if (color >= Grid.ZONE_CODE) {
        return String.fromCharCode(('A'.charCodeAt() + color - Grid.ZONE_CODE));
    }
    if (color < Grid.DAME_COLOR || color >= Grid.COLOR_CHARS.length) {
        throw new Error('Invalid color ' + color);
    }
    if (color < 0) color += Grid.COLOR_CHARS.length;
    return Grid.COLOR_CHARS[color];
};

// Returns the name of the color/player (e.g. "black")
Grid.colorName = function (color) { // TODO remove me or?
    return Grid.COLOR_NAMES[color];
};

Grid.charToColor = function (char) {
    return Grid.CIRCULAR_COLOR_CHARS.indexOf(char) + Grid.DAME_COLOR;
};

Grid.prototype.toText = function (block) {
    return this.toTextExt(true, '\n', block);
};

Grid.prototype.toLine = function (block) {
    return this.toTextExt(false, ',', block);
};

// Receives a block of code and calls it for each vertex.
// The block should return a string representation.
// This method returns the concatenated string showing the grid.
Grid.prototype.toTextExt = function (withLabels, endOfRow, block) {
    var yx = new Grid(this.gsize).yx;
    var maxlen = 1, i, j, val;
    for (j = this.gsize; j >= 1; j--) {
        for (i = 1; i <= this.gsize; i++) {
            val = block(this.yx[j][i]);
            if (val === null) {
                val = '';
            }
            yx[j][i] = val;
            if (val.length > maxlen) {
                maxlen = val.length;
            }
        }
    }
    var numChar = maxlen;
    var white = '          ';
    var s = '';
    for (j = this.gsize; j >= 1; j--) {
        if (withLabels) {
            s += '%2d'.format(j) + ' ';
        }
        for (i = 1; i <= this.gsize; i++) {
            val = yx[j][i];
            if (val.length < numChar) {
                val = white.substr(1, numChar - val.length) + val;
            }
            s += val;
        }
        s += endOfRow;
    }
    if (withLabels) {
        s += '   ';
        for (i = 1; i <= this.gsize; i++) {
            s += white.substr(1, numChar - 1) + Grid.xLabel(i);
        }
        s += '\n';
    }
    if (endOfRow !== '\n') {
        return s.chop();
    }
    return s;
};

Grid.prototype.toString = function () {
    var s = '';
    for (var j = this.gsize; j >= 1; j--) {
        for (var i = 1; i <= this.gsize; i++) {
            s += Grid.colorToChar(this.yx[j][i]);
        }
        s += '\n';
    }
    return s;
};

// Returns a text "image" of the grid. See also copy? method.
// Image is upside-down to help compare with a copy paste from console log.
// So last row (j==gsize) comes first in image
Grid.prototype.image = function () {
    if (main.instanceOf(Object, this.yx[1][1])) {
        return this.toLine(function (s) {
            return Grid.colorToChar(s.color);
        });
    } else {
        return this.toLine(function (c) {
            return Grid.colorToChar(c);
        });
    }
};

// Watch out our images are upside-down on purpose (to help copy paste from screen)
// So last row (j==gsize) comes first in image
Grid.prototype.loadImage = function (image) {
    var rows = image.split(/\"|,/);
    if (rows.length !== this.gsize) {
        throw new Error('Invalid image: ' + rows.length + ' rows instead of ' + this.gsize);
    }
    for (var j = this.gsize; j >= 1; j--) {
        var row = rows[this.gsize - j];
        if (row.length !== this.gsize) {
            throw new Error('Invalid image: row ' + row);
        }
        for (var i = 1; i <= this.gsize; i++) {
            this.yx[j][i] = Grid.charToColor(row[i - 1]);
        }
    }
};

var COLUMNS = 'abcdefghjklmnopqrstuvwxyz'; // NB: "i" is skipped

// Parses a move like "c12" into 3,12
Grid.move2xy = function (move) {
    var i = COLUMNS.indexOf(move[0]) + 1;
    var j = parseInt(move.substr(1, 2));
    if (!i || isNaN(j)) throw new Error('Illegal move parsed: ' + move);
    return [i, j];
};

// Builds a string representation of a move (3,12->"c12")
Grid.xy2move = function (i, j) {
    return COLUMNS[i - 1] + j;
};

// Converts a numeric X coordinate in a letter (e.g 3->c)
Grid.xLabel = function (i) {
    return COLUMNS[i - 1];
};
<|endoftext|>


<commit_before>/* jshint maxparams: 5 */

(function(W, D, E, H, U) {
	'use strict';

	/**
	 * Setup initial variables
	 */
	var support = H && H.pushState,
		entries = [],
		settings = {},
		root = '',
		path = '',

		/**
		 * Return current path
		 *
		 * @private
		 * @param {object} loc
		 * @returns {string}
		 */
		_path = function(loc) {
			loc = loc || location;
			return loc.pathname + loc.search + loc.hash;
		},

		/**
		 * Determine if path is valid for history navigation
		 *
		 * @private
		 * @param {HTMLElement} el
		 */
		_isValid = function(el) {
			var host = el.hostname,
				path = el.pathname,
				loc = location;

			if ((host && host != loc.hostname) ||
				(el.hash && path == loc.pathname)) {
				return false;
			}

			var exts = settings.extensions,
				segs = path.split('.'),
				ext;

			if (segs.length > 1) {
				ext = segs.pop().split(/#|\?/)[0];
			}

			return ! ext || (exts && exts.indexOf(ext) > -1);
		},

		/**
		 * Reset references and variables for a given selector
		 *
		 * @private
		 * @param sel
		 */
		_reset = function(sel) {
			W.$setRef(sel);
			W.$setVar(sel);

			W.history.bind();
		};

	W.fn.make('history', {
		/**
		 * Set the initial state and popstate event, and bind global actions
		 *
		 * @param {object} [options]
		 * @param {boolean] [options.push=true]
		 * @param {string] [options.partials='title,main']
		 * @param {boolean} [options.run=true]
		 * @param {($|HTMLElement|string)} [options.bind]
		 * @param {object} [options.request]
		 * @param {array} [options.extensions]
		 */
		init: function(options) {
			if (! this.request) {
				path = _path();
				settings = W.$extend({
					partials: 'title,main',
					push: true,
					request: {},
					run: true,
					scrollTop: 0
				}, options);
				root = settings.request.root || '';

				this.request = settings.request;
				delete settings.request;

				if (support) {
					// Set current state
					H.replaceState(0, '', path);

					// Listen for browser navigation
					E.on(W._win, 'popstate.history', function(e) {
						if (e.state !== null) {
							var path = _path(),
								conf = entries[path.replace(/^\//g, '')];

							W.history.go(W.$extend(
								conf || {
									request: {
										root: ''
									}
								}, {
									path: path,
									push: false,
									pop: true
								}
							));
						}
					});
				}

				// Bind PJAX actions
				this.bind();
			}
		},

		/**
		 * Bind element events and form submit events to PJAX
		 *
		 * @param {object} [events]
		 * @param {($|HTMLElement|Object|string)} [a] - settings or context
		 * @param {($|HTMLElement|string)} [context=document]
		 */
		bind: function(events, a, context) {
			events = events || settings.bind;

			if (typeof a !== 'object') {
				context = a;
				a = {};
			}

			if (support && typeof events == 'object') {
				var keys = Object.keys(events),
					i = 0;

				for (; i < keys.length; i++) {
					var event = keys[i],
						sel = events[event];

					$(sel).each(function(el) {
						var evt = event.split(' ').map(function(val) {
								return val + '.history';
							}).join(' '),
							loc = el.getAttribute('data-url'),
							l = el;

						if (loc || a.action) {
							l = W._doc.createElement('a');
							l.href = loc || el.action;
						}

						// Ensure the path exists and is local
						if (evt && _isValid(l)) {
							var options = W.$extend(true, {}, a);
							options.path = _path(l);

							E.on(el, evt, function(e) {
								if (! e.metaKey) {
									W.history.go(options);
									e.preventDefault();
								}
							});
						}
					}, {
						context: context
					});
				}
			}
		},

		/**
		 * Navigate to a new path or within the browser history
		 *
		 * @param {object} options
		 * @param {string} [options.path=current path]
		 * @param {boolean} [options.push=true]
		 * @param {boolean} [options.run=true]
		 * @param {string} [options.title='']
		 * @param {object} [options.request]
		 * @param {string} [options.action='replace']
		 * @param {($|HTMLElement|string)} [options.scrollTop]
		 */
		go: function(options) {
			var scope = this;

			if (! scope.request) {
				scope.init();
			}

			var globalRequest = scope.request,
				conf = W.$extend(
					{},
					settings,
					options
				),
				request = conf.request || {};

			request.root = request.root !== U ?
				request.root :
				root;

			request.url = request.url !== U ?
				request.url :
				conf.path;

			// Navigate to external URL or if history isn't supported
			var a = W._doc.createElement('a');
			a.href = request.root + request.url;

			if (! support || ! _isValid(a)) {
				W._win.location = request.url;
				return false;
			}

			if (conf.begin && W.$exec(conf.begin) === false) {
				return;
			}

			// Reset URL to exclude root
			a.href = request.url;

			request.url = _path(a);
			conf.request = request;

			// Request partial Ajax
			if (request.url) {
				var sendEvents = [],
					successEvents = [],
					errorEvents = [],
					completeEvents = [],
					partials = conf.partials,
					targets = W.$(partials);

				// Set Pjax header
				request.headers = request.headers || {};
				request.headers['X-PJAX'] = 'true';

				// Process send events
				if (request.send) {
					sendEvents.push(request.send);
				}

				if (globalRequest.send) {
					sendEvents.push(globalRequest.send);
				}

				request.send = sendEvents;

				// Compile success events
				successEvents.push(function(html) {
					if (conf.replace) {
						W.$exec(conf.replace, {
							args: [html]
						});
					}

					// Evaluate unload routes against updated path
					if (W.routes && conf.run) {
						W.routes.run({
							event: 'unload',
							path: path
						});
					}

					if (partials) {
						html = W.$parseHTML('' + html + '');

						// Make partial replacements from response
						W.$each(partials.split(','), function(sel) {
							W.$each(sel, function(el) {
								var target = W.$(sel)[0];

								if (target) {
									var parent = target.parentNode;

									conf.action == 'append' ?
										parent.appendChild(el) :
										parent.replaceChild(el, target);

									_reset(parent);
								}
							}, {
								context: html
							});
						});
					} else {
						targets.innerHTML = html;

						_reset(targets);
					}
				});

				if (request.success) {
					successEvents.push(request.success);
				}

				if (globalRequest.success) {
					successEvents.push(globalRequest.success);
				}

				successEvents.push(function() {
					// Scroll vertically to target
					if (conf.scrollTop !== false) {
						var top = typeof conf.scrollTop == 'number' ?
								conf.scrollTop :
								W.$(conf.scrollTop)[0].getBoundingClientRect().top +
									W._win.pageYOffset,
							anim = W.animate;

						if (anim) {
							anim.tween(W._body, {
								scrollTop: top
							});
						} else {
							W._body.scrollTop = top;
						}
					}
				});

				request.success = successEvents;

				// Compile error events
				if (request.error) {
					errorEvents.push(request.error);
				}

				if (globalRequest.error) {
					errorEvents.push(globalRequest.error);
				}

				request.error = errorEvents;

				// Compile complete events
				if (request.complete) {
					completeEvents.push(request.complete);
				}

				if (globalRequest.complete) {
					completeEvents.push(globalRequest.complete);
				}

				completeEvents.push(function(xhr) {
					if (xhr.status == 200) {
						scope.$private.process(conf);
					}
				});

				request.complete = completeEvents;

				// Make Ajax request
				request.args = request.args || [];
				request.args.unshift(targets);

				D.request(request);
			} else {
				scope.$private.process(conf);
			}
		}
	}, {
		/**
		 * Process the history state of the request
		 *
		 * @param {object} conf
		 */
		process: function(conf) {
			var key = conf.path.replace(/^\//g, ''),
				request = conf.request,
				method = request.method;

			entries[key] = conf;

			if (! method || method == 'get') {
				conf.path = D.$private.getUrl(request);
			}

			var obj = {
				args: [
					{
						dir: conf.push ? 1 : -1,
						path: conf.path,
						prev: path
					}
				]
			};

			// Add entry to HTML5 history
			if (conf.push && support) {
				H.pushState(0, '', conf.path);
			}

			// Update document title
			if (conf.title) {
				W._doc.title = conf.title;
			}

			if (W.routes) {
				// Update current path
				W.routes.uri(conf.path);
				W.routes.uri({
					history: true
				});

				// Evaluate routes against updated path
				if (conf.run) {
					W.routes.run({
						event: 'pop',
						path: path
					});

					W.routes.run({
						path: conf.path
					});
				}

				path = conf.path;
			}

			if (conf.push && conf.pushstate) {
				W.$exec(conf.pushstate, obj);
			}

			if (conf.pop && conf.popstate) {
				W.$exec(conf.popstate, obj);
			}

			if (conf.end) {
				W.$exec(conf.end, obj);
			}
		}
	});
})(Wee, Wee.data, Wee.events, history, undefined);<commit_msg>Inject config object into history begin callback<commit_after>/* jshint maxparams: 5 */

(function(W, D, E, H, U) {
	'use strict';

	/**
	 * Setup initial variables
	 */
	var support = H && H.pushState,
		entries = [],
		settings = {},
		root = '',
		path = '',

		/**
		 * Return current path
		 *
		 * @private
		 * @param {object} loc
		 * @returns {string}
		 */
		_path = function(loc) {
			loc = loc || location;
			return loc.pathname + loc.search + loc.hash;
		},

		/**
		 * Determine if path is valid for history navigation
		 *
		 * @private
		 * @param {HTMLElement} el
		 */
		_isValid = function(el) {
			var host = el.hostname,
				path = el.pathname,
				loc = location;

			if ((host && host != loc.hostname) ||
				(el.hash && path == loc.pathname)) {
				return false;
			}

			var exts = settings.extensions,
				segs = path.split('.'),
				ext;

			if (segs.length > 1) {
				ext = segs.pop().split(/#|\?/)[0];
			}

			return ! ext || (exts && exts.indexOf(ext) > -1);
		},

		/**
		 * Reset references and variables for a given selector
		 *
		 * @private
		 * @param sel
		 */
		_reset = function(sel) {
			W.$setRef(sel);
			W.$setVar(sel);

			W.history.bind();
		};

	W.fn.make('history', {
		/**
		 * Set the initial state and popstate event, and bind global actions
		 *
		 * @param {object} [options]
		 * @param {boolean] [options.push=true]
		 * @param {string] [options.partials='title,main']
		 * @param {boolean} [options.run=true]
		 * @param {($|HTMLElement|string)} [options.bind]
		 * @param {object} [options.request]
		 * @param {array} [options.extensions]
		 */
		init: function(options) {
			if (! this.request) {
				path = _path();
				settings = W.$extend({
					partials: 'title,main',
					push: true,
					request: {},
					run: true,
					scrollTop: 0
				}, options);
				root = settings.request.root || '';

				this.request = settings.request;
				delete settings.request;

				if (support) {
					// Set current state
					H.replaceState(0, '', path);

					// Listen for browser navigation
					E.on(W._win, 'popstate.history', function(e) {
						if (e.state !== null) {
							var path = _path(),
								conf = entries[path.replace(/^\//g, '')];

							W.history.go(W.$extend(
								conf || {
									request: {
										root: ''
									}
								}, {
									path: path,
									push: false,
									pop: true
								}
							));
						}
					});
				}

				// Bind PJAX actions
				this.bind();
			}
		},

		/**
		 * Bind element events and form submit events to PJAX
		 *
		 * @param {object} [events]
		 * @param {($|HTMLElement|Object|string)} [a] - settings or context
		 * @param {($|HTMLElement|string)} [context=document]
		 */
		bind: function(events, a, context) {
			events = events || settings.bind;

			if (typeof a !== 'object') {
				context = a;
				a = {};
			}

			if (support && typeof events == 'object') {
				var keys = Object.keys(events),
					i = 0;

				for (; i < keys.length; i++) {
					var event = keys[i],
						sel = events[event];

					$(sel).each(function(el) {
						var evt = event.split(' ').map(function(val) {
								return val + '.history';
							}).join(' '),
							loc = el.getAttribute('data-url'),
							l = el;

						if (loc || a.action) {
							l = W._doc.createElement('a');
							l.href = loc || el.action;
						}

						// Ensure the path exists and is local
						if (evt && _isValid(l)) {
							var options = W.$extend(true, {}, a);
							options.path = _path(l);

							E.on(el, evt, function(e) {
								if (! e.metaKey) {
									W.history.go(options);
									e.preventDefault();
								}
							});
						}
					}, {
						context: context
					});
				}
			}
		},

		/**
		 * Navigate to a new path or within the browser history
		 *
		 * @param {object} options
		 * @param {string} [options.path=current path]
		 * @param {boolean} [options.push=true]
		 * @param {boolean} [options.run=true]
		 * @param {string} [options.title='']
		 * @param {object} [options.request]
		 * @param {string} [options.action='replace']
		 * @param {($|HTMLElement|string)} [options.scrollTop]
		 */
		go: function(options) {
			var scope = this;

			if (! scope.request) {
				scope.init();
			}

			var globalRequest = scope.request,
				conf = W.$extend(
					{},
					settings,
					options
				),
				request = conf.request || {};

			request.root = request.root !== U ?
				request.root :
				root;

			request.url = request.url !== U ?
				request.url :
				conf.path;

			// Navigate to external URL or if history isn't supported
			var a = W._doc.createElement('a');
			a.href = request.root + request.url;

			if (! support || ! _isValid(a)) {
				W._win.location = request.url;
				return false;
			}

			if (conf.begin && W.$exec(conf.begin, {
					args: [conf]
				}) === false) {
				return;
			}

			// Reset URL to exclude root
			a.href = request.url;

			request.url = _path(a);
			conf.request = request;

			// Request partial Ajax
			if (request.url) {
				var sendEvents = [],
					successEvents = [],
					errorEvents = [],
					completeEvents = [],
					partials = conf.partials,
					targets = W.$(partials);

				// Set Pjax header
				request.headers = request.headers || {};
				request.headers['X-PJAX'] = 'true';

				// Process send events
				if (request.send) {
					sendEvents.push(request.send);
				}

				if (globalRequest.send) {
					sendEvents.push(globalRequest.send);
				}

				request.send = sendEvents;

				// Compile success events
				successEvents.push(function(html) {
					if (conf.replace) {
						W.$exec(conf.replace, {
							args: [html]
						});
					}

					// Evaluate unload routes against updated path
					if (W.routes && conf.run) {
						W.routes.run({
							event: 'unload',
							path: path
						});
					}

					if (partials) {
						html = W.$parseHTML('' + html + '');

						// Make partial replacements from response
						W.$each(partials.split(','), function(sel) {
							W.$each(sel, function(el) {
								var target = W.$(sel)[0];

								if (target) {
									var parent = target.parentNode;

									conf.action == 'append' ?
										parent.appendChild(el) :
										parent.replaceChild(el, target);

									_reset(parent);
								}
							}, {
								context: html
							});
						});
					} else {
						targets.innerHTML = html;

						_reset(targets);
					}
				});

				if (request.success) {
					successEvents.push(request.success);
				}

				if (globalRequest.success) {
					successEvents.push(globalRequest.success);
				}

				successEvents.push(function() {
					// Scroll vertically to target
					if (conf.scrollTop !== false) {
						var top = typeof conf.scrollTop == 'number' ?
								conf.scrollTop :
								W.$(conf.scrollTop)[0].getBoundingClientRect().top +
									W._win.pageYOffset,
							anim = W.animate;

						if (anim) {
							anim.tween(W._body, {
								scrollTop: top
							});
						} else {
							W._body.scrollTop = top;
						}
					}
				});

				request.success = successEvents;

				// Compile error events
				if (request.error) {
					errorEvents.push(request.error);
				}

				if (globalRequest.error) {
					errorEvents.push(globalRequest.error);
				}

				request.error = errorEvents;

				// Compile complete events
				if (request.complete) {
					completeEvents.push(request.complete);
				}

				if (globalRequest.complete) {
					completeEvents.push(globalRequest.complete);
				}

				completeEvents.push(function(xhr) {
					if (xhr.status == 200) {
						scope.$private.process(conf);
					}
				});

				request.complete = completeEvents;

				// Make Ajax request
				request.args = request.args || [];
				request.args.unshift(targets);

				D.request(request);
			} else {
				scope.$private.process(conf);
			}
		}
	}, {
		/**
		 * Process the history state of the request
		 *
		 * @param {object} conf
		 */
		process: function(conf) {
			var key = conf.path.replace(/^\//g, ''),
				request = conf.request,
				method = request.method;

			entries[key] = conf;

			if (! method || method == 'get') {
				conf.path = D.$private.getUrl(request);
			}

			var obj = {
				args: [
					{
						dir: conf.push ? 1 : -1,
						path: conf.path,
						prev: path
					}
				]
			};

			// Add entry to HTML5 history
			if (conf.push && support) {
				H.pushState(0, '', conf.path);
			}

			// Update document title
			if (conf.title) {
				W._doc.title = conf.title;
			}

			if (W.routes) {
				// Update current path
				W.routes.uri(conf.path);
				W.routes.uri({
					history: true
				});

				// Evaluate routes against updated path
				if (conf.run) {
					W.routes.run({
						event: 'pop',
						path: path
					});

					W.routes.run({
						path: conf.path
					});
				}

				path = conf.path;
			}

			if (conf.push && conf.pushstate) {
				W.$exec(conf.pushstate, obj);
			}

			if (conf.pop && conf.popstate) {
				W.$exec(conf.popstate, obj);
			}

			if (conf.end) {
				W.$exec(conf.end, obj);
			}
		}
	});
})(Wee, Wee.data, Wee.events, history, undefined);<|endoftext|>


<commit_before>import Game from 'game/index';

const game = Game();

game
	.on('end', level => {
		game.start(level === 32 ? 1 : level + 1);
	})
	.start(1);
<commit_msg>Fix import syntax<commit_after>import Game from 'game';

const game = Game();

game
	.on('end', level => {
		game.start(level === 32 ? 1 : level + 1);
	})
	.start(1);
<|endoftext|>


<commit_before>var run = require("./colorscheme-less");

var command;
var file;

if (process.argv[0] === "node" || process.argv[0] === "iojs") {
	command = process.argv[2];
	file = process.argv[3];
}
else {
	// run directly as JS (windows)
	command = process.argv[1];
	file = process.argv[2];
}

if (!command && !file) {
	console.log("Usage: colorscheme-less [generate|shuffle] [path/to/file.less]");
	process.exit();
}

if (!file) {
	file = command;
	command = "generate";
}

console.log("command: " + command);
console.log("file: " + file);

run(command, file)
.then(function () {
	console.log("success.");
	process.exit();
});

<commit_msg>I don't know what I'm doing<commit_after>var run = require("./colorscheme-less");

var command;
var file;

command = process.argv[2];
file = process.argv[3];

if (!command && !file) {
	console.log("Usage: colorscheme-less [generate|shuffle] [path/to/file.less]");
	process.exit();
}

if (!file) {
	file = command;
	command = "generate";
}

console.log("command: " + command);
console.log("file: " + file);

run(command, file)
.then(function () {
	console.log("success.");
	process.exit();
});

<|endoftext|>


<commit_before>import * as React from 'react'
import TagsInput from 'react-tagsinput'
import { difference, isEqual, orderBy } from 'lodash'

export default class TagBar extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      tags: this.clean(props.tags, props),
    }
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      tags: this.clean(nextProps.tags, nextProps),
    })
  }

  clean(list, props = this.props) {
    let tags = difference(list, props.banned)
    if (props.unique) tags = orderBy(tags)
    return tags
  }

  render() {
    const {
      className, tags, readonly, unique,
      inputSettings, tagSettings, onChange,
    } = this.props

    return (
      <TagsInput
        className={className} value={tags} readonly={readonly}
        inputProps={inputSettings} tagProps={tagSettings}
        renderInput={props => !readonly &&
          <input type="text" ref="input"
            className={props.className}
            placeholder={props.placeholder}
          />
        }
        renderTag={props =>

            <a className="icon icon-tag" href={`/page/${props.tag}`}>{props.tag}
            { !readonly &&  props.onRemove(props.key)} /> }

        }
        onChange={updated => {
          let clean = this.clean(updated)
          if (!isEqual(clean, this.state.tags))
            this.props.onChange(clean)
        }}
        onlyUnique={unique}
      />
    )
  }
}

TagBar.propTypes = {
  banned: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
  className: React.PropTypes.string,
  onChange: React.PropTypes.func.isRequired,
  readonly: React.PropTypes.bool.isRequired,
  tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
  unique: React.PropTypes.bool.isRequired,

  input: React.PropTypes.shape({
    className: React.PropTypes.string,
    placeholder: React.PropTypes.string,
  }),
  tagSettings: React.PropTypes.shape({
    className: React.PropTypes.string,
    classNameRemove: React.PropTypes.string,
  }),
}
TagBar.defaultProps = {
  banned: [],
  className: 'tag-bar',
  onChange: () => {},
  readonly: false,
  tags: [],
  unique: true,

  inputSettings: {
    className: 'tag-bar-input',
    placeholder: 'add tag'
  },
  tagSettings: {
    className: 'tag',
    classNameRemove: 'remove'
  },
}
<commit_msg>:bug:fix - restored functionality of adding tags<commit_after>import * as React from 'react'
import TagsInput from 'react-tagsinput'
import { difference, isEqual, orderBy } from 'lodash'

export default class TagBar extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      tags: this.clean(props.tags, props),
    }
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      tags: this.clean(nextProps.tags, nextProps),
    })
  }

  clean(list, props = this.props) {
    let tags = difference(list, props.banned)
    if (props.unique) tags = orderBy(tags)
    return tags
  }

  render() {
    const {
      className, tags, readonly, unique,
      inputSettings, tagSettings, onChange,
    } = this.props

    return (
      <TagsInput
        className={className} value={tags} readonly={readonly}
        inputProps={inputSettings} tagProps={tagSettings}
        renderInput={props => !readonly &&
          <input type="text" ref="input" {...props}
            className={props.className}
            placeholder={props.placeholder}
          />
        }
        renderTag={props =>

            <a className="icon icon-tag" href={`/page/${props.tag}`}>{props.tag}
            { !readonly &&  props.onRemove(props.key)} /> }

        }
        onChange={updated => {
          let clean = this.clean(updated)
          if (!isEqual(clean, this.state.tags))
            this.props.onChange(clean)
        }}
        onlyUnique={unique}
      />
    )
  }
}

TagBar.propTypes = {
  banned: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
  className: React.PropTypes.string,
  onChange: React.PropTypes.func.isRequired,
  readonly: React.PropTypes.bool.isRequired,
  tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
  unique: React.PropTypes.bool.isRequired,

  input: React.PropTypes.shape({
    className: React.PropTypes.string,
    placeholder: React.PropTypes.string,
  }),
  tagSettings: React.PropTypes.shape({
    className: React.PropTypes.string,
    classNameRemove: React.PropTypes.string,
  }),
}
TagBar.defaultProps = {
  banned: [],
  className: 'tag-bar',
  onChange: () => {},
  readonly: false,
  tags: [],
  unique: true,

  inputSettings: {
    className: 'tag-bar-input',
    placeholder: 'add tag'
  },
  tagSettings: {
    className: 'tag',
    classNameRemove: 'remove'
  },
}
<|endoftext|>


<commit_before>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Returns a map such that map[locale][stringKey] will be the string value (with fallbacks to English where needed).
 * Loads each string file only once, and only loads the repository/locale combinations necessary.
 * Requires global.phet.chipper.strings to be set by the string.js plugin.
 */

// built-in node APIs
var assert = require( 'assert' );
var path = require( 'path' );

// modules
var localeInfo = require( '../../../chipper/js/data/localeInfo' ); // Locale information
var ChipperConstants = require( '../../../chipper/js/common/ChipperConstants' );

/**
 * @param grunt - the grunt instance
 * @param {Object} buildConfig - see getBuildConfig.js
 * @returns map[locale][stringKey]
 */
module.exports = function( grunt, buildConfig ) {
  'use strict';

  var fallbackLocale = ChipperConstants.FALLBACK_LOCALE; // local var to improve readability

  assert( global.phet && global.phet.chipper && global.phet.chipper.strings, 'missing global.phet.chipper.strings' );
  assert( buildConfig.locales.indexOf( fallbackLocale ) !== -1, 'fallback locale is required' );

  // Get metadata of repositories that we want to load strings from (that were referenced in the sim)
  var stringRepositories = []; // { name: {string}, path: {string}, requirejsNamespace: {string} }
  for ( var stringKey in global.phet.chipper.strings ) {
    var repositoryName = global.phet.chipper.strings[ stringKey ].repositoryName;

    if ( stringRepositories.every( function( repo ) { return repo.name !== repositoryName; } ) ) {
      stringRepositories.push( {
        name: repositoryName,
        path: global.phet.chipper.strings[ stringKey ].repositoryPath,
        requirejsNamespace: global.phet.chipper.strings[ stringKey ].requirejsNamespace
      } );

      // If a string depends on an unlisted dependency, fail out
      if ( buildConfig.phetLibs.indexOf( repositoryName ) < 0 ) {
        throw new Error( repositoryName + ' is missing from phetLib in package.json' );
      }
    }
  }

  // Load all the required string files into memory, so we don't load them multiple times (for each usage)
  var repoStringMap = {}; // maps [repositoryName][locale] => contents of locale string file
  stringRepositories.forEach( function( repository ) {
    repoStringMap[ repository.name ] = {};

    buildConfig.locales.forEach( function( locale ) {

      assert( localeInfo[ locale ], 'unsupported locale: ' + locale );
      var isRTL = localeInfo[ locale ].direction === 'rtl';

      var basePath;
      // pick a location that is in the repo, or babel
      if ( locale === fallbackLocale ) {
        basePath = repository.path + '/';
      }
      else {
        basePath = repository.path + '/../babel/' + repository.name + '/';
      }

      // Read optional string file
      var stringsFilename = path.normalize( basePath + repository.name + '-strings_' + locale + '.json' );
      var fileContents;
      try {
        fileContents = grunt.file.readJSON( stringsFilename );
      }
      catch( error ) {
        grunt.log.warn( 'missing string file: ' + stringsFilename );
        fileContents = {};
      }
      var fileMap = repoStringMap[ repository.name ][ locale ] = {};

      for ( var stringKeyMissingPrefix in fileContents ) {
        var stringData = fileContents[ stringKeyMissingPrefix ];

        // Pad LTR/RTL language values with unicode embedding marks (see https://github.com/phetsims/joist/issues/152)
        // Uses directional formatting characters: http://unicode.org/reports/tr9/#Directional_Formatting_Characters
        stringData.value = ( isRTL ? '\u202b' : '\u202a' ) + stringData.value + '\u202c';

        // Add the requirejs namespaces (eg, JOIST) to the key
        fileMap[ repository.requirejsNamespace + '/' + stringKeyMissingPrefix ] = fileContents[ stringKeyMissingPrefix ];
      }
    } );
  } );

  // combine our strings into [locale][stringKey] map, using the fallback locale where necessary
  var stringMap = {};
  buildConfig.locales.forEach( function( locale ) {
    stringMap[ locale ] = {};

    for ( var stringKey in global.phet.chipper.strings ) {
      var repositoryName = global.phet.chipper.strings[ stringKey ].repositoryName;

      // English fallback
      assert( repoStringMap[ repositoryName ][ fallbackLocale ][ stringKey ] !== undefined,
        'Missing string: ' + stringKey + ' in ' + repositoryName + ' for fallback locale: ' + fallbackLocale );
      var fallbackString = repoStringMap[ repositoryName ][ fallbackLocale ][ stringKey ].value;
      stringMap[ locale ][ stringKey ] = fallbackString;

      // Extract 'value' field from non-fallback (babel) strings file, and overwrites the default if available.
      if ( locale !== fallbackLocale &&
           repoStringMap[ repositoryName ] &&
           repoStringMap[ repositoryName ][ locale ] &&
           repoStringMap[ repositoryName ][ locale ][ stringKey ] &&

           // If the string in rosetta is empty we want to use the fallback locale string.
           // Test for length of 2 and not 0 because the directional embedding marks are included in empty strings.
           repoStringMap[ repositoryName ][ locale ][ stringKey ].value.length > 2 ) {
        stringMap[ locale ][ stringKey ] = repoStringMap[ repositoryName ][ locale ][ stringKey ].value;
      }
    }
  } );                                                                            #33

  return stringMap;
};
<commit_msg>#330 edit comment<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Returns a map such that map[locale][stringKey] will be the string value (with fallbacks to English where needed).
 * Loads each string file only once, and only loads the repository/locale combinations necessary.
 * Requires global.phet.chipper.strings to be set by the string.js plugin.
 */

// built-in node APIs
var assert = require( 'assert' );
var path = require( 'path' );

// modules
var localeInfo = require( '../../../chipper/js/data/localeInfo' ); // Locale information
var ChipperConstants = require( '../../../chipper/js/common/ChipperConstants' );

/**
 * @param grunt - the grunt instance
 * @param {Object} buildConfig - see getBuildConfig.js
 * @returns map[locale][stringKey]
 */
module.exports = function( grunt, buildConfig ) {
  'use strict';

  var fallbackLocale = ChipperConstants.FALLBACK_LOCALE; // local var to improve readability

  assert( global.phet && global.phet.chipper && global.phet.chipper.strings, 'missing global.phet.chipper.strings' );
  assert( buildConfig.locales.indexOf( fallbackLocale ) !== -1, 'fallback locale is required' );

  // Get metadata of repositories that we want to load strings from (that were referenced in the sim)
  var stringRepositories = []; // { name: {string}, path: {string}, requirejsNamespace: {string} }
  for ( var stringKey in global.phet.chipper.strings ) {
    var repositoryName = global.phet.chipper.strings[ stringKey ].repositoryName;

    if ( stringRepositories.every( function( repo ) { return repo.name !== repositoryName; } ) ) {
      stringRepositories.push( {
        name: repositoryName,
        path: global.phet.chipper.strings[ stringKey ].repositoryPath,
        requirejsNamespace: global.phet.chipper.strings[ stringKey ].requirejsNamespace
      } );

      // If a string depends on an unlisted dependency, fail out
      if ( buildConfig.phetLibs.indexOf( repositoryName ) < 0 ) {
        throw new Error( repositoryName + ' is missing from phetLib in package.json' );
      }
    }
  }

  // Load all the required string files into memory, so we don't load them multiple times (for each usage)
  var repoStringMap = {}; // maps [repositoryName][locale] => contents of locale string file
  stringRepositories.forEach( function( repository ) {
    repoStringMap[ repository.name ] = {};

    buildConfig.locales.forEach( function( locale ) {

      assert( localeInfo[ locale ], 'unsupported locale: ' + locale );
      var isRTL = localeInfo[ locale ].direction === 'rtl';

      var basePath;
      // pick a location that is in the repo, or babel
      if ( locale === fallbackLocale ) {
        basePath = repository.path + '/';
      }
      else {
        basePath = repository.path + '/../babel/' + repository.name + '/';
      }

      // Read optional string file
      var stringsFilename = path.normalize( basePath + repository.name + '-strings_' + locale + '.json' );
      var fileContents;
      try {
        fileContents = grunt.file.readJSON( stringsFilename );
      }
      catch( error ) {
        grunt.log.warn( 'missing string file: ' + stringsFilename );
        fileContents = {};
      }
      var fileMap = repoStringMap[ repository.name ][ locale ] = {};

      for ( var stringKeyMissingPrefix in fileContents ) {
        var stringData = fileContents[ stringKeyMissingPrefix ];

        // Pad LTR/RTL language values with unicode embedding marks (see https://github.com/phetsims/joist/issues/152)
        // Uses directional formatting characters: http://unicode.org/reports/tr9/#Directional_Formatting_Characters
        stringData.value = ( isRTL ? '\u202b' : '\u202a' ) + stringData.value + '\u202c';

        // Add the requirejs namespaces (eg, JOIST) to the key
        fileMap[ repository.requirejsNamespace + '/' + stringKeyMissingPrefix ] = fileContents[ stringKeyMissingPrefix ];
      }
    } );
  } );

  // combine our strings into [locale][stringKey] map, using the fallback locale where necessary
  var stringMap = {};
  buildConfig.locales.forEach( function( locale ) {
    stringMap[ locale ] = {};

    for ( var stringKey in global.phet.chipper.strings ) {
      var repositoryName = global.phet.chipper.strings[ stringKey ].repositoryName;

      // English fallback
      assert( repoStringMap[ repositoryName ][ fallbackLocale ][ stringKey ] !== undefined,
        'Missing string: ' + stringKey + ' in ' + repositoryName + ' for fallback locale: ' + fallbackLocale );
      var fallbackString = repoStringMap[ repositoryName ][ fallbackLocale ][ stringKey ].value;
      stringMap[ locale ][ stringKey ] = fallbackString;

      // Extract 'value' field from non-fallback (babel) strings file, and overwrites the default if available.
      if ( locale !== fallbackLocale &&
           repoStringMap[ repositoryName ] &&
           repoStringMap[ repositoryName ][ locale ] &&
           repoStringMap[ repositoryName ][ locale ][ stringKey ] &&

           // If the string's value is empty we want to use the fallback locale string.
           // Test for length of 2 and not 0 because the directional embedding marks are included in empty strings.
           repoStringMap[ repositoryName ][ locale ][ stringKey ].value.length > 2 ) {
        stringMap[ locale ][ stringKey ] = repoStringMap[ repositoryName ][ locale ][ stringKey ].value;
      }
    }
  } );                                                                            #33

  return stringMap;
};
<|endoftext|>


<commit_before>var mysql        = require('../');
var Connection   = require('./Connection');
var EventEmitter = require('events').EventEmitter;
var Util         = require('util');
var PoolConnection = require('./PoolConnection');

module.exports = Pool;

Util.inherits(Pool, EventEmitter);
function Pool(options) {
  EventEmitter.call(this);
  this.config = options.config;
  this.config.connectionConfig.pool = this;

  this._allConnections   = [];
  this._freeConnections  = [];
  this._connectionQueue  = [];
  this._closed           = false;
}

Pool.prototype.getConnection = function (cb) {

  if (this._closed) {
    return process.nextTick(function(){
      return cb(new Error('Pool is closed.'));
    });
  }

  var connection;

  if (this._freeConnections.length > 0) {
    connection = this._freeConnections.shift();

    return process.nextTick(function(){
      cb(null, connection);
    });
  }

  if (this.config.connectionLimit === 0 || this._allConnections.length < this.config.connectionLimit) {
    connection = new PoolConnection(this, { config: this.config.connectionConfig });

    this._allConnections.push(connection);

    return connection.connect(function(err) {
      if (this._closed) {
        return cb(new Error('Pool is closed.'));
      }
      if (err) {
        return cb(err);
      }

      this.emit('connection', connection);
      return cb(null, connection);
    }.bind(this));
  }

  if (!this.config.waitForConnections) {
    return process.nextTick(function(){
      return cb(new Error('No connections available.'));
    });
  }

  if (this.config.queueLimit && this._connectionQueue.length >= this.config.queueLimit) {
    return cb(new Error('Queue limit reached.'));
  }

  if (cb && process.domain)
    cb = process.domain.bind(cb);
  this._connectionQueue.push(cb);
};

Pool.prototype.releaseConnection = function (connection) {
  var cb;

  if (!connection._pool) {
    // The connection has been removed from the pool and is no longer good.
    if (this._connectionQueue.length) {
      cb = this._connectionQueue.shift();

      process.nextTick(this.getConnection.bind(this, cb));
    }
  } else if (this._connectionQueue.length) {
    cb = this._connectionQueue.shift();

    process.nextTick(cb.bind(null, null, connection));
  } else {
    this._freeConnections.push(connection);
  }
};

Pool.prototype.end = function (cb) {
  this._closed = true;

  if (typeof cb != "function") {
    cb = function (err) {
      if (err) throw err;
    };
  }

  var calledBack        = false;
  var closedConnections = 0;
  var connection;

  var endCB = function(err) {
    if (calledBack) {
      return;
    }

    if (err || ++closedConnections >= this._allConnections.length) {
      calledBack = true;
      return cb(err);
    }
  }.bind(this);

  if (this._allConnections.length === 0) {
    return process.nextTick(endCB);
  }

  for (var i = 0; i < this._allConnections.length; i++) {
    connection = this._allConnections[i];
    connection._realEnd(endCB);
  }
};

Pool.prototype.query = function (sql, values, cb) {
  if (typeof values === 'function') {
    cb = values;
    values = null;
  }

  if (!cb) {
    // Ignore results and errors if no cb supplied; matches connection.query
    cb = function () {};
  }

  var connection;
  var query = Connection.createQuery(sql, values, function (err, rows, fields) {
    connection.release();
    cb.apply(this, arguments);
  });

  if (this.config.connectionConfig.trace) {
    // Long stack trace support
    query._callSite = new Error;
  }

  this.getConnection(function (err, conn) {
    if (err) return cb(err);

    connection = conn;
    conn.query(query);
  });
};

Pool.prototype._removeConnection = function(connection) {
  var index;

  if ((index = this._allConnections.indexOf(connection)) !== -1) {
    // Remove connection from all connections
    this._allConnections.splice(index, 1);
  }

  if ((index = this._freeConnections.indexOf(connection)) !== -1) {
    // Remove connection from free connections
    this._freeConnections.splice(index, 1);
  }

  this.releaseConnection(connection);
};

Pool.prototype.escape = function(value) {
  return mysql.escape(value, this.config.connectionConfig.stringifyObjects, this.config.connectionConfig.timezone);
};
<commit_msg>lint: lined up requirements<commit_after>var mysql          = require('../');
var Connection     = require('./Connection');
var EventEmitter   = require('events').EventEmitter;
var Util           = require('util');
var PoolConnection = require('./PoolConnection');

module.exports = Pool;

Util.inherits(Pool, EventEmitter);
function Pool(options) {
  EventEmitter.call(this);
  this.config = options.config;
  this.config.connectionConfig.pool = this;

  this._allConnections   = [];
  this._freeConnections  = [];
  this._connectionQueue  = [];
  this._closed           = false;
}

Pool.prototype.getConnection = function (cb) {

  if (this._closed) {
    return process.nextTick(function(){
      return cb(new Error('Pool is closed.'));
    });
  }

  var connection;

  if (this._freeConnections.length > 0) {
    connection = this._freeConnections.shift();

    return process.nextTick(function(){
      cb(null, connection);
    });
  }

  if (this.config.connectionLimit === 0 || this._allConnections.length < this.config.connectionLimit) {
    connection = new PoolConnection(this, { config: this.config.connectionConfig });

    this._allConnections.push(connection);

    return connection.connect(function(err) {
      if (this._closed) {
        return cb(new Error('Pool is closed.'));
      }
      if (err) {
        return cb(err);
      }

      this.emit('connection', connection);
      return cb(null, connection);
    }.bind(this));
  }

  if (!this.config.waitForConnections) {
    return process.nextTick(function(){
      return cb(new Error('No connections available.'));
    });
  }

  if (this.config.queueLimit && this._connectionQueue.length >= this.config.queueLimit) {
    return cb(new Error('Queue limit reached.'));
  }

  if (cb && process.domain)
    cb = process.domain.bind(cb);
  this._connectionQueue.push(cb);
};

Pool.prototype.releaseConnection = function (connection) {
  var cb;

  if (!connection._pool) {
    // The connection has been removed from the pool and is no longer good.
    if (this._connectionQueue.length) {
      cb = this._connectionQueue.shift();

      process.nextTick(this.getConnection.bind(this, cb));
    }
  } else if (this._connectionQueue.length) {
    cb = this._connectionQueue.shift();

    process.nextTick(cb.bind(null, null, connection));
  } else {
    this._freeConnections.push(connection);
  }
};

Pool.prototype.end = function (cb) {
  this._closed = true;

  if (typeof cb != "function") {
    cb = function (err) {
      if (err) throw err;
    };
  }

  var calledBack        = false;
  var closedConnections = 0;
  var connection;

  var endCB = function(err) {
    if (calledBack) {
      return;
    }

    if (err || ++closedConnections >= this._allConnections.length) {
      calledBack = true;
      return cb(err);
    }
  }.bind(this);

  if (this._allConnections.length === 0) {
    return process.nextTick(endCB);
  }

  for (var i = 0; i < this._allConnections.length; i++) {
    connection = this._allConnections[i];
    connection._realEnd(endCB);
  }
};

Pool.prototype.query = function (sql, values, cb) {
  if (typeof values === 'function') {
    cb = values;
    values = null;
  }

  if (!cb) {
    // Ignore results and errors if no cb supplied; matches connection.query
    cb = function () {};
  }

  var connection;
  var query = Connection.createQuery(sql, values, function (err, rows, fields) {
    connection.release();
    cb.apply(this, arguments);
  });

  if (this.config.connectionConfig.trace) {
    // Long stack trace support
    query._callSite = new Error;
  }

  this.getConnection(function (err, conn) {
    if (err) return cb(err);

    connection = conn;
    conn.query(query);
  });
};

Pool.prototype._removeConnection = function(connection) {
  var index;

  if ((index = this._allConnections.indexOf(connection)) !== -1) {
    // Remove connection from all connections
    this._allConnections.splice(index, 1);
  }

  if ((index = this._freeConnections.indexOf(connection)) !== -1) {
    // Remove connection from free connections
    this._freeConnections.splice(index, 1);
  }

  this.releaseConnection(connection);
};

Pool.prototype.escape = function(value) {
  return mysql.escape(value, this.config.connectionConfig.stringifyObjects, this.config.connectionConfig.timezone);
};
<|endoftext|>


<commit_before>var assert = require('better-assert');
var Promise = require('../');
var sentinel = {};
var promise = new Promise(function (resolve) {
  resolve(sentinel);
});

var _it = it;
describe('resolver-tests', function () {
  describe('The Promise Constructor', function () {
    it('can be called without new with the same results', function (done) {
      Promise(function (resolve) { resolve(null); }).then(done);
    })
    it('has `Object.getPrototypeOf(promise) === Promise.prototype`', function () {
      assert(Object.getPrototypeOf(promise) === Promise.prototype)
    })
    it('has `promise.constructor === Promise`', function () {
      assert(promise.constructor === Promise)
    })
    it('has `promise.constructor === Promise.prototype.constructor`', function () {
      assert(promise.constructor === Promise.prototype.constructor)
    })
    it('has `Promise.length === 1`', function () {
      assert(Promise.length === 1)
    })
    describe('if resolver is not a function', function () {
      it('must throw a `TypeError`', function () {
        try {
          new Promise({})
        } catch (ex) {
          assert(ex instanceof TypeError)
          return
        }
        throw new Error('Should have thrown a TypeError')
      })
    })
    describe('if resolver is a function', function () {
      it('must be called with the promise\'s resolver arguments', function () {
        new Promise(function (resolve, reject) {
          assert(typeof resolve === 'function')
          assert(typeof reject === 'function')
          done();
        })
      })
      it('must be called immediately, before `Promise` returns', function () {
        var called = false;
        new Promise(function (resolve, reject) {
          called = true;
        })
        assert(called)
      })
    })
    describe('Calling resolve(x)', function () {
      describe('if promise is resolved', function () {
        it('nothing happens', function (done) {
          var thenable = {then: function (onComplete) {
            setTimeout(function () {
              onComplete(sentinel)
            }, 50)
          }};
          new Promise(function (resolve) {
            process.nextTick(function () {
              resolve(thenable)
              resolve(null)
            });
          })
          .then(function (result) {
            assert(result === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
      describe('otherwise', function () {
        describe('if x is a thenable', function () {
          it('assimilates the thenable', function () {

          })
        })
        describe('otherwise', function () {
          it('is fulfilled with x as the fulfillment value', function (done) {
            new Promise(function (resolve, reject) {
              resolve(sentinel)
            })
            .then(function (fulfillmentValue) {
              assert(fulfillmentValue === sentinel)
            })
            .then(function () {
              done()
            }, function (err) {
              done(err || new Error('Promise rejected'));
            })
          })
        })
      })
    })
    describe('Calling reject(x)', function () {
      describe('if promise is resolved', function () {
        it('nothing happens', function (done) {
          var thenable = {then: function (onComplete) {
            setTimeout(function () {
              onComplete(sentinel)
            }, 50)
          }};
          new Promise(function (resolve, reject) {
            process.nextTick(function () {
              resolve(thenable)
              reject('foo')
            });
          })
          .then(function (result) {
            assert(result === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
      describe('otherwise', function () {
        it('is rejected with x as the rejection reason', function (done) {
          new Promise(function (resolve, reject) {
            reject(sentinel)
          })
          .then(null, function (rejectionReason) {
            assert(rejectionReason === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
    })
  })
  describe('if resolver throws', function () {
    describe('if promise is resolved', function () {
      it('nothing happens', function (done) {
        var thenable = {then: function (onComplete) {
          setTimeout(function () {
            onComplete(sentinel)
          }, 50)
        }};
        new Promise(function (resolve, reject) {
          resolve(thenable)
          throw new Error('foo');
        })
        .then(function (result) {
          assert(result === sentinel)
        })
        .then(function () {
          done()
        }, function (err) {
          done(err || new Error('Promise rejected'));
        })
      })
    })
    describe('otherwise', function () {
      it('is rejected with e as the rejection reason', function () {
        new Promise(function (resolve, reject) {
          throw sentinel
        })
        .then(null, function (rejectionReason) {
          assert(rejectionReason === sentinel)
        })
        .then(function () {
          done()
        }, function (err) {
          done(err || new Error('Promise rejected'));
        })
      })
    })
  })
})<commit_msg>Fix test<commit_after>var assert = require('better-assert');
var Promise = require('../');
var sentinel = {};
var promise = new Promise(function (resolve) {
  resolve(sentinel);
});

var _it = it;
describe('resolver-tests', function () {
  describe('The Promise Constructor', function () {
    it('has `Object.getPrototypeOf(promise) === Promise.prototype`', function () {
      assert(Object.getPrototypeOf(promise) === Promise.prototype)
    })
    it('has `promise.constructor === Promise`', function () {
      assert(promise.constructor === Promise)
    })
    it('has `promise.constructor === Promise.prototype.constructor`', function () {
      assert(promise.constructor === Promise.prototype.constructor)
    })
    it('has `Promise.length === 1`', function () {
      assert(Promise.length === 1)
    })
    describe('if resolver is not a function', function () {
      it('must throw a `TypeError`', function () {
        try {
          new Promise({})
        } catch (ex) {
          assert(ex instanceof TypeError)
          return
        }
        throw new Error('Should have thrown a TypeError')
      })
    })
    describe('if resolver is a function', function () {
      it('must be called with the promise\'s resolver arguments', function () {
        new Promise(function (resolve, reject) {
          assert(typeof resolve === 'function')
          assert(typeof reject === 'function')
          done();
        })
      })
      it('must be called immediately, before `Promise` returns', function () {
        var called = false;
        new Promise(function (resolve, reject) {
          called = true;
        })
        assert(called)
      })
    })
    describe('Calling resolve(x)', function () {
      describe('if promise is resolved', function () {
        it('nothing happens', function (done) {
          var thenable = {then: function (onComplete) {
            setTimeout(function () {
              onComplete(sentinel)
            }, 50)
          }};
          new Promise(function (resolve) {
            process.nextTick(function () {
              resolve(thenable)
              resolve(null)
            });
          })
          .then(function (result) {
            assert(result === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
      describe('otherwise', function () {
        describe('if x is a thenable', function () {
          it('assimilates the thenable', function () {

          })
        })
        describe('otherwise', function () {
          it('is fulfilled with x as the fulfillment value', function (done) {
            new Promise(function (resolve, reject) {
              resolve(sentinel)
            })
            .then(function (fulfillmentValue) {
              assert(fulfillmentValue === sentinel)
            })
            .then(function () {
              done()
            }, function (err) {
              done(err || new Error('Promise rejected'));
            })
          })
        })
      })
    })
    describe('Calling reject(x)', function () {
      describe('if promise is resolved', function () {
        it('nothing happens', function (done) {
          var thenable = {then: function (onComplete) {
            setTimeout(function () {
              onComplete(sentinel)
            }, 50)
          }};
          new Promise(function (resolve, reject) {
            process.nextTick(function () {
              resolve(thenable)
              reject('foo')
            });
          })
          .then(function (result) {
            assert(result === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
      describe('otherwise', function () {
        it('is rejected with x as the rejection reason', function (done) {
          new Promise(function (resolve, reject) {
            reject(sentinel)
          })
          .then(null, function (rejectionReason) {
            assert(rejectionReason === sentinel)
          })
          .then(function () {
            done()
          }, function (err) {
            done(err || new Error('Promise rejected'));
          })
        })
      })
    })
  })
  describe('if resolver throws', function () {
    describe('if promise is resolved', function () {
      it('nothing happens', function (done) {
        var thenable = {then: function (onComplete) {
          setTimeout(function () {
            onComplete(sentinel)
          }, 50)
        }};
        new Promise(function (resolve, reject) {
          resolve(thenable)
          throw new Error('foo');
        })
        .then(function (result) {
          assert(result === sentinel)
        })
        .then(function () {
          done()
        }, function (err) {
          done(err || new Error('Promise rejected'));
        })
      })
    })
    describe('otherwise', function () {
      it('is rejected with e as the rejection reason', function () {
        new Promise(function (resolve, reject) {
          throw sentinel
        })
        .then(null, function (rejectionReason) {
          assert(rejectionReason === sentinel)
        })
        .then(function () {
          done()
        }, function (err) {
          done(err || new Error('Promise rejected'));
        })
      })
    })
  })
})<|endoftext|>


<commit_before>var playurl="http://ni.fe.up.pt/uni";
var room="";
var playerName="";
var status;
var active=false; //boolean para bloquear inputs durante chamadas ao servidor

//flags
var colorSelBuffer="";
var cardupdate=false;
var drawbuffer=false;
var skipdraw=false;
var readychecked=false;
var inlobby=false;
var ingame=false;
var inqueue=true;
var gameactive=true;
//pointer ao set timeout para o desativar quando fizer /quit
var timerfunc;
//milisegundos para fazer novo request de status/lobby
var timerms=1000;

function Card(color,value) {

	this.color = color;
	this.value = value;
	switch(color)
	{
		case 0:this.colortext="Red";break;
		case 1:this.colortext="Green";break;
		case 2:this.colortext="Blue";break;
		case 3:this.colortext="Yellow";break;
		case 4:this.colortext="Wild";break;
		default:this.colortext="Error";
	}
	switch(value)
	{
		case 10:this.valuetext="";break;
		case 11:this.valuetext="+2";break;
		case 12:this.valuetext="";break;
		case 13:this.valuetext="";break;
		case 14:this.valuetext="";break;
		default:this.valuetext=value;
	}
}

Card.prototype.html = function() {
	return 	'
' +
			'
' +
			'
' +
			this.valuetext +
			'
' +
			'
' +
			'
';
}

function ParseMao(mao )
{
	var htmlstr="";
	var card;
	for (var i=0;i< mao.length;i++)
	{
		card=new Card(mao[i].c,mao[i].t);
		htmlstr+=card.html();
	}
	return htmlstr;
}

function QueryStatus()
{
	ingame=true;
	if (skipdraw)
	{
		$("#drawcard").hide();
		$("#skipturn").show();
	}
	else
	{

		$("#drawcard").show();
		$("#skipturn").hide();
	}

	$.ajax({
		url: playurl+room+'status',
		type: 'GET',
		success: function(data, cenas, res){

			if( res )
			{
				if( res.status === 204 )
				{
					$("#statusmsg").text("Jogo terminado");
						$("#statusmsg").show();
					console.log('Jogo desativado');
				}
				else
				if( res.status === 304 )
				{
					//não fazer nada
					console.log('Página não modificada.');
				}
				else if( res.status === 200 )
				{

					console.log('Jogo activo, e modificado.. Fazer cenas com os dados recolhidos...'+JSON.stringify(data));
					if (data.s==0||data.t==false)
					{
						active=false;
						if (data.t==false)
						{

						$("#statusmsg").text("À espera da sua vez");

						$("#statusmsg").show();
							if (!cardupdate){
							$("#cardsdiv").html(ParseMao(data.l));
							console.log('done cardsupdate');
							cardupdate=true;
							}
						}

						else

						{

							$("#statusmsg").text("Jogo pausado");

							$("#statusmsg").show();

						}

					}

					else{
						cardupdate=false;
						active=true;
						if (data.b>0){
							$("#statusmsg").text("Tem "+data.b+" cartas em espera.");
							$("acceptdraw").show();
							$("#statusmsg").show();
						}
						else
						{
							$("#statusmsg").text("É a sua vez");
							$("#statusmsg").show();

						}
						$("#cardsdiv").html(ParseMao(data.l));
						console.log('done');

					}
				}
				else
				{
					$("#statusmsg").text("Falha na comunicação com o servidor para atualizar o jogo");
					$("#statusmsg").show();
				}
			}

		}
	}).fail(function(res){
		var st = ( res ? res.status : -1 ) ;

		$("#statusmsg").text("Falha a comunicar com o servidor para atualizar o jogo");
		$("#statusmsg").show();
		console.log("Status Fail: " + st);
	}).always(function(res){
		if(ingame) timerfunc=setTimeout(QueryStatus, timerms);
	});

}

function QueryLobby()
{
	inlobby=true;
	$.getJSON(playurl+room+"lobby",{},function(data){

				console.log("sucesso querylobby "+JSON.stringify(data));

				if (data.q==false)
				{
					inqueue=false;
					if (data.v==false) {

						$("#readycheck").show();
						$("#statusmsg").text("Inicie o ready check");
						$("#statusmsg").show();
					}
					else{
						readychecked=true;
						$("#statusmsg").text("À espera dos outros jogadores");
						$("#statusmsg").show();
						$("#readycheck").hide();
						if (data.s==1)
						{
							inlobby=false;
							gameactive=true;
							QueryStatus();
						}

					}
				}
				else
				{
					$("#statusmsg").text("Em queue");
					$("#statusmsg").show();
					inqueue=true;
				}

		},'json').fail(
		function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "lobbyRequest Failed: " + err);

			$("#statusmsg").text("Falha a comunicar com o servidor para atualizar o estado");
			$("#statusmsg").show();
	}).always(function(){
		active=true;
				if(inlobby) timerfunc=setTimeout(QueryLobby,timerms);
	});
}

function playCard(card){
	active=false;
	clearTimeout(timerfunc);
	var color=card.data("color");
	var value=card.data("value");

	if ((value==13||value==14)&&colorSelBuffer=="")
	{
		colorSelBuffer=	$("#cardsdiv").html();
		var c1=new Card(0,value);
		var c2=new Card(1,value);
		var c3=new Card(2,value);
		var c4=new Card(3,value);
		$("#cardsdiv").html(c1.html()+c2.html()+c3.html()+c4.html());
		$("#statusmsg").text("Escolha uma cor");
		$("#statusmsg").show();
		active=true;
	}else
	{
		$.post(playurl+room+"play/"+value+"/"+color,{},function(data){
			//fixe

			skipdraw=false;
			console.log("play sucessefull with "+color+" "+value+" ");
		},'json').fail(function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "playRequest with "+color+" "+value+" Failed: " + err);
			active=true;
			$("#statusmsg").text("Jogada inválida.");
			$("#statusmsg").show();
		}).always(function(){
			if (colorSelBuffer!="")
			{
				$("#statusmsg").text("Boa escolha");//troll :)
				$("#statusmsg").show();
				$("#cardsdiv").html(colorSelBuffer);
				colorSelBuffer="";
			}
			active=true;
			QueryStatus();
		});
	}
}

function skipPlay(){
	active=false;
	clearTimeout(timerfunc);
	$.getJSON(playurl+room+"/skip-turn",{},function(data){
		//fixe

		skipdraw=false;
		console.log("skip sucessefull");
	},'json').fail(function(jqxhr, textStatus, error ) {
		var err = textStatus + ', ' + error;
		console.log( "skipRequest Failed: " + err);
		active=true;
		$("#statusmsg").text("Erro a comunicar passagem. Por favor tente outra vez.");
		$("#statusmsg").show();
	}).always(function(){
		active=true;
		QueryStatus();
	});
}

function drawOne(){
	active=false;
	clearTimeout(timerfunc);
	$.getJSON(playurl+room+"/get-one",{},function(data){
		//fixe

		skipdraw=true;
		console.log("draw sucessefull");
	},'json').fail(function(jqxhr, textStatus, error ) {
		var err = textStatus + ', ' + error;
		console.log( "drawRequest Failed: " + err);
		active=true;
		$("#statusmsg").text("Erro a comunicar pedido. Por favor tente outra vez.");
		$("#statusmsg").show();
	}).always(function(){
		active=true;
		QueryStatus();
	});
}

$(document).ready(function() {

	$.ajaxSetup({
		xhrFields: {
		withCredentials: true
		}
	});

	$("#gamejoin").click(function(){

		active=false;
		$("#loadmsg").html("A carregar o jogo.");
		$("#lobby").hide();
		$("#loading").show();

		room="/"+$("#roomslt").val()+"/";
		playerName=$("#name").val();
		console.log(playerName+" "+room);

		$.post(playurl+room+"lobby",{name:playerName},function(data){

				active=true;
				console.log("sucesso lobby");
				$("#loading").hide();
				if (data=="null")//json de jogo cheiro
				{
					$('#lobbyerrormsg').text("Jogo cheio. Por favor tente outro jogo.");
					$('#lobbyerrormsg').show();
				}else{
					//TODO joinar o jogo
					$("#game").show();
					console.log(data.q);
					if (data.q==false)
					{
						inqueue=false;
						QueryLobby();
					}
					else
					{
						inqueue=true;
						QueryLobby();
					}
				}
		},'json').fail(
		function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "lobbyRequest Failed: " + err);
			active=true;
			$("#loading").hide();
			$('#lobbyerrormsg').text("Erro a entrar no jogo. Por favor tente outra vez.");
			$('#lobbyerrormsg').show();
			$('#lobby').show();
		})/*.always(function(){
			alert("x3");
		})*/;
	});

	$(document).on('click','.card',function(event){
		if (active==true&&gameactive==true){
			$("#statusmsg").text("A processar jogada");
		$("#statusmsg").show();
			playCard($(this));

		}
		console.log($(this).data("color")+" "+$(this).data("value")+" "+active);
	});

	$("#readycheck").click(function(){
		if (active==true){
			active=false;

			$.post(playurl+room+"vote-start",{
			},function(data){
				$("#readycheck").hide();
				$("#statusmsg").text("À espera dos outros jogadores");
				$("#statusmsg").show();

			}).fail(
			function(){

			}).always(function(){
				active=true;
			});
		}
		console.log("readycheck "+active);

	});

	$("#skipturn").click(function(){
		if (active && gameactive && skipdraw){
			skipPlay();

		}
		console.log("skipturn "+active);

	});

	$("#drawcard").click(function(){
		if (active && gameactive && !skipdraw){
			drawOne();

		}
		console.log("drawcard "+active);

	});

	$("#acceptdraw").click(function(){
		if (active==true&&gameactive==true){

		/*
		$.post(playurl,{//args

		},function(data){
				//console.log(data);
				if (data=="null")//json de jogo cheio

				{

				}else{
					//TODO  sacar as cartas

				}
		}).fail(
		function(){

		});*/
		}
		console.log("acceptdraw "+active);

	});

	$("#exitbtn").click(function(){
		if (active==true){
			active=false;
		$.post(playurl+room+"quit",function(data){
				active=true;
				ingame=false;
				inlobby=false;
				clearTimeout(timerfunc);
				console.log("sucesso sair");
				$("#game").hide();
				$("#statusmsg").hide();
				$("#lobby").show();
				$("#lobbyerrormsg").hide();
				$("#cardsdiv").html("");
				});
		}

		console.log("exitbtn "+active);

	});

	active=true; //ativar os campos

	//teste
	/*$("#lobby").hide();
	$("#game").show();
	var c1=new Card(0,11);
	var c2=new Card(1,9);
	var c3=new Card(2,10);
	var c4=new Card(3,5);
	var c5=new Card(3,2);
	var c6=new Card(1,6);
	var c7=new Card(4,13);
	var c8=new Card(4,14);
	$("#cardsdiv").append(c1.html());
	$("#cardsdiv").append(c2.html());
	$("#cardsdiv").append(c3.html());
	$("#cardsdiv").append(c4.html());
	$("#cardsdiv").append(c5.html());
	$("#cardsdiv").append(c6.html());
	$("#cardsdiv").append(c7.html());
	$("#cardsdiv").append(c8.html());
	*/

});

<commit_msg>deixar o botao de sair funcionar depois de o jogo acabar<commit_after>var playurl="http://ni.fe.up.pt/uni";
var room="";
var playerName="";
var status;
var active=false; //boolean para bloquear inputs durante chamadas ao servidor

//flags
var colorSelBuffer="";
var cardupdate=false;
var drawbuffer=false;
var skipdraw=false;
var readychecked=false;
var inlobby=false;
var ingame=false;
var inqueue=true;
var gameactive=true;
//pointer ao set timeout para o desativar quando fizer /quit
var timerfunc;
//milisegundos para fazer novo request de status/lobby
var timerms=1000;

function Card(color,value) {

	this.color = color;
	this.value = value;
	switch(color)
	{
		case 0:this.colortext="Red";break;
		case 1:this.colortext="Green";break;
		case 2:this.colortext="Blue";break;
		case 3:this.colortext="Yellow";break;
		case 4:this.colortext="Wild";break;
		default:this.colortext="Error";
	}
	switch(value)
	{
		case 10:this.valuetext="";break;
		case 11:this.valuetext="+2";break;
		case 12:this.valuetext="";break;
		case 13:this.valuetext="";break;
		case 14:this.valuetext="";break;
		default:this.valuetext=value;
	}
}

Card.prototype.html = function() {
	return 	'
' +
			'
' +
			'
' +
			this.valuetext +
			'
' +
			'
' +
			'
';
}

function ParseMao(mao )
{
	var htmlstr="";
	var card;
	for (var i=0;i< mao.length;i++)
	{
		card=new Card(mao[i].c,mao[i].t);
		htmlstr+=card.html();
	}
	return htmlstr;
}

function QueryStatus()
{
	ingame=true;
	if (skipdraw)
	{
		$("#drawcard").hide();
		$("#skipturn").show();
	}
	else
	{

		$("#drawcard").show();
		$("#skipturn").hide();
	}

	$.ajax({
		url: playurl+room+'status',
		type: 'GET',
		success: function(data, cenas, res){

			if( res )
			{
				if( res.status === 204 )
				{
					gameactive=false;
					$("#statusmsg").text("Jogo terminado");
						$("#statusmsg").show();
					console.log('Jogo desativado');
				}
				else
				if( res.status === 304 )
				{
					//não fazer nada
					console.log('Página não modificada.');
				}
				else if( res.status === 200 )
				{

					console.log('Jogo activo, e modificado.. Fazer cenas com os dados recolhidos...'+JSON.stringify(data));
					if (data.s==0||data.t==false)
					{
						active=false;
						if (data.t==false)
						{

						$("#statusmsg").text("À espera da sua vez");

						$("#statusmsg").show();
							if (!cardupdate){
							$("#cardsdiv").html(ParseMao(data.l));
							console.log('done cardsupdate');
							cardupdate=true;
							}
						}

						else

						{

							$("#statusmsg").text("Jogo pausado");

							$("#statusmsg").show();

						}

					}

					else{
						cardupdate=false;
						active=true;
						if (data.b>0){
							$("#statusmsg").text("Tem "+data.b+" cartas em espera.");
							$("acceptdraw").show();
							$("#statusmsg").show();
						}
						else
						{
							$("#statusmsg").text("É a sua vez");
							$("#statusmsg").show();

						}
						$("#cardsdiv").html(ParseMao(data.l));
						console.log('done');

					}
				}
				else
				{
					$("#statusmsg").text("Falha na comunicação com o servidor para atualizar o jogo");
					$("#statusmsg").show();
				}
			}

		}
	}).fail(function(res){
		var st = ( res ? res.status : -1 ) ;

		$("#statusmsg").text("Falha a comunicar com o servidor para atualizar o jogo");
		$("#statusmsg").show();
		console.log("Status Fail: " + st);
	}).always(function(res){
		if(ingame) timerfunc=setTimeout(QueryStatus, timerms);
	});

}

function QueryLobby()
{
	inlobby=true;
	$.getJSON(playurl+room+"lobby",{},function(data){

				console.log("sucesso querylobby "+JSON.stringify(data));

				if (data.q==false)
				{
					inqueue=false;
					if (data.v==false) {

						$("#readycheck").show();
						$("#statusmsg").text("Inicie o ready check");
						$("#statusmsg").show();
					}
					else{
						readychecked=true;
						$("#statusmsg").text("À espera dos outros jogadores");
						$("#statusmsg").show();
						$("#readycheck").hide();
						if (data.s==1)
						{
							inlobby=false;
							gameactive=true;
							QueryStatus();
						}

					}
				}
				else
				{
					$("#statusmsg").text("Em queue");
					$("#statusmsg").show();
					inqueue=true;
				}

		},'json').fail(
		function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "lobbyRequest Failed: " + err);

			$("#statusmsg").text("Falha a comunicar com o servidor para atualizar o estado");
			$("#statusmsg").show();
	}).always(function(){
		active=true;
				if(inlobby) timerfunc=setTimeout(QueryLobby,timerms);
	});
}

function playCard(card){
	active=false;
	clearTimeout(timerfunc);
	var color=card.data("color");
	var value=card.data("value");

	if ((value==13||value==14)&&colorSelBuffer=="")
	{
		colorSelBuffer=	$("#cardsdiv").html();
		var c1=new Card(0,value);
		var c2=new Card(1,value);
		var c3=new Card(2,value);
		var c4=new Card(3,value);
		$("#cardsdiv").html(c1.html()+c2.html()+c3.html()+c4.html());
		$("#statusmsg").text("Escolha uma cor");
		$("#statusmsg").show();
		active=true;
	}else
	{
		$.post(playurl+room+"play/"+value+"/"+color,{},function(data){
			//fixe

			skipdraw=false;
			console.log("play sucessefull with "+color+" "+value+" ");
		},'json').fail(function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "playRequest with "+color+" "+value+" Failed: " + err);
			active=true;
			$("#statusmsg").text("Jogada inválida.");
			$("#statusmsg").show();
		}).always(function(){
			if (colorSelBuffer!="")
			{
				$("#statusmsg").text("Boa escolha");//troll :)
				$("#statusmsg").show();
				$("#cardsdiv").html(colorSelBuffer);
				colorSelBuffer="";
			}
			active=true;
			QueryStatus();
		});
	}
}

function skipPlay(){
	active=false;
	clearTimeout(timerfunc);
	$.getJSON(playurl+room+"/skip-turn",{},function(data){
		//fixe

		skipdraw=false;
		console.log("skip sucessefull");
	},'json').fail(function(jqxhr, textStatus, error ) {
		var err = textStatus + ', ' + error;
		console.log( "skipRequest Failed: " + err);
		active=true;
		$("#statusmsg").text("Erro a comunicar passagem. Por favor tente outra vez.");
		$("#statusmsg").show();
	}).always(function(){
		active=true;
		QueryStatus();
	});
}

function drawOne(){
	active=false;
	clearTimeout(timerfunc);
	$.getJSON(playurl+room+"/get-one",{},function(data){
		//fixe

		skipdraw=true;
		console.log("draw sucessefull");
	},'json').fail(function(jqxhr, textStatus, error ) {
		var err = textStatus + ', ' + error;
		console.log( "drawRequest Failed: " + err);
		active=true;
		$("#statusmsg").text("Erro a comunicar pedido. Por favor tente outra vez.");
		$("#statusmsg").show();
	}).always(function(){
		active=true;
		QueryStatus();
	});
}

$(document).ready(function() {

	$.ajaxSetup({
		xhrFields: {
		withCredentials: true
		}
	});

	$("#gamejoin").click(function(){

		active=false;
		$("#loadmsg").html("A carregar o jogo.");
		$("#lobby").hide();
		$("#loading").show();

		room="/"+$("#roomslt").val()+"/";
		playerName=$("#name").val();
		console.log(playerName+" "+room);

		$.post(playurl+room+"lobby",{name:playerName},function(data){

				active=true;
				console.log("sucesso lobby");
				$("#loading").hide();
				if (data=="null")//json de jogo cheiro
				{
					$('#lobbyerrormsg').text("Jogo cheio. Por favor tente outro jogo.");
					$('#lobbyerrormsg').show();
				}else{
					//TODO joinar o jogo
					$("#game").show();
					console.log(data.q);
					if (data.q==false)
					{
						inqueue=false;
						QueryLobby();
					}
					else
					{
						inqueue=true;
						QueryLobby();
					}
				}
		},'json').fail(
		function(jqxhr, textStatus, error ) {
			var err = textStatus + ', ' + error;
			console.log( "lobbyRequest Failed: " + err);
			active=true;
			$("#loading").hide();
			$('#lobbyerrormsg').text("Erro a entrar no jogo. Por favor tente outra vez.");
			$('#lobbyerrormsg').show();
			$('#lobby').show();
		})/*.always(function(){
			alert("x3");
		})*/;
	});

	$(document).on('click','.card',function(event){
		if (active==true&&gameactive==true){
			$("#statusmsg").text("A processar jogada");
		$("#statusmsg").show();
			playCard($(this));

		}
		console.log($(this).data("color")+" "+$(this).data("value")+" "+active);
	});

	$("#readycheck").click(function(){
		if (active==true){
			active=false;

			$.post(playurl+room+"vote-start",{
			},function(data){
				$("#readycheck").hide();
				$("#statusmsg").text("À espera dos outros jogadores");
				$("#statusmsg").show();

			}).fail(
			function(){

			}).always(function(){
				active=true;
			});
		}
		console.log("readycheck "+active);

	});

	$("#skipturn").click(function(){
		if (active && gameactive && skipdraw){
			skipPlay();

		}
		console.log("skipturn "+active);

	});

	$("#drawcard").click(function(){
		if (active && gameactive && !skipdraw){
			drawOne();

		}
		console.log("drawcard "+active);

	});

	$("#acceptdraw").click(function(){
		if (active==true&&gameactive==true){

		/*
		$.post(playurl,{//args

		},function(data){
				//console.log(data);
				if (data=="null")//json de jogo cheio

				{

				}else{
					//TODO  sacar as cartas

				}
		}).fail(
		function(){

		});*/
		}
		console.log("acceptdraw "+active);

	});

	$("#exitbtn").click(function(){
		if (active==true||!gameactive){
			active=false;
		$.post(playurl+room+"quit",function(data){
				active=true;
				ingame=false;
				inlobby=false;
				clearTimeout(timerfunc);
				console.log("sucesso sair");
				$("#game").hide();
				$("#statusmsg").hide();
				$("#lobby").show();
				$("#lobbyerrormsg").hide();
				$("#cardsdiv").html("");
				});
		}

		console.log("exitbtn "+active);

	});

	active=true; //ativar os campos

	//teste
	/*$("#lobby").hide();
	$("#game").show();
	var c1=new Card(0,11);
	var c2=new Card(1,9);
	var c3=new Card(2,10);
	var c4=new Card(3,5);
	var c5=new Card(3,2);
	var c6=new Card(1,6);
	var c7=new Card(4,13);
	var c8=new Card(4,14);
	$("#cardsdiv").append(c1.html());
	$("#cardsdiv").append(c2.html());
	$("#cardsdiv").append(c3.html());
	$("#cardsdiv").append(c4.html());
	$("#cardsdiv").append(c5.html());
	$("#cardsdiv").append(c6.html());
	$("#cardsdiv").append(c7.html());
	$("#cardsdiv").append(c8.html());
	*/

});

<|endoftext|>