diff --git a/CHANGELOG b/CHANGELOG index 118e884c..98c1fc04 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,21 @@ # nodegame-server change log +# 7.0.3 +- New build: NDDB computes indexes by default, widgets improvements. + +# 7.0.2 +- Minified CSS with cssnano. + +# 7.0.0 +- Minified nodegame-full.min.js with terser. +- Upgraded: Winston3, Socket.IO 4, Bootstrap 5 (partial support). +- Dropped: PhantomJS +- REMOTE_DISPATCH option for waiting room. +- JWT Cookies are parsed only if auth or noAuthCookie is on. +- New CSS styles for survey. +- New authorization mode: 'external'. +- GameRoom.computeBonus: showBonus, headerAdd, and prolific options. + # 6.3.0 - CSS: Bomb widget is adaptive to media query, VisualRound is more compact. - Fixed renderTemplate bug when auth is on. diff --git a/conf/http.js b/conf/http.js index b7b96b28..4d69e5a8 100644 --- a/conf/http.js +++ b/conf/http.js @@ -1,6 +1,6 @@ /** * # http.js - * Copyright(c) 2020 Stefano Balietti + * Copyright(c) 2023 Stefano Balietti * MIT Licensed * * Configuration file for Express server in nodegame-server @@ -245,9 +245,15 @@ function configure(app, servernode) { let listOfGames = J.keys(gamesObj); // Remove aliases. let filteredGames = listOfGames.filter(function(name) { - return (!gamesObj[name].disabled && !gamesObj[name].errored && - (!gamesObj[name].alias || - gamesObj[name].alias.indexOf(name) === -1)); + // WAS: + // return (!gamesObj[name].disabled && !gamesObj[name].errored && + // (!gamesObj[name].alias || + // gamesObj[name].alias.indexOf(name) === -1)); + let g = gamesObj[name]; + if (g.disabled || g.errored) return false; + if (g.info.card === false) return false; + if (g.alias && g.alias.indexOf(name) !== -1) return false; + return true; }); if (J.isArray(servernode.homePage.cardsOrder)) { filteredGames = @@ -267,15 +273,20 @@ function configure(app, servernode) { let i = 0; for (let j = 0; j < filteredGames.length; j++) { let name = filteredGames[j]; - if (i >= colors.length) i = 0; - let color = colors[i]; // Mixout name and description from package.json // if not in card, or if no card is defined. let card = J.mixout(gamesObj[name].info.card || {}, { name: name.charAt(0).toUpperCase() + name.slice(1), description: gamesObj[name].info.description }); + + if (i >= colors.length) i = 0; + let color = card.color || colors[i]; + games.push({ + // If someone rename `card.name` the link still needs + // to point to name. + _name: name, name: card.name, color: color, url: card.url, diff --git a/conf/loggers.js b/conf/loggers.js index 52363563..98b15206 100644 --- a/conf/loggers.js +++ b/conf/loggers.js @@ -1,6 +1,6 @@ /** * # loggers.js - * Copyright(c) 2020 Stefano Balietti + * Copyright(c) 2021 Stefano Balietti * MIT Licensed * * Configuration file for Winston.js in nodegame-server @@ -13,81 +13,116 @@ const winston = require('winston'); // Variable loggers is winston.loggers. function configure(loggers, logDir) { + let format = winston.format; let logLevel = winston.level; + let transports = winston.transports; + + const logFormatter = format.printf((info) => { + let { timestamp, level, stack, message } = info; + message = stack || message; + return `${timestamp} ${level}: ${message}`; + }); + + // const msgFormatter = format.printf((info) => { + // let { timestamp, level, message } = info; + // message = stack || message; + // return `${timestamp} ${level}: ${message}`; + // }); + + let consoleFormat = format.combine(format.colorize(), format.simple(), + format.timestamp(), logFormatter); + + let msgFormat = format.combine(format.simple()); // ServerNode. loggers.add('servernode', { - console: { - level: logLevel, - colorize: true - }, - file: { - level: logLevel, - timestamp: true, - filename: path.join(logDir, 'servernode.log'), - maxsize: 1000000, - maxFiles: 10 - } + format: winston.format.simple(), + transports: [ + new transports.Console({ + level: logLevel, + // colorize: true + format: consoleFormat + }), + new transports.File({ + format: winston.format.simple(), + level: logLevel, + timestamp: true, + filename: path.join(logDir, 'servernode.log'), + maxsize: 1000000, + maxFiles: 10 + }) + ] + }); // Channel. loggers.add('channel', { - console: { - level: logLevel, - colorize: true, - }, - file: { - level: logLevel, - timestamp: true, - filename: path.join(logDir, 'channels.log'), - maxsize: 1000000, - maxFiles: 10 - } + // format: winston.format.simple(), + // format: format.errors({ stack: true }), + transports: [ + new transports.Console({ + level: logLevel, + // colorize: true + format: consoleFormat + }), + new transports.File({ + format: winston.format.simple(), + level: logLevel, + timestamp: true, + filename: path.join(logDir, 'channels.log'), + maxsize: 1000000, + maxFiles: 10 + }) + ] }); // Messages. // Make custom levels and only File transports for messages. - let msgLogger = loggers.add('messages'); - msgLogger.remove(winston.transports.Console); - msgLogger.add(winston.transports.File, { - timestamp: true, - maxsize: 1000000, - filename: path.join(logDir, 'messages.log') - }); - - // Do not change, or logging might be affected. - // Logger.js hardcodes the values for speed. - msgLogger.setLevels({ - // Log none. - none: 0, - // All DATA msgs. - data: 1, - // All SET and DATA msgs. - set: 3, - // All SET, GET and DATA msgs. - get: 5, - // All SETUP, SET, GET and DATA msgs. - setup: 7, - // All messages, but **not** PLAYER_UPDATE, SERVERCOMMAND and ALERT. - game: 9, - // All messages. - all: 11 + loggers.add('messages', { + levels: { + // Log none. + none: 0, + // All DATA msgs. + data: 1, + // All SET and DATA msgs. + set: 3, + // All SET, GET and DATA msgs. + get: 5, + // All SETUP, SET, GET and DATA msgs. + setup: 7, + // All messages, but **not** PLAYER_UPDATE, SERVERCOMMAND and ALERT. + game: 9, + // All messages. + all: 11 + }, + transports: [ + new transports.File({ + level: 'all', + timestamp: true, + maxsize: 1000000, + filename: path.join(logDir, 'messages.log'), + format: msgFormat + }) + ] }); - // Set default logging level for messages. - msgLogger.level = 'all'; - // Clients. loggers.add('clients', { - console: { - level: logLevel, - colorize: true, - }, - file: { - level: 'silly', - timestamp: true, - filename: path.join(logDir, 'clients.log') - } + // format: format.errors({ stack: true }), + transports: [ + new transports.Console({ + level: logLevel, + // colorize: true + format: consoleFormat + }), + new transports.File({ + // format: consoleFormat, + format: winston.format.simple(), + level: 'silly', + timestamp: true, + filename: path.join(logDir, 'clients.log') + }) + ] }); return true; diff --git a/lib/Logger.js b/lib/Logger.js index 89f0ecc8..7b5cb603 100644 --- a/lib/Logger.js +++ b/lib/Logger.js @@ -120,6 +120,7 @@ Logger.prototype.logText = function(text, level, meta = {}) { Logger.prototype.logMsg = function(gm, type, gmString) { var level, curLevel; + // TODO: this might not be accurate in winston v3. curLevel = this.logger.levels[this.logger.level]; if (curLevel === 0) return; diff --git a/lib/ServerNode.js b/lib/ServerNode.js index 04505a8b..7e5c5d10 100644 --- a/lib/ServerNode.js +++ b/lib/ServerNode.js @@ -333,23 +333,28 @@ ServerNode.prototype.init = function(options) { } }); - // Loading default config files. - this.logger.verbose('ServerNode.init: loading default conf files'); if (options.logDir) this.logDir = resolvePath(options.logDir); + // Loggers first. this.loadConfFile(path.join(this.defaultConfDir, 'loggers.js'), - this.configureLoggers); + this.configureLoggers, false); + // Setting servernode logger. this.logger = winston.loggers.get('servernode'); + // Print what loadConfFile could not. + this.logger.debug('ServerNode.loadConfFile: loaded ' + + path.join(this.defaultConfDir, 'loggers.js')); + // Loading remaining conf. this.loadConfDir(this.defaultConfDir, { loggers: false }); - // Loading user configuration files + // Loading user configuration files. if (options.confDir) { this.logger.verbose('ServerNode.init: loading user conf files'); - // We load the loggers configuration file first, so that - // the the output is nicely formatted. + // Loggers first let dir = resolvePath(options.confDir); this.loadConfFile(path.join(dir, 'loggers.js'), this.configureLoggers); + // Re-setting servernode logger. this.logger = winston.loggers.get('servernode'); + // Loading remaining conf. this.loadConfDir(dir, { loggers: false }); } @@ -959,6 +964,7 @@ ServerNode.prototype.loadConfDir = function(dir, mask, force) { * * @param {string} file The path to the configuration file * @param {function} cb The callback function (e.g. ServerNode.configureHTTP) + * @param {boolean} silent If FALSE, do not call logger (might not be ready) * * @see ServerNode.loadConfDir * @see ServerNode.configure @@ -966,7 +972,7 @@ ServerNode.prototype.loadConfDir = function(dir, mask, force) { * @see ServerNode.confiureSIO * @see ServerNode.confiureLoggers */ -ServerNode.prototype.loadConfFile = function(file, cb) { +ServerNode.prototype.loadConfFile = function(file, cb, log = true) { if ('string' !== typeof file) { throw new TypeError('ServerNode.loadConfFile: file must be string.' + 'Found: ' + file); @@ -994,7 +1000,8 @@ ServerNode.prototype.loadConfFile = function(file, cb) { // care of passing the right parameters to it. cb.call(this, conf); - this.logger.debug('ServerNode.loadConfFile: loaded ' + file) + // The first time it is called, this.logger is not yet set. + if (log) this.logger.debug('ServerNode.loadConfFile: loaded ' + file); }; /** diff --git a/lib/rooms/WaitingRoom.js b/lib/rooms/WaitingRoom.js index 3943300e..ca2f799a 100644 --- a/lib/rooms/WaitingRoom.js +++ b/lib/rooms/WaitingRoom.js @@ -1347,7 +1347,10 @@ WaitingRoom.prototype.dispatch = (function() { // Shuffle and sort players, if necessary. // This means that at least two groups will be created. - if (nPlayersToDispatch > groupSize) { + // Old line + // if (nPlayersToDispatch > groupSize) { + // New line + if (nPlayers > groupSize) { if (this.PLAYER_GROUPING) { groups = this.PLAYER_GROUPING(pList, numberOfGames); diff --git a/package.json b/package.json index 7f50bb84..bbef65d2 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,60 @@ { - "name": "nodegame-server" - , "description": "nodeGame server for the browser and node.js" - , "version": "6.3.0" - , "main" : "index.js" - , "homepage": "http://nodegame.org" - , "keywords": [ "game", "multiplayer", "experiment", "behavioral", "socket.io", "websockets"] - , "author": "Stefano Balietti " - , "contributors": [ - { "name": "Stefano Balietti", "email": "futur.dorko@gmail.com" } - ] - , "repository": { - "type": "git" - , "url": "https://github.com/nodeGame/nodegame-server.git" + "name": "nodegame-server", + "description": "nodeGame server for the browser and node.js", + "version": "7.0.3", + "main": "index.js", + "homepage": "http://nodegame.org", + "keywords": [ + "game", + "multiplayer", + "experiment", + "behavioral", + "socket.io", + "websockets" + ], + "author": "Stefano Balietti ", + "contributors": [ + { + "name": "Stefano Balietti", + "email": "futur.dorko@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/nodeGame/nodegame-server.git" + }, + "dependencies": { + "archiver": "*", + "body-parser": "*", + "commander": "^7.0.0", + "cookie-parser": "*", + "cookie-session": "*", + "errorhandler": "*", + "express": "4.17.1", + "jade": "1.11.0", + "JSON": "1.0.0", + "jsonwebtoken": "8.5.1", + "JSUS": "^1.1.0", + "NDDB": "^3.0.0", + "nodegame-game-template": "*", + "nodegame-monitor": "*", + "request": "2.88.0", + "shelf.js": ">= 0.3.7", + "socket.io": "4.1.3", + "winston": "3.3.3" + }, + "devDependencies": { + "cssnano": "^5.0.8", + "mocha": ">=4.0.1", + "postcss": "^8.3.11", + "postcss-cli": "^9.0.1", + "should": ">=13.1.3" + }, + "engines": { + "node": ">= 10.0" + }, + "license": "MIT", + "scripts": { + "test": "make test" } - , "dependencies": { - "express": "4.17.1" - , "body-parser": "*" - , "cookie-parser": "*" - , "cookie-session": "*" - , "errorhandler": "*" - , "archiver": "*" - , "socket.io": "4.1.3" - , "request": "2.88.0" - , "winston": "2.4.5" - , "jsonwebtoken": "8.5.0" - , "nodegame-monitor": "*" - , "nodegame-game-template": "*" - , "JSUS": "^1.1.0" - , "NDDB": "^2.0.0" - , "shelf.js": ">= 0.3.7" - , "commander": "^7.0.0" - , "jade": "1.11.0" - , "JSON": "1.0.0" - } - , "devDependencies": { - "mocha": ">=4.0.1", - "should": ">=13.1.3" - } - , "engines": { "node": ">= 6.0" } - , "license": "MIT" - , "scripts": { - "test": "make test" - } } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..ffb2269a --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + require('cssnano')({ + preset: 'default', + }), + ], +}; diff --git a/public/images/arrow-left.png b/public/images/arrow-left.png new file mode 100644 index 00000000..d7af20d5 Binary files /dev/null and b/public/images/arrow-left.png differ diff --git a/public/images/arrow-right.png b/public/images/arrow-right.png new file mode 100644 index 00000000..3fc947ba Binary files /dev/null and b/public/images/arrow-right.png differ diff --git a/public/javascripts/nodegame-full.js b/public/javascripts/nodegame-full.js index e7550268..83fc6b72 100644 --- a/public/javascripts/nodegame-full.js +++ b/public/javascripts/nodegame-full.js @@ -6036,7 +6036,7 @@ if (!Array.prototype.indexOf) { // ### __update.indexes // If TRUE, rebuild indexes on every insert and remove - this.__update.indexes = false; + this.__update.indexes = true; // ### __update.sort // If TRUE, sort db on every insert and remove @@ -10455,7 +10455,7 @@ if (!Array.prototype.indexOf) { node.support = JSUS.compatibility(); // Auto-Generated. - node.version = '6.2.0'; + node.version = '7.1.0'; })(window); @@ -10980,7 +10980,8 @@ if (!Array.prototype.indexOf) { str = 'DEBUG mode: client-side error ' + 'detected.

'; str += msg; - str += '

' + + str += '

Open the DevTools in your browser ' + + 'for details.
' + 'This message will not be shown in production mode.'; W.lockScreen(str); } @@ -23079,120 +23080,6 @@ if (!Array.prototype.indexOf) { * * @return {array} matches The matches according to the algorithm */ - function pairMatcherOld(alg, n, options) { - var ps, matches, bye; - var i, lenI, j, lenJ, jj; - var id1, id2; - var roundsLimit, cycle, cycleI, skipBye; - - if ('number' === typeof n && n > 1) { - ps = J.seq(0, (n-1)); - } - else if (J.isArray(n) && n.length > 1) { - ps = n.slice(); - n = ps.length; - } - else { - throw new TypeError('pairMatcher.' + alg + ': n must be ' + - 'number > 1 or array of length > 1.'); - } - options = options || {}; - - bye = 'undefined' !== typeof options.bye ? options.bye : -1; - skipBye = options.skipBye || false; - - // Make sure we have even numbers. - if ((n % 2) === 1) { - ps.push(bye); - n += 1; - } - - // Limit rounds. - if ('number' === typeof options.rounds) { - if (options.rounds <= 0) { - throw new Error('pairMatcher.' + alg + ': options.rounds ' + - 'must be a positive number or undefined. ' + - 'Found: ' + options.rounds); - } - if (options.rounds > (n-1)) { - throw new Error('pairMatcher.' + alg + ': ' + - 'options.rounds cannot be greater than ' + - (n-1) + '. Found: ' + options.rounds); - } - // Here roundsLimit does not depend on n (must be smaller). - roundsLimit = options.rounds; - } - else { - roundsLimit = n-1; - } - - if ('undefined' !== typeof options.cycle) { - cycle = options.cycle; - if (cycle !== 'mirror_invert' && cycle !== 'mirror' && - cycle !== 'repeat_invert' && cycle !== 'repeat') { - - throw new Error('pairMatcher.' + alg + ': options.cycle ' + - 'must be equal to "mirror"/"mirror_invert", ' + - '"repeat"/"repeat_invert" or undefined . ' + - 'Found: ' + options.cycle); - } - - matches = new Array(roundsLimit*2); - } - else { - matches = new Array(roundsLimit); - } - - i = -1, lenI = roundsLimit; - for ( ; ++i < lenI ; ) { - // Shuffle list of ids for random. - if (alg === 'random') ps = J.shuffle(ps); - // Create a new array for round i. - lenJ = n / 2; - matches[i] = skipBye ? new Array(lenJ-1) : new Array(lenJ); - // Check if new need to cycle. - if (cycle) { - if (cycle === 'mirror' || cycle === 'mirror_invert') { - cycleI = (roundsLimit*2) -i -1; - } - else { - cycleI = i+roundsLimit; - } - matches[cycleI] = skipBye ? - new Array(lenJ-1) : new Array(lenJ); - } - // Counter jj is updated only if not skipBye, - // otherwise we create holes in the matches array. - jj = j = -1; - for ( ; ++j < lenJ ; ) { - id1 = ps[j]; - id2 = ps[n - 1 - j]; - if (!skipBye || (id1 !== bye && id2 !== bye)) { - jj++; - // Insert match. - matches[i][jj] = [ id1, id2 ]; - // Insert cycle match (if any). - if (cycle === 'repeat') { - matches[cycleI][jj] = [ id1, id2 ]; - } - else if (cycle === 'repeat_invert') { - matches[cycleI][jj] = [ id2, id1 ]; - } - else if (cycle === 'mirror') { - matches[cycleI][jj] = [ id1, id2 ]; - } - else if (cycle === 'mirror_invert') { - matches[cycleI][jj] = [ id2, id1 ]; - } - } - } - // Permutate for next round. - ps.splice(1, 0, ps.pop()); - } - return matches; - } - - function pairMatcher(alg, n, options) { var ps, matches, bye; var i, lenI, j, lenJ, jj; @@ -23540,9 +23427,6 @@ if (!Array.prototype.indexOf) { "use strict"; - // ## Global scope - var J = parent.JSUS; - exports.MatcherManager = MatcherManager; /** @@ -25413,7 +25297,9 @@ if (!Array.prototype.indexOf) { } // Add options, if missing. - if (!widget.options) widget.options = {}; + // User can specify the options in a nested object, or flat them + // down in case there are no conflicts. + if (!widget.options) widget.options = widget; // Make main callback to get/append the widget. widgetCb = function() { @@ -25427,6 +25313,7 @@ if (!Array.prototype.indexOf) { if (!widget.options.className) { widget.options.className = 'centered'; } + widget.options.widgetStep = true; // Default id 'container' (as in default.html). if ('string' === typeof widget.root) { @@ -25447,7 +25334,7 @@ if (!Array.prototype.indexOf) { widgetRoot, widget.options); } - this[widget.ref] = widgetObj; + node.game[widget.ref] = widgetObj; }; // Make the step callback. @@ -28374,6 +28261,17 @@ if (!Array.prototype.indexOf) { return this.status === GameTimer.PAUSED; }; + /** + * ### GameTimer.isDestroyed + * + * Returns TRUE if the timer is destroyed + * + * @return {boolean} TRUE if timer is destroyed + */ + GameTimer.prototype.isDestroyed = function() { + return this.status === GameTimer.DESTROYED; + }; + /** * ### GameTimer.isTimeUp | isTimeup * @@ -29700,120 +29598,6 @@ if (!Array.prototype.indexOf) { * * @return {array} matches The matches according to the algorithm */ - function pairMatcherOld(alg, n, options) { - var ps, matches, bye; - var i, lenI, j, lenJ, jj; - var id1, id2; - var roundsLimit, cycle, cycleI, skipBye; - - if ('number' === typeof n && n > 1) { - ps = J.seq(0, (n-1)); - } - else if (J.isArray(n) && n.length > 1) { - ps = n.slice(); - n = ps.length; - } - else { - throw new TypeError('pairMatcher.' + alg + ': n must be ' + - 'number > 1 or array of length > 1.'); - } - options = options || {}; - - bye = 'undefined' !== typeof options.bye ? options.bye : -1; - skipBye = options.skipBye || false; - - // Make sure we have even numbers. - if ((n % 2) === 1) { - ps.push(bye); - n += 1; - } - - // Limit rounds. - if ('number' === typeof options.rounds) { - if (options.rounds <= 0) { - throw new Error('pairMatcher.' + alg + ': options.rounds ' + - 'must be a positive number or undefined. ' + - 'Found: ' + options.rounds); - } - if (options.rounds > (n-1)) { - throw new Error('pairMatcher.' + alg + ': ' + - 'options.rounds cannot be greater than ' + - (n-1) + '. Found: ' + options.rounds); - } - // Here roundsLimit does not depend on n (must be smaller). - roundsLimit = options.rounds; - } - else { - roundsLimit = n-1; - } - - if ('undefined' !== typeof options.cycle) { - cycle = options.cycle; - if (cycle !== 'mirror_invert' && cycle !== 'mirror' && - cycle !== 'repeat_invert' && cycle !== 'repeat') { - - throw new Error('pairMatcher.' + alg + ': options.cycle ' + - 'must be equal to "mirror"/"mirror_invert", ' + - '"repeat"/"repeat_invert" or undefined . ' + - 'Found: ' + options.cycle); - } - - matches = new Array(roundsLimit*2); - } - else { - matches = new Array(roundsLimit); - } - - i = -1, lenI = roundsLimit; - for ( ; ++i < lenI ; ) { - // Shuffle list of ids for random. - if (alg === 'random') ps = J.shuffle(ps); - // Create a new array for round i. - lenJ = n / 2; - matches[i] = skipBye ? new Array(lenJ-1) : new Array(lenJ); - // Check if new need to cycle. - if (cycle) { - if (cycle === 'mirror' || cycle === 'mirror_invert') { - cycleI = (roundsLimit*2) -i -1; - } - else { - cycleI = i+roundsLimit; - } - matches[cycleI] = skipBye ? - new Array(lenJ-1) : new Array(lenJ); - } - // Counter jj is updated only if not skipBye, - // otherwise we create holes in the matches array. - jj = j = -1; - for ( ; ++j < lenJ ; ) { - id1 = ps[j]; - id2 = ps[n - 1 - j]; - if (!skipBye || (id1 !== bye && id2 !== bye)) { - jj++; - // Insert match. - matches[i][jj] = [ id1, id2 ]; - // Insert cycle match (if any). - if (cycle === 'repeat') { - matches[cycleI][jj] = [ id1, id2 ]; - } - else if (cycle === 'repeat_invert') { - matches[cycleI][jj] = [ id2, id1 ]; - } - else if (cycle === 'mirror') { - matches[cycleI][jj] = [ id1, id2 ]; - } - else if (cycle === 'mirror_invert') { - matches[cycleI][jj] = [ id2, id1 ]; - } - } - } - // Permutate for next round. - ps.splice(1, 0, ps.pop()); - } - return matches; - } - - function pairMatcher(alg, n, options) { var ps, matches, bye; var i, lenI, j, lenJ, jj; @@ -40173,11 +39957,11 @@ if (!Array.prototype.indexOf) { * * Inits the widget after constructor and default properties are added * - * @param {object} options Configuration options + * @param {object} opts Configuration options * * @see Widgets.get */ - Widget.prototype.init = function(options) {}; + Widget.prototype.init = function(opts) {}; /** * ### Widget.listeners @@ -40221,14 +40005,14 @@ if (!Array.prototype.indexOf) { * * Returns the values currently stored by the widget * - * @param {mixed} options Settings controlling the content of return value + * @param {mixed} opts Settings controlling the content of return value * * @return {mixed} The values of the widget */ - Widget.prototype.getValues = function(options) {}; + Widget.prototype.getValues = function(opts) {}; /** - * ### Widget.getValues + * ### Widget.setValues * * Set the stored values directly * @@ -40246,7 +40030,7 @@ if (!Array.prototype.indexOf) { * Deletes current selection, any highlighting, and other data * that the widget might have collected to far. */ - Widget.prototype.reset = function(options) {}; + Widget.prototype.reset = function(opts) {}; /** * ### Widget.highlight @@ -41419,7 +41203,7 @@ if (!Array.prototype.indexOf) { * @see Widgets.instances */ Widgets.prototype.get = function(widgetName, options) { - var WidgetPrototype, widget, changes; + var WidgetPrototype, widget, changes, tmp; if ('string' !== typeof widgetName) { throw new TypeError('Widgets.get: widgetName must be string.' + @@ -41459,17 +41243,37 @@ if (!Array.prototype.indexOf) { widget = new WidgetPrototype(options); // Set ID. - if ('undefined' !== typeof options.id) { - if ('number' === typeof options.id) options.id += ''; - if ('string' === typeof options.id) { - widget.id = options.id; + tmp = options.id; + if ('undefined' !== typeof tmp) { + if ('number' === typeof tmp) tmp += ''; + if ('string' === typeof tmp) { + + if ('undefined' !== typeof options.idPrefix) { + if ('string' === typeof options.idPrefix && + 'number' !== typeof options.idPrefix) { + + tmp = options.idPrefix + tmp; + } + else { + throw new TypeError('Widgets.get: options.idPrefix ' + + 'must be string, number or ' + + 'undefined. Found: ' + + options.idPrefix); + } + } + + widget.id = tmp; } else { throw new TypeError('Widgets.get: options.id must be ' + 'string, number or undefined. Found: ' + - options.id); + tmp); } } + // Assign step id as widget id, if widget step and no custom id. + else if (options.widgetStep) { + widget.id = node.game.getStepId(); + } // Set prototype values or options values. if ('undefined' !== typeof options.title) { @@ -41867,7 +41671,11 @@ if (!Array.prototype.indexOf) { if (strict) return w instanceof node.Widget; return ('object' === typeof w && 'function' === typeof w.append && - 'function' === typeof w.getValues); + 'function' === typeof w.getValues && + // Used by widgets.append + 'function' === typeof w.isHidden && + 'function' === typeof w.isCollapsed + ); }; /** @@ -42265,56 +42073,56 @@ if (!Array.prototype.indexOf) { * * @param {object} options Optional. Configuration options */ - BackButton.prototype.init = function(options) { + BackButton.prototype.init = function(opts) { var tmp; - options = options || {}; + opts = opts || {}; //Button - if ('undefined' === typeof options.id) { + if ('undefined' === typeof opts.id) { tmp = BackButton.className; } - else if ('string' === typeof options.id) { - tmp = options.id; + else if ('string' === typeof opts.id) { + tmp = opts.id; } - else if (false === options.id) { + else if (false === opts.id) { tmp = ''; } else { - throw new TypeError('BackButton.init: options.id must ' + + throw new TypeError('BackButton.init: opts.id must ' + 'be string, false, or undefined. Found: ' + - options.id); + opts.id); } this.button.id = tmp; - if ('undefined' === typeof options.className) { + if ('undefined' === typeof opts.className) { tmp = 'btn btn-lg btn-secondary'; } - else if (options.className === false) { + else if (opts.className === false) { tmp = ''; } - else if ('string' === typeof options.className) { - tmp = options.className; + else if ('string' === typeof opts.className) { + tmp = opts.className; } - else if (J.isArray(options.className)) { - tmp = options.className.join(' '); + else if (J.isArray(opts.className)) { + tmp = opts.className.join(' '); } else { - throw new TypeError('BackButton.init: options.className must ' + + throw new TypeError('BackButton.init: opts.className must ' + 'be string, array, or undefined. Found: ' + - options.className); + opts.className); } this.button.className = tmp; // Button text. - this.button.value = 'string' === typeof options.text ? - options.text : this.getText('back'); + this.button.value = 'string' === typeof opts.text ? + opts.text : this.getText('back'); this.stepOptions.acrossStages = - 'undefined' === typeof options.acrossStages ? - false : !!options.acrossStages; + 'undefined' === typeof opts.acrossStages ? + false : !!opts.acrossStages; this.stepOptions.acrossRounds = - 'undefined' === typeof options.acrossRounds ? - true : !!options.acrossRounds; + 'undefined' === typeof opts.acrossRounds ? + true : !!opts.acrossRounds; }; BackButton.prototype.append = function() { @@ -45186,7 +44994,7 @@ if (!Array.prototype.indexOf) { /** * # ChoiceManager - * Copyright(c) 2020 Stefano Balietti + * Copyright(c) 2021 Stefano Balietti * MIT Licensed * * Creates and manages a set of selectable choices forms (e.g., ChoiceTable). @@ -45201,18 +45009,16 @@ if (!Array.prototype.indexOf) { // ## Meta-data - ChoiceManager.version = '1.2.1'; + ChoiceManager.version = '1.4.1'; ChoiceManager.description = 'Groups together and manages a set of ' + - 'selectable choices forms (e.g. ChoiceTable).'; + 'survey forms (e.g., ChoiceTable).'; ChoiceManager.title = false; ChoiceManager.className = 'choicemanager'; // ## Dependencies - ChoiceManager.dependencies = { - JSUS: {} - }; + ChoiceManager.dependencies = {}; /** * ## ChoiceManager constructor @@ -45306,6 +45112,16 @@ if (!Array.prototype.indexOf) { storeRef: false }; + + /** + * ### ChoiceManager.simplify + * + * If TRUE, it returns getValues() returns forms.values + * + * @see ChoiceManager.getValue + */ + this.simplify = null; + /** * ### ChoiceManager.freeText * @@ -45421,6 +45237,9 @@ if (!Array.prototype.indexOf) { this.required = !!options.required; } + // If TRUE, it returns getValues returns forms.values. + this.simplify = !!options.simplify; + // After all configuration options are evaluated, add forms. if ('undefined' !== typeof options.forms) this.setForms(options.forms); @@ -45455,7 +45274,7 @@ if (!Array.prototype.indexOf) { * @see ChoiceManager.buildTableAndForms */ ChoiceManager.prototype.setForms = function(forms) { - var form, formsById, i, len, parsedForms; + var form, formsById, i, len, parsedForms, name; if ('function' === typeof forms) { parsedForms = forms.call(node.game); if (!J.isArray(parsedForms)) { @@ -45484,16 +45303,11 @@ if (!Array.prototype.indexOf) { for ( ; ++i < len ; ) { form = parsedForms[i]; if (!node.widgets.isWidget(form)) { - if ('string' === typeof form.name) { - // Add defaults. - J.mixout(form, this.formsOptions); - form = node.widgets.get(form.name, form); - } - if (!node.widgets.isWidget(form)) { - throw new Error('ChoiceManager.setForms: one of the ' + - 'forms is not a widget-like element: ' + - form); - } + // TODO: smart checking form name. Maybe in Stager already? + name = form.name || 'ChoiceTable'; + // Add defaults. + J.mixout(form, this.formsOptions); + form = node.widgets.get(name, form); } if (form.id) { @@ -45778,7 +45592,7 @@ if (!Array.prototype.indexOf) { * @see ChoiceManager.verifyChoice */ ChoiceManager.prototype.getValues = function(opts) { - var obj, i, len, form, lastErrored; + var obj, i, len, form, lastErrored, res; obj = { order: this.order, forms: {}, @@ -45794,13 +45608,17 @@ if (!Array.prototype.indexOf) { form = this.forms[i]; // If it is hidden or disabled we do not do validation. if (form.isHidden() || form.isDisabled()) { - obj.forms[form.id] = form.getValues({ + res = form.getValues({ markAttempt: false, highlight: false }); + if (res) obj.forms[form.id] = res; } else { - obj.forms[form.id] = form.getValues(opts); + // ContentBox does not return a value. + res = form.getValues(opts); + if (!res) continue; + obj.forms[form.id] = res; // Backward compatible (requiredChoice). if ((form.required || form.requiredChoice) && (obj.forms[form.id].choice === null || @@ -45832,6 +45650,14 @@ if (!Array.prototype.indexOf) { } // if (obj.missValues.length) obj.isCorrect = false; if (this.textarea) obj.freetext = this.textarea.value; + + // Simplify everything, if requested. + if (opts.simplify || this.simplify) { + res = obj; + obj = obj.forms; + if (res.isCorrect === false) obj.isCorrect = false; + if (res.freetext) obj.freetext = res.freetext; + } return obj; }; @@ -45861,6 +45687,24 @@ if (!Array.prototype.indexOf) { // ## Helper methods. +// In progress. +// const createOnClick = (choice, question) => { +// return function(value, removed, td) { +// var w, hide; +// w = node.widgets.lastAppended.formsById[question]; +// if (J.isArray(choice)) { +// hide = !J.inArray(this.currentChoice, choice); +// } +// else { +// hide = this.currentChoice !== choice; +// } +// if (hide) w.hide(); +// else w.show(); +// W.adjustFrameHeight(); +// }; +// }; +// onclick: createOnClick([0, 1], 'crypto_occupation') + })(node); /** @@ -45882,7 +45726,7 @@ if (!Array.prototype.indexOf) { // ## Meta-data - ChoiceTable.version = '1.8.0'; + ChoiceTable.version = '1.8.1'; ChoiceTable.description = 'Creates a configurable table where ' + 'each cell is a selectable choice.'; @@ -45985,7 +45829,7 @@ if (!Array.prototype.indexOf) { * @see ChoiceTable.onclick */ this.listener = function(e) { - var name, value, td; + var name, value, td, tr; var i, len, removed; e = e || window.event; @@ -45995,8 +45839,12 @@ if (!Array.prototype.indexOf) { if ('undefined' === typeof that.choicesIds[td.id]) { // It might be a nested element, try the parent. td = td.parentNode; - if (!td || 'undefined' === typeof that.choicesIds[td.id]) { - return; + if (!td) return; + if ('undefined' === typeof that.choicesIds[td.id]) { + td = td.parentNode; + if (!td || 'undefined' === typeof that.choicesIds[td.id]) { + return; + } } } @@ -46017,7 +45865,8 @@ if (!Array.prototype.indexOf) { if (value.length === 1) return; name = value[0]; - value = value[1]; + value = parseInt(value[1], 10); + // value = value[1]; // Choice disabled. // console.log('VALUE: ', value); @@ -47101,6 +46950,9 @@ if (!Array.prototype.indexOf) { else if (J.isElement(choice) || J.isNode(choice)) { td.appendChild(choice); } + else if (node.widgets.isWidget(choice)) { + node.widgets.append(choice, td); + } else { throw new Error('ChoiceTable.renderChoice: invalid choice: ' + choice); @@ -47443,10 +47295,10 @@ if (!Array.prototype.indexOf) { */ ChoiceTable.prototype.isChoiceCurrent = function(choice) { var i, len; - if ('number' === typeof choice) { - choice = '' + choice; + if ('string' === typeof choice) { + choice = parseInt(choice, 10); } - else if ('string' !== typeof choice) { + else if ('number' !== typeof choice) { throw new TypeError('ChoiceTable.isChoiceCurrent: choice ' + 'must be string or number. Found: ' + choice); } @@ -47824,8 +47676,8 @@ if (!Array.prototype.indexOf) { * @return {string} The checked choice */ function checkCorrectChoiceParam(that, choice) { - if ('number' === typeof choice) choice = '' + choice; - if ('string' !== typeof choice) { + if ('string' === typeof choice) choice = parseInt(choice, 10); + if ('number' !== typeof choice) { throw new TypeError('ChoiceTable.setCorrectChoice: each choice ' + 'must be number or string. Found: ' + choice); } @@ -49248,6 +49100,223 @@ if (!Array.prototype.indexOf) { })(node); +/** + * # Consent + * Copyright(c) 2021 Stefano Balietti + * MIT Licensed + * + * Displays a consent form with buttons to accept/reject it + * + * www.nodegame.org + */ +(function(node) { + + "use strict"; + + node.widgets.register('Consent', Consent); + + // ## Meta-data + + Consent.version = '0.3.0'; + Consent.description = 'Displays a configurable consent form.'; + + Consent.title = false; + Consent.panel = false; + Consent.className = 'consent'; + + Consent.texts = { + + areYouSure: 'You did not consent and are about to leave the ' + + 'study. Are you sure?', + + printText: + '

If you need a copy of this consent form, you may ' + + 'print a copy of this page for your records.

', + + printBtn: 'Print this page', + + consentTerms: 'Do you understand and consent to these terms?', + + agree: 'Yes, I agree', + + notAgree: 'No, I do not agree', + + showHideConsent: function(w, s) { + return (s === 'hide' ? 'Hide' : 'Show') + ' Consent Form'; + } + + }; + + /** + * ## Consent constructor + * + * Creates a new instance of Consent + * + * @param {object} options Optional. Configuration options + * which is forwarded to Consent.init. + * + * @see Consent.init + */ + function Consent() { + + /** + * ## Consent.consent + * + * The object containing the variables to substitute + * + * Default: node.game.settings.CONSENT + */ + this.consent = null; + + /** + * ## Consent.showPrint + * + * If TRUE, the print button is shown + * + * Default: TRUE + */ + this.showPrint = null; + } + + // ## Consent methods. + + /** + * ### Consent.init + * + * Initializes the widget + * + * @param {object} opts Optional. Configuration options. + */ + Consent.prototype.init = function(opts) { + opts = opts || {}; + + this.consent = opts.consent || node.game.settings.CONSENT; + + if (this.consent && 'object' !== typeof this.consent) { + throw new TypeError('Consent: consent must be object or ' + + 'undefined. Found: ' + this.consent); + } + + this.showPrint = opts.showPrint === false ? false : true; + }; + + Consent.prototype.enable = function() { + var a, na; + if (this.notAgreed) return; + a = W.gid('agree'); + if (a) a.disabled = false; + na = W.gid('notAgree'); + if (na) na.disabled = false; + }; + + Consent.prototype.disable = function() { + var a, na; + if (this.notAgreed) return; + a = W.gid('agree'); + if (a) a.disabled = true; + na = W.gid('notAgree'); + if (na) na.disabled = true; + }; + + Consent.prototype.append = function() { + var consent, html; + // Hide not agreed div. + W.hide('notAgreed'); + + consent = W.gid('consent'); + html = ''; + + // Print. + if (this.showPrint) { + html = this.getText('printText'); + html += '

'; + } + + // Header for buttons. + html += '' + this.getText('consentTerms') + '
'; + + // Buttons. + html += '
' + + '
'; + + consent.innerHTML += html; + setTimeout(function() { W.adjustFrameHeight(); }); + }; + + Consent.prototype.listeners = function() { + var that = this; + var consent = this.consent; + node.on('FRAME_LOADED', function() { + var a, na, p, id; + + // Replace all texts. + if (consent) { + for (p in consent) { + if (consent.hasOwnProperty(p)) { + // Making lower-case and replacing underscore + // s with dashes. + id = p.toLowerCase(); + id = id.replace(new RegExp("_", 'g'), "-"); + W.setInnerHTML(id, consent[p]); + } + } + } + + // Add listeners on buttons. + a = W.gid('agree'); + na = W.gid('notAgree'); + + if (!a) throw new Error('Consent: agree button not found'); + if (!na) throw new Error('Consent: notAgree button not found'); + + + a.onclick = function() { node.done({ consent: true }); }; + na.onclick = function() { + var showIt, confirmed; + + confirmed = confirm(that.getText('areYouSure')); + if (!confirmed) return; + + node.emit('CONSENT_REJECTING'); + + that.notAgreed = true; + node.set({ + consent: false, + // Need to send these two because it's not a DONE msg. + time: node.timer.getTimeSince('step'), + timeup: false + }); + a.disabled = true; + na.disabled = true; + a.onclick = null; + na.onclick = null; + + node.socket.disconnect(); + W.hide('consent'); + W.show('notAgreed'); + + // If a show-consent button is found enable it. + showIt = W.gid('show-consent'); + if (showIt) { + showIt.onclick = function() { + var div, s; + div = W.toggle('consent'); + s = div.style.display === '' ? 'hide' : 'show'; + this.innerHTML = that.getText('showHideConsent', s); + }; + } + node.emit('CONSENT_REJECTED'); + }; + }); + }; + +})(node); + /** * # ContentBox * Copyright(c) 2019 Stefano Balietti @@ -53832,6 +53901,719 @@ if (!Array.prototype.indexOf) { })(node); +(function(node) { + + node.widgets.register('Dropdown', Dropdown); + + // Meta-data. + + Dropdown.version = '0.3.0'; + Dropdown.description = 'Creates a configurable dropdown menu.'; + + Dropdown.texts = { + // Texts here (more info on this later). + error: function (w, value) { + if (value !== null && w.fixedChoice && + w.choices.indexOf(value) < 0) { + return 'No custom values allowed.' + } + if (value !== null && w.correctChoice !== null) { + return 'Not correct, try again.'; + } + if (value !== null && w.verifyChoice().err) { + return w.verifyChoice().err; + } + + return 'Answer required.'; + } + }; + + // Title is displayed in the header. + Dropdown.title = false; + // Classname is added to the widgets. + Dropdown.className = 'dropdown'; + + // Constructor taking a configuration parameter. + // The options object is always existing. + function Dropdown() { + var that; + that = this; + + // You can define widget properties here, + // but they should get assigned a value in init. + + this.id = null; + + /** + * ### Dropdown.mainText + * + * Main text above the dropdown + */ + this.mainText = null; + + /** + * ### Dropdown.labelText + * + * A label text for the input + */ + this.labelText = null; + + /** + * ### Dropdown.placeholder + * + * A placeholder text for the input + */ + this.placeholder = null; + + /** + * ### Dropdown.choices + * + * The array available choices + */ + this.choices = null; + + /** + * ### Dropdown.tag + * + * The HTML tag: "datalist" or "select" + */ + this.tag = null; + + /** + * ### Dropdown.menu + * + * Holder of the HTML element (datalist or select) + */ + this.menu = null; + + /** + * ### Dropdown.listener + * + * The main listener + * + * @see Dropdown.onchange + */ + this.listener = function (e) { + var menu, timeout; + + e = e || window.event; + menu = e.target || e.srcElement; + + that.currentChoice = menu.value; + if (that.currentChoice.length === 0) that.currentChoice = null; + + // Relative time. + if ('string' === typeof that.timeFrom) { + that.timeCurrentChoice = node.timer.getTimeSince(that.timeFrom); + } + // Absolute time. + else { + that.timeCurrentChoice = Date.now ? + Date.now() : new Date().getTime(); + } + + // One more change. + that.numberOfChanges++; + + // Remove any warning/errors on change. + if (that.isHighlighted()) that.unhighlight(); + + if (timeout) clearTimeout(timeout); + + timeout = setTimeout(function () { + that.verifyChoice(); + if (that.verifyChoice().err) { + that.setError(that.verifyChoice().err) + } + + }, that.validationSpeed); + + // Call onchange, if any. + if (that.onchange) { + that.onchange(that.currentChoice, that); + } + + }; + + /* + * ### Dropdown.onchange + * + * User defined onchange function + */ + this.onchange = null; + + /** + * ### Dropdown.timeCurrentChoice + * + * Time when the last choice was made + */ + this.timeCurrentChoice = null; + + /** + * ### Dropdown.timeFrom + * + * Time is measured from timestamp as saved by node.timer + * + * Default event is a new step is loaded (user can interact with + * the screen). Set it to FALSE, to have absolute time. + * + * @see node.timer.getTimeSince + */ + this.timeFrom = 'step'; + + /** + * ### Dropdown.numberOfChanges + * + * Total number of changes between different choices + */ + this.numberOfChanges = 0; + + /** + * ### Dropdown.currentChoice + * + * Choice associated with currently selected cell/s + * + * The field is a number. + */ + this.currentChoice = null; + + /** + * ### Dropdown.shuffleChoices + * + * If TRUE, choices are shuffled. + */ + this.shuffleChoices = null; + + /** + * ### Dropdown.order + * + * The current order of display of choices + * + */ + this.order = null; + + /** + * ### Dropdown.errorBox + * + * An HTML element displayed when a validation error occurs + */ + this.errorBox = null; + + /** + * ### Dropdown.correctChoice + * + * The correct choice/s + * + * The field is an array or number|string. + * + */ + this.correctChoice = null; + + /** + * ### Dropdown.requiredChoice + * + * If True, a choice is required. + */ + this.requiredChoice = null; + + /** + * ### Dropdown.fixedChoice + * + * If True, custom values in menu do not validated. + */ + this.fixedChoice = null; + + /** + * ### Dropdown.inputWidth + * + * The width of the input form as string (css attribute) + * + * Some types preset it automatically + */ + this.inputWidth = null; + + /** + * ### CustomInput.userValidation + * + * An additional validation executed after the main validation function + * + * The function returns an object like: + * + * ```javascript + * { + * value: 'validvalue', + * err: 'This error occurred' // If invalid. + * } + * ``` + */ + this.validation = null; + + /** + * ### Dropdown.validationSpeed + * + * How often (in milliseconds) the validation function is called + * + * Default: 500 + */ + this.validationSpeed = 500; + + } + + + Dropdown.prototype.init = function (options) { + // Init widget variables, but do not create + // HTML elements, they should be created in append. + + var tmp; + + if (!this.id) { + throw new TypeError('Dropdown.init: options.id is missing'); + } + + if ('string' === typeof options.mainText) { + this.mainText = options.mainText; + } + else if ('undefined' !== typeof options.mainText) { + throw new TypeError('Dropdown.init: options.mainText must ' + + 'be string or undefined. Found: ' + + options.mainText); + } + + // Set the labelText, if any. + if ('string' === typeof options.labelText) { + this.labelText = options.labelText; + } + else if ('undefined' !== typeof options.labelText) { + throw new TypeError('Dropdown.init: options.labelText must ' + + 'be string or undefined. Found: ' + + options.labelText); + } + + // Set the placeholder text, if any. + if ('string' === typeof options.placeholder) { + this.placeholder = options.placeholder; + } + else if ('undefined' !== typeof options.placeholder) { + throw new TypeError('Dropdown.init: options.placeholder must ' + + 'be string or undefined. Found: ' + + options.placeholder); + } + + // Add the choices. + if ('undefined' !== typeof options.choices) { + this.choices = options.choices; + } + + // Option requiredChoice, if any. + if ('boolean' === typeof options.requiredChoice) { + this.requiredChoice = options.requiredChoice; + } + else if ('undefined' !== typeof options.requiredChoice) { + throw new TypeError('Dropdown.init: options.requiredChoice ' + + 'be boolean or undefined. Found: ' + + options.requiredChoice); + } + + // Add the correct choices. + if ('undefined' !== typeof options.correctChoice) { + if (this.requiredChoice) { + throw new Error('Dropdown.init: cannot specify both ' + + 'options requiredChoice and correctChoice'); + } + if (J.isArray(options.correctChoice) && + options.correctChoice.length > options.choices.length) { + throw new Error('Dropdown.init: options.correctChoice ' + + 'length cannot exceed options.choices length'); + } + else { + this.correctChoice = options.correctChoice; + } + + } + + // Option fixedChoice, if any. + if ('boolean' === typeof options.fixedChoice) { + this.fixedChoice = options.fixedChoice; + } + else if ('undefined' !== typeof options.fixedChoice) { + throw new TypeError('Dropdown.init: options.fixedChoice ' + + 'be boolean or undefined. Found: ' + + options.fixedChoice); + } + + if ("undefined" === typeof options.tag || + "datalist" === options.tag || + "select" === options.tag) { + this.tag = options.tag; + } + else { + throw new TypeError('Dropdown.init: options.tag must ' + + 'be "datalist" or "select". Found: ' + + options.tag); + } + + // Set the main onchange listener, if any. + if ('function' === typeof options.listener) { + this.listener = function (e) { + options.listener.call(this, e); + }; + } + else if ('undefined' !== typeof options.listener) { + throw new TypeError('Dropdown.init: opts.listener must ' + + 'be function or undefined. Found: ' + + options.listener); + } + + // Set an additional onchange, if any. + if ('function' === typeof options.onchange) { + this.onchange = options.onchange; + } + else if ('undefined' !== typeof options.onchange) { + throw new TypeError('Dropdownn.init: opts.onchange must ' + + 'be function or undefined. Found: ' + + options.onchange); + } + + // Set an additional validation, if any. + if ('function' === typeof options.validation) { + this.validation = options.validation; + } + else if ('undefined' !== typeof options.validation) { + throw new TypeError('Dropdownn.init: opts.validation must ' + + 'be function or undefined. Found: ' + + options.validation); + } + + + // Option shuffleChoices, default false. + if ('undefined' === typeof options.shuffleChoices) tmp = false; + else tmp = !!options.shuffleChoices; + this.shuffleChoices = tmp; + + if (options.width) { + if ('string' !== typeof options.width) { + throw new TypeError('Dropdownn.init:width must be string or ' + + 'undefined. Found: ' + options.width); + } + this.inputWidth = options.width; + } + + // Validation Speed + if ('undefined' !== typeof options.validationSpeed) { + + tmp = J.isInt(options.valiadtionSpeed, 0, undefined, true); + if (tmp === false) { + throw new TypeError('Dropdownn.init: validationSpeed must ' + + ' a non-negative number or undefined. Found: ' + + options.validationSpeed); + } + this.validationSpeed = tmp; + } + + } + + // Implements the Widget.append method. + Dropdown.prototype.append = function () { + + if (W.gid(this.id)) { + throw new Error('Dropdown.append: id is not unique: ' + this.id); + } + var text = this.text; + var label = this.label; + + text = W.get('p'); + text.innerHTML = this.mainText; + text.id = 'p'; + this.bodyDiv.appendChild(text); + + label = W.get('label'); + label.innerHTML = this.labelText + this.bodyDiv.appendChild(label); + + this.setChoices(this.choices, true); + + this.errorBox = W.append('div', this.bodyDiv, { + className: 'errbox', id: 'errbox' + }); + }; + + + Dropdown.prototype.setChoices = function (choices, append) { + var tag, option, order; + var select, datalist, input, create; + var i, len; + + // TODO validate choices. + this.choices = choices; + + if (!append) return; + + create = false; + if (this.menu) this.menu.innerHTML = ''; + else create = true; + + if (create) { + tag = this.tag; + if (tag === "datalist" || "undefined" === typeof tag) { + + datalist = W.get('datalist'); + datalist.id = "dropdown"; + + input = W.get('input'); + input.setAttribute('list', datalist.id); + input.id = this.id; + input.autocomplete = "off"; + + this.bodyDiv.appendChild(input); + this.bodyDiv.appendChild(datalist); + this.menu = input; + + } + else { + + select = W.get('select'); + select.id = this.id; + + this.bodyDiv.appendChild(select); + this.menu = select; + } + } + + // Set width. + if (this.inputWidth) this.menu.style.width = this.inputWidth; + + // Adding placeholder. + if (this.placeholder) { + if (tag === "datalist") { + this.menu.placeholder = this.placeholder; + } + else { + option = W.get('option'); + option.value = ""; + option.innerHTML = this.placeholder; + option.setAttribute("disabled", ""); + option.setAttribute("selected", ""); + option.setAttribute("hidden", ""); + this.menu.appendChild(option); + } + } + + // Adding all options. + len = choices.length; + order = J.seq(0, len - 1); + if (this.shuffleChoices) order = J.shuffle(order); + for (i = 0; i < len; i++) { + option = W.get('option'); + option.value = choices[order[i]]; + option.innerHTML = choices[order[i]]; + this.menu.appendChild(option); + } + + this.enable(); + } + + /** + * ### Dropdown.verifyChoice + * + * Compares the current choice/s with the correct one/s + * + * Depending on current settings, there are three modes of verifying + * choices: + * + * - requiredChoice: either true or false. + * - correctChoice: the choices are compared against correct ones. + * - fixedChoice: compares the choice with given choices. + * + * @return {boolean|null} TRUE if current choice is correct, + * FALSE if it is not correct, or NULL if no correct choice + * was set + * + */ + Dropdown.prototype.verifyChoice = function () { + + var that = this; + var correct = this.correctChoice; + var current = this.currentChoice; + var correctOptions; + var res = { value: '' }; + + + if (this.tag === "select" && this.numberOfChanges === 0) { + current = this.currentChoice = this.menu.value; + } + + if (this.requiredChoice) { + res.value = current !== null && current !== this.placeholder; + } + + // If no correct choice is set return null. + if ('undefined' === typeof correct) res.value = null; + if ('string' === typeof correct) { + res.value = current === correct; + } + if ('number' === typeof correct) { + res.value = current === this.choices[correct]; + } + if (J.isArray(correct)) { + correctOptions = correct.map(function (x) { + return that.choices[x]; + }); + res.value = correctOptions.indexOf(current) >= 0; + } + + if (this.fixedChoice) { + if (this.choices.indexOf(current) < 0) res.value = false; + } + + if (this.validation) this.validation(this.currentChoice, res); + + return res; + }; + + /** + * ### Dropdown.setError + * + * Set the error msg inside the errorBox + * + * @param {string} The error msg (can contain HTML) + * + * @see Dropdown.errorBox + */ + Dropdown.prototype.setError = function (err) { + // TODO: the errorBox is added only if .append() is called. + // However, DropdownGroup use the table without calling .append(). + if (this.errorBox) this.errorBox.innerHTML = err || ''; + if (err) this.highlight(); + else this.unhighlight(); + }; + + /** + * ### Dropdown.highlight + * + * Highlights the input + * + * @param {string} The style for the table's border. + * Default '3px solid red' + * + * @see Dropdown.highlighted + */ + Dropdown.prototype.highlight = function (border) { + if (border && 'string' !== typeof border) { + throw new TypeError('Dropdown.highlight: border must be ' + + 'string or undefined. Found: ' + border); + } + if (this.highlighted) return; + this.menu.style.border = border || '3px solid red'; + this.highlighted = true; + this.emit('highlighted', border); + }; + + /** + * ### Dropdown.unhighlight + * + * Removes highlight + * + * @see Dropdown.highlighted + */ + Dropdown.prototype.unhighlight = function () { + if (this.highlighted !== true) return; + this.menu.style.border = ''; + this.highlighted = false; + this.setError(); + this.emit('unhighlighted'); + }; + + /** + * ### Dropdown.getValues + * + * Returns the values for current selection and other paradata + * + * Paradata that is not set or recorded will be omitted + * + * @return {object} Object containing the choice and paradata + * + * @see Dropdown.verifyChoice + */ + Dropdown.prototype.getValues = function (opts) { + var obj; + opts = opts || {}; + var verif = this.verifyChoice().value; + + obj = { + id: this.id, + choice: this.fixedChoice ? + this.choices.indexOf(this.currentChoice) : this.currentChoice, + time: this.timeCurrentChoice, + nChanges: this.numberOfChanges + }; + if ('undefined' === typeof opts.highlight) opts.highlight = true; + if (this.shuffleChoices) obj.order = this.order; + + // Option getValue backward compatible. + if (opts.addValue !== false && opts.getValue !== false) { + obj.value = this.currentChoice; + } + + if (null !== this.correctChoice || null !== this.requiredChoice || + null !== this.fixedChoice) { + obj.isCorrect = verif; + if (!obj.isCorrect && opts.highlight) this.highlight(); + } + if (obj.isCorrect === false) { + this.setError(this.getText('error', obj.value)); + } + return obj; + }; + + /** + * ### Dropdown.listeners + * + * Implements Widget.listeners + * + * Adds two listeners two disable/enable the widget on events: + * INPUT_DISABLE, INPUT_ENABLE + * + * @see Widget.listeners + */ + Dropdown.prototype.listeners = function () { + var that = this; + node.on('INPUT_DISABLE', function () { + that.disable(); + }); + node.on('INPUT_ENABLE', function () { + that.enable(); + }); + }; + + /** + * ### Dropdown.disable + * + * Enables the dropdown menu + */ + Dropdown.prototype.disable = function () { + if (this.disabled === true) return; + this.disabled = true; + if (this.menu) this.menu.removeEventListener('change', this.listener); + this.emit('disabled'); + }; + + /** + * ### Dropdown.enable + * + * Enables the dropdown menu + */ + Dropdown.prototype.enable = function () { + if (this.disabled === false) return; + if (!this.menu) { + throw new Error('Dropdown.enable: dropdown menu not found.'); + } + this.disabled = false; + this.menu.addEventListener('change', this.listener); + this.emit('enabled'); + }; + +})(node); + /** * # EmailForm * Copyright(c) 2021 Stefano Balietti @@ -54270,7 +55052,7 @@ if (!Array.prototype.indexOf) { // ## Add Meta-data - EndScreen.version = '0.7.1'; + EndScreen.version = '0.7.2'; EndScreen.description = 'Game end screen. With end game message, ' + 'email form, and exit code.'; @@ -54673,7 +55455,9 @@ if (!Array.prototype.indexOf) { } - if (data.showBonus !== false) { + if ('undefined' !== typeof data.bonus && + data.showBonus !== false) { + if (preWin !== '') preWin += ' + '; preWin += data.bonus; } @@ -54717,7 +55501,9 @@ if (!Array.prototype.indexOf) { } if (!err) { - if (totalWin !== preWin) totalWin = preWin + ' = ' + totalWin; + if (totalWin !== preWin & preWin !== '') { + totalWin = preWin + ' = ' + totalWin; + } totalWin += ' ' + this.totalWinCurrency; } } @@ -57641,7 +58427,7 @@ if (!Array.prototype.indexOf) { * @param {object} opts Optional. Configuration options. */ RiskGauge.prototype.init = function(opts) { - var gauge; + var gauge, that; if ('undefined' !== typeof opts.method) { if ('string' !== typeof opts.method) { throw new TypeError('RiskGauge.init: method must be string ' + @@ -57663,6 +58449,11 @@ if (!Array.prototype.indexOf) { // Call method. gauge = this.methods[this.method].call(this, opts); + // Add defaults. + that = this; + gauge.isHidden = function() { return that.isHidden(); }; + gauge.isCollapsed = function() { return that.isCollapsed(); }; + // Check properties. if (!node.widgets.isWidget(gauge)) { throw new Error('RiskGauge.init: method ' + this.method + @@ -58453,10 +59244,6 @@ if (!Array.prototype.indexOf) { // ## Dependencies - Slider.dependencies = { - JSUS: {} - }; - Slider.texts = { currentValue: function(widget, value) { return 'Value: ' + value; @@ -58985,9 +59772,7 @@ if (!Array.prototype.indexOf) { // ## Dependencies - SVOGauge.dependencies = { - JSUS: {} - }; + SVOGauge.dependencies = {}; /** * ## SVOGauge constructor @@ -59062,7 +59847,7 @@ if (!Array.prototype.indexOf) { * @param {object} opts Optional. Configuration options. */ SVOGauge.prototype.init = function(opts) { - var gauge; + var gauge, that; if ('undefined' !== typeof opts.method) { if ('string' !== typeof opts.method) { throw new TypeError('SVOGauge.init: method must be string ' + @@ -59085,8 +59870,18 @@ if (!Array.prototype.indexOf) { // Call method. gauge = this.methods[this.method].call(this, opts); + + // Add defaults. + that = this; + gauge.isHidden = function() { return that.isHidden(); }; + gauge.isCollapsed = function() { return that.isCollapsed(); }; + // Check properties. - checkGauge(this.method, gauge); + if (!node.widgets.isWidget(gauge)) { + throw new Error('SVOGauge.init: method ' + this.method + + ' created invalid gauge: missing default widget ' + + 'methods.') + } // Approved. this.gauge = gauge; @@ -59150,41 +59945,6 @@ if (!Array.prototype.indexOf) { return this.gauge.setValues(opts); }; - // ## Helper functions. - - /** - * ### checkGauge - * - * Checks if a gauge is properly constructed, throws an error otherwise - * - * @param {string} method The name of the method creating it - * @param {object} gauge The object to check - * - * @see ModdGauge.init - */ - function checkGauge(method, gauge) { - if (!gauge) { - throw new Error('SVOGauge.init: method ' + method + - 'did not create element gauge.'); - } - if ('function' !== typeof gauge.getValues) { - throw new Error('SVOGauge.init: method ' + method + - ': gauge missing function getValues.'); - } - if ('function' !== typeof gauge.enable) { - throw new Error('SVOGauge.init: method ' + method + - ': gauge missing function enable.'); - } - if ('function' !== typeof gauge.disable) { - throw new Error('SVOGauge.init: method ' + method + - ': gauge missing function disable.'); - } - if ('function' !== typeof gauge.append) { - throw new Error('SVOGauge.init: method ' + method + - ': gauge missing function append.'); - } - } - // ## Available methods. // ### SVO_Slider @@ -59340,8 +60100,7 @@ if (!Array.prototype.indexOf) { // ## Dependencies VisualRound.dependencies = { - GamePlot: {}, - JSUS: {} + GamePlot: {} }; /** @@ -59790,12 +60549,16 @@ if (!Array.prototype.indexOf) { // Compute current values. this.curStage = stage.stage; + // Stage can be indexed by id or number in the sequence. if ('string' === typeof this.curStage) { this.curStage = this.gamePlot.normalizeGameStage(stage).stage; } this.curStage -= this.stageOffset; + // 0.0.0 + if (this.curStage < 1) return; + this.curStep = stage.step; this.curRound = stage.round; @@ -60391,7 +61154,7 @@ if (!Array.prototype.indexOf) { // ## Meta-data - VisualStage.version = '0.10.0'; + VisualStage.version = '0.11.0'; VisualStage.description = 'Displays the name of the current, previous and next step of the game.'; @@ -60408,7 +61171,6 @@ if (!Array.prototype.indexOf) { // ## Dependencies VisualStage.dependencies = { - JSUS: {}, Table: {} }; @@ -60451,10 +61213,10 @@ if (!Array.prototype.indexOf) { // Default display settings. - // ### VisualStage.showRounds + // ### VisualStage.addRound // // If TRUE, round number is added to the name of steps in repeat stages - this.showRounds = true; + this.addRound = true; // ### VisualStage.showPrevious // @@ -60486,8 +61248,8 @@ if (!Array.prototype.indexOf) { } this.displayMode = opts.displayMode; } - if ('undefined' !== typeof opts.rounds) { - this.showRounds = !!opts.rounds; + if ('undefined' !== typeof opts.addRound) { + this.addRound = !!opts.addRound; } if ('undefined' !== typeof opts.previous) { this.showPrevious = !!opts.previous; @@ -60629,10 +61391,19 @@ if (!Array.prototype.indexOf) { * @return {string} name The name of the step */ VisualStage.prototype.getStepName = function(gameStage, curStage, mod) { - var name, round; + var name, round, preprocess, addRound; // Get the name. If no step property is defined, use the id and // do some text replacing. name = node.game.plot.getProperty(gameStage, 'name'); + if ('function' === typeof name) { + preprocess = name; + name = null; + } + else if ('object' === typeof name && name !== null) { + preprocess = name.preprocess; + addRound = name.addRound; + name = name.name; + } if (!name) { name = node.game.plot.getStep(gameStage); if (!name) { @@ -60644,15 +61415,15 @@ if (!Array.prototype.indexOf) { if (this.capitalize) name = capitalize(name); } } + if (!preprocess) preprocess = this.preprocess; + if ('undefined' === typeof addRound) addRound = this.addRound; + + round = getRound(gameStage, curStage, mod); // If function, executes it. - if ('function' === typeof name) name = name.call(node.game); + if (preprocess) name = preprocess.call(node.game, name, mod, round); + if (addRound && round) name += ' ' + round; - if (this.showRounds) { - round = getRound(gameStage, curStage, mod); - if (round) name += ' ' + round; - } - if (this.preprocess) name = this.preprocess(name, mod, round); return name; }; @@ -60763,7 +61534,7 @@ if (!Array.prototype.indexOf) { /** * # VisualTimer - * Copyright(c) 2019 Stefano Balietti + * Copyright(c) 2021 Stefano Balietti * MIT Licensed * * Display a configurable timer for the game @@ -60780,7 +61551,7 @@ if (!Array.prototype.indexOf) { // ## Meta-data - VisualTimer.version = '0.9.2'; + VisualTimer.version = '0.9.3'; VisualTimer.description = 'Display a configurable timer for the game. ' + 'Can trigger events. Only for countdown smaller than 1h.'; @@ -60790,8 +61561,7 @@ if (!Array.prototype.indexOf) { // ## Dependencies VisualTimer.dependencies = { - GameTimer: {}, - JSUS: {} + GameTimer: {} }; /** @@ -61070,13 +61840,7 @@ if (!Array.prototype.indexOf) { options = options || {}; oldOptions = this.options; - if (this.internalTimer) { - node.timer.destroyTimer(this.gameTimer); - this.internalTimer = null; - } - else { - this.gameTimer.removeHook(this.updateHookName); - } + destroyTimer(this); this.gameTimer = null; this.activeBox = null; @@ -61143,12 +61907,10 @@ if (!Array.prototype.indexOf) { * * Stops the timer display and stores the time left in `activeBox.timeLeft` * - * @param {object} options Configuration object - * * @see GameTimer.isStopped * @see GameTimer.stop */ - VisualTimer.prototype.stop = function(options) { + VisualTimer.prototype.stop = function() { if (!this.gameTimer.isStopped()) { this.activeBox.timeLeft = this.gameTimer.timeLeft; this.gameTimer.stop(); @@ -61320,13 +62082,7 @@ if (!Array.prototype.indexOf) { // Handle destroy. this.on('destroyed', function() { - if (that.internalTimer) { - node.timer.destroyTimer(that.gameTimer); - that.internalTimer = null; - } - else { - that.gameTimer.removeHook('VisualTimer_' + that.wid); - } + destroyTimer(that); that.bodyDiv.removeChild(that.mainBox.boxDiv); that.bodyDiv.removeChild(that.waitBox.boxDiv); }); @@ -61506,6 +62262,30 @@ if (!Array.prototype.indexOf) { this.bodyDiv.className = className; }; + // Helper function. + + function destroyTimer(that) { + if (that.internalTimer) { + if (!that.gameTimer.isDestroyed()) { + node.timer.destroyTimer(that.gameTimer); + } + that.internalTimer = null; + } + else { + that.gameTimer.removeHook('VisualTimer_' + that.wid); + } + } + + // if (this.internalTimer) { + // if (!this.gameTimer.isDestroyed()) { + // node.timer.destroyTimer(this.gameTimer); + // } + // this.internalTimer = null; + // } + // else { + // this.gameTimer.removeHook(this.updateHookName); + // } + })(node); /** @@ -61533,7 +62313,6 @@ if (!Array.prototype.indexOf) { // ## Dependencies WaitingRoom.dependencies = { - JSUS: {}, VisualTimer: {} }; @@ -62362,7 +63141,7 @@ if (!Array.prototype.indexOf) { WaitingRoom.prototype.stopTimer = function() { if (this.timer) { node.info('waiting room: STOPPING TIMER'); - this.timer.destroy(); + this.timer.stop(); } }; diff --git a/public/javascripts/nodegame-full.min.js b/public/javascripts/nodegame-full.min.js new file mode 100644 index 00000000..b8f96c3c --- /dev/null +++ b/public/javascripts/nodegame-full.min.js @@ -0,0 +1,10 @@ +var JSON;void 0===String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),"undefined"==typeof console&&(this.console={log:function(){}}),Date.now||(Date.now=function(){return(new Date).getTime()}),"indexOf"in Array.prototype||(Array.prototype.indexOf=function(find,i){void 0===i&&(i=0),i<0&&(i+=this.length),i<0&&(i=0);for(var n=this.length;ithis.length-1&&(i=this.length-1),i++;i-- >0;)if(i in this&&this[i]===find)return i;return-1}),"function"!=typeof Object.create&&(Object.create=function(){var Temp=function(){};return function(prototype){if(arguments.length>1)throw Error("Second argument not supported");if("object"!=typeof prototype)throw TypeError("Argument must be an object");Temp.prototype=prototype;var result=new Temp;return Temp.prototype=null,result}}()),JSON||(JSON={}),function(){"use strict";var global=new Function("return this")(),JSON=global.JSON;function f(n){return n<10?"0"+n:n}JSON||(JSON={}),"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){return escapable.lastIndex=0,escapable.test(string)?'"'+string.replace(escapable,(function(a){var c=meta[a];return"string"==typeof c?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}))+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,partial,mind=gap,value=holder[key];switch(value&&"object"==typeof value&&"function"==typeof value.toJSON&&(value=value.toJSON(key)),"function"==typeof rep&&(value=rep.call(holder,key,value)),typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value)return"null";if(gap+=indent,partial=[],"[object Array]"===Object.prototype.toString.apply(value)){for(length=value.length,i=0;i>>0;if(0===len)return-1;var n=+fromIndex||0;if(Math.abs(n)===1/0&&(n=0),n>=len)return-1;for(k=Math.max(n>=0?n:len-Math.abs(n),0);k>>0;if("function"!=typeof fun)throw new TypeError;for(var res=[],thisp=arguments[1],i=0;i=end;)out.push(func(i)),i-=increment;return out},ARRAY.each=function(array,cb,context){var i,len;if("object"!=typeof array)throw new TypeError("ARRAY.each: array must be object. Found: "+array);if("function"!=typeof cb)throw new TypeError("ARRAY.each: cb must be function. Found: "+cb);for(context=context||this,len=array.length,i=0;i=N&&(result.push(group),count=0,group=[]),group.push(copy[idx]),copy.splice(idx,1),len=copy.length,count++;return group.length>0&&result.push(group),result},ARRAY._latinSquare=function(S,N,self){if(self=void 0===self||self,S===N&&!self)return!1;for(var seq=[],latin=[],i=0;iS&&(N=S),ARRAY._latinSquare(S,N,!0))},ARRAY.latinSquareNoSelf=function(S,N){return N||(N=S-1),!(!S||S<0||N<0)&&(N>S&&(N=S-1),ARRAY._latinSquare(S,N,!1))},ARRAY.generateCombinations=function combinations(arr,k){var i,subI,ret,sub,next;for(ret=[],i=0;i0;i--)tmp=copy[j=Math.floor(Math.random()*(i+1))],copy[j]=copy[i],copy[i]=tmp;return copy}},ARRAY.getNRandom=function(array,N){return ARRAY.shuffle(array).slice(0,N)},ARRAY.distinct=function(array){var out=[];return array?(ARRAY.each(array,(function(e){ARRAY.inArray(e,out)||out.push(e)})),out):out},ARRAY.transpose=function(array){if(array){var w,h,i,j,t=[];if(w=array.length||0,h=ARRAY.isArray(array[0])?array[0].length:0,0===w||0===h)return t;for(i=0;i100)throw new Error("DOM.generateUniqueId: could not find unique id within 100 trials.");return id}}(),DOM.removeClass=function(elem,className,force){var regexpr;if(!force&&!DOM.isElement(elem))throw new TypeError("DOM.removeClass: elem must be HTMLElement. Found: "+elem);if(className){if("string"!=typeof className||""===className.trim())throw new TypeError("DOM.removeClass: className must be HTMLElement. Found: "+className);regexpr=new RegExp("(?:^|\\s)"+className+"(?!\\S)"),elem.className=elem.className.replace(regexpr,"")}return elem},DOM.addClass=function(elem,className,force){if(!force&&!DOM.isElement(elem))throw new TypeError("DOM.addClass: elem must be HTMLElement. Found: "+elem);if(className){if(className instanceof Array&&(className=className.join(" ")),"string"!=typeof className||""===className.trim())throw new TypeError("DOM.addClass: className must be HTMLElement. Found: "+className);elem.className?elem.className+=" "+className:elem.className=className}return elem},DOM.getElementsByClassName=function(document,className,nodeName){var result,node,tag,seek,i,rightClass;if(result=[],tag=nodeName||"*",document.evaluate)for(seek="//"+tag+'[contains(concat(" ", normalize-space(@class), " "), "'+className+' ")]',seek=document.evaluate(seek,document,null,0,null);node=seek.iterateNext();)result.push(node);else for(rightClass=new RegExp("(^| )"+className+"( |$)"),seek=document.getElementsByTagName(tag),i=0;i1){var Properties=new Object(arguments[1]);for(var prop in Properties)hasOwn.call(Properties,prop)&&(obj[prop]=Properties[prop])}return obj}}():Object.create,OBJ.equals=function(o1,o2){var type1,type2,p;if((type1=typeof o1)!==(type2=typeof o2))return!1;if("undefined"===type1||"undefined"===type2)return o1===o2;if(null===o1||null===o2)return o1===o2;if("number"===type1&&isNaN(o1)&&"number"===type2&&isNaN(o2))return isNaN(o1)&&isNaN(o2);if(type1 in{number:"",string:"",boolean:""})return o1===o2;if("function"===type1)return o1.toString()===o2.toString();for(p in o1)if(o1.hasOwnProperty(p)){if(void 0===o2[p]&&void 0!==o1[p])return!1;if(!o2[p]&&o1[p])return!1;if("function"==typeof o1[p]){if(o1[p].toString()!==o2[p].toString())return!1}else if(!OBJ.equals(o1[p],o2[p]))return!1}for(p in o2)if(o2.hasOwnProperty(p)){if(void 0===o1[p]&&void 0!==o2[p])return!1;if(!o1[p]&&o2[p])return!1}return!0},OBJ.isEmpty=function(o){var key;if(!o)return!0;if("string"==typeof o)return""===o.trim();if("number"==typeof o)return!1;if("function"==typeof o)return!1;for(key in o)if(o.hasOwnProperty(key))return!1;return!0},OBJ.size=OBJ.getListSize=function(obj){var n,key;if(!obj)return 0;if("number"==typeof obj)return 0;if("string"==typeof obj)return 0;for(key in n=0,obj)obj.hasOwnProperty(key)&&n++;return n},OBJ._obj2Array=function(obj,keyed,level,cur_level){var result,key;if("object"!=typeof obj)return[obj];if(level){if((cur_level=void 0!==cur_level?cur_level:1)>level)return[obj];cur_level+=1}for(key in result=[],obj)obj.hasOwnProperty(key)&&(keyed&&result.push(key),"object"==typeof obj[key]?result=result.concat(OBJ._obj2Array(obj[key],keyed,level,cur_level)):result.push(obj[key]));return result},OBJ.obj2Array=function(obj,level){return OBJ._obj2Array(obj,!1,level)},OBJ.obj2KeyedArray=OBJ.obj2KeyArray=function(obj,level){return OBJ._obj2Array(obj,!0,level)},OBJ.obj2QueryString=function(obj){var str,key;if("object"!=typeof obj)throw new TypeError("JSUS.objectToQueryString: obj must be object.");for(key in str=[],obj)obj.hasOwnProperty(key)&&str.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key]));return"?"+str.join("&")},OBJ.keys=function(){return function(obj,level,options){var keys,type,allKeys,leafKeys,levelKeys,separator,myLevel,curParent;if(2===arguments.length&&"object"==typeof level&&(level=(options=level).level),"all"===(type=(options=options||{}).type?options.type.toLowerCase():"all"))allKeys=!0;else if("leaf"===type)leafKeys=!0;else{if("level"!==type)throw new Error("keys: unknown type option: "+type);levelKeys=!0}if(options.cb&&"function"!=typeof options.cb)throw new TypeError("JSUS.keys: options.cb must be function or undefined. Found: "+options.cb);if(void 0===level?myLevel=0:"number"==typeof level?myLevel=level:"string"==typeof level&&(myLevel=parseInt(level,10)),"number"!=typeof myLevel||isNaN(myLevel))throw new Error("JSUS.keys: level must be number, undefined or a parsable string. Found: "+level);return level<0?[]:(options.concat&&(separator=void 0===options.separator?".":options.separator),curParent=options.parent?options.parent+separator:"",!options.concat&&options.distinct&&(keys={}),_keys(obj,myLevel,0,curParent,options.concat,allKeys,leafKeys,levelKeys,separator,options.array||[],keys,options.skip||{},options.cb))};function _keys(obj,level,curLevel,curParent,concatKeys,allKeys,leafKeys,levelKeys,separator,res,uniqueKeys,skipKeys,cb){var key,isLevel,isObj,tmp;for(key in isLevel=curLevel===level,obj)obj.hasOwnProperty(key)&&(isObj="object"==typeof obj[key],(allKeys||leafKeys&&(isLevel||!isObj)||levelKeys&&isLevel)&&(concatKeys?skipKeys[tmp=curParent+key]||(cb?_doCb(tmp,res,cb):res.push(tmp)):skipKeys[key]||(uniqueKeys?uniqueKeys[key]||(cb?_doCb(key,res,cb):res.push(key),uniqueKeys[key]=!0):cb?_doCb(key,res,cb):res.push(key))),isObj&&curLevel1&&(res.push(tmp[1]),tmp.length>2&&res.push(tmp[2]))):function(){for(var i=-1,len=tmp.length;++i=level)makeClone(value,out,keysArray);else for(i in curPosAsKey=posAsKeys||!JSUS.isArray(value),value)value.hasOwnProperty(i)&&("object"==typeof value[i]&&level&&curLevel+1<=level?splitValue(value[i],out,curLevel+1,curPosAsKey?keysArray.concat(i):keysArray):makeClone(value[i],out,curPosAsKey?keysArray.concat(i):keysArray))},function(o,key,l,positionAsKey){var out;if("object"!=typeof o)throw new TypeError("JSUS.split: o must be object. Found: "+o);if("string"!=typeof key||""===key.trim())throw new TypeError("JSUS.split: key must a non-empty string. Found: "+key);if(l&&("number"!=typeof l||l<0))throw new TypeError("JSUS.split: l must a non-negative number or undefined. Found: "+l);return model=JSUS.clone(o),"object"!=typeof o[key]?[model]:(out=[],_key=key,model[key]={},level=void 0===l?1:l,posAsKeys=positionAsKey,splitValue(o[key],out,0,[]),_key=void 0,model=void 0,level=void 0,posAsKeys=void 0,out)}),OBJ.melt=function(keys,values){for(var o={},valen=values.length,i=0;istop)return;return name}JSUS.log("Cannot find unique name in undefined object","ERR")},OBJ.randomKey=function(obj){var keys;if("object"!=typeof obj)throw new TypeError("OBJ.randomKey: obj must be object. Found: "+obj);return(keys=Object.keys(obj))[keys.length*Math.random()<<0]},OBJ.augment=function(obj1,obj2,keys){var i,k;for(keys=keys||OBJ.keys(obj1),i=0;i=1?normal(mu,sigma):(multiplier=Math.sqrt(-2*Math.log(s)/s),x2=v2*multiplier,genReady=!0,sigma*(v1*multiplier)+mu)};var oldMu,oldSigma,x2,multiplier,genReady},RANDOM.nextNormal=RANDOM.getNormalGenerator(),RANDOM.nextLogNormal=function(mu,sigma){if("number"!=typeof mu)throw new TypeError("nextLogNormal: mu must be number.");if("number"!=typeof sigma)throw new TypeError("nextLogNormal: sigma must be number.");return Math.exp(RANDOM.nextNormal(mu,sigma))},RANDOM.nextExponential=function(lambda){if("number"!=typeof lambda)throw new TypeError("nextExponential: lambda must be number.");if(lambda<=0)throw new TypeError("nextExponential: lambda must be greater than 0.");return-Math.log(1-Math.random())/lambda},RANDOM.nextBinomial=function(p,trials){var counter,sum;if("number"!=typeof p)throw new TypeError("nextBinomial: p must be number.");if("number"!=typeof trials)throw new TypeError("nextBinomial: trials must be number.");if(p<0||p>1)throw new TypeError("nextBinomial: p must between 0 and 1.");if(trials<1)throw new TypeError("nextBinomial: trials must be greater than 0.");for(counter=0,sum=0;counter 0 or undefined. Found: "+len);if(void 0!==chars){if("string"!=typeof chars||""===chars.trim())throw new Error("randomString: chars must a non-empty string or undefined. Found: "+chars)}else if(useChars)throw new Error("randomString: useChars is TRUE, but chars is undefined.");if(len=len||6,chars=chars||"a",mask="",useChars)mask=chars;else if(chars.indexOf("a")>-1&&(mask+="abcdefghijklmnopqrstuvwxyz"),chars.indexOf("A")>-1&&(mask+="ABCDEFGHIJKLMNOPQRSTUVWXYZ"),chars.indexOf("1")>-1&&(mask+="0123456789"),chars.indexOf("!")>-1&&(mask+="!~`@#$%^&*()_+-={}[]:\";'<>?,./|\\"),(nSpaces=chars.indexOf("_"))>-1)if(nSpaces=chars.charAt(nSpaces+1),1===(nSpaces=JSUS.isInt(nSpaces,0)||1))mask+=" ";else if(2===nSpaces)mask+=" ";else if(3===nSpaces)mask+=" ";else for(i=-1;++iupper:n>=upper))&&n))},PARSE.isEmail=function(email){var idx;return"string"==typeof email&&(!(email.trim().length<5)&&(-1!==(idx=email.indexOf("@"))&&0!==idx&&idx!==email.length-1&&!(-1===(idx=email.lastIndexOf("."))||idx===email.length-1||idx>idx+1)))},PARSE.range=function(expr,available){var i,len,x,solution,begin,end,lowerBound,numbers,invalidChars,invalidBeforeOpeningBracket,invalidDot;if(solution=[],void 0===expr)return solution;if("number"==typeof expr)expr=""+expr;else if("string"!=typeof expr)throw new TypeError("PARSE.range: expr must be string, number, undefined. Found: "+expr);if(void 0===available)available=expr;else if(JSUS.isArray(available)){if(0===available.length)return solution;begin=Math.min.apply(null,available),end=Math.max.apply(null,available)}else if("object"==typeof available){if("function"!=typeof available.next)throw new TypeError("PARSE.range: available.next must be function. Found: "+available.next);if("function"!=typeof available.isFinished)throw new TypeError("PARSE.range: available.isFinished must be function. Found: "+available.isFinished);if("number"!=typeof available.begin)throw new TypeError("PARSE.range: available.begin must be number. Found: "+available.begin);if("number"!=typeof available.end)throw new TypeError("PARSE.range: available.end must be number. Found: "+available.end);begin=available.begin,end=available.end}else{if("string"!=typeof available)throw new TypeError("PARSE.range: available must be string, array, object or undefined. Found: "+available);if(null===(numbers=(available=preprocessRange(available)).match(/([-+]?\d+)/g)))throw new Error("PARSE.range: no numbers in available: "+available);lowerBound=Math.min.apply(null,numbers),available=PARSE.range(available,{begin:lowerBound,end:Math.max.apply(null,numbers),value:lowerBound,next:function(){return this.value++},isFinished:function(){return this.value>this.end}}),begin=Math.min.apply(null,available),end=Math.max.apply(null,available)}if(invalidChars=/[^ \*\d<>=!\|&\.\[\],\(\)\-\+%]/g,(expr=(expr=preprocessRange(expr=(expr=expr.replace(/end/g,parseInt(end,10))).replace(/begin/g,parseInt(begin,10)))).replace(/([-+]?\d+\.\d+)/g,(function(match,p1){return parseInt(p1,10)}))).match(invalidChars))throw new Error("PARSE.range: invalid characters found: "+expr);if(invalidChars=/[^ \d<>=!\|&,\(\)\-\+%x\.]/g,invalidBeforeOpeningBracket=/[^ &!|\(] *\(/g,invalidDot=/\.[^\d]|[^\d]\./,(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=(expr=expr.replace(/([^& ]) *& *([^& ])/g,"$1&&$2")).replace(/([^| ]) *\| *([^| ])/g,"$1||$2")).replace(/([-+]?\d+)/g,"(x==$1)")).replace(/% *\(x==([-+]?\d+)\)/,"!(x%$1)")).replace(/!\(x%([-+]?\d+)\) *={1,} *\(x==([-+]?\d+)\)/g,"(x%$1==$2)")).replace(/([<>]=?) *\(x==([-+]?\d+)\)/g,"(x$1$2)")).replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(\+?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$3&&!((x- $1)%$2))")).replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(-\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x<=$1&&x>=$3&&!((x- $1)%$2))")).replace(/\(x==([-+]?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$2)")).replace(/([(\[]) *\(x==([-+]?\d+)\) *, *\(x==([-+]?\d+)\) *([\])])/g,(function(match,p1,p2,p3,p4){return"(x>"+("("==p1?"":"=")+p2+"&&x<"+(")"==p4?"":"=")+p3+")"}))).replace("*",1)).replace(/\s/g,"")).replace(/\)[,] *(!*)\(/g,")||$1(")).match(invalidChars))throw new Error("PARSE.range: invalid characters found: "+expr);if(expr.match(invalidBeforeOpeningBracket))throw new Error("PARSE.range: invalid character before opending bracket found: "+expr);if(expr.match(invalidDot))throw new Error("PARSE.range: invalid dot found: "+expr);if(JSUS.isArray(available))for(i=-1,len=available.length;++i1?res[1].trim():""},JSUS.extend(PARSE)}("undefined"!=typeof JSUS?JSUS:module.parent.exports.JSUS),function(J){"use strict";if("undefined"!=typeof module&&void 0!==module.exports?(J=module.parent.exports.JSUS||require("JSUS").JSUS,module.exports=NDDB,module.exports.NDDB=NDDB):(J=JSUS,window.NDDB=NDDB),!J)throw new Error("NDDB: missing dependency: JSUS.");var df=J.compatibility().defineProperty;function NDDB(opts,db){var that;that=this,opts=opts||{},this.name=opts.name||"nddb",this.nddbid=new NDDBIndex("nddbid",this),this.db=[],this.lastSelection=[],this.hashtray=new NDDBHashtray,this.tags={},this.hooks={insert:[],remove:[],update:[],setwd:[],save:[],load:[]},this.sharedHooks={insert:[],remove:[],update:[],setwd:[],save:[],load:[]},this.nddb_pointer=0,this.query=new QueryBuilder,this.filters={},this.addDefaultFilters(),this.__userDefinedFilters={},this.__C={},this.__H={},this.__I={},this.__V={},this.__update={},this.__update.pointer=!1,this.__update.indexes=!0,this.__update.sort=!1,this.__shared={},this.__formats={},this.__defaultFormat=null,this.__wd=null,this.__parentDb=null,this.log=console.log,this.globalCompare=function(o1,o2){return-1},this.comparator("*",(function(o1,o2,trigger1,trigger2){var d,c,res;for(d in o1){if(c=that.getComparator(d),o2[d]=o2["*"],(res=c(o1,o2))===trigger1)return res;if("undefined"!==trigger2&&res===trigger2)return res}return 0===trigger1?1===trigger2?-1:1:1===trigger1?0===trigger2?-1:0:0===trigger2?1:0})),"function"==typeof this.addDefaultFormats&&this.addDefaultFormats(),this.__cache={},this.init(opts),db&&this.importDB(db),opts.journal&&"function"==typeof NDDB.prototype.journal&&this.journal({filename:opts.journal,load:!0,cb:opts.cb})}function queryError(text,d,op,value){var err;throw"(?)",err=this._getConstrName()+"._analyzeQuery: "+text+". Malformed query: "+d||"(?) "+op||"(?) "+value||"(?).",new Error(err)}function getValuesArray(o){return J.obj2Array(o,1)}function getKeyValuesArray(o){return J.obj2KeyedArray(o,1)}function getValuesArray_KeyString(o,key){var el=J.getNestedValue(key,o);if(void 0!==el)return J.obj2Array(el,1)}function getValuesArray_KeyArray(o,key){var el=J.subobj(o,key);if(!J.isEmpty(el))return J.obj2Array(el,1)}function getKeyValuesArray_KeyString(o,key){var el=J.getNestedValue(key,o);if(void 0!==el)return key.split(".").concat(J.obj2KeyedArray(el))}function getKeyValuesArray_KeyArray(o,key){var el=J.subobj(o,key);if(!J.isEmpty(el))return J.obj2KeyedArray(el)}function nddb_insert(o,doUpdate){var nddbid;return"object"!=typeof o&&"function"!=typeof o&&this.throwErr("TypeError","insert","object or function expected, "+typeof o+" received"),void 0===o._nddbid&&((nddbid=J.uniqueKey(this.nddbid.resolve))||this.throwErr("Error","insert","failed to create index: "+o),df?Object.defineProperty(o,"_nddbid",{value:nddbid}):o._nddbid=nddbid),this.nddbid.resolve[o._nddbid]=this.db.length,!1!==this.emit("insert",o,this.db.length)&&(this.db.push(o),doUpdate&&(this._indexIt(o,this.db.length-1),this._hashIt(o),this._viewIt(o)),!0)}function executeSaveLoad(that,method,file,cb,options){var ff,format;return that.storageAvailable()||that.throwErr("Error","save","no persistent storage available"),void 0===options&&"object"==typeof cb?(options=cb,cb=void 0):void 0===cb&&"function"==typeof options&&(cb=options,options=void 0),function(that,method,file,cb,options){"string"==typeof file&&""!==file.trim()||that.throwErr("TypeError",method,"file must be a non-empty string. Found: "+file),cb&&"function"!=typeof cb&&that.throwErr("TypeError",method,"cb must be function or undefined. Found: "+cb),options&&"object"!=typeof options&&("function"==typeof options&&void 0===cb||that.throwErr("TypeError",method,"options must be object or undefined. Found: "+options))}(that,method,file,cb,options),format=(options=options||{}).format||function(file){var format;return(format=file.lastIndexOf("."))<0?null:file.substr(format+1)}(file),ff=function(that,method,format){var ff,defFormat;format&&(ff=that.getFormat(format));ff&&(ff[method]||that.throwErr("Error",method,"format "+format+" found, but method "+method+" not available"),ff=ff[method]);ff||((defFormat=that.getDefaultFormat())||that.throwErr("Error",method,"format "+format+" not found and no default format specified"),(ff=that.getFormat(defFormat,method))||that.throwErr("Error",method,"format "+format+" not found, but default format has no method "+method));return ff}(that,method,format),that.emit("s"===method.charAt(0)?"save":"load",options,{file:file,format:format,cb:cb}),ff(that,file,cb,options),that}function QueryBuilder(){this.reset()}function findCallback(obj){return obj.cb}function NDDBHashtray(){this.resolve={}}function NDDBIndex(idx,nddb){this.idx=idx,this.nddb=nddb,this.resolve={},this.keys=[],this.resolveKeys={}}NDDB.db=function(opts,db){return new NDDB(opts,db)},NDDB.lineBreak="\n",NDDB.decycle=function(e){return JSON&&"function"==typeof JSON.decycle&&(e=JSON.decycle(e)),e},NDDB.retrocycle=function(e){return JSON&&"function"==typeof JSON.retrocycle&&(e=JSON.retrocycle(e)),e},NDDB.prototype.addFilter=function(op,cb){this.filters[op]=cb,this.__userDefinedFilters[op]=this.filters[op]},NDDB.prototype.addDefaultFilters=function(){var that;function generalLike(d,value,comparator,sensitive){var regex;return RegExp.escape=function(str){return str.replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")},regex=(regex=RegExp.escape(value)).replace(/%/g,".*").replace(/_/g,"."),regex=new RegExp("^"+regex+"$",sensitive),"object"==typeof d?function(elem){var i,len;for(len=d.length,i=0;i0&&(value[d]=value[1]["*"],c(elem,value,-1)<0))return elem;return void 0!==elem[d]||void 0!==J.getNestedValue(d,elem)?elem:void 0}:function(elem){return void 0!==elem[d]||void 0!==J.getNestedValue(d,elem)?elem:void 0}},this.filters["=="]=function(d,value,comparator){return function(elem){if(0===comparator(elem,value,0))return elem}},this.filters["!="]=function(d,value,comparator){return function(elem){if(0!==comparator(elem,value,0))return elem}},this.filters[">"]=function(d,value,comparator){return"object"==typeof d||"*"===d?function(elem){if(1===comparator(elem,value,1))return elem}:function(elem){if(void 0!==elem[d])return 1===comparator(elem,value,1)?elem:void 0}},this.filters[">="]=function(d,value,comparator){return"object"==typeof d||"*"===d?function(elem){var compared=comparator(elem,value,0,1);if(1===compared||0===compared)return elem}:function(elem){if(void 0!==elem[d]){var compared=comparator(elem,value,0,1);return 1===compared||0===compared?elem:void 0}}},this.filters["<"]=function(d,value,comparator){return"object"==typeof d||"*"===d?function(elem){if(-1===comparator(elem,value,-1))return elem}:function(elem){if(void 0!==elem[d])return-1===comparator(elem,value,-1)?elem:void 0}},this.filters["<="]=function(d,value,comparator){return"object"==typeof d||"*"===d?function(elem){var compared=comparator(elem,value,0,-1);if(-1===compared||0===compared)return elem}:function(elem){if(void 0!==elem[d]){var compared=comparator(elem,value,0,-1);return-1===compared||0===compared?elem:void 0}}},this.filters["><"]=function(d,value,comparator){return"object"==typeof d?function(elem){var i,len;for(len=d.length,i=0;i0&&comparator(elem,value[1],-1)<0)return elem}:"*"===d?function(elem){var d,c;for(d in elem)if(c=that.getComparator(d),value[d]=value[0]["*"],c(elem,value,1)>0&&(value[d]=value[1]["*"],c(elem,value,-1)<0))return elem}:function(elem){if(comparator(elem,value[0],1)>0&&comparator(elem,value[1],-1)<0)return elem}},this.filters["<>"]=function(d,value,comparator){return"object"==typeof d||"*"===d?function(elem){if(comparator(elem,value[0],-1)<0||comparator(elem,value[1],1)>0)return elem}:function(elem){if(void 0!==elem[d])return comparator(elem,value[0],-1)<0||comparator(elem,value[1],1)>0?elem:void 0}},this.filters.in=function(d,value,comparator){return"object"==typeof d?function(elem){var i,len;for(len=value.length,i=0;iv2?1:v2>v1?-1:v2===v1?0:1)};else{for(comparators={},len=d.length,i=0;i<","<>","in","!in"]))value instanceof Array||(errText="range-queries need an array as third parameter",queryError.call(this,errText,d,op,value)),"<>"!==op&&"><"!==op||J.isArray(d)||(value[0]=J.setNestedValue(d,value[0]),value[1]=J.setNestedValue(d,value[1]));else if(J.inArray(op,["!=",">","==",">=","<","<="]))if(void 0===value&&(errText="value cannot be undefined in comparison queries",queryError.call(this,errText,d,op,value)),J.isArray(d))for(len=d.length,i=0;i0?db.slice(0,limit):db.slice(limit)),this.breed(db)},NDDB.prototype.reverse=function(){return this.db.reverse(),this},NDDB.prototype.sort=function(d){var func,that;return d?"function"==typeof d?func=d:d instanceof Array?(that=this,func=function(a,b){var i,result;for(i=0;i 0. Found: "+N),N>(len=this.db.length)&&!1!==strict&&this.throwErr("Error","random","not enough items in db. Found: "+len+". Requested: "+N),Nmax||isNaN(max))&&(max=tmp);return max},NDDB.prototype.skim=function(skim){return"string"==typeof skim||J.isArray(skim)||this.throwErr("TypeError","skim","skim must be string or array"),this.breed(this.map((function(e){var skimmed=J.skim(e,skim);if(!J.isEmpty(skimmed))return skimmed})))},NDDB.prototype.keep=function(keep){return"string"==typeof keep||J.isArray(keep)||this.throwErr("TypeError","keep","keep must be string or array"),this.breed(this.map((function(e){var subobj=J.subobj(e,keep);if(!J.isEmpty(subobj))return subobj})))},NDDB.prototype.diff=function(nddb){return J.isArray(nddb)||("object"==typeof nddb&&J.isArray(nddb.db)||this.throwErr("TypeError","diff","nddb must be array or NDDB"),nddb=nddb.db),nddb.length?this.breed(J.arrayDiff(this.fetch(),nddb)):this.breed([])},NDDB.prototype.intersect=function(nddb){return J.isArray(nddb)||("object"==typeof nddb&&J.isArray(nddb.db)||this.throwErr("TypeError","intersect","nddb must be array or NDDB"),nddb=nddb.db),nddb.length?this.breed(J.arrayIntersect(this.fetch(),nddb)):this.breed([])},NDDB.prototype.get=function(pos){return"number"!=typeof pos&&this.throwErr("TypeError","get","pos must be number"),this.db[pos]},NDDB.prototype.current=function(){return this.db[this.nddb_pointer]},NDDB.prototype.next=function(){var el;return this.nddb_pointer++,(el=NDDB.prototype.current.call(this))||this.nddb_pointer--,el},NDDB.prototype.previous=function(){var el;return this.nddb_pointer--,(el=NDDB.prototype.current.call(this))||this.nddb_pointer++,el},NDDB.prototype.first=function(doNotUpdatePointer){var db=this.fetch();if(db.length)return doNotUpdatePointer||(this.nddb_pointer=0),db[0]},NDDB.prototype.last=function(doNotUpdatePointer){var db=this.fetch();if(db.length)return doNotUpdatePointer||(this.nddb_pointer=db.length-1),db[db.length-1]},NDDB.prototype.tag=function(tag,idx){var ref,typeofIdx;return"string"!=typeof tag&&"number"!=typeof tag&&this.throwErr("TypeError","tag","tag must be string or number"),ref=null,"undefined"===(typeofIdx=typeof idx)?ref=this.db[this.db.length-1]:"number"===typeofIdx?((idx>this.length||idx<0)&&this.throwErr("Error","tag","invalid index provided: "+idx),ref=this.db[idx]):ref=idx,this.tags[tag]=ref,ref},NDDB.prototype.resolveTag=function(tag){return"string"!=typeof tag&&this.throwErr("TypeError","resolveTag","tag must be string"),this.tags[tag]},NDDB.prototype.load=function(file,opts,cb){return executeSaveLoad(this,"load",file,cb,opts)},NDDB.prototype.save=function(file,opts,cb){return executeSaveLoad(this,"save",file,cb,opts)},NDDB.prototype.loadSync=function(file,opts,cb){return executeSaveLoad(this,"loadSync",file,cb,opts)},NDDB.prototype.saveSync=function(file,opts,cb){return executeSaveLoad(this,"saveSync",file,cb,opts)},NDDB.prototype.addFormat=function(format,obj){var f,i,len;for(!function(that,format,obj){"string"==typeof format||J.isArray(format)||format.length||that.throwErr("TypeError","addFormat","format must be a non-empty string or array");"object"!=typeof obj&&that.throwErr("TypeError","addFormat","obj must be object");obj.save||obj.saveSync||that.throwErr("Error","addFormat","format must at least one save function: sync or async");obj.load||obj.loadSync||that.throwErr("Error","addFormat","format must at least one load function: sync or async");(obj.save||obj.load)&&("function"!=typeof obj.save&&that.throwErr("TypeError","addFormat","save function is not a function"),"function"!=typeof obj.load&&that.throwErr("TypeError","addFormat","load function is not a function"));(obj.saveSync||obj.loadSync)&&("function"!=typeof obj.saveSync&&that.throwErr("TypeError","addFormat","saveSync function is not a function"),"function"!=typeof obj.loadSync&&that.throwErr("TypeError","addFormat","loadSync function is not a function"))}(this,format,obj),J.isArray(format)||(format=[format]),i=-1,len=format.length;++i-1;i--){if(f=findCallback(line[i]),type=line[i].type,resOK=void 0!==f(elem),"OR"===type){if(resOK)return elem}else if("AND"===type){if(!resOK)return;if("OR"===prevType&&!prevResOK)return}prevType=type,prevResOK="AND"===type?resOK:resOK||prevResOK}return elem};switch(f1=findCallback(line[0]),f2=findCallback(line[1]),f3=findCallback(line[2]),line[1].type+"_"+line[2].type){case"OR_OR":return function(elem){return void 0!==f1(elem)||void 0!==f2(elem)||void 0!==f3(elem)?elem:void 0};case"OR_AND":return function(elem){if(void 0!==f3(elem))return void 0!==f2(elem)||void 0!==f1(elem)?elem:void 0};case"AND_OR":return function(elem){return void 0!==f3(elem)||void 0!==f2(elem)&&void 0!==f1(elem)?elem:void 0};case"AND_AND":return function(elem){if(void 0!==f3(elem)&&void 0!==f2(elem))return void 0!==f1(elem)?elem:void 0}}}}},NDDBHashtray.prototype.set=function(key,nddbid,hash){this.resolve[key+"_"+nddbid]=hash},NDDBHashtray.prototype.get=function(key,nddbid){return this.resolve[key+"_"+nddbid]},NDDBHashtray.prototype.remove=function(key,nddbid){delete this.resolve[key+"_"+nddbid]},NDDBHashtray.prototype.clear=function(){this.resolve={}},NDDBIndex.prototype._add=function(idx,dbidx){this.resolve[idx]=dbidx,void 0===this.resolveKeys[idx]&&(this.resolveKeys[idx]=this.keys.length,this.keys.push(""+idx))},NDDBIndex.prototype._remove=function(idx){delete this.resolve[idx],this.keys.splice(this.resolveKeys[idx],1),delete this.resolveKeys[idx]},NDDBIndex.prototype.size=function(){return this.keys.length},NDDBIndex.prototype.get=function(idx){return void 0!==this.resolve[idx]&&this.nddb.db[this.resolve[idx]]},NDDBIndex.prototype.remove=function(idx){var o,dbidx;return void 0!==(dbidx=this.resolve[idx])&&(void 0!==(o=this.nddb.db[dbidx])&&(!1!==this.nddb.emit("remove",o,dbidx)&&(this.nddb.db.splice(dbidx,1),this._remove(idx),this.nddb._autoUpdate(),o)))},NDDBIndex.prototype.pop=NDDBIndex.prototype.remove,NDDBIndex.prototype.update=function(idx,update){var o,dbidx,nddb;return void 0!==update&&(void 0!==(dbidx=this.resolve[idx])&&(o=(nddb=this.nddb).db[dbidx],!1!==nddb.emit("update",o,update,dbidx)&&(J.mixin(o,update),nddb.__update.indexes&&(nddb._indexIt(o,dbidx,idx),nddb._hashIt(o),nddb._viewIt(o)),nddb._autoUpdate({indexes:!1}),o)))},NDDBIndex.prototype.getAllKeys=function(){return this.keys.slice(0)},NDDBIndex.prototype.getAllKeyElements=function(){var out,idx,i,len;for(out={},i=-1,len=this.keys.length;++i1?iamdone:iamdone&&pl.isStepDone(stage,"STAGE_UPTO")},exports.stepRules.OTHERS_SYNC_STEP=function(stage,myStageLevel,pl){return!!pl.size()&&(stage=pl.first().stage,pl.arePlayersSync(stage,node.constants.stageLevels.DONE,"EXACT"))},exports.stepRules.OTHERS_SYNC_STAGE=function(stage,myStageLevel,pl,game){var nSteps;return!!pl.size()&&(stage=pl.first().stage,1!==(nSteps=game.plot.stepsToNextStage(stage))&&(stage={stage:stage.stage,step:stage.step+(nSteps-1),round:stage.round}),pl.arePlayersSync(stage,node.constants.stageLevels.DONE,"EXACT",!0))}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var J=parent.JSUS;function ErrorManager(node){this.lastError=null,this.init(node)}parent.ErrorManager=ErrorManager,ErrorManager.prototype.init=function(node){var that;that=this,J.isNodeJS()||(window.onerror=function(msg,url,lineno,colno,error){var str;return msg=node.game.getCurrentGameStage().toString()+"@"+J.getTime()+"> "+url+" "+lineno+","+colno+": "+msg,error&&JSON.stringify(error),that.lastError=msg,node.err(msg),node.debug&&(W.init({waitScreen:!0}),str="DEBUG mode: client-side error detected.

",str+=msg,str+='

Open the DevTools in your browser for details.
This message will not be shown in production mode.',W.lockScreen(str)),!node.debug})}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var J=parent.JSUS,NDDB=parent.NDDB,GameStage=parent.GameStage;function EventEmitter(name,node){if("string"!=typeof name)throw new TypeError("EventEmitter constructor: name must be string. Found: "+name);this.node=node,this.name=name,this.events={},this.recordChanges=!1,this.changes={added:[],removed:[]},this.labels={},this.history=new EventHistory(this.node)}function EventEmitterManager(node){this.node=node,this.ee={},this.createEE("ng"),this.createEE("game"),this.createEE("stage"),this.createEE("step")}function EventHistory(node){this.node=node,this.history=new NDDB,this.history.hash("stage",(function(e){var stage;if(e)return stage="object"==typeof e.stage?e.stage:this.node.game.stage,node.GameStage.toHash(stage,"S.s.r")}))}exports.EventEmitter=EventEmitter,exports.EventEmitterManager=EventEmitterManager,EventEmitter.prototype.on=function(type,listener,label){if("string"!=typeof type||""===type)throw new TypeError("EventEmitter.on: type must be a non-empty string. Found: "+type);if("function"!=typeof listener)throw new TypeError("EventEmitter.on: listener must be function.Found: "+listener);label&&function(that,listener,label,method){if("string"!=typeof label&&"number"!=typeof label)throw new TypeError("EventEmitter."+method+": label must be string or undefined. Found: "+label);if(that.labels[label])throw new Error("EventEmitter."+method+": label is not unique: "+label);that.labels[label]=!0,listener.__ngid=""+label}(this,listener,label,"on"),this.events[type]?"object"==typeof this.events[type]?this.events[type].push(listener):this.events[type]=[this.events[type],listener]:this.events[type]=listener,this.recordChanges&&this.changes.added.push({type:type,listener:listener}),this.node.silly(this.name+".on: added: "+type)},EventEmitter.prototype.once=function(type,listener,label){var that=this;label||(label=J.uniqueKey(this.labels,type)),this.on(type,(function(){var i,len,args;for(args=[],i=-1,len=arguments.length;++i0?1:result<0?-1:0):1:-1:0}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";exports.PlayerList=PlayerList;var syncTypes,J=parent.JSUS,NDDB=parent.NDDB,GameStage=parent.GameStage,stageLevels=parent.constants.stageLevels,stateLevels=parent.constants.stateLevels;function PlayerList(options,db){(options=options||{}).name=options.name||"plist",options.update||(options.update={}),void 0===options.update.indexes&&(options.update.indexes=!0),this.pcounter=0,NDDB.call(this,options),this.id||this.index("id",(function(p){return p.id})),db&&this.importDB(db),this.globalCompare=PlayerList.comparePlayers}function array2Groups(array){var i,len,settings;for(settings=this.cloneSettings(),i=-1,len=array.length;++ip2.count?-1:0},PlayerList.prototype.importDB=function(db){var i,len;if(!J.isArray(db))throw new TypeError("PlayerList.importDB: db must be array.");for(i=-1,len=db.length;++i0)return!1}if(checkOutliers&&outlier)return!1;if(void 0!==stageLevel&&p.stageLevel!==stageLevel)return!1}return!0},PlayerList.prototype.toString=function(eol){var out,EOL;return out="",EOL=eol||"\n",this.each((function(p){var stage;out+=p.id+": "+p.name,stage=new GameStage(p.stage),out+=": "+stage+EOL})),out},PlayerList.prototype.getNGroups=function(N){var groups;if("number"!=typeof N||isNaN(N)||N<1)throw new TypeError("PlayerList.getNGroups: N must be a number > 0: "+N);return groups=J.getNGroups(this.db,N),array2Groups.call(this,groups)},PlayerList.prototype.getGroupsSizeN=function(N){var groups;if("number"!=typeof N||isNaN(N)||N<1)throw new TypeError("PlayerList.getNGroups: N must be a number > 0: "+N);return groups=J.getGroupsSizeN(this.db,N),array2Groups.call(this,groups)},PlayerList.prototype.getRandom=function(N){var shuffled;if(void 0===N&&(N=1),"number"!=typeof N||isNaN(N)||N<1)throw new TypeError("PlayerList.getRandom: N must be a number > 0 or undefined: "+N+".");return shuffled=this.shuffle(),1===N?shuffled.first():shuffled.limit(N).fetch()},syncTypes={STAGE:"",STAGE_UPTO:"",EXACT:""},exports.Player=Player,Player.prototype.toString=function(){return(this.name||"")+" ("+this.id+") "+new GameStage(this.stage)}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,node){"use strict";var GameStage=node.GameStage,J=node.JSUS;function GameMsg(gm){gm=gm||{},this.id=void 0===gm.id?Math.floor(1e6*Math.random()):gm.id,this.sid=gm.sid,this.session=gm.session,this.stage=gm.stage,this.action=gm.action,this.target=gm.target,this.from=gm.from,this.to=gm.to,this.text=gm.text,this.data=gm.data,this.priority=gm.priority,this.reliable=gm.reliable,this.created=J.getDate(),this.forward=0}exports.GameMsg=GameMsg,GameMsg.clone=function(gameMsg){return new GameMsg(gameMsg)},GameMsg.prototype.stringify=function(){return JSON.stringify(this)},GameMsg.prototype.toString=function(){var SPT,line,tmp;return SPT=",\t","\t",'"','"unknown"\t',line=this.created+SPT,line+=this.id+SPT,line+=this.session+SPT,line+=this.action+SPT,line+=this.target?this.target.length<6?this.target+SPT+"\t":this.target+SPT:'"unknown"\t',line+=this.from?this.from.length<6?this.from+SPT+"\t":this.from+SPT:'"unknown"\t',line+=this.to?this.to.length<6?this.to+SPT+"\t":this.to+SPT:'"unknown"\t',null===this.text||void 0===this.text?line+='"no text",\t':"number"==typeof this.text?line+=""+this.text:(tmp=this.text.toString()).length>12?line+='"'+tmp.substr(0,9)+'..."'+SPT:tmp.length<6?line+='"'+tmp+'"'+",\t\t":line+='"'+tmp+'"'+SPT,null===this.data||void 0===this.data?line+='"no data",\t':"number"==typeof this.data?line+=""+this.data:(tmp=this.data.toString()).length>12?line+='"'+tmp.substr(0,9)+'..."'+SPT:tmp.length<9?line+='"'+tmp+'"'+",\t\t":line+='"'+tmp+'"'+SPT,line+=new GameStage(this.stage)+SPT,line+=this.reliable+SPT,line+=this.priority},GameMsg.prototype.toSMS=function(){var line="["+this.from+"]->["+this.to+"]\t";return line+="|"+this.action+"."+this.target+"|\t",line+=" "+this.text+" "},GameMsg.prototype.toInEvent=function(){return"in."+this.toEvent()},GameMsg.prototype.toOutEvent=function(){return"out."+this.toEvent()},GameMsg.prototype.toEvent=function(){return this.action+"."+this.target}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";exports.GamePlot=GamePlot;var GameStage=parent.GameStage,J=parent.JSUS;function GamePlot(node,stager){var tmpCache,handler;this.node=node,this.stager=null,this.cache={},this.tmpCache=(tmpCache={},handler=function(prop,value){if(void 0===prop)return tmpCache;if("string"==typeof prop)return 1===arguments.length?tmpCache[prop]:(tmpCache[prop]=value,value);throw new TypeError("GamePlot.tmpCache: prop must be string. Found: "+prop)},handler.clear=function(){var tmp;return tmp=tmpCache,tmpCache={},tmp},handler.hasOwnProperty=function(prop){if("string"!=typeof prop)throw new TypeError("GamePlot.tmpCache.hasProperty: prop must be string. Found: "+prop);return tmpCache.hasOwnProperty(prop)},handler),this._normalizedCache={},this.init(stager)}function cacheStepProperty(that,gameStage,property,value){that.cache[gameStage]||(that.cache[gameStage]={}),that.cache[gameStage][property]=value}GamePlot.GAMEOVER="NODEGAME_GAMEOVER",GamePlot.END_SEQ="NODEGAME_END_SEQ",GamePlot.NO_SEQ="NODEGAME_NO_SEQ",GamePlot.prototype.init=function(stager){if(stager){if("object"!=typeof stager)throw new Error("GamePlot.init: called with invalid stager.");this.stager=stager}else this.stager=null;this.cache={},this.tmpCache.clear()},GamePlot.prototype.nextStage=function(curStage,execLoops){var seqObj,stageNo,normStage;if(!this.stager)return GamePlot.NO_SEQ;if(this.isFlexibleMode())return console.log("***GamePlot.nextStage: method not available in flexible mode.***"),null;if(null===(normStage=this.normalizeGameStage(curStage)))return this.node.silly("GamePlot.nextStage: invalid stage: "+curStage),null;if(0===(stageNo=normStage.stage))return new GameStage({stage:1,step:1,round:1});if("gameover"===(seqObj=this.stager.sequence[stageNo-1]).type)return GamePlot.GAMEOVER;if(execLoops=void 0===execLoops||execLoops,this.stager.stages[seqObj.id],stageNo=this.stager.sequence.length)return GamePlot.END_SEQ;seqObj=this.stager.sequence[stageNo]}return"gameover"===this.stager.sequence[stageNo].type?GamePlot.GAMEOVER:new GameStage({stage:stageNo+1,step:1,round:1})}return GamePlot.END_SEQ},GamePlot.prototype.next=function(curStage,execLoops){var seqObj,stageObj,stageNo,stepNo,normStage,nextStage;if(!this.stager)return GamePlot.NO_SEQ;if(seqObj=null,stageObj=null,normStage=null,nextStage=null,this.isFlexibleMode()){if(0===(curStage=new GameStage(curStage)).stage)return this.stager.generalNextFunction&&(nextStage=this.stager.generalNextFunction()),nextStage?new GameStage({stage:nextStage,step:1,round:1}):GamePlot.END_SEQ;if(void 0===(stageObj=this.stager.stages[curStage.stage]))throw new Error("Gameplot.next: received non-existent stage: "+curStage.stage);if((stepNo="number"==typeof curStage.step?curStage.step:stageObj.steps.indexOf(curStage.step)+1)<1)throw new Error("GamePlot.next: received non-existent step: "+stageObj.id+"."+curStage.step);return stepNo+1<=stageObj.steps.length?new GameStage({stage:stageObj.id,step:stepNo+1,round:1}):(this.stager.nextFunctions[stageObj.id]?nextStage=this.stager.nextFunctions[stageObj.id]():this.stager.generalNextFunction&&(nextStage=this.stager.generalNextFunction()),nextStage===GamePlot.GAMEOVER?GamePlot.GAMEOVER:nextStage?new GameStage({stage:nextStage,step:1,round:1}):GamePlot.END_SEQ)}if(null===(normStage=this.normalizeGameStage(curStage)))return this.node.silly("GamePlot.next: invalid stage: "+curStage),null;if(0===(stageNo=normStage.stage))return new GameStage({stage:1,step:1,round:1});if(stepNo=normStage.step,"gameover"===(seqObj=this.stager.sequence[stageNo-1]).type)return GamePlot.GAMEOVER;if(execLoops=void 0===execLoops||execLoops,stageObj=this.stager.stages[seqObj.id],stepNo+1<=seqObj.steps.length)return new GameStage({stage:stageNo,step:stepNo+1,round:normStage.round});if("repeat"===seqObj.type&&normStage.round+1<=seqObj.num)return new GameStage({stage:stageNo,step:1,round:normStage.round+1});if("doLoop"===seqObj.type||"loop"===seqObj.type){if(!execLoops)return null;if(seqObj.cb.call(this.node.game))return new GameStage({stage:stageNo,step:1,round:normStage.round+1})}if(stageNo=this.stager.sequence.length)return GamePlot.END_SEQ;seqObj=this.stager.sequence[stageNo]}return"gameover"===this.stager.sequence[stageNo].type?GamePlot.GAMEOVER:new GameStage({stage:stageNo+1,step:1,round:1})}return GamePlot.END_SEQ},GamePlot.prototype.previous=function(curStage,execLoops){var normStage,seqObj,prevSeqObj,stageNo,stepNo,prevStepNo;if(!this.stager)return GamePlot.NO_SEQ;if(null,null,null===(normStage=this.normalizeGameStage(curStage)))return this.node.warn("GamePlot.previous: invalid stage: "+curStage),null;if(0===(stageNo=normStage.stage))return new GameStage;if(stepNo=normStage.step,seqObj=this.stager.sequence[stageNo-1],execLoops=void 0===execLoops||execLoops,stepNo>1)return new GameStage({stage:stageNo,step:stepNo-1,round:normStage.round});if(normStage.round>1)return new GameStage({stage:stageNo,step:seqObj.steps.length,round:normStage.round-1});if(1===stageNo)return new GameStage;if(prevSeqObj=this.stager.sequence[stageNo-2],!execLoops&&"loop"===seqObj.type)return null;for(;"loop"===prevSeqObj.type&&!prevSeqObj.cb.call(this.node.game);){if(--stageNo<=1)return new GameStage;prevSeqObj=this.stager.sequence[stageNo-2]}return prevStepNo=prevSeqObj.steps.length,"repeat"===prevSeqObj.type?new GameStage({stage:stageNo-1,step:prevStepNo,round:prevSeqObj.num}):new GameStage({stage:stageNo-1,step:prevStepNo,round:1})},GamePlot.prototype.jump=function(curStage,delta,execLoops){var stageType;if(execLoops=void 0===execLoops||execLoops,delta<0)for(;delta<0;){if(!((curStage=this.previous(curStage,execLoops))instanceof GameStage)||0===curStage.stage)return curStage;if(delta++,!execLoops)if("loop"===(stageType=this.stager.sequence[curStage.stage-1].type)){if(delta<0)return null}else if("doLoop"===stageType)return delta<-1?null:curStage}else for(;delta>0;){if(!((curStage=this.next(curStage,execLoops))instanceof GameStage))return curStage;if(delta--,!execLoops&&("loop"===(stageType=this.stager.sequence[curStage.stage-1].type)||"doLoop"===stageType))return delta>0?null:curStage}return curStage},GamePlot.prototype.stepsToNextStage=function(gameStage,countRepeat){var seqObj,totSteps,stepNo;if(!this.stager)return null;if(!(gameStage=this.normalizeGameStage(gameStage)))return null;if(0===gameStage.stage)return 1;if(!(seqObj=this.getSequenceObject(gameStage)))return null;if(stepNo=gameStage.step,totSteps=seqObj.steps.length,countRepeat)if("repeat"===seqObj.type)gameStage.round>1&&(stepNo=(gameStage.round-1)*totSteps+stepNo),totSteps*=seqObj.num;else if("loop"===seqObj.type||"doLoop"===seqObj.type)return null;return 1+totSteps-stepNo},GamePlot.prototype.stepsToPreviousStage=function(gameStage){return console.log("GamePlot.stepsToPreviousStage is **deprecated**. UseGamePlot.stepsFromPreviousStage instead."),this.stepsFromPreviousStage(gameStage)},GamePlot.prototype.stepsFromPreviousStage=function(gameStage,countRepeat){var seqObj,stepNo;if(!this.stager)return null;if(!(gameStage=this.normalizeGameStage(gameStage))||0===gameStage.stage)return null;if(!(seqObj=this.getSequenceObject(gameStage)))return null;if(stepNo=gameStage.step,countRepeat)if("repeat"===seqObj.type)gameStage.round>1&&(stepNo=seqObj.steps.length*(gameStage.round-1)+stepNo);else if("loop"===seqObj.type||"doLoop"===seqObj.type)return null;return stepNo},GamePlot.prototype.getSequenceObject=function(gameStage){return this.stager&&(gameStage=this.normalizeGameStage(gameStage))?this.stager.sequence[gameStage.stage-1]:null},GamePlot.prototype.getStage=function(gameStage){var stageObj;return this.stager?((gameStage=this.normalizeGameStage(gameStage))&&(stageObj=(stageObj=this.stager.sequence[gameStage.stage-1])?this.stager.stages[stageObj.id]:null),stageObj||null):null},GamePlot.prototype.getStep=function(gameStage){var seqObj,stepObj;return this.stager?((seqObj=this.getSequenceObject(gameStage))&&(stepObj=this.stager.steps[seqObj.steps[gameStage.step-1]]),stepObj||null):null},GamePlot.prototype.getStepRule=function(gameStage){var rule;return"string"==typeof(rule=this.getProperty(gameStage,"stepRule"))&&(rule=parent.stepRules[rule]),rule||this.stager.getDefaultStepRule()},GamePlot.prototype.getGlobal=function(gameStage,globalVar){var stepObj,stageObj,stepGlobals,stageGlobals,defaultGlobals;return gameStage=new GameStage(gameStage),(stepObj=this.getStep(gameStage))&&(stepGlobals=stepObj.globals)&&stepGlobals.hasOwnProperty(globalVar)?stepGlobals[globalVar]:(stageObj=this.getStage(gameStage))&&(stageGlobals=stageObj.globals)&&stageGlobals.hasOwnProperty(globalVar)?stageGlobals[globalVar]:this.stager&&(defaultGlobals=this.stager.getDefaultGlobals())&&defaultGlobals.hasOwnProperty(globalVar)?defaultGlobals[globalVar]:null},GamePlot.prototype.getGlobals=function(gameStage){var stepstage,globals;if("string"!=typeof gameStage&&"object"!=typeof gameStage)throw new TypeError("GamePlot.getGlobals: gameStage must be string or object.");return globals={},this.stager?(J.mixin(globals,this.stager.getDefaultGlobals()),(stepstage=this.getStage(gameStage))&&J.mixin(globals,stepstage.globals),(stepstage=this.getStep(gameStage))&&J.mixin(globals,stepstage.globals),globals):globals},GamePlot.prototype.getProperty=function(gameStage,prop,notFound,mask){var stepObj,stageObj,defaultProps,found,res;if("string"!=typeof prop)throw new TypeError("GamePlot.getProperty: property must be string. Found: "+prop);if(gameStage=new GameStage(gameStage),"object"!=typeof(mask=mask||{}))throw new TypeError("GamePlot.getProperty: mask must be object or undefined. Found: "+mask);return!mask.tmpCache&&this.tmpCache.hasOwnProperty(prop)&&0===GameStage.compare(gameStage,this.node.player.stage)?this.tmpCache(prop):!mask.tmpCache&&this.cache[gameStage]&&this.cache[gameStage].hasOwnProperty(prop)?this.cache[gameStage][prop]:(mask.step||(stepObj=this.getStep(gameStage))&&stepObj.hasOwnProperty(prop)&&(res=stepObj[prop],found=!0),found||mask.stage||(stageObj=this.getStage(gameStage))&&stageObj.hasOwnProperty(prop)&&(res=stageObj[prop],found=!0),found||mask.game||!this.stager||(defaultProps=this.stager.getDefaultProperties())&&defaultProps.hasOwnProperty(prop)&&(res=defaultProps[prop],found=!0),found?(cacheStepProperty(this,gameStage,prop,res),res):void 0===notFound?null:notFound)},GamePlot.prototype.updateProperty=function(gameStage,property,value){var stepObj,stageObj,defaultProps,found;if(gameStage=new GameStage(gameStage),"string"!=typeof property)throw new TypeError("GamePlot.updateProperty: property must be string. Found: "+property);return(stepObj=this.getStep(gameStage))&&stepObj.hasOwnProperty(property)&&(stepObj[property]=value,found=!0),found||(stageObj=this.getStage(gameStage))&&stageObj.hasOwnProperty(property)&&(stageObj[property]=value,found=!0),!found&&this.stager&&(defaultProps=this.stager.getDefaultProperties())&&defaultProps.hasOwnProperty(property)&&(defaultProps[property]=value,found=!0),!!found&&(cacheStepProperty(this,gameStage,property,value),!0)},GamePlot.prototype.setStepProperty=function(gameStage,property,value){var stepObj;if(gameStage=new GameStage(gameStage),"string"!=typeof property)throw new TypeError("GamePlot.setStepProperty: property must be string");return!!(stepObj=this.getStep(gameStage))&&(stepObj[property]=value,cacheStepProperty(this,gameStage,property,value),!0)},GamePlot.prototype.setStageProperty=function(gameStage,property,value){var stageObj;if(gameStage=new GameStage(gameStage),"string"!=typeof property)throw new TypeError("GamePlot.setStageProperty: property must be string");return!!(stageObj=this.getStage(gameStage))&&(stageObj[property]=value,!0)},GamePlot.prototype.isReady=function(){return this.stager&&(this.stager.sequence.length>0||null!==this.stager.generalNextFunction||!J.isEmpty(this.stager.nextFunctions))},GamePlot.prototype.normalizeGameStage=function(gameStage){var stageNo,stageObj,stepNo,seqIdx,seqObj,gs;if(this.isFlexibleMode())throw new Error("GamePlot.normalizeGameStage: invalid call in flexible sequence.");if("string"==typeof gameStage&&this._normalizedCache[gameStage])return this._normalizedCache[gameStage];if("number"==typeof(gs=new GameStage(gameStage)).stage){if(0===gs.stage)return new GameStage;stageNo=gs.stage}else{if("string"!=typeof gs.stage)throw new Error("GamePlot.normalizeGameStage: gameStage.stage must be number or string: "+typeof gs.stage);if(gs.stage===GamePlot.GAMEOVER||gs.stage===GamePlot.END_SEQ||gs.stage===GamePlot.NO_SEQ)return null;for(seqIdx=0;seqIdxthis.stager.sequence.length)return this.node.silly("GamePlot.normalizeGameStage: non-existent stage: "+gs.stage),null;if(!(seqObj=this.stager.sequence[stageNo-1]))return null;if("gameover"===seqObj.type)return new GameStage({stage:stageNo,step:1,round:gs.round});if(!(stageObj=this.stager.stages[seqObj.id]))return null;if("number"==typeof gs.step)stepNo=gs.step;else{if("string"!=typeof gs.step)throw new Error("GamePlot.normalizeGameStage: gameStage.step must be number or string: "+typeof gs.step);stepNo=seqObj.steps.indexOf(gs.step)+1}return stepNo<1||stepNo>stageObj.steps.length?(this.node.silly("normalizeGameStage non-existent step: "+stageObj.id+"."+gs.step),null):"number"!=typeof gs.round?null:(gs=new GameStage({stage:stageNo,step:stepNo,round:gs.round}),"string"==typeof gameStage&&(this._normalizedCache[gameStage]=gs),gs)},GamePlot.prototype.isFlexibleMode=function(){return 0===this.stager.sequence.length},GamePlot.prototype.getRound=function(gs,mod){var seqObj;if(0===(gs=new GameStage(gs)).stage)return null;if(!(seqObj=this.getSequenceObject(gs)))return null;if(!mod||"current"===mod)return gs.round;if("past"===mod)return gs.round-1;if("total"===mod)return"repeat"===seqObj.type?seqObj.num:"plain"===seqObj.type?1:null;if("remaining"===mod)return"repeat"===seqObj.type?seqObj.num-gs.round:"plain"===seqObj.type?1:null;throw new TypeError("GamePlot.getRound: mod must be a known string or undefined. Found: "+mod)}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";exports.GameMsgGenerator=GameMsgGenerator;var GameMsg=parent.GameMsg,GameStage=parent.GameStage,constants=parent.constants;function GameMsgGenerator(node){this.node=node}GameMsgGenerator.prototype.create=function(msg){var gameStage,priority,node;return node=this.node,gameStage=msg.stage?msg.stage:node.game?node.game.getCurrentGameStage():new GameStage("0.0.0"),priority=void 0!==msg.priority?msg.priority:msg.target===constants.target.GAMECOMMAND||msg.target===constants.target.REDIRECT||msg.target===constants.target.PCONNECT||msg.target===constants.target.PDISCONNECT||msg.target===constants.target.PRECONNECT||msg.target===constants.target.SERVERCOMMAND||msg.target===constants.target.SETUP?1:0,new GameMsg({session:void 0!==msg.session?msg.session:node.socket.session,stage:gameStage,action:msg.action||constants.action.SAY,target:msg.target||constants.target.DATA,from:node.player?node.player.id:constants.UNDEFINED_PLAYER,to:void 0!==msg.to?msg.to:"SERVER",text:void 0!==msg.text?""+msg.text:null,data:void 0!==msg.data?msg.data:{},priority:priority,reliable:msg.reliable||1})}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";exports.PushManager=PushManager;var GameStage=parent.GameStage,DONE=parent.constants.stageLevels.DONE,PUSH_STEP=parent.constants.gamecommands.push_step,GAMECOMMAND=parent.constants.target.GAMECOMMAND;function PushManager(node,options){this.node=node,this.timer=null,this.offsetWaitTime=PushManager.offsetWaitTime,this.replyWaitTime=PushManager.replyWaitTime,this.checkPushWaitTime=PushManager.checkPushWaitTime,this.init(options)}function forceDisconnect(node,p){var msg;node.warn("push-manager: disconnecting "+p.id),msg=node.msg.create({target:"SERVERCOMMAND",text:"DISCONNECT",data:{id:p.id,sid:p.sid}}),node.socket.send(msg)}function checkAndAssignWaitTime(method,options,name,that){var n;if(void 0!==(n=options[name])&&(n=options[name+="WaitTime"]),void 0!==n){if("number"!=typeof n||n<0)throw new TypeError("PushManager."+method+": options."+name+"must be a positive number. Found: "+n);return that[name]=n,n}}PushManager.offsetWaitTime=5e3,PushManager.replyWaitTime=2e3,PushManager.checkPushWaitTime=2e3,PushManager.prototype.init=function(options){!function(method,options,that){checkAndAssignWaitTime(method,options,"offset",that),checkAndAssignWaitTime(method,options,"reply",that),checkAndAssignWaitTime(method,options,"check",that)}("init",options=options||{},this)},PushManager.prototype.startTimer=function(conf){var stage,that,offset,node;if(!0===conf||void 0===conf)conf={};else if("object"!=typeof conf)throw new TypeError("PushManager.startTimer: conf must be object, TRUE, or undefined. Found: "+conf);node=this.node,this.timer?this.clearTimer():this.timer=node.timer.createTimer({name:"push_clients",validity:"game"}),offset=void 0!==conf.offset?node.timer.parseInput("offset",conf.offset):this.offsetWaitTime,stage={stage:node.player.stage.stage,step:node.player.stage.step,round:node.player.stage.round},node.info("push-manager: starting timer with offset "+offset),that=this,this.timer.init({milliseconds:offset,update:offset,timeup:function(){that.pushGame.call(that,stage,conf)}}),this.timer.start()},PushManager.prototype.clearTimer=function(){this.timer&&!this.timer.isStopped()&&(this.node.silly("push-manager: timer cleared."),this.timer.stop())},PushManager.prototype.isActive=function(){return!this.timer.isStopped()},PushManager.prototype.pushGame=function(stage,conf){var m,node,replyWaitTime,checkPushWaitTime;(node=this.node).info("push-manager: checking clients"),"object"==typeof conf&&(replyWaitTime=checkAndAssignWaitTime(m="pushGame",conf,"reply",conf),checkPushWaitTime=checkAndAssignWaitTime(m,conf,"check",conf)),void 0===replyWaitTime&&(replyWaitTime=this.replyWaitTime),void 0===checkPushWaitTime&&(checkPushWaitTime=this.checkPushWaitTime),node.game.pl.each((function(p){p.stageLevel!==DONE&&0===GameStage.compare(p.stage,stage)&&(node.warn("push-manager: push needed: "+p.id),node.get(PUSH_STEP,(function(value){!function(node,p,stage,milliseconds){node.info("push-manager: received reply from "+p.id),setTimeout((function(){var pp;node.game.pl.exist(p.id)&&(pp=node.game.pl.get(p.id),0!==GameStage.compare(pp.stage,stage)||pp.stageLevel===DONE?node.info("push-manager: push worked for "+p.id):forceDisconnect(node,pp))}),milliseconds||0)}(node,p,stage,checkPushWaitTime)}),p.id,{timeout:replyWaitTime,executeOnce:!0,target:GAMECOMMAND,timeoutCb:function(){forceDisconnect(node,p)}}))}))}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";exports.SizeManager=SizeManager;var J=parent.JSUS;function SizeManager(node){this.node=node,this.checkSize=function(){return!0},this.changeHandler=function(op,obj){return!0},this.minThresold=null,this.minCb=null,this.minRecoveryCb=null,this.maxThreshold=null,this.minCbCalled=!1,this.maxCb=null,this.maxRecoveryCb=null,this.maxCbCalled=!1,this.exactThreshold=null,this.exactCb=null,this.exactRecoveryCb=null,this.exactCbCalled=!1}SizeManager.prototype.clear=function(){this.minThreshold=null,this.minCb=null,this.minRecoveryCb=null,this.minCbCalled=!1,this.maxThreshold=null,this.maxCb=null,this.maxRecoveryCb=null,this.maxCbCalled=!1,this.exactThreshold=null,this.exactCb=null,this.exactRecoveryCb=null,this.exactCbCalled=!1,this.changeHandler=function(op,obj){return!0},this.checkSize=function(){return!0}},SizeManager.prototype.init=function(step){var node,property,doPlChangeHandler;if(this.clear(),node=this.node,step=step||node.player.stage,(property=node.game.plot.getProperty(step,"minPlayers"))&&(this.setHandler("min",property),doPlChangeHandler=!0),property=node.game.plot.getProperty(step,"maxPlayers")){if(this.setHandler("max",property),"*"===this.minThreshold)throw new Error('SizeManager.init: maxPlayers cannot be"*" if minPlayers is "*"');if(this.maxThreshold<=this.minThreshold)throw new Error("SizeManager.init: maxPlayers must be greater than minPlayers: "+this.maxThreshold+"<="+this.minThreshold);doPlChangeHandler=!0}if(property=node.game.plot.getProperty(step,"exactPlayers")){if(doPlChangeHandler)throw new Error("SizeManager.init: exactPlayers cannot be set if either minPlayers or maxPlayers is set.");this.setHandler("exact",property),doPlChangeHandler=!0}return doPlChangeHandler?(this.changeHandler=this.changeHandlerFull,this.addListeners(),this.checkSize=this.checkSizeFull):(this.checkSize=function(){return!0},this.changeHandler=function(){return!0}),doPlChangeHandler},SizeManager.prototype.checkSizeFull=function(){var nPlayers,limit;return nPlayers=this.node.game.pl.size(),this.node.player.admin||nPlayers++,!((limit=this.minThreshold)&&"*"!==limit&&nPlayerslimit)&&(!(limit=this.exacThreshold)||"*"===limit||nPlayers===limit))},SizeManager.prototype.changeHandlerFull=function(op,player){var threshold,nPlayers,game,res;return res=!0,nPlayers=(game=this.node.game).pl.size(),this.node.player.admin||nPlayers++,(threshold=this.minThreshold)&&("pdisconnect"===op?("*"===threshold||nPlayersthreshold)&&(this.maxCbCalled||(this.maxCbCalled=!0,game.getProperty("onWrongPlayerNum").call(game,"max",this.maxCb,player)),res=!1):"pdisconnect"===op&&(this.maxCbCalled&&game.getProperty("onCorrectPlayerNum").call(game,"max",this.maxRecoveryCb,player),this.maxCbCalled=!1)),(threshold=this.exactThreshold)&&(nPlayers!==threshold?(this.exactCbCalled||(this.exactCbCalled=!0,game.getProperty("onWrongPlayerNum").call(game,"exact",this.exactCb,player)),res=!1):(this.exactCbCalled&&game.getProperty("onCorrectPlayerNum").call(game,"exact",this.exactRecoveryCb,player),this.exactCbCalled=!1)),res},SizeManager.prototype.setHandler=function(type,values){values=function(name,property,node){var num,cb,recoverCb,newArray;if("number"==typeof property)newArray=!0,property=[property];else if(!J.isArray(property))throw new TypeError("SizeManager.init: "+name+"Players property must be number or non-empty array. Found: "+property);if(num=property[0],cb=property[1]||null,recoverCb=property[2]||null,"@"===num)num=node.game.pl.size()||1,newArray||((property=property.slice(0))[0]=num);else if("*"!==num&&("number"!=typeof num||!isFinite(num)||num<1))throw new TypeError("SizeManager.init: "+name+"Players must be a finite number greater than 1 or a wildcard (*,@). Found: "+num);if(cb){if("function"!=typeof cb)throw new TypeError("SizeManager.init: "+name+"Players cb must be function or undefined. Found: "+cb)}else property[1]=null;if(recoverCb){if("function"!=typeof cb)throw new TypeError("SizeManager.init: "+name+"Players recoverCb must be function or undefined. Found: "+recoverCb)}else property[2]=null;return property}(type,values,this.node),this[type+"Threshold"]=values[0],this[type+"Cb"]=values[1],this[type+"RecoveryCb"]=values[2]},SizeManager.prototype.addListeners=function(){var that;that=this,this.node.events.step.on("in.say.PCONNECT",(function(p){that.changeHandler("pconnect",p.data)}),"plManagerCon"),this.node.events.step.on("in.say.PDISCONNECT",(function(p){that.changeHandler("pdisconnect",p.data)}),"plManagerDis")},SizeManager.prototype.removeListeners=function(){this.node.events.step.off("in.say.PCONNECT","plManagerCon"),this.node.events.step.off("in.say.PDISCONNECT","plManagerDis")}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,node){var J=node.JSUS,Stager=exports.Stager={},blockTypes={BLOCK_DEFAULT:"__default",BLOCK_STAGEBLOCK:"__stageBlock_",BLOCK_STAGE:"__stage",BLOCK_STEPBLOCK:"__stepBlock_",BLOCK_STEP:"__step",BLOCK_ENCLOSING:"__enclosing_",BLOCK_ENCLOSING_STEPS:"__enclosing_steps",BLOCK_ENCLOSING_STAGES:"__enclosing_stages"};Stager.blockTypes=blockTypes,Stager.checkPositionsParameter=function(positions,method){var err;if(void 0===positions)return;"number"==typeof positions&&(isNaN(positions)||positions<0||!isFinite(positions)?err=!0:positions+="");if(err||"string"!=typeof positions||""===positions.trim())throw new TypeError("Stager."+method+": positions must be a non-empty string, a positive finite number, or undefined. Found: "+positions);return positions},Stager.addStageBlock=function(that,id,type,positions){var toClose;that.currentStage!==BLOCK_DEFAULT&&(toClose=type===BLOCK_STAGEBLOCK?1:2,that.endBlocks(toClose+that.openStepBlocks),that.openStepBlocks=0);addBlock(that,id,type,positions,BLOCK_STAGE)},Stager.addBlock=addBlock,Stager.checkFinalized=function(that,method){if(that.finalized)throw new Error("Stager."+method+": stager has been already finalized")},Stager.handleStepsArray=function(that,stageId,steps,method){var i,len;for(i=-1,len=steps.length;++i1&&isDefaultStep(this.unfinishedItems[0].item)&&(this.itemsIds[this.unfinishedItems[0].item.id]=null,this.unfinishedItems.splice(0,1)),i=-1,len=this.unfinishedItems.length;++i0;){if(this.unfinishedItems.sort(sortFunction),item=(entry=this.unfinishedItems.pop()).item,0===(positions=entry.positions).length)throw new Error("Block.finalize: no valid position for entry "+item.id+" in Block "+this.id);for(chosenPosition=positions[J.randomInt(0,positions.length)-1],this.items[chosenPosition]=item,this.takenPositions.push(chosenPosition),i=-1,len=this.unfinishedItems.length;++i 1");J.isArray(stageId)?stageId.forEach((_stageId=>{setSkipStageStep(that,_stageId,stepId,value,method)})):J.isArray(stepId)?stepId.forEach((_stepId=>{setSkipStageStep(that,stageId,_stepId,value,method)})):setSkipStageStep(that,stageId,stepId,value,method)}function setSkipStageStep(that,stageId,stepId,value,method){var allStepsSkipped,steps,i;if("string"!=typeof stageId||""===stageId.trim())throw new TypeError("Stager."+method+": stageId must be a non-empty string. Found: "+stageId);if(that.stages[stageId]||console.log("**warn: Stager."+method+': unknown stage: "'+stageId+'" (you may still add it later)'),stepId){if("string"!=typeof stepId||""===stepId.trim())throw new TypeError("Stager."+method+": stepId must be a non-empty string or undefined.Found: "+stepId);return that.steps[stepId]||console.log("**warn: Stager."+method+': unknown step: "'+stepId+'" (you may still add it later)'),void 0!==value&&(that.toSkip.steps[stageId+"."+stepId]=value),that.toSkip.stages[stageId]||that.toSkip.steps[stageId+"."+stepId]}if(void 0!==value&&(that.toSkip.stages[stageId]=value),that.toSkip.stages[stageId])return!0;for(allStepsSkipped=!0,steps=that.stages[stageId].steps,i=0;i1&&isDefaultStep(that.steps[steps[i]])||that.toSkip.steps[stageId+"."+steps[i]])){allStepsSkipped=!1;break}return allStepsSkipped}function validateExtendedStep(stepId,update,updateFunction){var errBegin;if(updateFunction){if(errBegin="Stager.extendStep: update function must return an object with ",!update||"object"!=typeof update)throw new TypeError(errBegin+"id and cb. Found: "+update+". Step id: "+stepId);if(update.id!==stepId)throw new Error("Stager.extendStep: update function cannot alter the step id: "+stepId);if("function"!=typeof update.cb)throw new TypeError(errBegin+"a valid callback. Step id:"+stepId);if(update.init&&"function"!=typeof update.init)throw new TypeError(errBegin+"invalid init property. Function or undefined expected, found: "+typeof update.init+". Step id:"+stepId);if(update.exit&&"function"!=typeof update.exit)throw new TypeError(errBegin+"invalid exit property. Function or undefined expected, found: "+typeof update.exit+". Step id:"+stepId);if(update.done&&"function"!=typeof update.done)throw new TypeError(errBegin+"invalid done property. Function or undefined expected, found: "+typeof update.done+". Step id:"+stepId)}else{if(update.hasOwnProperty("id"))throw new Error("Stager.extendStep: update.id cannot be set. Step id: "+stepId);if(update.cb&&"function"!=typeof update.cb)throw new TypeError("Stager.extendStep: update.cb must be function or undefined. Step id:"+stepId);if(update.init&&"function"!=typeof update.init)throw new TypeError("Stager.extendStep: update.init must be function or undefined. Step id:"+stepId);if(update.exit&&"function"!=typeof update.exit)throw new TypeError("Stager.extendStep: update.exit must be function or undefined. Step id:"+stepId);if(update.done&&"function"!=typeof update.done)throw new TypeError("Stager.extendStep: update.done must be function or undefined. Step id:"+stepId)}}function validateExtendedStage(that,stageId,update,updateFunction){var block,i,len;if(updateFunction&&update.id!==stageId||!updateFunction&&update.hasOwnProperty("id"))throw new Error("Stager.extendStage: id cannot be altered: "+stageId);if(update.cb)throw new TypeError("Stager.extendStage: update.cb cannot be specified. Stage id: "+stageId);if(update.init&&"function"!=typeof update.init)throw new TypeError("Stager.extendStage: update.init must be function or undefined. Stage id:"+stageId);if(update.exit&&"function"!=typeof update.exit)throw new TypeError("Stager.extendStage: update.exit must be function or undefined. Stage id:"+stageId);if(update.done&&"function"!=typeof update.done)throw new TypeError("Stager.extendStage: update.done must be function or undefined. Stage id:"+stageId);if(update.steps){if(!J.isArray(update.steps))throw new Error("Stager.extendStage: update.steps must be array or undefined. Stage id: "+stageId+"Found: "+update.steps);if(!update.steps.length)throw new Error("Stager.extendStage: update.steps is an empty array. Stage id: "+stageId);if(J.equals(that.stages[stageId].steps,update.steps))return;if(handleStepsArray(that,stageId,update.steps,"extendStage"),!(block=that.findBlockWithItem(stageId)))return;for((block=void 0!==block.unfinishedItems[1]?block.unfinishedItems[1].item:that.blocks[that.blocks.length-1]).removeAllItems(),i=-1,len=update.steps.length;++i{this.steps[stepId]?this.extendStep(stepId,update):console.log('**warn: Stager.extendSteps: step with id " '+stepId+'" not found')}))},Stager.prototype.extendAllStages=function(update){var stage;for(stage in this.stages)this.stages.hasOwnProperty(stage)&&this.extendStage(stage,update)},Stager.prototype.extendStages=function(stageIds,update){if(!J.isArray(stageIds))throw new TypeError("Stager.extendSteps: stageIds must be array. Found: "+stageIds);stageIds.forEach((stageId=>{this.stages[stageId]?this.extendStage(stageId,update):console.log('**warn: Stager.extendStages: stage with id " '+stageId+'" not found')}))},Stager.prototype.skip=function(stageId,stepId){checkFinalized(this,"skip"),setSkipStageStepArray(this,stageId,stepId,!0,"skip")},Stager.prototype.unskip=function(stageId,stepId){checkFinalized(this,"unskip"),setSkipStageStepArray(this,stageId,stepId,!1,"unskip")},Stager.prototype.isSkipped=function(stageId,stepId){return!!setSkipStageStep(this,stageId,stepId,void 0,"isSkipped")}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,node){var Stager=node.Stager,checkPositionsParameter=Stager.checkPositionsParameter,addStageBlock=Stager.addStageBlock,addBlock=Stager.addBlock,blockTypes=Stager.blockTypes,BLOCK_DEFAULT=blockTypes.BLOCK_DEFAULT,BLOCK_STAGEBLOCK=blockTypes.BLOCK_STAGEBLOCK,BLOCK_STEPBLOCK=blockTypes.BLOCK_STEPBLOCK,BLOCK_STEP=blockTypes.BLOCK_STEP,BLOCK_ENCLOSING=blockTypes.BLOCK_ENCLOSING,BLOCK_ENCLOSING_STEPS=blockTypes.BLOCK_ENCLOSING_STEPS;Stager.prototype.stepBlock=function(id,positions){var curBlock,err;if(1===arguments.length)console.log("***deprecation warning: Stager.stepBlock will require two parameters in the next version.***"),positions=id;else{if("string"!=typeof id||""===id.trim())throw new TypeError("Stager.stepBlock: id must be a non-empty string. Found: "+id);if(this.blocksIds[id])throw new Error("Stager.stepBlock: non-unique id: "+id)}if(!(curBlock=this.getCurrentBlock())||curBlock.id===BLOCK_DEFAULT||!curBlock.isType(BLOCK_ENCLOSING_STEPS)&&!curBlock.isType(BLOCK_STEPBLOCK))throw err="Stager.stepBlock: block ",id&&(err+='"'+id+'"'),err+="cannot be added here. Did add at least one stage before?",new Error(err);if(curBlock.isType(BLOCK_STEPBLOCK)&&0===curBlock.size())throw err="Stager.stepBlock: block ",id&&(err+='"'+id+'"'),err+="cannot be added here. Did add at least one step in the previous step block?",new Error(err);return checkPositionsParameter(positions,"stepBlock"),addBlock(this,id,BLOCK_STEPBLOCK,positions,BLOCK_STEP),this.openStepBlocks++,this},Stager.prototype.stageBlock=function(id,positions){var curBlock,err;if(1===arguments.length)console.log("***deprecation warning: Stager.stageBlock will require two parameters in the next version.***"),positions=id;else{if("string"!=typeof id||""===id.trim())throw new TypeError("Stager.stageBlock: id must be a non-empty string. Found: "+id);if(this.blocksIds[id])throw new Error("Stager.stageBlock: non-unique id: "+id)}if((curBlock=this.getCurrentBlock())&&curBlock.id!==BLOCK_DEFAULT&&curBlock.isType(BLOCK_STAGEBLOCK))throw err="Stager.stageBlock: block ",id&&(err+='"'+id+'"'),err+="cannot be added here. Did add at least one stage in the previous stage block?",new Error(err);return checkPositionsParameter(positions,"stageBlock"),addStageBlock(this,id,BLOCK_STAGEBLOCK,positions),this},Stager.prototype.getCurrentBlock=function(){return 0!==this.unfinishedBlocks.length&&this.unfinishedBlocks[this.unfinishedBlocks.length-1]},Stager.prototype.endBlock=function(options){var block,currentBlock,found,i;if(!this.unfinishedBlocks.length)return this;if(options=options||{},(block=this.unfinishedBlocks.pop()).isType(BLOCK_STEPBLOCK)){i=this.blocks.length-1;do{found=-1!==(currentBlock=this.blocks[i]).id.indexOf(BLOCK_ENCLOSING),i--}while(!found&&i>=0);if(!found)throw new Error("Stager.endBlock: could not find enclosing block for stepBlock "+block.name);currentBlock.add(block,block.positions)}else block.isType(BLOCK_STAGEBLOCK)?block.id!==BLOCK_DEFAULT&&-1===block.id.indexOf(BLOCK_ENCLOSING)&&this.blocks[0].add(block,block.positions):(currentBlock=this.getCurrentBlock())&¤tBlock.add(block,block.positions);return options.finalize&&block.finalize(),this},Stager.prototype.endBlocks=function(n,options){var i;for(i=0;i0||this.node.game.isReady()?this.node.emit(msg.toInEvent(),msg):(this.node.silly("B: "+msg),this.buffer.push(msg)))},Socket.prototype.onMessage=Socket.prototype.onMessageHI,Socket.prototype.setMsgListener=function(msgHandler){if(msgHandler&&"function"!=typeof msgHandler)throw new TypeError("Socket.setMsgListener: msgHandler must be a function or undefined. Found: "+msgHandler);this.onMessage=msgHandler||this.onMessageFull},Socket.prototype.shouldClearBuffer=function(){return this.node.game.isReady()},Socket.prototype.clearBuffer=function(msgHandler){var nelem,msg,i,funcCtx,func;for(msgHandler?(funcCtx=this.node.game,func=msgHandler):(funcCtx=this.node.events,func=this.node.events.emit),nelem=this.buffer.length,i=0;i 2 or undefined. Found: "+min);if(min=min||2,max&&"number"!=typeof max||maxmax)throw err="Roler.setRoles: roles must contain at least "+min+" roles",max&&(err+=" and no more than "+max),err+=". Found: "+len,new Error(err);for(rolesObj={},i=-1;++i0&&!rowFound)return!1;for(;++j1)ps=J.seq(0,n-1);else{if(!(J.isArray(n)&&n.length>1))throw new TypeError("pairMatcher."+alg+": n must be number > 1 or array of length > 1.");ps=n.slice(),n=ps.length}if(bye=void 0!==(options=options||{}).bye?options.bye:-1,skipBye=options.skipBye||!1,n%2==1&&(ps.push(bye),n+=1),options.fixedRoles&&!1===options.canMatchSameRole&&(fixedRolesNoSameMatch=!0),"number"==typeof options.rounds){if(options.rounds<=0)throw new Error("pairMatcher."+alg+": options.rounds must be a positive number or undefined. Found: "+options.rounds);if(options.rounds>n-1)throw new Error("pairMatcher."+alg+": options.rounds cannot be greater than "+(n-1)+". Found: "+options.rounds);roundsLimit=options.rounds}else roundsLimit=fixedRolesNoSameMatch?Math.floor(n/2):n-1;if(void 0!==options.cycle){if("mirror_invert"!==(cycle=options.cycle)&&"mirror"!==cycle&&"repeat_invert"!==cycle&&"repeat"!==cycle)throw new Error("pairMatcher."+alg+': options.cycle must be equal to "mirror"/"mirror_invert", "repeat"/"repeat_invert" or undefined . Found: '+options.cycle);matches=new Array(2*roundsLimit)}else matches=new Array(roundsLimit);for(i=-1,lenI=roundsLimit;++inRows)return!!mod&&(this.x=x,this.y=0,null);if(void 0===y)return!mod||(this.x=x,this.y=this.resolvedMatches[nRows].length,fetchMatch[mod].call(this,x,y,id));if("number"!=typeof y)throw new TypeError("Matcher."+m+": y must be number or undefined.");if(y<0||isNaN(y))throw new Error("Matcher."+m+": y cannot be negative or NaN. Found: "+y);return y<=this.resolvedMatches[x].length-1?!mod||(this.x=x,this.y=y,fetchMatch[mod].call(this,x,y)):!!mod&&(this.x=x,this.y=y,null)}exports.Matcher=Matcher,Matcher.bye=-1,Matcher.missingId="bot",Matcher.randomAssigner=function(ids){return J.shuffle(ids)},Matcher.linearAssigner=function(ids){return J.clone(ids)},Matcher.prototype.init=function(options){if((options=options||{}).assignerCb&&this.setAssignerCb(options.assignerCb),options.ids&&this.setIds(options.ids),options.bye&&(this.bye=options.bye),options.missingId&&(this.missingId=options.missingId),null===options.x)this.x=null;else if("number"==typeof options.x){if(options.x<0)throw new Error("Matcher.init: options.x cannot be negative.Found: "+options.x);this.x=options.x}else if(options.x)throw new TypeError("Matcher.init: options.x must be number, null or undefined. Found: "+options.x);if(null===options.y)this.y=null;else if("number"==typeof options.y){if(options.y<0)throw new Error("Matcher.init: options.y cannot be negative.Found: "+options.y);this.y=options.y}else if(options.y)throw new TypeError("Matcher.init: options.y must be number, null or undefined. Found: "+options.y);options.doRoles||options.roles?(this.roler||(this.roler=new Roler),this.roler.init({missingId:this.missingId,roles:options.roles}),this.doRoles=!0):void 0!==options.doRoles&&(this.doRoles=!!options.doRoles),void 0!==options.doObjLists&&(this.doObjLists=!!options.doObjLists),void 0!==options.doIdLists&&(this.doIdLists=!!options.doIdLists)},Matcher.prototype.generateMatches=function(alg){var matches;if("string"!=typeof alg)throw new TypeError("Matcher.generateMatches: alg must be string. Found: "+alg);if("roundrobin"!==(alg=alg.toLowerCase())&&"round_robin"!==alg&&"random"!==alg&&"random_pairs"!==alg)throw new Error("Matcher.generateMatches: unknown algorithm: "+alg);return matches=pairMatcher(alg,arguments[1],arguments[2]),this.setMatches(matches),matches},Matcher.prototype.setMatches=function(matches){if(!J.isArray(matches)||!matches.length)throw new TypeError("Matcher.setMatches: matches must be a non-empty array. Found: "+matches);this.matches=matches,resetResolvedData(this)},Matcher.prototype.getMatches=function(){return this.matches},Matcher.prototype.setIds=function(ids){var i,len;if(!J.isArray(ids)||!ids.length)throw new TypeError("Matcher.setIds: ids must be a non-empty array. Found: "+ids);for(this.idsMap={},i=-1,len=ids.length;++i=0&&!isNaN(x))return x>out.length-1?null:out[x];throw new TypeError("Matcher.getMatchFor: x must be a positive number or undefined. Found: "+x)},Matcher.prototype.getMatchObject=function(x,y){if(!this.resolvedMatchesObj)throw new Error("Matcher.getMatchObject: no obj matches found.");return hasOrGetNext.call(this,"getMatchObject",3,x,y)},Matcher.prototype.normalizeRound=function(round){if(!this.matches)throw new TypeError("Matcher.normalizeRound: no matches found.");if("number"!=typeof round||isNaN(round)||round<1)throw new TypeError("Matcher.normalizeRound: round must be a number > 0. Found: "+round);return(round-1)%this.matches.length},Matcher.prototype.replaceId=function(oldId,newId){var m,i,len,j,lenJ,h,lenH,rowFound;if("string"!=typeof oldId)throw new TypeError("Matcher.replaceId: oldId should be string. Found: "+oldId);if("string"!=typeof newId||""===newId.trim())throw new TypeError("Matcher.replaceId: newId should be a non-empty string. Found: "+newId);if(!this.resolvedMatches)return!1;if(void 0===(m=this.idsMap[oldId]))return!1;for(this.idsMap[newId]=!0,delete this.idsMap[oldId],i=-1,len=(m=this.ids).length;++in-1&&(nRounds=n-1),"random"===settings.match?(doRoles&&(this.roler.clear(),this.roler.setRoles(settings.roles,2),this.matcher.init({doRoles:doRoles})),this.matcher.generateMatches("random",n,{rounds:nRounds,skipBye:settings.skipBye,bye:settings.bye,fixedRoles:settings.fixedRoles,canMatchSameRole:settings.canMatchSameRole}),this.matcher.setIds(game.pl.id.getAllKeys()),this.matcher.match(!0)):!this.matcher.matches||settings.reInit?(doRoles&&(this.roler.clear(),this.roler.setRoles(settings.roles,2),this.matcher.init({doRoles:doRoles})),this.matcher.generateMatches("roundrobin",n,{rounds:nRounds,cycle:settings.cycle,skipBye:settings.skipBye,bye:settings.bye,fixedRoles:settings.fixedRoles,canMatchSameRole:settings.canMatchSameRole}),settings.assignerCb&&this.matcher.setAssignerCb(settings.assignerCb),this.matcher.setIds(game.pl.id.getAllKeys()),this.matcher.match(!0)):this.matcher.hasNext()||this.matcher.init({x:null,y:null}),nMatchesIdx="number"==typeof this.matcher.x?this.matcher.x+1:0,len=(roundMatches=this.matcher.getMatch(nMatchesIdx)).length,matches=n%2==0?new Array(2*len):settings.skipBye?new Array(2*len-2):new Array(2*len-1),missId=this.matcher.missingId,matchedRoles=this.roler.getRolifiedMatches(),ii=i=-1;++i=stateLevels.FINISHING?node.warn("Game.gameover called on a finishing game."):(node.emit("GAME_ALMOST_OVER"),(onGameover=this.plot.stager.getOnGameover())&&(this.setStateLevel(stateLevels.FINISHING),onGameover.call(node.game)),this.setStateLevel(stateLevels.GAMEOVER),this.setStageLevel(stageLevels.DONE),node.log("game over."),node.emit("GAME_OVER"))},Game.prototype.isPaused=function(){return this.paused},Game.prototype.pause=function(param){var msgHandler,node;if(!this.isPausable())throw new Error("Game.pause: game cannot be paused.");(node=this.node).emit("PAUSING",param),this.paused=!0,this.pauseCounter++,(msgHandler=this.plot.getProperty(this.getCurrentGameStage(),"pauseMsgHandler"))&&node.socket.setMsgListener((function(msg){msg=node.socket.secureParse(msg),msgHandler.call(node.game,msg.toInEvent(),msg)})),node.timer.setTimestamp("paused"),node.emit("PAUSED",param),node.log("game paused.")},Game.prototype.resume=function(param){var msgHandler,node;if(!this.isResumable())throw new Error("Game.resume: game cannot be resumed.");(node=this.node).emit("RESUMING",param),this.paused=!1,msgHandler=this.plot.getProperty(this.getCurrentGameStage(),"resumeMsgHandler"),node.socket.clearBuffer(msgHandler),node.socket.setMsgListener(),node.timer.setTimestamp("resumed"),node.emit("RESUMED",param),this.shouldEmitPlaying()&&this.node.emit("PLAYING"),node.log("game resumed.")},Game.prototype.shouldStep=function(stageLevel){var stepRule,curStep;if(!this.sizeManager.checkSize()||!this.isSteppable())return!1;if(curStep=this.getCurrentGameStage(),"function"!=typeof(stepRule=this.plot.getStepRule(curStep)))throw new TypeError("Game.shouldStep: stepRule must be function. Found: "+stepRule);return stepRule(curStep,stageLevel=stageLevel||this.getStageLevel(),this.pl,this)},Game.prototype.breakStage=function(doBreak){var b;return b=this._breakStage,void 0!==doBreak&&(this._breakStage=!!doBreak),b},Game.prototype.stepBack=function(options){var prevStep;return!!(prevStep=this.getPreviousStep(1,options))&&(this._steppedSteps.splice(this._steppedSteps.length-2,2),this.gotoStep(prevStep,options))},Game.prototype.step=function(options){var curStep,nextStep;return curStep=this.getCurrentGameStage(),nextStep=this.breakStage(!1)?this.plot.nextStage(curStep):this.plot.next(curStep),this.gotoStep(nextStep,options)},Game.prototype.gotoStep=function(nextStep,options){var node,tmp,curStep,curStageObj,nextStageObj,stageInit,stepInitCb,matcherOptions,matches,role,partner,i,len,pid,remoteOptions,curStepExitCb;if(!this.isSteppable())throw new Error("Game.gotoStep: game cannot be stepped");if("string"!=typeof nextStep&&"object"!=typeof nextStep)throw new TypeError("Game.gotoStep: nextStep must be a object or a string. Found: "+nextStep);if(options&&"object"!=typeof options)throw new TypeError("Game.gotoStep: options must be object or undefined. Found: "+options);if((node=this.node).silly("Next step ---\x3e "+nextStep),this.timer.reset(),this.pushManager.clearTimer(),curStep=this.getCurrentGameStage(),curStageObj=this.plot.getStage(curStep),curStepExitCb=this.plot.getProperty(curStep,"exit",null,{stage:!0}),this.plot.tmpCache.clear(),node.socket.journalOn&&(node.socket.journalOn=!1,node.socket.journal.clear()),this.plot.getProperty(nextStep,"syncStepping"))if((matcherOptions=this.plot.getProperty(nextStep,"matcher"))&&"object"==typeof matcherOptions)for(i=-1,len=(matches=this.matcher.match(matcherOptions)).length;++istateLevels.INITIALIZING},Game.prototype.isPausable=function(){return!this.paused&&this.getStateLevel()>stateLevels.INITIALIZING},Game.prototype.isResumable=function(){return this.paused&&this.getStateLevel()>stateLevels.INITIALIZING},Game.prototype.isSteppable=function(){var stateLevel;return(stateLevel=this.getStateLevel())>stateLevels.INITIALIZING&&stateLevel0?prevStep=this._steppedSteps[len]:("boolean"==typeof opts&&(execLoops=opts),prevStep=this.plot.jump(this.getCurrentGameStage(),-delta,execLoops)),"object"==typeof opts){if(curStep=node.game.getCurrentGameStage(),!1===opts.acrossStages&&curStep.stage!==prevStep.stage)return null;if(!1===opts.acrossRounds&&curStep.round!==prevStep.round)return null;if(opts.noZeroStep&&0===prevStep.stage)return null}return prevStep},Game.prototype.getNextStep=function(delta){if("number"!=typeof(delta=delta||1)||delta<1)throw new TypeError("Game.getNextStep: delta must be a positive number or undefined: ",delta);return this.plot.jump(this.getCurrentGameStage(),delta,!1)},Game.prototype.updateGlobals=function(stage){var newGlobals,g;if(stage=stage||this.getCurrentGameStage(),newGlobals=this.plot.getGlobals(stage),"undefined"!=typeof window&&this.node.window){for(g in newGlobals)newGlobals.hasOwnProperty(g)&&("node"===g||"W"===g?node.warn("Game.updateGlobals: invalid name: "+g):window[g]=newGlobals[g]);for(g in this.globals)this.globals.hasOwnProperty(g)&&!newGlobals.hasOwnProperty(g)&&("node"===g&&"W"===g||delete window[g])}return this.globals=newGlobals,this.globals},Game.prototype.getProperty=function(prop,nf){return this.plot.getProperty(this.getCurrentGameStage(),prop,nf)},Game.prototype.getStageId=function(stage){return(stage=this.plot.getStage(stage||this.getCurrentGameStage()))?stage.id:null},Game.prototype.getStepId=function(stage){return(stage=this.plot.getStep(stage||this.getCurrentGameStage()))?stage.id:null},Game.prototype.getRound=function(mod){return this.plot.getRound(this.getCurrentGameStage(),mod)},Game.prototype.isStage=function(stage,compareStage){var s;if(compareStage){if("object"!=typeof compareStage)throw new TypeError("Game.isStage: compareStage must be object or undefined. Found: "+compareStage);s=compareStage.stage}else s=this.getCurrentGameStage().stage;return"number"==typeof stage?stage===s:!(!(stage=this.plot.normalizeGameStage(stage))||stage.stage!==s)},Game.prototype.isStep=function(step,compareStage){var s;if(compareStage){if("object"!=typeof compareStage)throw new TypeError("Game.isStep: compareStage must be object or undefined. Found: "+compareStage);s=compareStage.step}else s=this.getCurrentGameStage().step;return"number"==typeof step?step===s:(-1===step.lastIndexOf(".")&&(step=this.getStageId(compareStage)+"."+step),!(!(step=this.plot.normalizeGameStage(step))||step.step!==s))},Game.prototype.isRound=function(round){var r;return r=this.getRound(),"number"==typeof round?round===r:!(!(round=this.plot.normalizeGameStage(round))||round.round!==r)},Game.prototype.isWidgetStep=function(){return this.widgetStep},Game.prototype.setRole=function(role,force){var roles,roleObj,prop;if("string"==typeof role&&""!==role.trim()){if(this.role&&!force)throw new Error('Game.setRole: attempt to change role "'+this.role+'" to "'+role+'" in step: '+this.getCurrentGameStage());if(!(roles=this.getProperty("roles")))throw new Error('Game.setRole: trying to set role "'+role+"\", but 'roles' not found in current step: "+this.getCurrentGameStage());if(!(roleObj=roles[role]))throw new Error('Game.setRole: role "'+role+'" not found in current step: '+this.getCurrentGameStage());for(prop in roleObj)roleObj.hasOwnProperty(prop)&&this.plot.tmpCache(prop,roleObj[prop])}else if(null!==role)throw new TypeError("Game.setRole: role must be string or null. Found: "+role);this.role=role,this.node.player.role=role},Game.prototype.getRole=function(){return this.role},Game.prototype.setPartner=function(partner,force){if("string"==typeof partner&&""!==partner.trim()){if(this.partner&&!force)throw new Error('Game.setPartner: attempt to change partner "'+this.partner+'" to "'+partner+'" in step: '+this.getCurrentGameStage())}else if(null!==partner)throw new TypeError("Game.setPartner: partner must be a non-empty string or null. Found: "+partner);this.partner=partner,this.node.player.partner=partner},Game.prototype.getPartner=function(){return this.partner}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var J=("undefined"!=typeof node?node:module.parent.exports).JSUS;function Timer(node,settings){var that;this.node=node,this.settings=settings||{},this.timers={},this._stepTimers=[],this._stageTimers=[],this.timestamps={},this._pausedTimestamps={},this._cumulPausedTimestamps={},this._effectiveDiffs={},that=this,this.node.on("PAUSED",(function(){var i,ts;for(i in ts=that.getTimestamp("paused"),that.timestamps)that.timestamps.hasOwnProperty(i)&&(that._pausedTimestamps[i]=ts)})),this.node.on("RESUMED",(function(){var i,time,pt,cpt,pausedTime;for(i in pt=that._pausedTimestamps,cpt=that._cumulPausedTimestamps,time=J.now(),pt)pt[i]&&pt.hasOwnProperty(i)&&(pausedTime=time-pt[i],cpt[i]?cpt[i]+=pausedTime:cpt[i]=pausedTime);that._pausedTimestamps={}})),function(that){var _minWait,_maxWait,_prob,args,i,len;function randomFire(method,hook,emit,ctx,args){var that,waitTime,callback,timerObj,tentativeName;if(that=this,void 0===_maxWait)_maxWait=5e3;else if("number"!=typeof _maxWait)throw resetWaits(),new TypeError("Timer."+method+": maxWait must be number or undefined. Found: "+_maxWait);if(void 0===_minWait)_minWait=_maxWait<1e3?0:1e3;else if("number"!=typeof _minWait)throw resetWaits(),new TypeError("Timer."+method+": minWait must be number or undefined. Found: "+_minWait);waitTime=J.randomInt(_minWait,_maxWait),callback=emit?function(){that.destroyTimer(timerObj),args?that.node.emit.apply(that.node.events,[hook].concat(args)):that.node.emit(hook)}:function(){that.destroyTimer(timerObj),hook.apply(ctx,args)},tentativeName=method+"_"+hook+"_"+J.randomInt(0,1e6),timerObj=this.createTimer({milliseconds:waitTime,timeup:callback,name:J.uniqueKey(this.timers,tentativeName)}),this.node.game&&this.node.game.isReady()?timerObj.start():this.node.once("PLAYING",(function(){timerObj.start()})),resetWaits()}function resetWaits(){_maxWait=5e3,_minWait=1e3}function done(param){evaluateProb()&&randomFire.call(that,"done",node.done,!1,node,[param])}function emit(event){if("string"!=typeof event)throw new TypeError("Timer.emit: event must be string. Found: "+event);if(evaluateProb()){if(2===(len=arguments.length))args=[arguments[1]];else if(3===len)args=[arguments[2],arguments[1]];else if(len>3)for(i=-1,len-=1,args=new Array(len);++i4)for(i=-1,len-=2,args=new Array(len);++i0;i--)that.fire(that.hooks[i-1]);return!(that.timeLeft<=0)||(that.doTimeup(),!1)}function checkInitialized(that){return"number"!=typeof that.milliseconds?"this.milliseconds must be a number":that.update>that.milliseconds?"this.update must not be greater than this.milliseconds":null}function checkDestroyed(that,method){if(that.status===GameTimer.DESTROYED)throw new Error("GameTimer."+method+": gameTimer marked as destroyed: "+that.name)}exports.Timer=Timer,Timer.prototype.setTimeout=function(timeup,milliseconds,validity){return this.createTimer({milliseconds:milliseconds||1,timeup:timeup,validity:validity}).start()},Timer.prototype.create=Timer.prototype.createTimer=function(options){var gameTimer,pausedCb,resumedCb,ee,val;if(options&&"object"!=typeof options&&"number"!=typeof options)throw new TypeError("Timer.createTimer: options must be undefined, object or number. Found: "+options);if("number"==typeof options&&(options={milliseconds:options}),(options=options||{}).name=options.name||J.uniqueKey(this.timers,"timer_"+J.randomInt(0,1e7)),this.timers[options.name])throw new Error("Timer.createTimer: timer name already in use: "+options.name);if(val=options.validity){if(!(ee=this.node.events.ee[val]))throw new Error('Timer.createTimer: validity must be "ng", "game", "stage", "step". Found: '+val)}else ee=this.node.getCurrentEventEmitter();return options.eventEmitterName=ee.name,this.node.game&&this.node.game.paused&&void 0===options.startPaused&&(options.startPaused=!0),gameTimer=new GameTimer(this.node,options),pausedCb=function(){gameTimer.isPaused()||gameTimer.pause()},resumedCb=function(){(gameTimer.isPaused()||gameTimer.startPaused)&&gameTimer.resume()},ee.on("PAUSED",pausedCb),ee.on("RESUMED",resumedCb),gameTimer.timerPausedCallback=pausedCb,gameTimer.timerResumedCallback=resumedCb,this.timers[gameTimer.name]=gameTimer,"step"===ee.name?this._stepTimers.push(gameTimer):"stage"===ee.name&&this._stageTimers.push(gameTimer),gameTimer},Timer.prototype.destroyTimer=function(gameTimer){var eeName;if("string"==typeof gameTimer){if(!this.timers[gameTimer])throw new Error("node.timer.destroyTimer: gameTimer not found: "+gameTimer);gameTimer=this.timers[gameTimer]}if("object"!=typeof gameTimer)throw new Error("node.timer.destroyTimer: gameTimer must be string or object. Found: "+gameTimer);gameTimer.isStopped()||gameTimer.stop(),(eeName=gameTimer.eventEmitterName)?(this.node.events.ee[eeName].remove("PAUSED",gameTimer.timerPausedCallback),this.node.events.ee[eeName].remove("RESUMED",gameTimer.timerResumedCallback)):(this.node.off("PAUSED",gameTimer.timerPausedCallback),this.node.off("RESUMED",gameTimer.timerResumedCallback)),gameTimer.syncWithStager(!1),gameTimer.status=GameTimer.DESTROYED,delete this.timers[gameTimer.name]},Timer.prototype.destroyStepTimers=function(){destroyTempTimers(this,"_stepTimers")},Timer.prototype.destroyStageTimers=function(){destroyTempTimers(this,"_stageTimers")},Timer.prototype.destroyAllTimers=function(all){var i;for(i in this.timers)if(this.timers.hasOwnProperty(i)){if(!all&&i===this.node.game.timer.name)continue;this.destroyTimer(this.timers[i])}this._stepTimers=[],this._stageTimers=[]},Timer.prototype.getTimer=function(name){if("string"!=typeof name)throw new TypeError("Timer.getTimer: name must be string. Found: "+name);return this.timers[name]||null},Timer.prototype.setTimestamp=function(name,time){var i;if(void 0===time&&(time=J.now()),"string"!=typeof name)throw new Error("Timer.setTimestamp: name must be a string. Found: "+name);if("number"!=typeof time)throw new Error("Timer.setTimestamp: time must be a number or undefined. Found: "+time);if(this.node.game.pauseCounter)for(i in this._pausedTimestamps[name]&&(this._pausedTimestamps[name]=null),this._cumulPausedTimestamps[name]&&(this._cumulPausedTimestamps[name]=null),this.node.game.isPaused()&&(this._pausedTimestamps[name]=time),this._effectiveDiffs[name]={},this.timestamps)this.timestamps.hasOwnProperty(i)&&(this._effectiveDiffs[name][i]=this.getTimeSince(i,!0));return this.timestamps[name]=time,time},Timer.prototype.getTimestamp=function(name){if("string"!=typeof name)throw new Error("Timer.getTimestamp: name must be a string. Found: "+name);return this.timestamps.hasOwnProperty(name)?this.timestamps[name]:null},Timer.prototype.getAllTimestamps=function(){return this.timestamps},Timer.prototype.getTimeSince=function(name,effective){var currentTime;if(currentTime=J.now(),"string"!=typeof name)throw new TypeError("Timer.getTimeSince: name must be string. Found: "+name);return this.timestamps.hasOwnProperty(name)?(effective&&(this._pausedTimestamps[name]&&(currentTime-=currentTime-this._pausedTimestamps[name]),this._cumulPausedTimestamps[name]&&(currentTime-=this._cumulPausedTimestamps[name])),currentTime-this.timestamps[name]):null},Timer.prototype.getTimeDiff=function(nameFrom,nameTo,effective){var timeFrom,timeTo,ed;if("string"!=typeof nameFrom)throw new TypeError("Timer.getTimeDiff: nameFrom must be string.Found: "+nameFrom);if("string"!=typeof nameTo)throw new TypeError("Timer.getTimeDiff: nameTo must be string. Found: "+nameTo);if(null==(timeFrom=this.timestamps[nameFrom]))throw new Error("Timer.getTimeDiff: nameFrom does not resolve to a valid timestamp: "+nameFrom);if(null==(timeTo=this.timestamps[nameTo]))throw new Error("Timer.getTimeDiff: nameTo does not resolve to a valid timestamp: "+nameTo);if(effective){if((ed=this._effectiveDiffs)[nameFrom]&&ed[nameFrom][nameTo])return ed[nameFrom][nameTo];if(ed[nameTo]&&ed[nameTo][nameFrom])return ed[nameTo][nameFrom]}return timeTo-timeFrom},Timer.prototype.parseInput=function(name,value,methodName){var num;if("string"!=typeof name)throw new TypeError((methodName||"Timer.parseInput")+": name must be string. Found: "+name);switch(typeof value){case"number":num=value;break;case"object":null!==value&&"function"==typeof value[name]&&(num=value[name].call(this.node.game));break;case"function":num=value.call(this.node.game);break;case"string":num=Number(value)}if("number"!=typeof num||num<0)throw new Error((methodName||"Timer.parseInput")+": "+name+" must be number >= 0. Found: "+num);return num},exports.GameTimer=GameTimer,GameTimer.STOPPED=-5,GameTimer.PAUSED=-3,GameTimer.UNINITIALIZED=-1,GameTimer.INITIALIZED=0,GameTimer.LOADING=3,GameTimer.RUNNING=5,GameTimer.DESTROYED=10,GameTimer.prototype.init=function(options){var i,len,node;if(checkDestroyed(this,"init"),this.status=GameTimer.UNINITIALIZED,this.timerId&&(clearInterval(this.timerId),this.timerId=null),options){if("object"!=typeof options)throw new TypeError("GameTimer.init: options must be object or undefined. Found: "+options);if(node=this.node,void 0!==options.milliseconds&&(this.milliseconds=node.timer.parseInput("milliseconds",options.milliseconds)),void 0!==options.update?this.update=node.timer.parseInput("update",options.update):this.update=this.update||this.milliseconds,options.timeup){if("function"!=typeof options.timeup&&"string"!=typeof options.timeup)throw new TypeError("GameTimer.init: options.timeup must be function or undefined. Found: "+options.timeup);this.timeup=options.timeup}else this.timeup=this.timeup||"TIMEUP";if(options.hooks)if(J.isArray(options.hooks))for(len=options.hooks.length,i=0;i0},GameTimer.prototype.isStopped=function(){return checkDestroyed(this,"isStopped"),this.status===GameTimer.UNINITIALIZED||this.status===GameTimer.INITIALIZED||this.status===GameTimer.STOPPED},GameTimer.prototype.isPaused=function(){return checkDestroyed(this,"isPaused"),this.status===GameTimer.PAUSED},GameTimer.prototype.isDestroyed=function(){return this.status===GameTimer.DESTROYED},GameTimer.prototype.isTimeUp=GameTimer.prototype.isTimeup=function(){return checkDestroyed(this,"isTimeup"),this._timeup},GameTimer.prototype.syncWithStager=function(sync,property){var that,ee;if(checkDestroyed(this,"syncWithStager"),void 0===sync)return this.stagerSync;if("boolean"!=typeof sync)throw new TypeError("GameTimer.syncWithStager: sync must be boolean or undefined. Found: "+sync);if(property){if("string"!=typeof property)throw new TypeError("GameTimer.syncWithStager: property must be string or undefined. Found: "+property);this.setStagerProperty(property)}return this.syncWithStager()===sync||(ee=this.node.events[this.eventEmitterName],!0===sync?(that=this,ee.on("PLAYING",(function(){var options;(options=that.getStepOptions())&&that.restart(options)}),this.name+"_PLAYING"),ee.on("REALLY_DONE",(function(){that.isStopped()||that.stop()}),this.name+"_REALLY_DONE")):(ee.off("PLAYING",this.name+"_PLAYING"),ee.off("REALLY_DONE",this.name+"_REALLY_DONE")),this.stagerSync=sync),sync},GameTimer.prototype.doTimeUp=GameTimer.prototype.doTimeup=function(){if(checkDestroyed(this,"doTimeup"),!this.isTimeup())return this.isStopped()||this.stop(),this._timeup=!0,this.fire(this.timeup)},GameTimer.prototype.setStagerProperty=function(property){if(checkDestroyed(this,"setStagerProperty"),"string"==typeof property)throw new TypeError("GameTimer.setStageProperty: property must be string. Found: "+property);this.stagerProperty=property},GameTimer.prototype.getStagerProperty=function(){return checkDestroyed(this,"getStagerProperty"),this.stagerProperty},GameTimer.prototype.getStepOptions=function(step,prop){var timer,timeup;if(checkDestroyed(this,"getStepOptions"),step=void 0!==step?step:this.node.game.getCurrentGameStage(),prop=prop||this.getStagerProperty(),null===(timer=this.node.game.plot.getProperty(step,prop)))return null;if("function"==typeof timer){if(null===(timer=timer.call(this.node.game)))return null}else"object"==typeof timer&&"function"==typeof(timer={milliseconds:timer.milliseconds,update:timer.update,timeup:timer.timeup,hooks:timer.hooks}).milliseconds&&(timer.milliseconds=timer.milliseconds.call(this.node.game));return"function"==typeof timer&&(timer=timer.call(this.node.game)),"number"==typeof timer&&(timer={milliseconds:timer}),"object"!=typeof timer||"number"!=typeof timer.milliseconds||timer.milliseconds<0?(this.node.warn("GameTimer.getStepOptions: invalid value for milliseconds. Found: "+timer.milliseconds),null):(void 0===timer.update&&(timer.update=timer.milliseconds),void 0===timer.timeup&&(timeup=this.node.game.plot.getProperty(step,"timeup"))&&(timer.timeup=timeup),timer)}}("undefined"!=typeof node?node:module.exports),function(exports,node){var fetchMatch,J=node.JSUS,Roler=node.Roler;function Matcher(options){options=options||{},this.x=null,this.y=null,this.matches=null,this.resolvedMatches=null,this.resolvedMatchesObj=null,this.resolvedMatchesById=null,this.ids=null,this.assignedIds=null,this.idsMap=null,this.assignedIdsMap=null,this.assignerCb=Matcher.randomAssigner,this.missingId=Matcher.missingId,this.bye=Matcher.bye,this.doObjLists=!0,this.doIdLists=!0,this.doRoles=!1,this.roler=options.roler||null,this.roler=options.roler||null,this.init(options)}function importMatchItem(i,j,item,map,miss){if("number"==typeof item)return void 0!==map[item]?map[item]:miss;if("string"==typeof item)return item;throw new TypeError("Matcher.match: items can be only string or number. Found: "+item+" at position "+i+","+j)}function resetResolvedData(matcher){matcher.resolvedMatches=null,matcher.resolvedMatchesObj=null,matcher.resolvedMatchesById=null,matcher.assignedIds=null,matcher.assignedIdsMap=null}function pairMatcher(alg,n,options){var ps,matches,bye,i,lenI,j,lenJ,jj,id1,id2,roundsLimit,cycle,cycleI,skipBye,fixedRolesNoSameMatch;if("number"==typeof n&&n>1)ps=J.seq(0,n-1);else{if(!(J.isArray(n)&&n.length>1))throw new TypeError("pairMatcher."+alg+": n must be number > 1 or array of length > 1.");ps=n.slice(),n=ps.length}if(bye=void 0!==(options=options||{}).bye?options.bye:-1,skipBye=options.skipBye||!1,n%2==1&&(ps.push(bye),n+=1),options.fixedRoles&&!1===options.canMatchSameRole&&(fixedRolesNoSameMatch=!0),"number"==typeof options.rounds){if(options.rounds<=0)throw new Error("pairMatcher."+alg+": options.rounds must be a positive number or undefined. Found: "+options.rounds);if(options.rounds>n-1)throw new Error("pairMatcher."+alg+": options.rounds cannot be greater than "+(n-1)+". Found: "+options.rounds);roundsLimit=options.rounds}else roundsLimit=fixedRolesNoSameMatch?Math.floor(n/2):n-1;if(void 0!==options.cycle){if("mirror_invert"!==(cycle=options.cycle)&&"mirror"!==cycle&&"repeat_invert"!==cycle&&"repeat"!==cycle)throw new Error("pairMatcher."+alg+': options.cycle must be equal to "mirror"/"mirror_invert", "repeat"/"repeat_invert" or undefined . Found: '+options.cycle);matches=new Array(2*roundsLimit)}else matches=new Array(roundsLimit);for(i=-1,lenI=roundsLimit;++inRows)return!!mod&&(this.x=x,this.y=0,null);if(void 0===y)return!mod||(this.x=x,this.y=this.resolvedMatches[nRows].length,fetchMatch[mod].call(this,x,y,id));if("number"!=typeof y)throw new TypeError("Matcher."+m+": y must be number or undefined.");if(y<0||isNaN(y))throw new Error("Matcher."+m+": y cannot be negative or NaN. Found: "+y);return y<=this.resolvedMatches[x].length-1?!mod||(this.x=x,this.y=y,fetchMatch[mod].call(this,x,y)):!!mod&&(this.x=x,this.y=y,null)}exports.Matcher=Matcher,Matcher.bye=-1,Matcher.missingId="bot",Matcher.randomAssigner=function(ids){return J.shuffle(ids)},Matcher.linearAssigner=function(ids){return J.clone(ids)},Matcher.prototype.init=function(options){if((options=options||{}).assignerCb&&this.setAssignerCb(options.assignerCb),options.ids&&this.setIds(options.ids),options.bye&&(this.bye=options.bye),options.missingId&&(this.missingId=options.missingId),null===options.x)this.x=null;else if("number"==typeof options.x){if(options.x<0)throw new Error("Matcher.init: options.x cannot be negative.Found: "+options.x);this.x=options.x}else if(options.x)throw new TypeError("Matcher.init: options.x must be number, null or undefined. Found: "+options.x);if(null===options.y)this.y=null;else if("number"==typeof options.y){if(options.y<0)throw new Error("Matcher.init: options.y cannot be negative.Found: "+options.y);this.y=options.y}else if(options.y)throw new TypeError("Matcher.init: options.y must be number, null or undefined. Found: "+options.y);options.doRoles||options.roles?(this.roler||(this.roler=new Roler),this.roler.init({missingId:this.missingId,roles:options.roles}),this.doRoles=!0):void 0!==options.doRoles&&(this.doRoles=!!options.doRoles),void 0!==options.doObjLists&&(this.doObjLists=!!options.doObjLists),void 0!==options.doIdLists&&(this.doIdLists=!!options.doIdLists)},Matcher.prototype.generateMatches=function(alg){var matches;if("string"!=typeof alg)throw new TypeError("Matcher.generateMatches: alg must be string. Found: "+alg);if("roundrobin"!==(alg=alg.toLowerCase())&&"round_robin"!==alg&&"random"!==alg&&"random_pairs"!==alg)throw new Error("Matcher.generateMatches: unknown algorithm: "+alg);return matches=pairMatcher(alg,arguments[1],arguments[2]),this.setMatches(matches),matches},Matcher.prototype.setMatches=function(matches){if(!J.isArray(matches)||!matches.length)throw new TypeError("Matcher.setMatches: matches must be a non-empty array. Found: "+matches);this.matches=matches,resetResolvedData(this)},Matcher.prototype.getMatches=function(){return this.matches},Matcher.prototype.setIds=function(ids){var i,len;if(!J.isArray(ids)||!ids.length)throw new TypeError("Matcher.setIds: ids must be a non-empty array. Found: "+ids);for(this.idsMap={},i=-1,len=ids.length;++i=0&&!isNaN(x))return x>out.length-1?null:out[x];throw new TypeError("Matcher.getMatchFor: x must be a positive number or undefined. Found: "+x)},Matcher.prototype.getMatchObject=function(x,y){if(!this.resolvedMatchesObj)throw new Error("Matcher.getMatchObject: no obj matches found.");return hasOrGetNext.call(this,"getMatchObject",3,x,y)},Matcher.prototype.normalizeRound=function(round){if(!this.matches)throw new TypeError("Matcher.normalizeRound: no matches found.");if("number"!=typeof round||isNaN(round)||round<1)throw new TypeError("Matcher.normalizeRound: round must be a number > 0. Found: "+round);return(round-1)%this.matches.length},Matcher.prototype.replaceId=function(oldId,newId){var m,i,len,j,lenJ,h,lenH,rowFound;if("string"!=typeof oldId)throw new TypeError("Matcher.replaceId: oldId should be string. Found: "+oldId);if("string"!=typeof newId||""===newId.trim())throw new TypeError("Matcher.replaceId: newId should be a non-empty string. Found: "+newId);if(!this.resolvedMatches)return!1;if(void 0===(m=this.idsMap[oldId]))return!1;for(this.idsMap[newId]=!0,delete this.idsMap[oldId],i=-1,len=(m=this.ids).length;++i=numLevel&&(info=this.nodename+"@"+this.player.stage.stage+"."+this.player.stage.step+"."+this.player.stage.round+" - "+J.getTimeM()+" > ",void 0!==prefix&&(info+=prefix),console.log(info+txt)),this.remoteVerbosity>=numLevel&&this.socket.isConnected()&&!this.player.placeholder&&(this.remoteLogMap[txt]||(this.remoteLogMap[txt]=!0,this.socket.send(this.msg.create({target:LOG,text:level,data:txt,to:"SERVER"})),this.remoteLogMap[txt]=null)))},NGC.prototype.info=function(txt){this.log(txt,"info","info - ")},NGC.prototype.warn=function(txt){this.log(txt,"warn","warn - ")},NGC.prototype.err=function(txt){this.log(txt,"error","error - ")},NGC.prototype.silly=function(txt){this.log(txt,"silly","silly - ")}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,node){"use strict";var J=node.JSUS,NGC=node.NodeGameClient;NGC.prototype.setup=function(property){var res,func,i,len,args;if("string"!=typeof property||""===property)throw new TypeError("node.setup: property must be a non-empty string. Found: "+property);if(!(func=this._setup[property]))throw new Error("node.setup: no such property to configure: "+property);switch(len=arguments.length){case 1:res=func.call(this);break;case 2:res=func.call(this,arguments[1]);break;case 3:res=func.call(this,arguments[1],arguments[2]);break;default:for(len-=1,args=new Array(len),i=-1;++i2){if(3===len)payload=[arguments[2]];else if(4===len)payload=[arguments[2],arguments[3]];else for(payload=new Array(len-2),i=2;i=2?(channel=arguments[0],socketOptions=arguments[1]):1===arguments.length&&("string"==typeof arguments[0]?channel=arguments[0]:socketOptions=arguments[0]),"undefined"!=typeof window&&(void 0===channel&&window.location&&window.location.pathname&&("/"!==(channel=window.location.pathname).charAt(0)&&(channel="/"+channel),"/"===channel.charAt(channel.length-1)&&(channel=channel.substring(0,channel.length-1))),channel&&"https://"!==channel.substr(0,8)&&"http://"!==channel.substr(0,7)&&window.location&&window.location.origin&&(channel=window.location.origin+channel),(!socketOptions||socketOptions&&!socketOptions.query)&&"undefined"!=typeof location&&location.search&&((socketOptions=socketOptions||{}).query=location.search.substr(1))),this.socket.connect(channel,socketOptions)}}("undefined"!=typeof node?node:module.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,Player=parent.Player,constants=parent.constants;NGC.prototype.createPlayer=function(player){if(this.player&&this.player.stateLevel>constants.stateLevels.STARTING&&this.player.stateLevel!==constants.stateLevels.GAMEOVER)throw new Error("node.createPlayer: cannot create player while game is running.");if(this.game.pl.exist(player.id))throw new Error("node.createPlayer: id already found in playerList: "+player.id);return(player=new Player(player)).stateLevel=this.player.stateLevel,player.stageLevel=this.player.stageLevel,this.player=player,this.player.strippedSid=this.player.sid.slice(2),this.emit("PLAYER_CREATED",this.player),this.player},NGC.prototype.setLanguage=function(lang,updateUriPrefix,sayIt){var language,langStr,shortName;if(!(language="string"==typeof lang?(shortName=(langStr=lang).toLowerCase().substr(0,2),{name:langStr,shortName:shortName,nativeName:langStr,path:shortName+"/"}):lang)||"object"!=typeof language)throw new TypeError("node.setLanguage: language must be object or string. Found: "+lang);if("string"!=typeof language.shortName)throw new TypeError("node.setLanguage: language.shortName must be string. Found: "+language.shortName);return this.player.lang=language,this.player.lang.path||(this.player.lang.path=language.shortName+"/"),updateUriPrefix&&(void 0!==this.window?this.window.setUriPrefix(this.player.lang.path):node.warn("node.setLanguage: updateUriPrefix is true, but window not found. Are you in a browser?")),sayIt&&node.socket.send(node.msg.create({target:"LANG",data:this.player.lang})),this.emit("LANGUAGE_SET"),this.player.lang}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,GameStage=parent.GameStage,STAGE_INIT=parent.constants.stateLevels.STAGE_INIT,STAGE_EXIT=parent.constants.stateLevels.STAGE_EXIT;NGC.prototype.getCurrentEventEmitter=function(){var gameStage,stateL;return this.game&&(gameStage=this.game.getCurrentGameStage())?0===GameStage.compare(gameStage,new GameStage)?this.events.ee.game:(stateL=this.game.getStateLevel())===STAGE_INIT||stateL===STAGE_EXIT?this.events.ee.stage:this.events.ee.step:this.events.ee.ng}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,J=parent.JSUS,stageLevels=parent.constants.stageLevels,GETTING_DONE=stageLevels.GETTING_DONE;NGC.prototype.say=function(label,to,payload){var msg;if("string"!=typeof label||""===label)throw new TypeError("node.say: label must be string. Found: "+label);if(to&&"string"!=typeof to&&(!J.isArray(to)||!to.length))throw new TypeError("node.say: to must be a non-empty array, string or undefined. Found: "+to);return msg=this.msg.create({target:this.constants.target.DATA,to:to,text:label,data:payload}),this.socket.send(msg)},NGC.prototype.set=function(o,to,text){var msg,tmp;if("string"==typeof o)tmp=o,(o={})[tmp]=!0;else if("object"!=typeof o)throw new TypeError("node.set: o must be object or string. Found: "+o);return msg=this.msg.create({action:this.constants.action.SET,target:this.constants.target.DATA,to:to||"SERVER",reliable:1,data:o}),text&&(msg.text=text),this.socket.send(msg)},NGC.prototype.get=function(key,cb,to,options){var msg,g,ee,that,res,timer,success,data,timeout,timeoutCb,executeOnce,target;if("string"!=typeof key)throw new TypeError("node.get: key must be string. Found: "+key);if(""===key)throw new TypeError("node.get: key cannot be empty.");if(key.split(".")>1)throw new TypeError('node.get: key cannot contain the dot "." character: '+key);if("function"!=typeof cb)throw new TypeError("node.get: cb must be function. Found: "+cb);if(void 0===to&&(to="SERVER"),"string"!=typeof to)throw new TypeError("node.get: to must be string or undefined. Found: "+to);if(options){if("object"!=typeof options)throw new TypeError("node.get: options must be object or undefined. Found: "+options);if(timeout=options.timeout,timeoutCb=options.timeoutCb,data=options.data,executeOnce=options.executeOnce,target=options.target,void 0!==timeout){if("number"!=typeof timeout)throw new TypeError("node.get: options.timeout must be number. Found: "+timeout);if(timeout<0&&-1!==timeout)throw new TypeError("node.get: options.timeout must be positive, 0, or -1. Found: "+timeout)}if(timeoutCb&&"function"!=typeof timeoutCb)throw new TypeError("node.get: options.timeoutCb must be function or undefined. Found: "+timeoutCb);if(target&&("string"!=typeof target||""===target.trim()))throw new TypeError("node.get: options.target must be a non-empty string or undefined. Found: "+target)}return msg=this.msg.create({action:this.constants.action.GET,target:target||this.constants.target.DATA,to:to,reliable:1,text:key,data:data}),res=this.socket.send(msg),key=key+"_"+msg.id,res&&(that=this,ee=this.getCurrentEventEmitter(),g=function(msg){msg.text===key&&(success=!0,executeOnce&&(ee.remove("in.say.DATA",g),void 0!==timer&&that.timer.destroyTimer(timer)),cb.call(that.game,msg.data))},ee.on("in.say.DATA",g),timeout>0&&(timer=this.timer.createTimer({milliseconds:timeout,timeup:function(){ee.remove("in.say.DATA",g),void 0!==timer&&that.timer.destroyTimer(timer),timeoutCb&&!success&&timeoutCb.call(that.game)}})).start()),res},NGC.prototype.done=function(param){var that,game,doneCb,stepTime,args,o;return stepTime=this.timer.getTimeSince("step"),(game=this.game).willBeDone||game.getStageLevel()>=GETTING_DONE?(this.err("node.done: done already called in step: "+game.getCurrentGameStage()),!1):!game.isWidgetStep()&&!game.timer.isTimeup()&&this.widgets&&this.widgets.isActionRequired({markAttempt:!0,highlight:!0})?(this.warn("node.done: there are widgets requiring action"),!1):(doneCb=game.plot.getProperty(game.getCurrentGameStage(),"done"))&&!1===(args=doneCb.call(game,param))?(this.silly("node.done: done callback returned false"),!1):(game.willBeDone=!0,args||(args=param),game.plot.getProperty(game.getCurrentGameStage(),"autoSet")&&("object"==typeof args?o=args:(o={},"string"!=typeof args&&"number"!=typeof args||(o[args]=!0)),o.time||(o.time=stepTime),void 0===o.timeup&&(o.timeup=game.timer.isTimeup()),game.role&&!o.role&&(o.role=game.role),game.partner&&!o.partner&&(o.partner=game.partner),o.stepId=game.getStepId(),o.stageId=game.getStageId(),o.done=!0,this.set(o,"SERVER","done")),this.game.setStageLevel(stageLevels.GETTING_DONE),that=this,setTimeout((function(){that.events.emit("DONE",param)}),0),!0)}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,node){"use strict";var NGC=node.NodeGameClient,J=node.JSUS;NGC.prototype.redirect=function(url,who){var msg;if("string"!=typeof url)throw new TypeError("node.redirect: url must be string. Found: "+url);if("string"!=typeof who&&!J.isArray(who))throw new TypeError("node.redirect: who must be string. Found: "+who);msg=this.msg.create({target:this.constants.target.REDIRECT,data:url,to:who}),this.socket.send(msg)},NGC.prototype.remoteCommand=function(command,to,options){var msg;if("string"!=typeof command)throw new TypeError("node.remoteCommand: command must be string.");if(!node.constants.gamecommands[command])throw new Error("node.remoteCommand: unknown command: "+command);if("string"!=typeof to&&!J.isArray(to))throw new TypeError("node.remoteCommand: to must be string or array. Found: "+to);options&&(options=J.stringify(options)),msg=this.msg.create({target:this.constants.target.GAMECOMMAND,text:command,data:options,to:to}),this.socket.send(msg)},NGC.prototype.remoteAlert=function(text,to){var msg;if("string"!=typeof text)throw new TypeError("node.remoteAlert: text must be string. Found: "+text);if("string"!=typeof to&&!J.isArray(to))throw new TypeError("node.remoteAlert: to must be string or array. Found: "+to);msg=this.msg.create({target:this.constants.target.ALERT,text:text,to:to}),this.socket.send(msg)},NGC.prototype.disconnectClient=function(p){var msg;if("object"!=typeof p)throw new TypeError("node.disconnectClient: p must be object. Found: "+p);this.info("node.disconnectClient: "+p.id),msg=this.msg.create({target:"SERVERCOMMAND",text:"DISCONNECT",data:{id:p.id,sid:p.sid}}),this.socket.send(msg)}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,J=parent.JSUS;NGC.prototype.env=function(env,func,ctx,params){var envValue,args;if("string"!=typeof env)throw new TypeError("node.env: env must be string.");if(func&&"function"!=typeof func)throw new TypeError("node.env: func must be function or undefined.");if(ctx&&"object"!=typeof ctx)throw new TypeError("node.env: ctx must be object or undefined.");if(args=[envValue=this._env[env]],params){if(!J.isArray(params))throw new TypeError("node.env: params must be array or undefined. Found: "+params);params=params.concat(args)}return func&&envValue&&func.apply(ctx||this,args),envValue},NGC.prototype.clearEnv=function(){this._env={}}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";("undefined"!=typeof node?node:module.parent.exports).NodeGameClient.prototype.getJSON=function(uris,dataCb,doneCb){var that,loadedCount,currentUri,uriIdx,tempCb,cbIdx,scriptTag,scriptTagName;if("string"==typeof uris)uris=[uris];else if("object"!=typeof uris||"number"!=typeof uris.length)throw new Error("NGC.getJSON: uris must be an array or a string");if("function"!=typeof dataCb)throw new Error("NGC.getJSON: dataCb must be a function");if(void 0!==doneCb&&"function"!=typeof doneCb)throw new Error("NGC.getJSON: doneCb must be undefined or function");if(0!==uris.length)for(that=this,loadedCount=0,void 0===this.tempCallbacks?this.tempCallbacks={counter:0}:this.tempCallbacks.counter++,cbIdx=this.tempCallbacks.counter,tempCb=function(data){dataCb(data),delete that.tempCallbacks[cbIdx],JSUS.size(that.tempCallbacks)<=1&&delete that.tempCallbacks},this.tempCallbacks[cbIdx]=tempCb,uriIdx=0;uriIdx=uris.length&&doneCb&&doneCb()}}(0,scriptTag);else doneCb&&doneCb()}}("undefined"!=typeof node?node:module.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,PlayerList=parent.PlayerList,Player=parent.Player,J=parent.JSUS,action=parent.constants.action,say=action.SAY+".",set=action.SET+".",get=action.GET+".",IN=parent.constants.IN;function emitGameCommandMsg(node,msg){var opts;return"string"!=typeof msg.text?(node.err('"in.'+msg.action+'.GAMECOMMAND": msg.text must be string. Found: '+msg.text),!1):parent.constants.gamecommands[msg.text]?(opts="string"==typeof msg.data?J.parse(msg.data):msg.data,node.emit("NODEGAME_GAMECOMMAND_"+msg.text,opts)):(node.err('"in.'+msg.action+'.GAMECOMMAND": unknown game command received: '+msg.text),!1)}NGC.prototype.addDefaultIncomingListeners=function(force){var node=this;return node.conf.incomingAdded&&!force?(node.err('node.addDefaultIncomingListeners: listeners already added. Use "force" to add again'),!1):(this.info("node: adding incoming listeners"),node.events.ng.on(IN+say+"BYE",(function(msg){msg.data,node.socket.disconnect(true)})),node.events.ng.on(IN+say+"PCONNECT",(function(msg){var p;"object"==typeof msg.data?(p=msg.data instanceof Player?node.game.pl.add(msg.data):node.game.pl.add(new Player(msg.data)),node.emit("UPDATED_PLIST","pconnect",p),node.game.shouldStep()&&node.game.step()):node.err("received PCONNECT, but invalid data: "+msg.data)})),node.events.ng.on(IN+say+"PDISCONNECT",(function(msg){var p;"object"==typeof msg.data?(p=node.game.pl.remove(msg.data.id),node.emit("UPDATED_PLIST","pdisconnect",p),node.game.shouldStep()&&node.game.step()):node.err("received PDISCONNECT, but invalid data: "+msg.data)})),node.events.ng.on(IN+say+"MCONNECT",(function(msg){"object"==typeof msg.data?(node.game.ml.add(new Player(msg.data)),node.emit("UPDATED_MLIST")):node.err("received MCONNECT, but invalid data: "+msg.data)})),node.events.ng.on(IN+say+"MDISCONNECT",(function(msg){"object"==typeof msg.data?(node.game.ml.remove(msg.data.id),node.emit("UPDATED_MLIST")):node.err("received MDISCONNECT, but invalid data: "+msg.data)})),node.events.ng.on(IN+say+"PLIST",(function(msg){msg.data&&(node.game.pl=new PlayerList({},msg.data),node.emit("UPDATED_PLIST","replace",node.game.pl))})),node.events.ng.on(IN+say+"MLIST",(function(msg){msg.data&&(node.game.ml=new PlayerList({},msg.data),node.emit("UPDATED_MLIST"))})),node.events.ng.on(IN+get+"DATA",(function(msg){var res;"string"==typeof msg.text&&""!==msg.text.trim()?(res=node.emit(get+msg.text,msg),J.isEmpty(res)||node.say(msg.text+"_"+msg.id,msg.from,res)):node.err('"in.get.DATA": msg.data must be a non-empty string.')})),node.events.ng.on(IN+set+"DATA",(function(msg){var o=msg.data;o.player=msg.from,o.stage=msg.stage,node.game.memory.add(o)})),node.events.ng.on(IN+say+"PLAYER_UPDATE",(function(msg){var p;p=node.game.pl.updatePlayer(msg.from,msg.data),node.emit("UPDATED_PLIST","pupdate",p),node.game.shouldStep()?node.game.step():node.game.shouldEmitPlaying()&&node.emit("PLAYING")})),node.events.ng.on(IN+say+"REDIRECT",(function(msg){return"string"!=typeof msg.data?(node.err('"in.say.REDIRECT": msg.data must be string: '+msg.data),!1):"undefined"!=typeof window&&window.location?void(window.location=msg.data):(node.err('"in.say.REDIRECT": window.location not found.'),!1)})),node.events.ng.on(IN+say+"SETUP",(function(msg){var payload,feature;"string"==typeof(feature=msg.text)?node._setup[feature]?(payload="string"==typeof msg.data?J.parse(msg.data):msg.data)?node.setup.apply(node,[feature].concat(payload)):node.err('"in.say.SETUP": error while parsing payload of incoming remote setup message.'):node.err('"in.say.SETUP": no such setup function: '+feature):node.err('"in.say.SETUP": msg.text must be string: '+feature)})),node.events.ng.on(IN+say+"GAMECOMMAND",(function(msg){emitGameCommandMsg(node,msg)})),node.events.ng.on(IN+get+"GAMECOMMAND",(function(msg){var res;res=emitGameCommandMsg(node,msg),J.isEmpty(res)||node.say(msg.text+"_"+msg.id,msg.from,res)})),node.events.ng.on(IN+say+"ALERT",(function(msg){if("string"==typeof msg.text&&""!==msg.text.trim())if("undefined"!=typeof window){if("undefined"==typeof alert)return void node.err('"in.say.ALERT": alert is not defined: '+msg.text);alert(msg.text)}else console.log("****** ALERT ******"),console.log(msg.text),console.log("*******************");else node.err('"in.say.ALERT": msg.text must be a non-empty string')})),node.events.ng.on(IN+get+"PLOT",(function(msg){return node.game.plot.stager?"state"===msg.text?node.game.plot.stager.getState():node.game.plot.stager.getSequence():null})),node.events.ng.on(IN+get+"PLIST",(function(){return node.game.pl.db})),node.events.ng.on(get+"PLAYER",(function(){return node.player})),node.events.ng.on(IN+get+"LANG",(function(){return node.player.lang})),node.events.ng.on(get+"LANG",(function(){return node.player.lang})),node.events.ng.on(IN+set+"LANG",(function(msg){node.setLanguage(msg.data)})),node.events.ng.on(get+"PING",(function(){return"pong"})),node.conf.incomingAdded=!0,node.silly("node: incoming listeners added."),!0)}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,GameStage=parent.GameStage,constants=parent.constants,stageLevels=constants.stageLevels,gcommands=constants.gamecommands,CMD="NODEGAME_GAMECOMMAND_";NGC.prototype.addDefaultInternalListeners=function(force){var node=this;if(this.conf.internalAdded&&!force)return this.err("Default internal listeners already added once. Use the force flag to re-add."),!1;function done(){var res;node.game.willBeDone=!1,node.game.beDone=!1,node.emit("REALLY_DONE"),res=node.game.shouldStep(stageLevels.DONE),node.game.setStageLevel(stageLevels.DONE),res&&setTimeout((function(){node.game.step()}),0)}return this.info("node: adding internal listeners."),this.events.ng.on("DONE",(function(){node.game.willBeDone&&(node.game.getStageLevel()>=stageLevels.PLAYING?done():node.game.willBeDone=!0)})),this.events.ng.on("STEP_CALLBACK_EXECUTED",(function(){node.window&&!node.window.isReady()||node.emit("LOADED")})),this.events.ng.on("LOADED",(function(){var frame;node.game.setStageLevel(constants.stageLevels.LOADED),node.socket.shouldClearBuffer()&&node.socket.clearBuffer(),node.window&&(frame=node.window.getFrame())&&(frame.style.visibility=""),node.game.shouldEmitPlaying()&&node.emit("PLAYING")})),this.events.ng.on("PLAYING",(function(){var currentTime;node.emit("BEFORE_PLAYING"),node.game.setStageLevel(stageLevels.PLAYING),node.socket.clearBuffer(),currentTime=(new Date).getTime(),node.timer.setTimestamp(node.game.getCurrentGameStage().toString(),currentTime),node.timer.setTimestamp("step",currentTime),node.game.willBeDone&&done()})),this.events.ng.on(CMD+gcommands.start,(function(options){node.game.isStartable()?(node.emit("BEFORE_GAMECOMMAND",gcommands.start,options),node.game.start(options)):node.warn('"'+CMD+gcommands.start+'": game cannot be started now.')})),this.events.ng.on(CMD+gcommands.pause,(function(options){node.game.isPausable()?(node.emit("BEFORE_GAMECOMMAND",gcommands.pause,options),node.game.pause(options)):node.warn('"'+CMD+gcommands.pause+'": game cannot be paused now.')})),this.events.ng.on(CMD+gcommands.resume,(function(options){node.game.isResumable()?(node.emit("BEFORE_GAMECOMMAND",gcommands.resume,options),node.game.resume(options)):node.warn('"'+CMD+gcommands.resume+'": game cannot be resumed now.')})),this.events.ng.on(CMD+gcommands.step,(function(options){node.game.isSteppable()?(node.emit("BEFORE_GAMECOMMAND",gcommands.step,options),options.breakStage&&node.game.breakStage(!0),node.game.step()):node.warn('"'+CMD+gcommands.step+'": game cannot be stepped now.')})),this.events.ng.on(CMD+gcommands.stop,(function(options){node.game.isStoppable()?(node.emit("BEFORE_GAMECOMMAND",gcommands.stop,options),node.game.stop()):node.warn('"'+CMD+gcommands.stop+'": game cannot be stopped now.')})),this.events.ng.on(CMD+gcommands.goto_step,(function(options){var step;node.game.isSteppable()?(options.targetStep?(step=options.targetStep,delete options.targetStep):(step=options,options=void 0),node.emit("BEFORE_GAMECOMMAND",gcommands.goto_step,step,options),step===parent.GamePlot.GAMEOVER||(step=new GameStage(step),node.game.plot.getStep(step))?node.game.gotoStep(step,options):node.err('"'+CMD+gcommands.goto_step+'": step not found: '+step)):node.warn('"'+CMD+gcommands.goto_step+'": game cannot be stepped now')})),this.events.ng.on(CMD+gcommands.clear_buffer,(function(){node.emit("BEFORE_GAMECOMMAND",gcommands.clear_buffer),node.socket.clearBuffer()})),this.events.ng.on(CMD+gcommands.erase_buffer,(function(){node.emit("BEFORE_GAMECOMMAND",gcommands.clear_buffer),node.socket.eraseBuffer()})),node.events.ng.on(CMD+gcommands.push_step,(function(){var stageLevel;return node.warn("push_step command. ",node.player.stage),node.game.timer.isTimeup()||node.game.timer.doTimeup(),node.game.willBeDone||(stageLevel=node.game.getStageLevel())!==stageLevels.DONE_CALLED&&stageLevel!==stageLevels.GETTING_DONE&&stageLevel!==stageLevels.DONE&&(node.done()||node.emit("DONE")),"ok!"})),this.conf.internalAdded=!0,this.silly("node: internal listeners added."),!0}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(exports,parent){"use strict";var NGC=parent.NodeGameClient,J=parent.JSUS,constants=parent.constants;NGC.prototype.addDefaultSetupFunctions=function(force){return this.conf.setupsAdded&&!force?(this.err("node.addDefaultSetups: setup functions already added. Use the force flag to re-add."),!1):(this.info("node: registering setup functions."),this.registerSetup("nodegame",(function(options){var i,setupOptions;if(options&&"object"!=typeof options)throw new TypeError('node.setup("nodegame"): options must object or undefined.');for(i in options=options||{},this._setup)this._setup.hasOwnProperty(i)&&"function"==typeof this._setup[i]&&"nodegame"!==i&&"prototype"!==i&&(setupOptions=void 0===options[i]?void 0:options[i],this.conf[i]=this._setup[i].call(this,setupOptions))})),this.registerSetup("socket",(function(conf){if(void 0!==conf)return this.socket.setup(conf),conf})),this.registerSetup("host",(function(host){var tokens;if(host||"undefined"!=typeof window&&void 0!==window.location&&(host=window.location.href),host){if("string"!=typeof host)throw new TypeError('node.setup("host"): if set, host must be string. Found: '+host);(tokens=host.split("/").slice(0,-2)).length>1&&(host=tokens.join("/")),host.lastIndexOf("/")!==host.length&&(host+="/")}return host})),this.registerSetup("verbosity",(function(level){if(void 0===level)return this.verbosity;if("string"==typeof level){if(!constants.verbosity_levels.hasOwnProperty(level))throw new Error('setup("verbosity"): level not found: '+level);this.verbosity=constants.verbosity_levels[level]}else{if("number"!=typeof level)throw new TypeError('node.setup("verbosity"): level must be number or string. Found: '+level);this.verbosity=level}return level})),this.registerSetup("nodename",(function(newName){if("string"!=typeof(newName=newName||constants.nodename))throw new TypeError('setup("nodename"): newName must be string. Found: '+newName);return this.nodename=newName,newName})),this.registerSetup("debug",(function(enable){return enable=!!enable||!1,this.debug=enable,enable})),this.registerSetup("env",(function(conf){var i;if(void 0!==conf){if("object"!=typeof conf)throw new TypeError('node.setup("env"): conf must be object or undefined. Found: '+conf);for(i in conf)conf.hasOwnProperty(i)&&(this._env[i]=conf[i]);return conf}})),this.registerSetup("events",(function(conf){if(conf){if("object"!=typeof conf)throw new TypeError('node.setup("events"): conf must be object or undefined. Found: '+conf)}else conf={};return void 0===conf.history&&(conf.history=this.conf.history||!1),void 0===conf.dumpEvents&&(conf.dumpEvents=this.conf.dumpEvents||!1),conf})),this.registerSetup("settings",(function(settings){if(void 0!==settings){if("object"!=typeof settings)throw new TypeError('node.setup("settings"): settings must be object or undefined. Found: '+settings);J.mixin(this.game.settings,settings)}return this.game.settings})),this.registerSetup("metadata",(function(metadata){if(void 0!==metadata){if("object"!=typeof metadata)throw new TypeError('node.setup("metadata"): metadata must be object or undefined. Found: '+metadata);J.mixin(this.game.metadata,metadata)}return this.game.metadata})),this.registerSetup("player",(function(player){if(void 0!==player){if("object"!=typeof player)throw new TypeError('setup("player"): player must be object or undefined. Found: '+player);this.createPlayer(player)}return this.player})),this.registerSetup("lang",(function(lang){if(void 0!==lang)if(J.isArray(lang))this.setLanguage(lang[0],lang[1]);else{if("string"!=typeof lang&&"object"!=typeof lang)throw new TypeError('setup("lang"): lang must be string, array, object or undefined. Found: '+lang);this.setLanguage(lang)}return this.player.lang})),function(node){function setupTimer(opts){var name,timer;if(name=opts.name||node.game.timer.name,!(timer=node.timer.getTimer(name)))return node.warn('setup("timer"): timer not found: '+name),!1;switch(opts.options&&timer.init(opts.options),opts.action){case"start":timer.start();break;case"stop":timer.stop();break;case"restart":timer.restart();break;case"pause":timer.pause();break;case"resume":timer.resume()}return!0}node.registerSetup("timer",(function(opts){var i,len,res;if(opts){if("object"!=typeof opts)throw new TypeError('setup("timer"): opts must object or undefined. Found: '+opts);if(J.isArray(opts))for(res=!0,i=-1,len=opts.length;++i0;i--)if(void 0!==(out=this.triggers[i-1].call(this,o))&&this.returnAt===TriggerManager.first)return out;return void 0!==out?out:o}}}("undefined"!=typeof node?node:module.exports,"undefined"!=typeof node?node:module.parent.exports),function(){var tmp=new window.node.NodeGameClient;JSUS.mixin(tmp,window.node),window.node=tmp}(),function(window,node){"use strict";var DOM,constants,windowLevels,screenLevels,CB_EXECUTED,WIN_LOADING,validPositions,nextTimeout,adjustIt;if(!J)throw new Error("GameWindow: JSUS not found");if(!(DOM=J.require("DOM")))throw new Error('GameWindow: J.require("DOM") failed');function onLoad(iframe,cb){W.isIE?function(iframe,cb){var iframeWin;function completed(event){var iframeDoc;iframeDoc=J.getIFrameDocument(iframe),"load"!==event.type&&"complete"!==iframeDoc.readyState||(iframe.detachEvent("onreadystatechange",completed),iframeWin.detachEvent("onload",completed),cb&&setTimeout((function(){cb()}),120))}iframeWin=iframe.contentWindow,iframe.attachEvent("onreadystatechange",completed),iframeWin.attachEvent("onload",completed)}(iframe,cb):function(iframe,cb){var iframeWin;function completed(){iframe.removeEventListener("load",completed,!1),iframeWin.removeEventListener("load",completed,!1),cb&&setTimeout((function(){cb()}),120)}iframeWin=iframe.contentWindow,iframe.addEventListener("load",completed,!1),iframeWin.addEventListener("load",completed,!1)}(iframe,cb)}function GameWindow(){if(this.setStateLevel("UNINITIALIZED"),void 0===window)throw new Error("GameWindow: no window found. Are you in a browser?");if(void 0===node)throw new Error("GameWindow: nodeGame not found");node.silly("node-window: loading..."),this.frameName=null,this.frameElement=null,this.frameWindow=null,this.frameDocument=null,this.frameRoot=null,this.headerElement=null,this.headerName=null,this.headerRoot=null,this.headerPosition=null,this.defaultHeaderPosition="top",this.conf={},this.uriChannel=null,this.areLoading=0,this.cacheSupported=null,this.directFrameDocumentAccess=null,this.cache={},this.currentURIs={},this.unprocessedUri=null,this.globalLibs=[],this.frameLibs={},this.uriPrefix=null,this.stateLevel=null,this.waitScreen=null,this.listenersAdded=null,this.screenState=node.constants.screenLevels.ACTIVE,this.styleElement=null,this.isIE=!!document.createElement("span").attachEvent,this.headerOffset=0,this.willResizeFrame=!1,this.addDefaultSetups(),this.addDefaultListeners(),setTimeout((function(){var scriptTag;(scriptTag=document.getElementsByTagName("noscript")).length>=1&&(scriptTag[0].style.display="none")}),1e3),this.init(GameWindow.defaults),node.silly("node-window: created.")}function handleFrameLoad(that,uri,iframe,frameName,loadCache,storeCache,func){var iframeDocumentElement,afterScripts;iframe=W.getElementById(frameName),iframeDocumentElement=W.getIFrameDocument(iframe).documentElement,loadCache&&(iframeDocumentElement.innerHTML=that.cache[uri].contents),frameName===that.frameName&&(that.frameWindow=iframe.contentWindow,that.frameDocument=that.getIFrameDocument(iframe),that.conf.rightClickDisabled&&J.disableRightClick(that.frameDocument),that.conf.noEscape&&(that.frameDocument.onkeydown=document.onkeydown)),that.styleElement=null,function(iframe){var idx,contentDocument,scriptNodes,scriptNode;for(contentDocument=W.getIFrameDocument(iframe),scriptNodes=W.getElementsByClassName(contentDocument,"injectedlib","script"),idx=0;idx=uris.length&&callback&&callback()}))}(currentUri,iframe),window.frames[iframeName].location.replace(currentUri)}else this.preCacheTest((function(){that.preCache(uris,callback)}));else callback&&callback()},GameWindow.prototype.clearCache=function(){this.cache={}},GameWindow.prototype.getElementById=GameWindow.prototype.gid=function(id){var el,frameDocument;return el=null,(frameDocument=this.getFrameDocument())&&frameDocument.getElementById&&(el=frameDocument.getElementById(id)),el||(el=document.getElementById(id)),el},GameWindow.prototype.getElementsByTagName=function(tag){var frameDocument;return(frameDocument=this.getFrameDocument())?frameDocument.getElementsByTagName(tag):document.getElementsByTagName(tag)},GameWindow.prototype.getElementsByClassName=function(className,tag){var doc;return doc=this.getFrameDocument()||document,J.getElementsByClassName(doc,className,tag)},GameWindow.prototype.loadFrame=function(uri,func,opts){var that,loadCache,storeCacheNow,storeCacheLater,scrollUp,autoParse,autoParsePrefix,autoParseMod,iframe,iframeName,iframeDocument,iframeWindow,frameDocumentElement,frameReady,lastURI;if("string"!=typeof uri)throw new TypeError("GameWindow.loadFrame: uri must be string. Found: "+uri);if(func&&"function"!=typeof func)throw new TypeError("GameWindow.loadFrame: func must be function or undefined. Found: "+func);if(opts&&"object"!=typeof opts)throw new TypeError("GameWindow.loadFrame: opts must be object or undefined. Found: "+opts);if(opts=opts||{},iframe=this.getFrame(),iframeName=this.frameName,!iframe)throw new Error("GameWindow.loadFrame: no frame found");if(!iframeName)throw new Error("GameWindow.loadFrame: frame has no name");if(this.setStateLevel("LOADING"),that=this,iframeWindow=iframe.contentWindow,frameReady="complete"===(frameReady=(iframeDocument=W.getIFrameDocument(iframe)).readyState),loadCache=GameWindow.defaults.cacheDefaults.loadCache,storeCacheNow=GameWindow.defaults.cacheDefaults.storeCacheNow,storeCacheLater=GameWindow.defaults.cacheDefaults.storeCacheLater,opts.cache){if(opts.cache.loadMode)if("reload"===opts.cache.loadMode)loadCache=!1;else{if("cache"!==opts.cache.loadMode)throw new Error("GameWindow.loadFrame: unkown cache load mode: "+opts.cache.loadMode);loadCache=!0}if(opts.cache.storeMode)if("off"===opts.cache.storeMode)storeCacheNow=!1,storeCacheLater=!1;else if("onLoad"===opts.cache.storeMode)storeCacheNow=!0,storeCacheLater=!1;else{if("onClose"!==opts.cache.storeMode)throw new Error("GameWindow.loadFrame: unkown cache store mode: "+opts.cache.storeMode);storeCacheNow=!1,storeCacheLater=!0}}if(void 0!==opts.autoParse){if("object"!=typeof opts.autoParse)throw new TypeError("GameWindow.loadFrame: opts.autoParse must be object or undefined. Found: "+opts.autoParse);if(void 0!==opts.autoParsePrefix){if("string"!=typeof opts.autoParsePrefix)throw new TypeError("GameWindow.loadFrame: opts.autoParsePrefix must be string or undefined. Found: "+opts.autoParsePrefix);autoParsePrefix=opts.autoParsePrefix}if(void 0!==opts.autoParseMod){if("string"!=typeof opts.autoParseMod)throw new TypeError("GameWindow.loadFrame: opts.autoParseMod must be string or undefined. Found: "+opts.autoParseMod);autoParseMod=opts.autoParseMod}autoParse=opts.autoParse}scrollUp=void 0===opts.scrollUp||opts.scrollUp,this.unprocessedUri=uri,null!==this.cacheSupported?(uri=this.processUri(uri),!1===this.cacheSupported?(storeCacheNow=!1,storeCacheLater=!1,loadCache=!1):(lastURI=this.currentURIs[iframeName],this.cache.hasOwnProperty(lastURI)&&this.cache[lastURI].cacheOnClose&&(frameDocumentElement=iframeDocument.documentElement,this.cache[lastURI].contents=frameDocumentElement.innerHTML),this.cache.hasOwnProperty(uri)||(this.cache[uri]={contents:null,cacheOnClose:!1}),this.cache[uri].cacheOnClose=storeCacheLater,null===this.cache[uri].contents&&(loadCache=!1)),this.currentURIs[iframeName]=uri,updateAreLoading(this,1),iframe.style.visibility="hidden",loadCache&&frameReady||onLoad(iframe,(function(){null===that.directFrameDocumentAccess&&function(that){try{that.frameDocument.getElementById("test"),that.directFrameDocumentAccess=!0}catch(e){that.directFrameDocumentAccess=!1}}(that),handleFrameLoad(that,uri,iframe,iframeName,loadCache,storeCacheNow,(function(){that.updateLoadFrameState(func,autoParse,autoParseMod,autoParsePrefix,scrollUp)}))})),loadCache?frameReady&&handleFrameLoad(this,uri,iframe,iframeName,loadCache,storeCacheNow,(function(){that.updateLoadFrameState(func,autoParse,autoParseMod,autoParsePrefix,scrollUp)})):iframeWindow.location.replace(uri),iframeWindow.node=node):this.preCacheTest((function(){that.loadFrame(uri,func,opts)}))},GameWindow.prototype.processUri=function(uri){return"/"!==uri.charAt(0)&&"http://"!==uri.substr(0,7)&&(this.uriPrefix&&(uri=this.uriPrefix+uri),this.uriChannel&&(uri=this.uriChannel+uri)),uri},GameWindow.prototype.updateLoadFrameState=function(func,autoParse,autoParseMod,autoParsePrefix,scrollUp){var loaded;(loaded=updateAreLoading(this,-1))&&this.setStateLevel("LOADED"),func&&func.call(node.game),autoParse&&this.searchReplace(autoParse,autoParseMod,autoParsePrefix),scrollUp&&window.scrollTo&&window.scrollTo(0,0),node.events.ee.game.emit("FRAME_LOADED"),node.events.ee.stage.emit("FRAME_LOADED"),node.events.ee.step.emit("FRAME_LOADED"),loaded?node.game.getStageLevel()===CB_EXECUTED&&node.emit("LOADED"):node.silly("game-window: "+this.areLoading+" frames still loading.")},GameWindow.prototype.clearPageBody=function(){this.reset(),document.body.innerHTML=""},GameWindow.prototype.clearPage=function(){this.reset();try{document.documentElement.innerHTML=""}catch(e){this.removeChildrenFromNode(document.documentElement)}},GameWindow.prototype.setUriPrefix=function(uriPrefix){if(null!==uriPrefix&&"string"!=typeof uriPrefix)throw new TypeError("GameWindow.setUriPrefix: uriPrefix must be string or null. Found: "+uriPrefix);this.conf.uriPrefix=this.uriPrefix=uriPrefix},GameWindow.prototype.setUriChannel=function(uriChannel){if("string"==typeof uriChannel)"/"!==uriChannel.charAt(0)&&(uriChannel="/"+uriChannel),"/"!==uriChannel.charAt(uriChannel.length-1)&&(uriChannel+="/");else if(null!==uriChannel)throw new TypeError("GameWindow.uriChannel: uriChannel must be string or null. Found: "+uriChannel);this.uriChannel=uriChannel},GameWindow.prototype.adjustFrameHeight=(adjustIt=function(userMinHeight){var iframe,minHeight,contentHeight;W.adjustHeaderOffset(),(iframe=W.getFrame())&&iframe.contentWindow&&(iframe.contentWindow.document.body?(!1===W.conf.adjustFrameHeight?minHeight="100vh":(minHeight=window.innerHeight||window.clientHeight,contentHeight=iframe.contentWindow.document.body.offsetHeight,contentHeight+=60,"top"===W.headerPosition&&(contentHeight+=W.headerOffset),minHeightDo not refresh the page!
Maximum Waiting Time: ",countdownResuming:opts.countdownResumingText||"Resuming soon...",formatCountdown:function(time){var out;return out="",(time=J.parseMilliseconds(time))[2]&&(out+=time[2]+" min "),time[3]&&(out+=time[3]+" sec"),out||0}},this.lockedInputs=[],this.enable()}exports.WaitScreen=WaitScreen,WaitScreen.version="0.10.0",WaitScreen.description="Shows a waiting screen",len=(inputTags=["button","select","textarea","input"]).length,WaitScreen.prototype.enable=function(){this.enabled||(node.events.ee.game.on("REALLY_DONE",event_REALLY_DONE),node.events.ee.game.on("STEPPING",event_STEPPING),node.events.ee.game.on("PLAYING",event_PLAYING),node.events.ee.game.on("PAUSED",event_PAUSED),node.events.ee.game.on("RESUMED",event_RESUMED),this.enabled=!0)},WaitScreen.prototype.disable=function(){this.enabled&&(node.events.ee.game.off("REALLY_DONE",event_REALLY_DONE),node.events.ee.game.off("STEPPING",event_STEPPING),node.events.ee.game.off("PLAYING",event_PLAYING),node.events.ee.game.off("PAUSED",event_PAUSED),node.events.ee.game.off("RESUMED",event_RESUMED),this.enabled=!1)},WaitScreen.prototype.lock=function(text,countdown){var frameDoc,t;t=this.defaultTexts,void 0===text&&(text=t.locked),void 0===document.getElementsByTagName&&node.warn("WaitScreen.lock: cannot lock inputs"),lockUnlockedInputs(document),(frameDoc=W.getFrameDocument())&&lockUnlockedInputs(frameDoc),this.waitingDiv||(this.root||(this.root=W.getFrameRoot()||document.body),this.waitingDiv=W.add("div",this.root,this.id),this.contentDiv=W.add("div",this.waitingDiv,"ng_waitscreen-content-div")),"none"===this.waitingDiv.style.display&&(this.waitingDiv.style.display=""),this.contentDiv.innerHTML=text,this.displayCountdown&&countdown?(this.countdownDiv||(this.countdownDiv=W.add("div",this.waitingDiv,"ng_waitscreen-countdown-div"),this.countdownDiv.innerHTML=t.countdown,this.countdownSpan=W.add("span",this.countdownDiv,"ng_waitscreen-countdown-span")),this.countdown=countdown,this.countdownSpan.innerHTML=t.formatCountdown(countdown),this.countdownDiv.style.display="",this.countdownInterval=setInterval((function(){var w;w=W.waitScreen,W.isScreenLocked()?(w.countdown-=1e3,w.countdown<0?(clearInterval(w.countdownInterval),w.countdownDiv.style.display="none",w.contentDiv.innerHTML=t.countdownResuming):w.countdownSpan.innerHTML=t.formatCountdown(w.countdown)):clearInterval(w.countdownInterval)}),1e3)):this.countdownDiv&&(this.countdownDiv.style.display="none")},WaitScreen.prototype.unlock=function(){var i,len;this.waitingDiv&&""===this.waitingDiv.style.display&&(this.waitingDiv.style.display="none"),this.countdownInterval&&clearInterval(this.countdownInterval);try{for(len=this.lockedInputs.length,i=-1;++i2&&(mod=arguments[1],prefix=arguments[2]),void 0===prefix)prefix="ng_replace_";else if(null===prefix)prefix="";else if("string"!=typeof prefix)throw new TypeError("GameWindow.searchReplace: prefix must be string, null or undefined. Found: "+prefix);if(elements=arguments[0],J.isArray(elements))for(i=-1,len=elements.length;++io2.dt)return-1}else{if(o1.dto2.dt)return 1}if(o1.dt===o2.dt){if(void 0===o1.dd)return-1;if(void 0===o2.dd)return 1;if(o1.ddo2.dd)return 1;if(o1.nddbido2.nddbid)return-1}return 0},this.DL=options.list||document.createElement(this.FIRST_LEVEL),this.DL.id=options.id||this.id,options.className&&(this.DL.className=options.className),this.options.title&&this.DL.appendChild(document.createTextNode(options.title)),this.htmlRenderer=new HTMLRenderer(options.render)},List.prototype._add=function(node){node&&(this.insert(node),this.auto_update&&this.parse())},List.prototype.addDT=function(elem,dt){if(void 0!==elem){this.last_dt++,dt=void 0!==dt?dt:this.last_dt,this.last_dd=0;var node=new Node({dt:dt,content:elem});return this._add(node)}},List.prototype.addDD=function(elem,dt,dd){if(void 0!==elem){var node=new Node({dt:dt=void 0!==dt?dt:this.last_dt,dd:dd=void 0!==dd?dd:this.last_dd++,content:elem});return this._add(node)}},List.prototype.parse=function(){this.sort();var appendDT=function(){var node=document.createElement(this.SECOND_LEVEL);return this.DL.appendChild(node),null,node,node},appendDD=function(){var node=document.createElement(this.THIRD_LEVEL);return this.DL.appendChild(node),node};if(this.DL){for(;this.DL.hasChildNodes();)this.DL.removeChild(this.DL.firstChild);this.options.title&&this.DL.appendChild(document.createTextNode(this.options.title))}for(var i=0;ithis.pointers[pointer])&&(this.pointers[pointer]=value),this.pointers[pointer]},Table.prototype.addMultiple=function(data,dim,x,y){var i,lenI,j,lenJ;if(validateInput("addMultiple",data,x,y),dim&&"string"!=typeof dim||dim&&void 0===this.pointers[dim])throw new TypeError("Table.addMultiple: dim must be a valid dimension (x or y) or undefined.");for(dim=dim||"x",x=this.getCurrPointer("x",x),y=this.getNextPointer("y",y),x=void 0!==x?x:null===this.pointers.x?0:this.pointers.x,y=void 0!==y?y:null===this.pointers.y?0:this.pointers.y,J.isArray(data)||(data=[data]),i=-1,lenI=data.length;++iold_y+1)for(diff=this.db[i].y-(old_y+1),j=0;j1&&(right=getPxNum((lastDocked=ws.docked[ws.docked.length-2]).panelDiv.style.right),right+=lastDocked.panelDiv.offsetWidth),right+=20,w.panelDiv.style.right=right+"px",tmp=0,right+=w.panelDiv.offsetWidth+200;ws.docked.length>1&&right>window.innerWidth&&tmp1&&(str+=''+(w.senderToNameMap[data.id]||data.id)+": "),str+=data.msg+""},quit:function(w,data){return(w.senderToNameMap[data.id]||data.id)+" left the chat"},noMoreParticipants:function(){return"No active participant left. Chat disabled."},collapse:function(w,data){return(w.senderToNameMap[data.id]||data.id)+" "+(data.collapsed?"mini":"maxi")+"mized the chat"},textareaPlaceholder:function(w){return w.useSubmitEnter?"Type something and press enter to send":"Type something"},submitButton:"Send",isTyping:"is typing..."},Chat.version="1.5.0",Chat.description="Offers a uni-/bi-directional communication interface between players, or between players and the server.",Chat.title="Chat",Chat.className="chat",Chat.panel=!1,Chat.dependencies={JSUS:{}},Chat.prototype.init=function(opts){var tmp,i,rec,sender,that;if(opts=opts||{},that=this,this.receiverOnly=!!opts.receiverOnly,"function"==typeof(tmp=opts.preprocessMsg))this.preprocessMsg=tmp;else if(tmp)throw new TypeError("Chat.init: preprocessMsg must be function or undefined. Found: "+tmp);if(tmp=opts.chatEvent){if("string"!=typeof tmp)throw new TypeError("Chat.init: chatEvent must be a non-empty string or undefined. Found: "+tmp);this.chatEvent=opts.chatEvent}else this.chatEvent="CHAT";if(this.storeMsgs=!!opts.storeMsgs,this.storeMsgs&&(this.db||(this.db=new NDDB)),this.useSubmitButton=void 0===opts.useSubmitButton?J.isMobileAgent():!!opts.useSubmitButton,this.useSubmitEnter=void 0===opts.useSubmitEnter||!!opts.useSubmitEnter,tmp=opts.participants,!J.isArray(tmp)||!tmp.length)throw new TypeError("Chat.init: participants must be a non-empty array. Found: "+tmp);for(this.recipientsIds=new Array(tmp.length),this.recipientsIdsQuitted=[],this.recipientToSenderMap={},this.recipientToNameMap={},this.senderToNameMap={},this.senderToRecipientMap={},i=0;i"+this.title+""),this.stats.unread++)),!0)},Chat.prototype.disable=function(){this.submitButton&&(this.submitButton.disabled=!0),this.textarea.disabled=!0,this.disabled=!0},Chat.prototype.enable=function(){this.submitButton&&(this.submitButton.disabled=!1),this.textarea.disabled=!1,this.disabled=!1},Chat.prototype.getValues=function(){var out;return out={participants:this.participants,totSent:this.stats.sent,totReceived:this.stats.received,totUnread:this.stats.unread,initialMsg:this.initialMsg},this.db&&(out.msgs=this.db.fetch()),out},Chat.prototype.sendMsg=function(opts){var to,ids,that;if(this.isDisabled())node.warn("Chat is disable, msg not sent.");else{if("object"==typeof opts){if(void 0!==opts.msg&&"object"==typeof opts.msg)throw new TypeError("Chat.sendMsg: opts.msg cannot be object. Found: "+opts.msg)}else if(void 0===opts)opts={msg:this.readTextarea()};else{if("string"!=typeof opts&&"number"!=typeof opts)throw new TypeError("Chat.sendMsg: opts must be string, number, object, or undefined. Found: "+opts);opts={msg:opts}}opts.msg=this.renderMsg(opts,"outgoing"),""!==opts.msg?0!==(ids=opts.recipients||this.recipientsIds).length?(to=1===ids.length?ids[0]:ids,node.say(this.chatEvent,to,opts),opts.silent||(that=this,this.writeMsg("outgoing",opts),that.textarea&&setTimeout((function(){that.textarea.value=""}))),this.amTypingTimeout&&(clearTimeout(this.amTypingTimeout),this.amTypingTimeout=null)):node.warn("Chat: empty recipient list, message not sent."):node.warn("Chat: message has no text, not sent.")}}}(node),function(node){"use strict";var Table=W.Table;function ChernoffFaces(options){var that=this;this.options=null,this.table=null,this.sc=null,this.fp=null,this.canvas=null,this.changes=[],this.onChange=null,this.onChangeCb=function(f,updateControls){void 0===updateControls&&(updateControls=!1),f||(f=that.sc?that.sc.getValues():FaceVector.random()),that.draw(f,updateControls)},this.timeFrom="step",this.features=null}function FacePainter(canvas,settings){this.canvas=new W.Canvas(canvas),this.scaleX=canvas.width/ChernoffFaces.width,this.scaleY=canvas.height/ChernoffFaces.heigth,this.face=null}function FaceVector(faceVector,defaults){var key;if(void 0===faceVector)for(key in FaceVector.defaults)FaceVector.defaults.hasOwnProperty(key)&&("color"===key?this.color="red":"lineWidth"===key?this.lineWidth=1:"scaleX"===key?this.scaleX=1:"scaleY"===key?this.scaleY=1:this[key]=FaceVector.defaults[key].min+Math.random()*FaceVector.defaults[key].range);else{if("object"!=typeof faceVector)throw new TypeError("FaceVector constructor: faceVector must be object or undefined.");for(key in this.scaleX=faceVector.scaleX||1,this.scaleY=faceVector.scaleY||1,this.color=faceVector.color||"green",this.lineWidth=faceVector.lineWidth||1,defaults=defaults||FaceVector.defaults)defaults.hasOwnProperty(key)&&(faceVector.hasOwnProperty(key)?this[key]=faceVector[key]:this[key]=defaults?defaults[key]:FaceVector.defaults[key].value)}}node.widgets.register("ChernoffFaces",ChernoffFaces),ChernoffFaces.version="0.6.2",ChernoffFaces.description="Display parametric data in the form of a Chernoff Face.",ChernoffFaces.title="ChernoffFaces",ChernoffFaces.className="chernofffaces",ChernoffFaces.dependencies={JSUS:{},Table:{},Canvas:{},SliderControls:{}},ChernoffFaces.FaceVector=FaceVector,ChernoffFaces.FacePainter=FacePainter,ChernoffFaces.width=100,ChernoffFaces.height=100,ChernoffFaces.onChange="CF_CHANGE",ChernoffFaces.prototype.init=function(options){this.options=options,options.features?this.features=new FaceVector(options.features):this.features||(this.features=FaceVector.random()),this.fp&&this.fp.draw(this.features),!1===options.onChange||null===options.onChange?this.onChange&&(node.off(this.onChange,this.onChangeCb),this.onChange=null):(this.onChange=void 0===options.onChange?ChernoffFaces.onChange:options.onChange,node.on(this.onChange,this.onChangeCb))},ChernoffFaces.prototype.getCanvas=function(){return this.canvas},ChernoffFaces.prototype.buildHTML=function(){var controlsOptions,tblOptions,options;this.table||(options=this.options,tblOptions={},this.id&&(tblOptions.id=this.id),"string"==typeof options.className?tblOptions.className=options.className:!1!==options.className&&(tblOptions.className="cf_table"),this.table=new Table(tblOptions),this.canvas||this.buildCanvas(),(void 0===options.controls||options.controls)&&(controlsOptions={id:"cf_controls",features:J.mergeOnKey(FaceVector.defaults,this.features,"value"),onChange:this.onChange,submit:"Send"},"object"==typeof options.controls?this.sc=options.controls:this.sc=node.widgets.get("SliderControls",controlsOptions)),this.sc?this.table.addRow([{content:this.sc,id:this.id+"_td_controls"},{content:this.canvas,id:this.id+"_td_cf"}]):this.table.add({content:this.canvas,id:this.id+"_td_cf"}),this.table.parse())},ChernoffFaces.prototype.buildCanvas=function(){var options;this.canvas||((options=this.options).canvas||(options.canvas={},void 0!==options.height&&(options.canvas.height=options.height),void 0!==options.width&&(options.canvas.width=options.width)),this.canvas=W.get("canvas",options.canvas),this.canvas.id="ChernoffFaces_canvas",this.fp=new FacePainter(this.canvas),this.fp.draw(this.features))},ChernoffFaces.prototype.append=function(){this.table||this.buildHTML(),this.bodyDiv.appendChild(this.table.table)},ChernoffFaces.prototype.draw=function(features,updateControls){var time;if("object"!=typeof features)throw new TypeError("ChernoffFaces.draw: features must be object.");this.options.trackChanges&&(time="string"==typeof this.timeFrom?node.timer.getTimeSince(this.timeFrom):Date.now?Date.now():(new Date).getTime(),this.changes.push({time:time,change:features})),this.features=features instanceof FaceVector?features:new FaceVector(features,this.features),this.fp.redraw(this.features),this.sc&&!1!==updateControls&&(this.sc.init({features:J.mergeOnKey(FaceVector.defaults,features,"value")}),this.sc.refresh())},ChernoffFaces.prototype.getValues=function(options){return options&&options.changes?{changes:this.changes,cf:this.features}:this.fp.face},ChernoffFaces.prototype.randomize=function(){var fv;return fv=FaceVector.random(),this.fp.redraw(fv),this.sc&&(this.sc.init({features:J.mergeOnValue(FaceVector.defaults,fv),onChange:this.onChange}),this.sc.refresh()),!0},FacePainter.prototype.draw=function(face,x,y){face&&(this.face=face,this.fit2Canvas(face),this.canvas.scale(face.scaleX,face.scaleY),x=x||this.canvas.centerX,y=y||this.canvas.centerY,this.drawHead(face,x,y),this.drawEyes(face,x,y),this.drawPupils(face,x,y),this.drawEyebrow(face,x,y),this.drawNose(face,x,y),this.drawMouth(face,x,y))},FacePainter.prototype.redraw=function(face,x,y){this.canvas.clear(),this.draw(face,x,y)},FacePainter.prototype.scale=function(x,y){this.canvas.scale(this.scaleX,this.scaleY)},FacePainter.prototype.fit2Canvas=function(face){var ratio;this.canvas?(ratio=this.canvas.width>this.canvas.height?this.canvas.width/face.head_radius*face.head_scale_x:this.canvas.height/face.head_radius*face.head_scale_y,face.scaleX=ratio/2,face.scaleY=ratio/2):console.log("No canvas found")},FacePainter.prototype.drawHead=function(face,x,y){var radius=face.head_radius;this.canvas.drawOval({x:x,y:y,radius:radius,scale_x:face.head_scale_x,scale_y:face.head_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawEyes=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.eye_height,y),spacing=face.eye_spacing,radius=face.eye_radius;this.canvas.drawOval({x:x-spacing,y:height,radius:radius,scale_x:face.eye_scale_x,scale_y:face.eye_scale_y,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawOval({x:x+spacing,y:height,radius:radius,scale_x:face.eye_scale_x,scale_y:face.eye_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawPupils=function(face,x,y){var radius=face.pupil_radius,spacing=face.eye_spacing,height=FacePainter.computeFaceOffset(face,face.eye_height,y);this.canvas.drawOval({x:x-spacing,y:height,radius:radius,scale_x:face.pupil_scale_x,scale_y:face.pupil_scale_y,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawOval({x:x+spacing,y:height,radius:radius,scale_x:face.pupil_scale_x,scale_y:face.pupil_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawEyebrow=function(face,x,y){var height=FacePainter.computeEyebrowOffset(face,y),spacing=face.eyebrow_spacing,length=face.eyebrow_length,angle=face.eyebrow_angle;this.canvas.drawLine({x:x-spacing,y:height,length:length,angle:angle,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawLine({x:x+spacing,y:height,length:0-length,angle:-angle,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawNose=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.nose_height,y),nastril_r_x=x+face.nose_width/2,nastril_r_y=height+face.nose_length,nastril_l_x=nastril_r_x-face.nose_width,nastril_l_y=nastril_r_y;this.canvas.ctx.lineWidth=face.lineWidth,this.canvas.ctx.strokeStyle=face.color,this.canvas.ctx.save(),this.canvas.ctx.beginPath(),this.canvas.ctx.moveTo(x,height),this.canvas.ctx.lineTo(nastril_r_x,nastril_r_y),this.canvas.ctx.lineTo(nastril_l_x,nastril_l_y),this.canvas.ctx.stroke(),this.canvas.ctx.restore()},FacePainter.prototype.drawMouth=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.mouth_height,y),startX=x-face.mouth_width/2,endX=x+face.mouth_width/2,top_y=height-face.mouth_top_y,bottom_y=height+face.mouth_bottom_y;this.canvas.ctx.moveTo(startX,height),this.canvas.ctx.quadraticCurveTo(x,top_y,endX,height),this.canvas.ctx.stroke(),this.canvas.ctx.moveTo(startX,height),this.canvas.ctx.quadraticCurveTo(x,bottom_y,endX,height),this.canvas.ctx.stroke()},FacePainter.computeFaceOffset=function(face,offset,y){return(y=y||0)-face.head_radius+2*face.head_radius*offset},FacePainter.computeEyebrowOffset=function(face,y){y=y||0;return FacePainter.computeFaceOffset(face,face.eye_height,y)-2-face.eyebrow_eyedistance},FaceVector.defaults={head_radius:{min:10,max:100,step:.01,value:30,label:"Face radius"},head_scale_x:{min:.2,max:2,step:.01,value:.5,label:"Scale head horizontally"},head_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale head vertically"},eye_height:{min:.1,max:.9,step:.01,value:.4,label:"Eye height"},eye_radius:{min:2,max:30,step:.01,value:5,label:"Eye radius"},eye_spacing:{min:0,max:50,step:.01,value:10,label:"Eye spacing"},eye_scale_x:{min:.2,max:2,step:.01,value:1,label:"Scale eyes horizontally"},eye_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale eyes vertically"},pupil_radius:{min:1,max:9,step:.01,value:1,label:"Pupil radius"},pupil_scale_x:{min:.2,max:2,step:.01,value:1,label:"Scale pupils horizontally"},pupil_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale pupils vertically"},eyebrow_length:{min:1,max:30,step:.01,value:10,label:"Eyebrow length"},eyebrow_eyedistance:{min:.3,max:10,step:.01,value:3,label:"Eyebrow from eye"},eyebrow_angle:{min:-2,max:2,step:.01,value:-.5,label:"Eyebrow angle"},eyebrow_spacing:{min:0,max:20,step:.01,value:5,label:"Eyebrow spacing"},nose_height:{min:.4,max:1,step:.01,value:.4,label:"Nose height"},nose_length:{min:.2,max:30,step:.01,value:15,label:"Nose length"},nose_width:{min:0,max:30,step:.01,value:10,label:"Nose width"},mouth_height:{min:.2,max:2,step:.01,value:.75,label:"Mouth height"},mouth_width:{min:2,max:100,step:.01,value:20,label:"Mouth width"},mouth_top_y:{min:-10,max:30,step:.01,value:-2,label:"Upper lip"},mouth_bottom_y:{min:-10,max:30,step:.01,value:20,label:"Lower lip"},scaleX:{min:0,max:20,step:.01,value:.2,label:"Scale X"},scaleY:{min:0,max:20,step:.01,value:.2,label:"Scale Y"},color:{min:0,max:20,step:.01,value:.2,label:"color"},lineWidth:{min:0,max:20,step:.01,value:.2,label:"lineWidth"}},function(defaults){var key;for(key in defaults)defaults.hasOwnProperty(key)&&(defaults[key].range=defaults[key].max-defaults[key].min)}(FaceVector.defaults),FaceVector.random=function(){return console.log("*** FaceVector.random is deprecated. Use new FaceVector() instead."),new FaceVector}}(node),function(node){"use strict";var Table=W.Table;function ChernoffFaces(options){this.options=options,this.id=options.id,this.table=new Table({id:"cf_table"}),this.root=options.root||document.createElement("div"),this.root.id=this.id,this.sc=node.widgets.get("Controls.Slider"),this.fp=null,this.canvas=null,this.dims=null,this.change="CF_CHANGE";var that=this;this.changeFunc=function(){that.draw(that.sc.getAllValues())},this.features=null,this.controls=null}function FacePainter(canvas,settings){this.canvas=new W.Canvas(canvas),this.scaleX=canvas.width/ChernoffFaces.defaults.canvas.width,this.scaleY=canvas.height/ChernoffFaces.defaults.canvas.heigth}function FaceVector(faceVector){for(var key in faceVector=faceVector||{},this.scaleX=faceVector.scaleX||1,this.scaleY=faceVector.scaleY||1,this.color=faceVector.color||"green",this.lineWidth=faceVector.lineWidth||1,FaceVector.defaults)FaceVector.defaults.hasOwnProperty(key)&&(faceVector.hasOwnProperty(key)?this[key]=faceVector[key]:this[key]=FaceVector.defaults[key].value)}node.widgets.register("ChernoffFacesSimple",ChernoffFaces),ChernoffFaces.defaults={},ChernoffFaces.defaults.id="ChernoffFaces",ChernoffFaces.defaults.canvas={},ChernoffFaces.defaults.canvas.width=100,ChernoffFaces.defaults.canvas.heigth=100,ChernoffFaces.version="0.4",ChernoffFaces.description="Display parametric data in the form of a Chernoff Face.",ChernoffFaces.dependencies={JSUS:{},Table:{},Canvas:{},"Controls.Slider":{}},ChernoffFaces.FaceVector=FaceVector,ChernoffFaces.FacePainter=FacePainter,ChernoffFaces.prototype.init=function(options){this.id=options.id||this.id;var PREF=this.id+"_";this.features=options.features||this.features||FaceVector.random(),this.controls=void 0===options.controls||options.controls;var idCanvas=options.idCanvas?options.idCanvas:PREF+"canvas";this.dims={width:options.width?options.width:ChernoffFaces.defaults.canvas.width,height:options.height?options.height:ChernoffFaces.defaults.canvas.heigth},this.canvas=W.getCanvas(idCanvas,this.dims),this.fp=new FacePainter(this.canvas),this.fp.draw(new FaceVector(this.features));var sc_options={id:"cf_controls",features:J.mergeOnKey(FaceVector.defaults,this.features,"value"),change:this.change,fieldset:{id:this.id+"_controls_fieldest",legend:this.controls.legend||"Controls"},submit:"Send"};this.sc=node.widgets.get("Controls.Slider",sc_options),this.controls&&this.table.add(this.sc),void 0===options.change?node.on(this.change,this.changeFunc):(options.change?node.on(options.change,this.changeFunc):node.removeListener(this.change,this.changeFunc),this.change=options.change),this.table.add(this.canvas),this.table.parse(),this.root.appendChild(this.table.table)},ChernoffFaces.prototype.getRoot=function(){return this.root},ChernoffFaces.prototype.getCanvas=function(){return this.canvas},ChernoffFaces.prototype.append=function(root){return root.appendChild(this.root),this.table.parse(),this.root},ChernoffFaces.prototype.listeners=function(){},ChernoffFaces.prototype.draw=function(features){if(features){var fv=new FaceVector(features);this.fp.redraw(fv),this.sc.init({features:J.mergeOnKey(FaceVector.defaults,features,"value")}),this.sc.refresh()}},ChernoffFaces.prototype.getAllValues=function(){return this.fp.face},ChernoffFaces.prototype.randomize=function(){var fv=FaceVector.random();this.fp.redraw(fv);var sc_options={features:J.mergeOnKey(FaceVector.defaults,fv,"value"),change:this.change};return this.sc.init(sc_options),this.sc.refresh(),!0},FacePainter.prototype.draw=function(face,x,y){face&&(this.face=face,this.fit2Canvas(face),this.canvas.scale(face.scaleX,face.scaleY),x=x||this.canvas.centerX,y=y||this.canvas.centerY,this.drawHead(face,x,y),this.drawEyes(face,x,y),this.drawPupils(face,x,y),this.drawEyebrow(face,x,y),this.drawNose(face,x,y),this.drawMouth(face,x,y))},FacePainter.prototype.redraw=function(face,x,y){this.canvas.clear(),this.draw(face,x,y)},FacePainter.prototype.scale=function(x,y){this.canvas.scale(this.scaleX,this.scaleY)},FacePainter.prototype.fit2Canvas=function(face){var ratio;this.canvas?(ratio=this.canvas.width>this.canvas.height?this.canvas.width/face.head_radius*face.head_scale_x:this.canvas.height/face.head_radius*face.head_scale_y,face.scaleX=ratio/2,face.scaleY=ratio/2):console.log("No canvas found")},FacePainter.prototype.drawHead=function(face,x,y){var radius=face.head_radius;this.canvas.drawOval({x:x,y:y,radius:radius,scale_x:face.head_scale_x,scale_y:face.head_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawEyes=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.eye_height,y),spacing=face.eye_spacing,radius=face.eye_radius;this.canvas.drawOval({x:x-spacing,y:height,radius:radius,scale_x:face.eye_scale_x,scale_y:face.eye_scale_y,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawOval({x:x+spacing,y:height,radius:radius,scale_x:face.eye_scale_x,scale_y:face.eye_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawPupils=function(face,x,y){var radius=face.pupil_radius,spacing=face.eye_spacing,height=FacePainter.computeFaceOffset(face,face.eye_height,y);this.canvas.drawOval({x:x-spacing,y:height,radius:radius,scale_x:face.pupil_scale_x,scale_y:face.pupil_scale_y,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawOval({x:x+spacing,y:height,radius:radius,scale_x:face.pupil_scale_x,scale_y:face.pupil_scale_y,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawEyebrow=function(face,x,y){var height=FacePainter.computeEyebrowOffset(face,y),spacing=face.eyebrow_spacing,length=face.eyebrow_length,angle=face.eyebrow_angle;this.canvas.drawLine({x:x-spacing,y:height,length:length,angle:angle,color:face.color,lineWidth:face.lineWidth}),this.canvas.drawLine({x:x+spacing,y:height,length:0-length,angle:-angle,color:face.color,lineWidth:face.lineWidth})},FacePainter.prototype.drawNose=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.nose_height,y),nastril_r_x=x+face.nose_width/2,nastril_r_y=height+face.nose_length,nastril_l_x=nastril_r_x-face.nose_width,nastril_l_y=nastril_r_y;this.canvas.ctx.lineWidth=face.lineWidth,this.canvas.ctx.strokeStyle=face.color,this.canvas.ctx.save(),this.canvas.ctx.beginPath(),this.canvas.ctx.moveTo(x,height),this.canvas.ctx.lineTo(nastril_r_x,nastril_r_y),this.canvas.ctx.lineTo(nastril_l_x,nastril_l_y),this.canvas.ctx.stroke(),this.canvas.ctx.restore()},FacePainter.prototype.drawMouth=function(face,x,y){var height=FacePainter.computeFaceOffset(face,face.mouth_height,y),startX=x-face.mouth_width/2,endX=x+face.mouth_width/2,top_y=height-face.mouth_top_y,bottom_y=height+face.mouth_bottom_y;this.canvas.ctx.moveTo(startX,height),this.canvas.ctx.quadraticCurveTo(x,top_y,endX,height),this.canvas.ctx.stroke(),this.canvas.ctx.moveTo(startX,height),this.canvas.ctx.quadraticCurveTo(x,bottom_y,endX,height),this.canvas.ctx.stroke()},FacePainter.computeFaceOffset=function(face,offset,y){return(y=y||0)-face.head_radius+2*face.head_radius*offset},FacePainter.computeEyebrowOffset=function(face,y){y=y||0;return FacePainter.computeFaceOffset(face,face.eye_height,y)-2-face.eyebrow_eyedistance}, +/*! + * + * A description of a Chernoff Face. + * + * This class packages the 11-dimensional vector of numbers from 0 through + * 1 that completely describe a Chernoff face. + * + */ +FaceVector.defaults={head_radius:{min:10,max:100,step:.01,value:30,label:"Face radius"},head_scale_x:{min:.2,max:2,step:.01,value:.5,label:"Scale head horizontally"},head_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale head vertically"},eye_height:{min:.1,max:.9,step:.01,value:.4,label:"Eye height"},eye_radius:{min:2,max:30,step:.01,value:5,label:"Eye radius"},eye_spacing:{min:0,max:50,step:.01,value:10,label:"Eye spacing"},eye_scale_x:{min:.2,max:2,step:.01,value:1,label:"Scale eyes horizontally"},eye_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale eyes vertically"},pupil_radius:{min:1,max:9,step:.01,value:1,label:"Pupil radius"},pupil_scale_x:{min:.2,max:2,step:.01,value:1,label:"Scale pupils horizontally"},pupil_scale_y:{min:.2,max:2,step:.01,value:1,label:"Scale pupils vertically"},eyebrow_length:{min:1,max:30,step:.01,value:10,label:"Eyebrow length"},eyebrow_eyedistance:{min:.3,max:10,step:.01,value:3,label:"Eyebrow from eye"},eyebrow_angle:{min:-2,max:2,step:.01,value:-.5,label:"Eyebrow angle"},eyebrow_spacing:{min:0,max:20,step:.01,value:5,label:"Eyebrow spacing"},nose_height:{min:.4,max:1,step:.01,value:.4,label:"Nose height"},nose_length:{min:.2,max:30,step:.01,value:15,label:"Nose length"},nose_width:{min:0,max:30,step:.01,value:10,label:"Nose width"},mouth_height:{min:.2,max:2,step:.01,value:.75,label:"Mouth height"},mouth_width:{min:2,max:100,step:.01,value:20,label:"Mouth width"},mouth_top_y:{min:-10,max:30,step:.01,value:-2,label:"Upper lip"},mouth_bottom_y:{min:-10,max:30,step:.01,value:20,label:"Lower lip"}},FaceVector.random=function(){var out={};for(var key in FaceVector.defaults)FaceVector.defaults.hasOwnProperty(key)&&(J.inArray(key,["color","lineWidth","scaleX","scaleY"])||(out[key]=FaceVector.defaults[key].min+Math.random()*FaceVector.defaults[key].max));return out.scaleX=1,out.scaleY=1,out.color="green",out.lineWidth=1,new FaceVector(out)},FaceVector.prototype.shuffle=function(){for(var key in this)this.hasOwnProperty(key)&&FaceVector.defaults.hasOwnProperty(key)&&"color"!==key&&(this[key]=FaceVector.defaults[key].min+Math.random()*FaceVector.defaults[key].max)},FaceVector.prototype.distance=function(face){return FaceVector.distance(this,face)},FaceVector.distance=function(face1,face2){var diff,sum=0;for(var key in face1)face1.hasOwnProperty(key)&&(sum+=(diff=face1[key]-face2[key])*diff);return Math.sqrt(sum)},FaceVector.prototype.toString=function(){var out="Face: ";for(var key in this)this.hasOwnProperty(key)&&(out+=key+" "+this[key]);return out}}(node),function(node){"use strict";function ChoiceManager(){this.dl=null,this.mainText=null,this.spanMainText=null,this.forms=null,this.formsById=null,this.order=null,this.shuffleForms=null,this.group=null,this.groupOrder=null,this.formsOptions={title:!1,frame:!1,storeRef:!1},this.simplify=null,this.freeText=null,this.textarea=null,this.required=null}node.widgets.register("ChoiceManager",ChoiceManager),ChoiceManager.version="1.4.1",ChoiceManager.description="Groups together and manages a set of survey forms (e.g., ChoiceTable).",ChoiceManager.title=!1,ChoiceManager.className="choicemanager",ChoiceManager.dependencies={},ChoiceManager.prototype.init=function(options){var tmp;if(tmp=void 0!==options.shuffleForms&&!!options.shuffleForms,this.shuffleForms=tmp,"string"==typeof options.group||"number"==typeof options.group)this.group=options.group;else if(void 0!==options.group)throw new TypeError("ChoiceManager.init: options.group must be string, number or undefined. Found: "+options.group);if("number"==typeof options.groupOrder)this.groupOrder=options.groupOrder;else if(void 0!==options.group)throw new TypeError("ChoiceManager.init: options.groupOrder must be number or undefined. Found: "+options.groupOrder);if("string"==typeof options.mainText)this.mainText=options.mainText;else if(void 0!==options.mainText)throw new TypeError("ChoiceManager.init: options.mainText must be string or undefined. Found: "+options.mainText);if(void 0!==options.formsOptions){if("object"!=typeof options.formsOptions)throw new TypeError("ChoiceManager.init: options.formsOptions must be object or undefined. Found: "+options.formsOptions);if(options.formsOptions.hasOwnProperty("name"))throw new Error("ChoiceManager.init: options.formsOptions cannot contain property name. Found: "+options.formsOptions);this.formsOptions=J.mixin(this.formsOptions,options.formsOptions)}this.freeText="string"==typeof options.freeText?options.freeText:!!options.freeText,void 0!==options.required&&(this.required=!!options.required),this.simplify=!!options.simplify,void 0!==options.forms&&this.setForms(options.forms)},ChoiceManager.prototype.setForms=function(forms){var form,formsById,i,len,parsedForms,name;if("function"==typeof forms){if(parsedForms=forms.call(node.game),!J.isArray(parsedForms))throw new TypeError("ChoiceManager.setForms: forms is a callback, but did not returned an array. Found: "+parsedForms)}else{if(!J.isArray(forms))throw new TypeError("ChoiceManager.setForms: forms must be array or function. Found: "+forms);parsedForms=forms}if(!(len=parsedForms.length))throw new Error("ChoiceManager.setForms: forms is an empty array.");for(formsById={},forms=new Array(len),i=-1;++i 1. Found: "+tmp);if(this.selectMultiple=tmp,tmp&&(this.selected=[],this.currentChoice=[]),"number"==typeof opts.requiredChoice){if(!J.isInt(opts.requiredChoice,0))throw new Error("ChoiceTable.init: if number, requiredChoice must a positive integer. Found: "+opts.requiredChoice);if("number"==typeof this.selectMultiple&&opts.requiredChoice>this.selectMultiple)throw new Error("ChoiceTable.init: requiredChoice cannot be larger than selectMultiple. Found: "+opts.requiredChoice+" > "+this.selectMultiple);this.requiredChoice=opts.requiredChoice}else if("boolean"==typeof opts.requiredChoice)this.requiredChoice=opts.requiredChoice?1:null;else if(void 0!==opts.requiredChoice)throw new TypeError("ChoiceTable.init: opts.requiredChoice be number, boolean or undefined. Found: "+opts.requiredChoice);if(void 0!==opts.oneTimeClick&&(this.oneTimeClick=!!opts.oneTimeClick),"string"==typeof opts.group||"number"==typeof opts.group)this.group=opts.group;else if(void 0!==opts.group)throw new TypeError("ChoiceTable.init: opts.group must be string, number or undefined. Found: "+opts.group);if("number"==typeof opts.groupOrder)this.groupOrder=opts.groupOrder;else if(void 0!==opts.groupOrder)throw new TypeError("ChoiceTable.init: opts.groupOrder must be number or undefined. Found: "+opts.groupOrder);if("function"==typeof opts.listener)this.listener=function(e){opts.listener.call(this,e)};else if(void 0!==opts.listener)throw new TypeError("ChoiceTable.init: opts.listener must be function or undefined. Found: "+opts.listener);if("function"==typeof opts.onclick)this.onclick=opts.onclick;else if(void 0!==opts.onclick)throw new TypeError("ChoiceTable.init: opts.onclick must be function or undefined. Found: "+opts.onclick);if("string"==typeof opts.mainText)this.mainText=opts.mainText;else if(void 0!==opts.mainText)throw new TypeError("ChoiceTable.init: opts.mainText must be string or undefined. Found: "+opts.mainText);if("string"==typeof opts.hint||!1===opts.hint)this.hint=opts.hint,this.requiredChoice&&(this.hint+=" *");else{if(void 0!==opts.hint)throw new TypeError("ChoiceTable.init: opts.hint must be a string, false, or undefined. Found: "+opts.hint);this.hint=this.getText("autoHint")}if(!1===opts.timeFrom||"string"==typeof opts.timeFrom)this.timeFrom=opts.timeFrom;else if(void 0!==opts.timeFrom)throw new TypeError("ChoiceTable.init: opts.timeFrom must be string, false, or undefined. Found: "+opts.timeFrom);if("string"==typeof opts.separator)this.separator=opts.separator;else if(void 0!==opts.separator)throw new TypeError("ChoiceTable.init: opts.separator must be string, or undefined. Found: "+opts.separator);if(tmp=this.id+this.separator.substring(0,this.separator.length-1),-1!==this.id.indexOf(this.separator)||-1!==tmp.indexOf(this.separator))throw new Error("ChoiceTable.init: separator cannot be included in the id or in the concatenation (id + separator). Please specify the right separator option. Found: "+this.separator);if("string"==typeof opts.left||"number"==typeof opts.left)this.left=""+opts.left;else if(J.isNode(opts.left)||J.isElement(opts.left))this.left=opts.left;else if(void 0!==opts.left)throw new TypeError("ChoiceTable.init: opts.left must be string, number, an HTML Element or undefined. Found: "+opts.left);if("string"==typeof opts.right||"number"==typeof opts.right)this.right=""+opts.right;else if(J.isNode(opts.right)||J.isElement(opts.right))this.right=opts.right;else if(void 0!==opts.right)throw new TypeError("ChoiceTable.init: opts.right must be string, number, an HTML Element or undefined. Found: "+opts.right);if(void 0===opts.className)this.className=ChoiceTable.className;else if(!1===opts.className)this.className=!1;else if("string"==typeof opts.className)this.className=ChoiceTable.className+" "+opts.className;else{if(!J.isArray(opts.className))throw new TypeError("ChoiceTable.init: opts.className must be string, array, or undefined. Found: "+opts.className);this.className=[ChoiceTable.className].concat(opts.className)}if(!1!==opts.tabbable&&(this.tabbable=!0),"function"==typeof opts.renderer)this.renderer=opts.renderer;else if(void 0!==opts.renderer)throw new TypeError("ChoiceTable.init: opts.renderer must be function or undefined. Found: "+opts.renderer);if("object"==typeof opts.table)this.table=opts.table;else if(void 0!==opts.table&&!1!==opts.table)throw new TypeError("ChoiceTable.init: opts.table must be object, false or undefined. Found: "+opts.table);if(this.table=opts.table,this.freeText="string"==typeof opts.freeText?opts.freeText:!!opts.freeText,void 0!==opts.choicesSetSize){if(!J.isInt(opts.choicesSetSize,0))throw new Error("ChoiceTable.init: choicesSetSize must be undefined or an integer > 0. Found: "+opts.choicesSetSize);if(this.left||this.right)throw new Error("ChoiceTable.init: choicesSetSize option cannot be specified when either left or right options are set.");this.choicesSetSize=opts.choicesSetSize}if(void 0!==opts.choices&&this.setChoices(opts.choices),void 0!==opts.correctChoice){if(this.requiredChoice)throw new Error("ChoiceTable.init: cannot specify both opts requiredChoice and correctChoice");this.setCorrectChoice(opts.correctChoice)}if(void 0!==opts.disabledChoices){if(!J.isArray(opts.disabledChoices))throw new Error("ChoiceTable.init: disabledChoices must be undefined or array. Found: "+opts.disabledChoices);(tmp=opts.disabledChoices.length)&&function(){for(var i=0;i=this.choicesSetSize)););this.rightCell&&(H||(tr=createTR(this)),tr.appendChild(this.rightCell)),i!==len&&makeSet.call(this,i,len,H,doSets)}return function(){var len,H,doSets;if(!this.choicesCells)throw new Error("ChoiceTable.buildTable: choices not set, cannot build table. Id: "+this.id);H="H"===this.orientation,len=this.choicesCells.length,doSets="number"==typeof this.choicesSetSize,makeSet.call(this,-1,len,H,doSets),this.enable()}}(),ChoiceTable.prototype.buildTableAndChoices=function(){var i,len,tr,td,H;for(len=this.choices.length,this.choicesCells=new Array(len),i=-1,(H="H"===this.orientation)&&(tr=createTR(this),this.left&&(td=this.renderSpecial("left",this.left),tr.appendChild(td)));++i=this.requiredChoice:null!==this.currentChoice;if(void 0===this.correctChoice)return null;if((markAttempt=void 0===markAttempt||markAttempt)&&this.attempts.push(this.currentChoice),this.selectMultiple){if((len=(correctChoice=J.isArray(this.correctChoice)?this.correctChoice:[this.correctChoice]).length)!==(lenJ=this.currentChoice.length))return!1;for(i=-1,clone=this.currentChoice.slice(0);++i(tmp="number"==typeof this.selectMultiple?this.selectMultiple:this.choices.length))throw new Error("ChoiceTable.setValues: values array cannot be larger than max allowed set: "+len+" > "+tmp);tmp=options.values}for(;++i

If you need a copy of this consent form, you may print a copy of this page for your records.

",printBtn:"Print this page",consentTerms:"Do you understand and consent to these terms?",agree:"Yes, I agree",notAgree:"No, I do not agree",showHideConsent:function(w,s){return("hide"===s?"Hide":"Show")+" Consent Form"}},Consent.prototype.init=function(opts){if(opts=opts||{},this.consent=opts.consent||node.game.settings.CONSENT,this.consent&&"object"!=typeof this.consent)throw new TypeError("Consent: consent must be object or undefined. Found: "+this.consent);this.showPrint=!1!==opts.showPrint},Consent.prototype.enable=function(){var a,na;this.notAgreed||((a=W.gid("agree"))&&(a.disabled=!1),(na=W.gid("notAgree"))&&(na.disabled=!1))},Consent.prototype.disable=function(){var a,na;this.notAgreed||((a=W.gid("agree"))&&(a.disabled=!0),(na=W.gid("notAgree"))&&(na.disabled=!0))},Consent.prototype.append=function(){var consent,html;W.hide("notAgreed"),consent=W.gid("consent"),html="",this.showPrint&&(html=this.getText("printText"),html+='

'),html+=""+this.getText("consentTerms")+"
",html+='
",consent.innerHTML+=html,setTimeout((function(){W.adjustFrameHeight()}))},Consent.prototype.listeners=function(){var that=this,consent=this.consent;node.on("FRAME_LOADED",(function(){var a,na,p,id;if(consent)for(p in consent)consent.hasOwnProperty(p)&&(id=(id=p.toLowerCase()).replace(new RegExp("_","g"),"-"),W.setInnerHTML(id,consent[p]));if(a=W.gid("agree"),na=W.gid("notAgree"),!a)throw new Error("Consent: agree button not found");if(!na)throw new Error("Consent: notAgree button not found");a.onclick=function(){node.done({consent:!0})},na.onclick=function(){var showIt;confirm(that.getText("areYouSure"))&&(node.emit("CONSENT_REJECTING"),that.notAgreed=!0,node.set({consent:!1,time:node.timer.getTimeSince("step"),timeup:!1}),a.disabled=!0,na.disabled=!0,a.onclick=null,na.onclick=null,node.socket.disconnect(),W.hide("consent"),W.show("notAgreed"),(showIt=W.gid("show-consent"))&&(showIt.onclick=function(){var s;s=""===W.toggle("consent").style.display?"hide":"show",this.innerHTML=that.getText("showHideConsent",s)}),node.emit("CONSENT_REJECTED"))}}))}}(node),function(node){"use strict";function ContentBox(){this.mainText=null,this.content=null,this.hint=null}node.widgets.register("ContentBox",ContentBox),ContentBox.version="0.2.0",ContentBox.description="Simply displays some content",ContentBox.title=!1,ContentBox.panel=!1,ContentBox.className="contentbox",ContentBox.dependencies={},ContentBox.prototype.init=function(opts){if("string"==typeof opts.mainText)this.mainText=opts.mainText;else if(void 0!==opts.mainText)throw new TypeError("ContentBox.init: mainText must be string or undefined. Found: "+opts.mainText);if("string"==typeof opts.content)this.content=opts.content;else if(void 0!==opts.content)throw new TypeError("ContentBox.init: content must be string or undefined. Found: "+opts.content);if("string"==typeof opts.hint)this.hint=opts.hint;else if(void 0!==opts.hint)throw new TypeError("ContentBox.init: hint must be string or undefined. Found: "+opts.hint)},ContentBox.prototype.append=function(){this.mainText&&W.append("span",this.bodyDiv,{className:"contentbox-maintext",innerHTML:this.mainText}),this.content&&W.append("div",this.bodyDiv,{className:"contentbox-content",innerHTML:this.content}),this.hint&&W.append("span",this.bodyDiv,{className:"contentbox-hint",innerHTML:this.hint})}}(node),function(node){"use strict";function Controls(options){this.options=options,this.listRoot=null,this.submit=null,this.changeEvent="Controls_change",this.hasChanged=!1}function SliderControls(options){Controls.call(this,options)}function jQuerySliderControls(options){Controls.call(this,options)}function RadioControls(options){Controls.call(this,options),this.groupName=void 0!==options.name?options.name:W.generateUniqueId(),this.radioElem=null}node.widgets.register("Controls",Controls),Controls.version="0.5.1",Controls.description="Wraps a collection of user-inputs controls.",Controls.title="Controls",Controls.className="controls",Controls.prototype.add=function(root,id,attributes){},Controls.prototype.getItem=function(id,attributes){},Controls.prototype.init=function(options){this.hasChanged=!1,void 0!==options.change&&(options.change?this.changeEvent=options.change:this.changeEvent=!1),this.list=new W.List(options),this.listRoot=this.list.getRoot(),options.features&&(this.features=options.features,this.populate())},Controls.prototype.append=function(){var that=this,idButton="submit_Controls";this.list.parse(),this.bodyDiv.appendChild(this.listRoot),this.options.submit&&(this.options.submit.id&&(idButton=this.options.submit.id,this.option.submit=this.option.submit.name),this.submit=W.add("button",this.bodyDiv,J.merge(this.options.attributes,{id:idButton,innerHTML:this.options.submit})),this.submit.onclick=function(){that.options.change&&node.emit(that.options.change)})},Controls.prototype.parse=function(){return this.list.parse()},Controls.prototype.populate=function(){var key,id,attributes,container,elem,that=this;for(key in this.features)this.features.hasOwnProperty(key)&&(id=key,(attributes=this.features[key]).id&&(id=attributes.id,delete attributes.id),container=document.createElement("div"),elem=this.add(container,id,attributes),this.changeEvent&&(elem.onchange=function(){node.emit(that.changeEvent)}),attributes.label&&W.add("label",container,{for:elem.id,innerHTML:attributes.label}),this.list.addDT(container))},Controls.prototype.listeners=function(){var that=this;node.on(this.changeEvent,(function(){that.hasChanged=!0}))},Controls.prototype.refresh=function(){var key,el;for(key in this.features)this.features.hasOwnProperty(key)&&(el=W.getElementById(key))&&(el.value=this.features[key].value);return!0},Controls.prototype.getValues=function(){var out,el,key;for(key in out={},this.features)this.features.hasOwnProperty(key)&&(el=W.getElementById(key))&&(out[key]=Number(el.value));return out},Controls.prototype.highlight=function(code){return W.highlight(this.listRoot,code)},SliderControls.prototype.__proto__=Controls.prototype,SliderControls.prototype.constructor=SliderControls,SliderControls.version="0.2.2",SliderControls.description="Collection of Sliders.",SliderControls.title="Slider Controls",SliderControls.className="slidercontrols",SliderControls.dependencies={Controls:{}},node.widgets.register("SliderControls",SliderControls),SliderControls.prototype.add=function(root,id,attributes){return(attributes=attributes||{}).id=id,attributes.type="range",W.add("input",root,attributes)},SliderControls.prototype.getItem=function(id,attributes){return(attributes=attributes||{}).id=id,W.get("input",attributes)},jQuerySliderControls.prototype.__proto__=Controls.prototype,jQuerySliderControls.prototype.constructor=jQuerySliderControls,jQuerySliderControls.version="0.14",jQuerySliderControls.description="Collection of jQuery Sliders.",jQuerySliderControls.title="jQuery Slider Controls",jQuerySliderControls.className="jqueryslidercontrols",jQuerySliderControls.dependencies={jQuery:{},Controls:{}},node.widgets.register("jQuerySliderControls",jQuerySliderControls),jQuerySliderControls.prototype.add=function(root,id,attributes){return jQuery("
",{id:id}).slider().appendTo(root)[0]},jQuerySliderControls.prototype.getItem=function(id,attributes){return jQuery("
",{id:id}).slider()},RadioControls.prototype.__proto__=Controls.prototype,RadioControls.prototype.constructor=RadioControls,RadioControls.version="0.1.2",RadioControls.description="Collection of Radio Controls.",RadioControls.title="Radio Controls",RadioControls.className="radiocontrols",RadioControls.dependencies={Controls:{}},node.widgets.register("RadioControls",RadioControls),RadioControls.prototype.populate=function(){var key,id,attributes,elem,that;for(key in that=this,this.radioElem||(this.radioElem=document.createElement("radio"),this.radioElem.group=this.name||"radioGroup",this.radioElem.group=this.className||"radioGroup",this.bodyDiv.appendChild(this.radioElem)),this.features)this.features.hasOwnProperty(key)&&(id=key,(attributes=this.features[key]).id&&(id=attributes.id,delete attributes.id),elem=this.add(this.radioElem,id,attributes),this.changeEvent&&(elem.onchange=function(){node.emit(that.changeEvent)}),this.list.addDT(elem))},RadioControls.prototype.add=function(root,id,attributes){var elem;return void 0===attributes.name&&(attributes.name=this.groupName),attributes.id=id,attributes.type="radio",(elem=W.add("input",root,attributes)).appendChild(document.createTextNode(attributes.label)),elem},RadioControls.prototype.getItem=function(id,attributes){return void 0===(attributes=attributes||{}).name&&(attributes.name=this.groupName),attributes.id=id,attributes.type="radio",W.get("input",attributes)},RadioControls.prototype.getValues=function(){var key,el;for(key in this.features)if(this.features.hasOwnProperty(key)&&(el=W.getElementById(key)).checked)return el.value;return!1}}(node),function(node){"use strict";node.widgets.register("CustomInput",CustomInput),CustomInput.version="0.12.0",CustomInput.description="Creates a configurable input form",CustomInput.title=!1,CustomInput.panel=!1,CustomInput.className="custominput",CustomInput.types={text:!0,number:!0,float:!0,int:!0,date:!0,list:!0,us_city_state_zip:!0,us_state:!0,us_zip:!0};var usTerrByAbbr,usStatesByAbbr,usStatesTerr,usStatesTerrByAbbr,usStatesLow,usTerrLow,usTerrByAbbrLow,usStatesByAbbrLow,usStatesTerrLow,usStatesTerrByAbbrLow,sepNames={",":"comma"," ":"space",".":"dot"},usStates={Alabama:"AL",Alaska:"AK",Arizona:"AZ",Arkansas:"AR",California:"CA",Colorado:"CO",Connecticut:"CT",Delaware:"DE",Florida:"FL",Georgia:"GA",Hawaii:"HI",Idaho:"ID",Illinois:"IL",Indiana:"IN",Iowa:"IA",Kansas:"KS",Kentucky:"KY",Louisiana:"LA",Maine:"ME",Maryland:"MD",Massachusetts:"MA",Michigan:"MI",Minnesota:"MN",Mississippi:"MS",Missouri:"MO",Montana:"MT",Nebraska:"NE",Nevada:"NV","New Hampshire":"NH","New Jersey":"NJ","New Mexico":"NM","New York":"NY","North Carolina":"NC","North Dakota":"ND",Ohio:"OH",Oklahoma:"OK",Oregon:"OR",Pennsylvania:"PA","Rhode Island":"RI","South Carolina":"SC","South Dakota":"SD",Tennessee:"TN",Texas:"TX",Utah:"UT",Vermont:"VT",Virginia:"VA",Washington:"WA","West Virginia":"WV",Wisconsin:"WI",Wyoming:"WY"},usTerr={"American Samoa":"AS","District of Columbia":"DC","Federated States of Micronesia":"FM",Guam:"GU","Marshall Islands":"MH","Northern Mariana Islands":"MP",Palau:"PW","Puerto Rico":"PR","Virgin Islands":"VI"};function CustomInput(){this.input=null,this.placeholder=null,this.inputWidth=null,this.type=null,this.preprocess=null,this.validation=null,this.userValidation=null,this.validationSpeed=500,this.postprocess=null,this.oninput=null,this.params={},this.errorBox=null,this.mainText=null,this.hint=null,this.requiredChoice=null,this.required=null,this.timeBegin=null,this.timeEnd=null,this.checkbox=null,this.checkboxText=null,this.checkboxCb=null,this.orientation=null}function getParsedDate(d,p){var res,day;if("string"==typeof d&&!(day=(d="today"===d?new Date:new Date(d)).getDate()))return!1;try{res={day:day||d.getDate(),month:d.getMonth()+1,year:d.getFullYear(),obj:d}}catch(e){return!1}return res.str=(p.dayPos?res.day+p.sep+res.month:res.month+p.sep+res.day)+p.sep,res.str+=2===p.yearDigits?res.year.substring(3,4):res.year,res}function getUsStatesList(s){switch(s){case"usStatesTerrByAbbrLow":return usStatesTerrByAbbrLow||(getUsStatesList("usStatesTerrLow"),usStatesTerrByAbbrLow=J.reverseObj(usStatesTerr,toLK)),usStatesTerrByAbbrLow;case"usStatesTerrByAbbr":return usStatesTerrByAbbr||(getUsStatesList("usStatesTerr"),usStatesTerrByAbbr=J.reverseObj(usStatesTerr)),usStatesTerrByAbbr;case"usTerrByAbbrLow":return usTerrByAbbrLow||(usTerrByAbbrLow=J.reverseObj(usTerr,toLK)),usTerrByAbbrLow;case"usTerrByAbbr":return usTerrByAbbr||(usTerrByAbbr=J.reverseObj(usTerr)),usTerrByAbbr;case"usStatesByAbbrLow":return usStatesByAbbrLow||(usStatesByAbbrLow=J.reverseObj(usStates,toLK)),usStatesByAbbrLow;case"usStatesByAbbr":return usStatesByAbbr||(usStatesByAbbr=J.reverseObj(usStates)),usStatesByAbbr;case"usStatesTerrLow":return usStatesTerrLow||(usStatesLow||(usStatesLow=objToLK(usStates)),usTerrLow||(usTerrLow=objToLK(usTerr)),usStatesTerrLow=J.merge(usStatesLow,usTerrLow)),usStatesTerrLow;case"usStatesTerr":return usStatesTerr||(usStatesTerr=J.merge(usStates,usTerr)),usStatesTerr;case"usStatesLow":return usStatesLow||(usStatesLow=objToLK(usStates)),usStatesLow;case"usStates":return usStates;case"usTerrLow":return usTerrLow||(usTerrLow=objToLK(usTerr)),usTerrLow;case"usTerr":return usTerr;default:throw new Error("getUsStatesList: unknown request: "+s)}}function toLK(key,value){return[key.toLowerCase(),value]}function objToLK(obj){var p,objLow;for(p in objLow={},obj)obj.hasOwnProperty(p)&&(objLow[p.toLowerCase()]=obj[p]);return objLow}function isValidUSZip(z){return 5===z.length&&J.isInt(z,0)}CustomInput.texts={listErr:"Check that there are no empty items; do not end with the separator",listSizeErr:function(w,param){return w.params.fixedSize?w.params.minItems+" items required":"min"===param?"Too few items. Min: "+w.params.minItems:"Too many items. Max: "+w.params.maxItems},usStateAbbrErr:"Not a valid state abbreviation (must be 2 characters)",usStateErr:"Not a valid state (full name required)",usZipErr:"Not a valid ZIP code (must be 5 digits)",autoHint:function(w){var res,sep;return"list"===w.type?res="(if more than one, separate with "+(sep=sepNames[w.params.listSep]||w.params.listSep)+")":"us_state"===w.type?res=w.params.abbr?"(Use 2-letter abbreviation)":"(Type the full name of the state)":"us_zip"===w.type?res="(Use 5-digit ZIP code)":"us_city_state_zip"===w.type?res="(Format: Town"+(sep=w.params.listSep)+" State"+sep+" ZIP code)":"date"===w.type?res=w.params.minDate&&w.params.maxDate?"(Must be between "+w.params.minDate.str+" and "+w.params.maxDate.str+")":w.params.minDate?"(Must be after "+w.params.minDate.str+")":w.params.maxDate?"(Must be before "+w.params.maxDate.str+")":"(Format: "+w.params.format+")":"number"!==w.type&&"int"!==w.type&&"float"!==w.type||(w.params.min&&w.params.max?res="(Must be between "+w.params.min+" and "+w.params.max+")":w.params.min?res="(Must be after "+w.params.min+")":w.params.max&&(res="(Must be before "+w.params.max+")")),w.required?(res||"")+" *":res||!1},numericErr:function(w){var str,p;return(p=w.params).exactly?"Must enter "+p.lower:(str="Must be ","float"===w.type?str+="a floating point number":"int"===w.type&&(str+="an integer"),p.between?(str+=" "+(p.leq?"≥ ":"<")+p.lower,str+=" and ",str+=(p.ueq?"≤ ":"> ")+p.upper):void 0!==p.lower?str+=" "+(p.leq?"≥ ":"< ")+p.lower:void 0!==p.upper&&(str+=" "+(p.ueq?"≤ ":"> ")+p.upper),str)},textErr:function(w,param){var str,p;return"num"===param?"Cannot contain numbers":(str="Must be ",(p=w.params).exactly?str+="exactly "+(p.lower+1):p.between?str+="between "+p.lower+" and "+p.upper:void 0!==p.lower?str+=" more than "+(p.lower-1):void 0!==p.upper&&(str+=" less than "+(p.upper+1)),str+=" characters long",p.between&&(str+=" (extremes included)"),str+=". Current length: "+param)},dateErr:function(w,param){return"invalid"===param?"Date is invalid":"min"===param?"Date must be after "+w.params.minDate.str:"max"===param?"Date must be before "+w.params.maxDate.str:"Must follow format "+w.params.format},emptyErr:"Cannot be empty"},CustomInput.dependencies={JSUS:{}},CustomInput.prototype.init=function(opts){var tmp,that,e,isText,setValues,cb;if(that=this,e="CustomInput.init: ",void 0===opts.orientation)tmp="V";else{if("string"!=typeof opts.orientation)throw new TypeError("CustomInput.init: orientation must be string, or undefined. Found: "+opts.orientation);if("h"===(tmp=opts.orientation.toLowerCase().trim()))tmp="H";else{if("v"!==tmp)throw new Error("CustomInput.init: unknown orientation: "+tmp);tmp="V"}}if(this.orientation=tmp,void 0!==opts.required&&(this.required=this.requiredChoice=!!opts.required),void 0!==opts.requiredChoice){if(!!this.required!=!!opts.requiredChoice)throw new TypeError("CustomInput.init: required and requiredChoice are incompatible. Option requiredChoice will be deprecated.");this.required=this.requiredChoice=!!opts.requiredChoice}if(void 0===this.required&&(this.required=this.requiredChoice=!1),opts.userValidation){if("function"!=typeof opts.userValidation)throw new TypeError("CustomInput.init: userValidation must be function or undefined. Found: "+opts.userValidation);this.userValidation=opts.userValidation}if(opts.type){if(!CustomInput.types[opts.type])throw new Error(e+"type not supported: "+opts.type);this.type=opts.type}else this.type="text";if(opts.validation){if("function"!=typeof opts.validation)throw new TypeError(e+"validation must be function or undefined. Found: "+opts.validation);tmp=opts.validation}else if("number"===this.type||"float"===this.type||"int"===this.type||"text"===this.type){if(isText="text"===this.type,void 0!==opts.min){if(!1===(tmp=J.isNumber(opts.min)))throw new TypeError(e+"min must be number or undefined. Found: "+opts.min);this.params.lower=opts.min,this.params.leq=!0}if(void 0!==opts.max){if(!1===(tmp=J.isNumber(opts.max)))throw new TypeError(e+"max must be number or undefined. Found: "+opts.max);this.params.upper=opts.max,this.params.ueq=!0}if(opts.strictlyGreater&&(this.params.leq=!1),opts.strictlyLess&&(this.params.ueq=!1),void 0!==this.params.lower&&void 0!==this.params.upper){if(this.params.lower>this.params.upper)throw new TypeError(e+"min cannot be greater than max. Found: "+opts.min+"> "+opts.max);if(this.params.lower===this.params.upper){if(!this.params.leq||!this.params.ueq)throw new TypeError(e+"min cannot be equal to max when strictlyGreater or strictlyLess are set. Found: "+opts.min);if(("int"===this.type||"text"===this.type)&&J.isFloat(this.params.lower))throw new TypeError(e+'min cannot be a floating point number and equal to max, when type is not "float". Found: '+opts.min);this.params.exactly=!0}else this.params.between=!0}if(isText){if(this.params.noNumbers=opts.noNumbers,void 0!==this.params.lower){if(this.params.lower<0)throw new TypeError(e+'min cannot be negative when type is "text". Found: '+this.params.lower);this.params.leq||this.params.lower++}if(void 0!==this.params.upper){if(this.params.upper<0)throw new TypeError(e+'max cannot be negative when type is "text". Found: '+this.params.upper);this.params.ueq||this.params.upper--}tmp=function(value){var len,p,out,err;return p=that.params,len=value.length,out={value:value},p.noNumbers&&/\d/.test(value)?err=that.getText("textErr","num"):(p.exactly?err=len!==p.lower:(void 0!==p.lower&&lenp.upper)&&(err=!0),err&&(err=that.getText("textErr",len))),err&&(out.err=err),out},setValues=function(){var a,b;return a=void 0!==that.params.lower?that.params.lower+1:5,b=void 0!==that.params.upper?that.params.upper:a+5,J.randomString(J.randomInt(a,b))}}else cb="float"===that.type?J.isFloat:"int"===that.type?J.isInt:J.isNumber,tmp=function(value){var res,p;return p=that.params,!1!==(res=cb(value,p.lower,p.upper,p.leq,p.ueq))?{value:res}:{value:value,err:that.getText("numericErr")}},setValues=function(){var p,a,b;return p=that.params,"float"===that.type?J.random():(a=0,void 0!==p.lower&&(a=p.leq?p.lower-1:p.lower),b=void 0!==p.upper?p.ueq?p.upper:p.upper-1:100+a,J.randomInt(a,b))};this.params.upper&&(this.params.upper<10?this.inputWidth="100px":this.params.upper<20&&(this.inputWidth="200px"))}else if("date"===this.type){if(void 0!==opts.format){if("mm-dd-yy"!==opts.format&&"dd-mm-yy"!==opts.format&&"mm-dd-yyyy"!==opts.format&&"dd-mm-yyyy"!==opts.format&&"mm.dd.yy"!==opts.format&&"dd.mm.yy"!==opts.format&&"mm.dd.yyyy"!==opts.format&&"dd.mm.yyyy"!==opts.format&&"mm/dd/yy"!==opts.format&&"dd/mm/yy"!==opts.format&&"mm/dd/yyyy"!==opts.format&&"dd/mm/yyyy"!==opts.format)throw new Error(e+"date format is invalid. Found: "+opts.format);this.params.format=opts.format}else this.params.format="mm/dd/yyyy";if(this.params.sep=this.params.format.charAt(2),tmp=this.params.format.split(this.params.sep),this.params.yearDigits=tmp[2].length,this.params.dayPos="d"===tmp[0].charAt(0)?0:1,this.params.monthPos=this.params.dayPos?0:1,this.params.dateLen=tmp[2].length+6,opts.minDate){if(!(tmp=getParsedDate(opts.minDate,this.params)))throw new Error(e+"minDate must be a Date object. Found: "+opts.minDate);this.params.minDate=tmp}if(opts.maxDate){if(!(tmp=getParsedDate(opts.maxDate,this.params)))throw new Error(e+"maxDate must be a Date object. Found: "+opts.maxDate);if(this.params.minDate&&this.params.minDate.obj>tmp.obj)throw new Error(e+"maxDate cannot be prior to minDate. Found: "+tmp.str+" < "+this.params.minDate.str);this.params.maxDate=tmp}2===this.params.yearDigits?this.inputWidth="100px":this.inputWidth="150px",this.placeholder=this.params.format,tmp=function(value){var p,tokens,tmp,res,dayNum,l1,l2;return p=that.params,3!==(tokens=value.split(p.sep)).length||tokens[2].length!==p.yearDigits?{err:that.getText("dateErr")}:(res={},2===p.yearDigits?(l1=-1,l2=100):(l1=-1,l2=1e4),!1!==(tmp=J.isInt(tokens[2],l1,l2))?res.year=tmp:res.err=!0,(tmp=J.isInt(tokens[p.monthPos],1,12,1,1))?res.month=tmp:res.err=!0,dayNum=1===tmp||3===tmp||5===tmp||7===tmp||8===tmp||10===tmp||12===tmp?31:2!==tmp?30:res.year%4==0&&res.year%100!=0||res.year%400==0?29:28,res.month=tmp,(tmp=J.isInt(tokens[p.dayPos],1,dayNum,1,1))?res.day=tmp:res.err=!0,res.err?res.err=that.getText("dateErr","invalid"):(p.minDate||p.maxDate)&&(tmp=new Date(value),p.minDate.obj&&p.minDate.obj>tmp?res.err=that.getText("dateErr","min"):p.maxDate.obj&&p.maxDate.objtmp)throw new TypeError(e+"maxItems must be larger than minItems. Found: "+tmp+" < "+this.params.minItems);this.params.maxItems=tmp}}tmp=function(value){var i,len,v,iVal,err;if(!(len=(value=value.split(that.params.listSep)).length))return value;if(iVal=that.params.itemValidation,i=0,!(v=value[0].trim()))return{err:that.getText("listErr")};if(iVal&&(err=iVal(v,1)))return err;if(value[i++]=v,len>1){if(!(v=value[1].trim()))return{err:that.getText("listErr")};if(iVal&&(err=iVal(v,i+1)))return err;value[i++]=v}if(len>2){if(!(v=value[2].trim()))return{err:that.getText("listErr")};if(iVal&&(err=iVal(v,i+1)))return err;value[i++]=v}if(len>3)for(;ithat.params.maxItems?{err:that.getText("listSizeErr","max")}:{value:value}},setValues="us_city_state_zip"===this.type?function(){var sep;return sep=that.params.listSep+" ",J.randomString(8)+sep+J.randomKey(usStatesTerrByAbbr)+sep+(Math.floor(9e4*Math.random())+1e4)}:function(opts){var p,minItems,nItems,i,str,sample;for(minItems=(p=that.params).minItems||0,opts.availableValues?(nItems=J.randomInt(minItems,opts.availableValues.length),nItems--,sample=J.sample(0,nItems-1)):(nItems=J.randomInt(minItems,p.maxItems||minItems+5),nItems--),str="",i=0;ithis.params.dateLen&&(input.value=input.value.substring(0,this.params.dateLen))}:"list"!==this.type&&"us_city_state_zip"!==this.type||""!==this.params.listSep.trim()&&(this.preprocess=function(input){var sep,len;len=input.value.length,sep=that.params.listSep,len>1&&len===input.selectionStart&&input.value.charAt(len-1)===sep&&input.value.charAt(len-2)!==sep&&(input.value+=" ")}));if(opts.postprocess){if("function"!=typeof opts.postprocess)throw new TypeError(e+"postprocess must be function or undefined. Found: "+opts.postprocess);this.postprocess=opts.postprocess}if(opts.oninput){if("function"!=typeof opts.oninput)throw new TypeError(e+"oninput must be function or undefined. Found: "+opts.oninput);this.oninput=opts.oninput}if(void 0!==opts.validationSpeed){if(!1===(tmp=J.isInt(opts.valiadtionSpeed,0,void 0,!0)))throw new TypeError(e+"validationSpeed must a non-negative number or undefined. Found: "+opts.validationSpeed);this.validationSpeed=tmp}if(opts.mainText){if("string"!=typeof opts.mainText)throw new TypeError(e+"mainText must be string or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}if(void 0!==opts.hint){if(!1!==opts.hint&&"string"!=typeof opts.hint)throw new TypeError(e+"hint must be a string, false, or undefined. Found: "+opts.hint);this.hint=opts.hint,this.required&&(this.hint+=" *")}else this.hint=this.getText("autoHint");if(opts.placeholder){if("string"!=typeof opts.placeholder)throw new TypeError(e+"placeholder must be string or undefined. Found: "+opts.placeholder);this.placeholder=opts.placeholder}if(opts.width){if("string"!=typeof opts.width)throw new TypeError(e+"width must be string or undefined. Found: "+opts.width);this.inputWidth=opts.width}if(opts.checkboxText){if("string"!=typeof opts.checkboxText)throw new TypeError(e+"checkboxText must be string or undefined. Found: "+opts.checkboxText);this.checkboxText=opts.checkboxText}if(opts.checkboxCb){if(!this.checkboxText)throw new TypeError(e+"checkboxCb cannot be defined if checkboxText is not defined");if("function"!=typeof opts.checkboxCb)throw new TypeError(e+"checkboxCb must be function or undefined. Found: "+opts.checkboxCb);this.checkboxCb=opts.checkboxCb}},CustomInput.prototype.append=function(){var that,timeout;that=this,this.mainText&&(this.spanMainText=W.append("span",this.bodyDiv,{className:"custominput-maintext",innerHTML:this.mainText})),this.hint&&W.append("span",this.spanMainText||this.bodyDiv,{className:"custominput-hint",innerHTML:this.hint}),this.input=W.append("input",this.bodyDiv),this.placeholder&&(this.input.placeholder=this.placeholder),this.inputWidth&&(this.input.style.width=this.inputWidth),this.errorBox=W.append("div",this.bodyDiv,{className:"errbox"}),this.input.oninput=function(){that.timeBegin?that.timeEnd=node.timer.getTimeSince("step"):that.timeEnd=that.timeBegin=node.timer.getTimeSince("step"),timeout&&clearTimeout(timeout),that.isHighlighted()&&that.unhighlight(),that.preprocess&&that.preprocess(that.input),timeout=setTimeout((function(){var res;that.validation&&(res=that.validation(that.input.value)).err&&that.setError(res.err),that.oninput&&that.oninput(res,that)}),that.validationSpeed)},this.input.onclick=function(){that.isHighlighted()&&that.unhighlight()},this.checkboxText&&(this.checkbox=W.append("input",this.bodyDiv,{type:"checkbox",className:"custominput-checkbox"}),W.append("span",this.bodyDiv,{className:"custominput-checkbox-text",innerHTML:this.checkboxText}),this.checkboxCb&&J.addEvent(this.checkbox,"change",(function(){that.checkboxCb(that.checkbox.checked,that)})))},CustomInput.prototype.setError=function(err){this.errorBox.innerHTML=err,this.highlight()},CustomInput.prototype.highlight=function(border){if(border&&"string"!=typeof border)throw new TypeError("CustomInput.highlight: border must be string or undefined. Found: "+border);this.input&&!this.highlighted&&(this.input.style.border=border||"3px solid red",this.highlighted=!0,this.emit("highlighted",border))},CustomInput.prototype.unhighlight=function(){this.input&&!0===this.highlighted&&(this.input.style.border="",this.highlighted=!1,this.errorBox.innerHTML="",this.emit("unhighlighted"))},CustomInput.prototype.disable=function(opts){this.disabled||this.isAppended()&&(this.disabled=!0,this.input.disabled=!0,!this.checkbox||opts&&!1===opts.checkbox||(this.checkbox.disable=!0),this.emit("disabled"))},CustomInput.prototype.enable=function(opts){!0===this.disabled&&this.isAppended()&&(this.disabled=!1,this.input.disabled=!1,!this.checkbox||opts&&!1===opts.checkbox||(this.checkbox.disable=!1),this.emit("enabled"))},CustomInput.prototype.reset=function(){this.input&&(this.input.value=""),this.isHighlighted()&&this.unhighlight(),this.timeBegin=this.timeEnd=null},CustomInput.prototype.getValues=function(opts){var res,valid;return opts=opts||{},res=this.input.value,opts.valuesOnly||(void 0===opts.markAttempt&&(opts.markAttempt=!0),void 0===opts.highlight&&(opts.highlight=!0),valid=!(res=this.validation?this.validation(res):{value:res}).err,res.timeBegin=this.timeBegin,res.timeEnd=this.timeEnd,this.postprocess&&(res.value=this.postprocess(res.value,valid)),valid?(opts.markAttempt&&(res.isCorrect=!0),opts.reset&&this.reset()):(opts.highlight&&this.setError(res.err),opts.markAttempt&&(res.isCorrect=!1)),this.checkbox&&(res.checked=this.checkbox.checked),res.id=this.id),res},CustomInput.prototype.setValues=function(opts){var value,tmp;if(void 0!==(opts=opts||{}).value)value=opts.value;else if(void 0!==opts.values)value=opts.values;else if(opts.availableValues){if(tmp=opts.availableValues,!J.isArray(tmp)||!tmp.length)throw new TypeError("CustomInput.setValues: availableValues must be a non-empty array or undefined. Found: "+tmp);if("list"===this.type){if(tmp.lengththis.n&&(this.path.transition().duration(500).ease("linear").attr("transform","translate("+x(-1)+")"),this.data.shift())}}(node),function(node){"use strict";var Table=W.Table;function DebugInfo(){this.table=null,this.interval=null,this.intervalTime=1e3}node.widgets.register("DebugInfo",DebugInfo),DebugInfo.version="0.6.2",DebugInfo.description="Display basic info a client's status.",DebugInfo.title="Debug Info",DebugInfo.className="debuginfo",DebugInfo.dependencies={Table:{}},DebugInfo.prototype.init=function(options){var that;"number"==typeof options.intervalTime&&(this.intervalTime=options.intervalTime),that=this,this.on("destroyed",(function(){clearInterval(that.interval),that.interval=null,node.silly("DebugInfo destroyed.")}))},DebugInfo.prototype.append=function(){var that;this.table=new Table,this.bodyDiv.appendChild(this.table.table),this.updateAll(),that=this,this.interval=setInterval((function(){that.updateAll()}),this.intervalTime)},DebugInfo.prototype.updateAll=function(){var stage,stageNo,stageId,playerId,stageLevel,stateLevel,winLevel,errMsg,connected,treatment,tmp;this.bodyDiv?("-",stageId="-",stageNo="-",(stage=node.game.getCurrentGameStage())&&(stageId=(tmp=node.game.plot.getStep(stage))?tmp.id:"-",stageNo=stage.toString()),stageLevel=J.getKeyByValue(node.constants.stageLevels,node.game.getStageLevel()),stateLevel=J.getKeyByValue(node.constants.stateLevels,node.game.getStateLevel()),winLevel=J.getKeyByValue(node.constants.windowLevels,W.getStateLevel()),playerId=node.player?node.player.id:"-",errMsg=node.errorManager.lastErr||"-",treatment=node.game.settings&&node.game.settings.treatmentName?node.game.settings.treatmentName:"-",connected=node.socket.connected?"yes":"no",this.table.clear(!0),this.table.addRow(["Treatment: ",treatment]),this.table.addRow(["Connected: ",connected]),this.table.addRow(["Player Id: ",playerId]),this.table.addRow(["Stage No: ",stageNo]),this.table.addRow(["Stage Id: ",stageId]),this.table.addRow(["Stage Lvl: ",stageLevel]),this.table.addRow(["State Lvl: ",stateLevel]),this.table.addRow(["Players : ",node.game.pl.size()]),this.table.addRow(["Win Lvl: ",winLevel]),this.table.addRow(["Win Loads: ",W.areLoading]),this.table.addRow(["Last Err: ",errMsg]),this.table.parse()):node.err("DebugInfo.updateAll: bodyDiv not found.")}}(node),function(node){"use strict";function DebugWall(){this.buttonsDiv=null,this.hiddenTypes={},this.counterIn=0,this.counterOut=0,this.counterLog=0,this.wall=null,this.wallDiv=null,this.origMsgInCb=null,this.origMsgOutCb=null,this.origLogCb=null}node.widgets.register("DebugWall",DebugWall),DebugWall.version="1.1.0",DebugWall.description="Intercepts incoming and outgoing messages, and logs and prints them numbered and timestamped. Warning! Modifies core functions, therefore its usage in production is not recommended.",DebugWall.title="Debug Wall",DebugWall.className="debugwall",DebugWall.dependencies={JSUS:{}},DebugWall.prototype.init=function(opts){var that;if(that=this,!1!==opts.msgIn&&(this.origMsgInCb=node.socket.onMessage,node.socket.onMessage=function(msg){that.write("in",that.makeTextIn(msg)),that.origMsgInCb.call(node.socket,msg)}),!1!==opts.msgOut&&(this.origMsgOutCb=node.socket.send,node.socket.send=function(msg){that.write("out",that.makeTextOut(msg)),that.origMsgOutCb.call(node.socket,msg)}),!1!==opts.log&&(this.origLogCb=node.log,node.log=function(txt,level,prefix){that.write(level||"info",that.makeTextLog(txt,level,prefix)),that.origLogCb.call(node,txt,level,prefix)}),opts.hiddenTypes){if("object"!=typeof opts.hiddenTypes)throw new TypeError("DebugWall.init: hiddenTypes must be object. Found: "+opts.hiddenTypes);this.hiddenTypes=opts.hiddenTypes}this.on("destroyed",(function(){that.origLogCb&&(node.log=that.origLogCb),that.origMsgOutCb&&(node.socket.send=that.origMsgOutCb),that.origMsgInCb&&(node.socket.onMessage=that.origMsgInCb)}))},DebugWall.prototype.append=function(){var displayIn,displayOut,displayLog,that,btnGroup,cb;this.buttonsDiv=W.add("div",this.bodyDiv,{className:"wallbuttonsdiv"}),btnGroup=W.add("div",this.buttonsDiv,{className:"btn-group",role:"group","aria-label":"Toggle visibility of messages on wall"}),W.add("input",btnGroup,{id:"debug-wall-incoming",className:"btn-check",autocomplete:"off",checked:!0,type:"checkbox"}),displayIn=W.add("label",btnGroup,{className:"btn btn-outline-primary",for:"debug-wall-incoming",innerHTML:"Incoming"}),W.add("input",btnGroup,{id:"debug-wall-outgoing",className:"btn-check",autocomplete:"off",checked:!0,type:"checkbox"}),displayOut=W.add("label",btnGroup,{className:"btn btn-outline-primary",for:"debug-wall-outgoing",innerHTML:"Outgoing"}),W.add("input",btnGroup,{id:"debug-wall-log",className:"btn-check",autocomplete:"off",checked:!0,type:"checkbox"}),displayLog=W.add("label",btnGroup,{className:"btn btn-outline-primary",for:"debug-wall-log",innerHTML:"Log"}),that=this,W.add("button",this.buttonsDiv,{className:"btn btn-outline-danger me-2",innerHTML:"Clear"}).onclick=function(){that.clear()},this.buttonsDiv.appendChild(btnGroup),cb=function(type){var items,i,vis,className;if(className="wall_"+type,(items=that.wall.getElementsByClassName(className))&&items.length){for(vis=""===items[0].style.display?"none":"",i=0;i200?(spanContainer=W.add("span",TDtext,{className:className+"_click",innerHTML:text.substr(0,200)}),spanExtra=W.add("span",spanContainer,{className:className+"_extra",innerHTML:text.substr(200,text.length),id:"wall_"+type+"_"+counter,style:{display:"none"}}),spanDots=W.add("span",spanContainer,{className:className+"_dots",innerHTML:" ...",id:"wall_"+type+"_"+counter}),spanContainer.onclick=function(){"none"===spanDots.style.display?(spanDots.style.display="",spanExtra.style.display="none"):(spanDots.style.display="none",spanExtra.style.display="")}):spanContainer=W.add("span",TDtext,{innerHTML:text}),this.wallDiv.scrollTop=this.wallDiv.scrollHeight):node.warn("Wall not appended, cannot write.")},DebugWall.prototype.makeTextIn=function(msg){var text,d;return text=(d=new Date(msg.created)).getHours()+":"+d.getMinutes()+":"+d.getSeconds()+":"+d.getMilliseconds(),text+=" | "+msg.to+" | "+msg.target+" | "+msg.action+" | "+msg.text+" | "+msg.data},DebugWall.prototype.makeTextOut=function(msg){return msg.from+" | "+msg.target+" | "+msg.action+" | "+msg.text+" | "+msg.data},DebugWall.prototype.makeTextLog=function(text){return text}}(node),function(node){"use strict";function DisconnectBox(){this.showStatus=null,this.showDiscBtn=null,this.statusSpan=null,this.disconnectBtn=null,this.userDiscFlag=null,this.ee=null,this.disconnectCb=null,this.connectCb=null}node.widgets.register("DisconnectBox",DisconnectBox),DisconnectBox.version="0.4.0",DisconnectBox.description="Monitors and handles disconnections",DisconnectBox.title=!1,DisconnectBox.panel=!1,DisconnectBox.className="disconnectbox",DisconnectBox.texts={leave:"Leave Task",left:"You Left",disconnected:"Disconnected!",connected:"Connected"},DisconnectBox.dependencies={},DisconnectBox.prototype.init=function(opts){if(opts.connectCb){if("function"!=typeof opts.connectCb)throw new TypeError("DisconnectBox.init: connectCb must be function or undefined. Found: "+opts.connectCb);this.connectCb=opts.connectCb}if(opts.disconnectCb){if("function"!=typeof opts.disconnectCb)throw new TypeError("DisconnectBox.init: disconnectCb must be function or undefined. Found: "+opts.disconnectCb);this.disconnectCb=opts.disconnectCb}this.showDiscBtn=!!opts.showDiscBtn,this.showStatus=!!opts.showStatus},DisconnectBox.prototype.append=function(){var that,con;that=this,con=node.socket.isConnected(),this.showStatus&&(this.statusSpan=W.add("span",this.bodyDiv),this.updateStatus(con?"connected":"disconnected")),this.showDiscBtn&&(this.disconnectBtn=W.add("button",this.bodyDiv,{innerHTML:this.getText(con?"leave":"left"),className:"btn",style:{"margin-left":"10px"}}),con||(this.disconnectBtn.disabled=!0),this.disconnectBtn.onclick=function(){that.disconnectBtn.disabled=!0,that.userDiscFlag=!0,node.socket.disconnect()})},DisconnectBox.prototype.updateStatus=function(status){this.statusSpan?(this.statusSpan.innerHTML=this.getText(status),this.statusSpan.className="disconnected"===status?"text-danger":""):node.warn("DisconnectBox.updateStatus: display disabled.")},DisconnectBox.prototype.listeners=function(){var that;that=this,this.ee=node.getCurrentEventEmitter(),this.ee.on("SOCKET_DISCONNECT",(function(){that.statusSpan&&that.updateStatus("disconnected"),that.disconnectBtn&&(that.disconnectBtn.disabled=!0,that.disconnectBtn.innerHTML=that.getText("left")),that.disconnectCb&&that.disconnectCb(that.userDiscFlag)})),this.ee.on("SOCKET_CONNECT",(function(){that.statusSpan&&that.updateStatus("connected"),that.disconnectBtn&&(that.disconnectBtn.disabled=!1,that.disconnectBtn.innerHTML=that.getText("leave")),that.connectCb&&that.disconnectCb(),that.userDiscFlag=!1}))}}(node),function(node){"use strict";function DoneButton(options){var that;if(that=this,"object"==typeof options.button)this.button=options.button;else{if(void 0!==options.button)throw new TypeError("DoneButton constructor: options.button must be object or undefined. Found: "+options.button);this.button=document.createElement("input"),this.button.type="button"}this.button.onclick=function(){that.onclick&&!1===that.onclick()||node.done()&&that.disable()},this.onclick=null,this.disableOnDisconnect=null,this.delayOnPlaying=800}node.widgets.register("DoneButton",DoneButton),DoneButton.version="1.1.0",DoneButton.description="Creates a button that if pressed emits node.done().",DoneButton.title=!1,DoneButton.className="donebutton",DoneButton.texts.done="Done",DoneButton.dependencies={JSUS:{}},DoneButton.prototype.init=function(opts){var tmp;if(void 0===(opts=opts||{}).id)tmp=DoneButton.className;else if("string"==typeof opts.id)tmp=opts.id;else{if(!1!==opts.id)throw new TypeError("DoneButton.init: id must be string, false, or undefined. Found: "+opts.id);tmp=!1}if(tmp&&(this.button.id=tmp),void 0===opts.className)tmp="btn btn-lg btn-primary";else if(!1===opts.className)tmp="";else if("string"==typeof opts.className)tmp=opts.className;else{if(!J.isArray(opts.className))throw new TypeError("DoneButton.init: className must be string, array, or undefined. Found: "+opts.className);tmp=opts.className.join(" ")}if(this.button.className=tmp,this.button.value="string"==typeof opts.text?opts.text:this.getText("done"),this.disableOnDisconnect=void 0===opts.disableOnDisconnect||!!opts.disableOnDisconnect,"number"==typeof(tmp=opts.delayOnPlaying))this.delayOnPlaying=tmp;else if(void 0!==tmp)throw new TypeError("DoneButton.init: delayOnPlaying must be number or undefined. Found: "+tmp);if(tmp=opts.onclick){if("function"!=typeof tmp)throw new TypeError("DoneButton.init: onclick must function or undefined. Found: "+tmp);this.onclick=tmp}},DoneButton.prototype.append=function(){node.game.isReady()||(this.disabled=!0,this.button.disabled=!0),this.bodyDiv.appendChild(this.button)},DoneButton.prototype.listeners=function(){var that,disabled;that=this,node.on("PLAYING",(function(){var prop,step,delay;step=node.game.getCurrentGameStage(),!1===(prop=node.game.plot.getProperty(step,"donebutton"))||prop&&!1===prop.enableOnPlaying?that.disable():(delay=prop&&prop.hasOwnProperty&&prop.hasOwnProperty("delayOnPlaying")?prop.delayOnPlaying:that.delayOnPlaying)?setTimeout((function(){disabled||that.enable()}),delay):that.enable(),"string"==typeof prop?that.button.value=prop:prop&&prop.text&&(that.button.value=prop.text)})),this.disableOnDisconnect&&(node.on("SOCKET_DISCONNECT",(function(){that.isDisabled()||(that.disable(),disabled=!0)})),node.on("SOCKET_CONNECT",(function(){disabled&&(that.isDisabled()&&that.enable(),disabled=!1)})))},DoneButton.prototype.updateText=function(text,duration){var oldText,that;duration&&(that=this,oldText=this.button.value,node.timer.setTimeout((function(){that.button.value=oldText}),duration)),this.button.value=text},DoneButton.prototype.disable=function(opts){this.disabled||(this.disabled=!0,this.button.disabled=!0,this.emit("disabled",opts))},DoneButton.prototype.enable=function(opts){this.disabled&&(this.disabled=!1,this.button.disabled=!1,this.emit("enabled",opts))}}(node),function(node){function Dropdown(){var that;that=this,this.id=null,this.mainText=null,this.labelText=null,this.placeHolder=null,this.choices=null,this.tag=null,this.menu=null,this.listener=function(e){var menu,timeout;menu=(e=e||window.event).target||e.srcElement,that.currentChoice=menu.value,0===that.currentChoice.length&&(that.currentChoice=null),"string"==typeof that.timeFrom?that.timeCurrentChoice=node.timer.getTimeSince(that.timeFrom):that.timeCurrentChoice=Date.now?Date.now():(new Date).getTime(),that.numberOfChanges++,that.isHighlighted()&&that.unhighlight(),timeout&&clearTimeout(timeout),timeout=setTimeout((function(){that.verifyChoice(),that.verifyChoice().err&&that.setError(that.verifyChoice().err)}),that.validationSpeed),that.onchange&&that.onchange(that.currentChoice,that)},this.onchange=null,this.timeCurrentChoice=null,this.timeFrom="step",this.numberOfChanges=0,this.currentChoice=null,this.shuffleChoices=null,this.order=null,this.errorBox=null,this.correctChoice=null,this.requiredChoice=null,this.fixedChoice=null,this.inputWidth=null,this.validation=null,this.validationSpeed=500}node.widgets.register("Dropdown",Dropdown),Dropdown.version="0.1.0",Dropdown.description="Creates a configurable dropdown menu.",Dropdown.texts={error:function(w,value){return null!==value&&w.fixedChoice&&w.choices.indexOf(value)<0?"No custom values allowed.":null!==value&&null!==w.correctChoice?"Not correct, try again.":null!==value&&w.verifyChoice().err?w.verifyChoice().err:"Answer required."}},Dropdown.title=!1,Dropdown.className="dropdown",Dropdown.prototype.init=function(options){var tmp;if(!this.id)throw new TypeError("Dropdown.init: options.id is missing");if("string"==typeof options.mainText)this.mainText=options.mainText;else if(void 0!==options.mainText)throw new TypeError("Dropdown.init: options.mainText must be string or undefined. Found: "+options.mainText);if("string"==typeof options.labelText)this.labelText=options.labelText;else if(void 0!==options.labelText)throw new TypeError("Dropdown.init: options.labelText must be string or undefined. Found: "+options.labelText);if("string"==typeof options.placeHolder)this.placeHolder=options.placeHolder;else if(void 0!==options.placeHolder)throw new TypeError("Dropdown.init: options.placeHolder must be string or undefined. Found: "+options.placeHolder);if(void 0!==options.choices&&(this.choices=options.choices),"boolean"==typeof options.requiredChoice)this.requiredChoice=options.requiredChoice;else if(void 0!==options.requiredChoice)throw new TypeError("Dropdown.init: options.requiredChoice be boolean or undefined. Found: "+options.requiredChoice);if(void 0!==options.correctChoice){if(this.requiredChoice)throw new Error("Dropdown.init: cannot specify both options requiredChoice and correctChoice");if(J.isArray(options.correctChoice)&&options.correctChoice.length>options.choices.length)throw new Error("Dropdown.init: options.correctChoice length cannot exceed options.choices length");this.correctChoice=options.correctChoice}if("boolean"==typeof options.fixedChoice)this.fixedChoice=options.fixedChoice;else if(void 0!==options.fixedChoice)throw new TypeError("Dropdown.init: options.fixedChoice be boolean or undefined. Found: "+options.fixedChoice);if(void 0!==options.tag&&"datalist"!==options.tag&&"select"!==options.tag)throw new TypeError('Dropdown.init: options.tag must be "datalist" or "select". Found: '+options.tag);if(this.tag=options.tag,"function"==typeof options.listener)this.listener=function(e){options.listener.call(this,e)};else if(void 0!==options.listener)throw new TypeError("Dropdown.init: opts.listener must be function or undefined. Found: "+options.listener);if("function"==typeof options.onchange)this.onchange=options.onchange;else if(void 0!==options.onchange)throw new TypeError("Dropdownn.init: opts.onchange must be function or undefined. Found: "+options.onchange);if("function"==typeof options.validation)this.validation=options.validation;else if(void 0!==options.validation)throw new TypeError("Dropdownn.init: opts.validation must be function or undefined. Found: "+options.validation);if(tmp=void 0!==options.shuffleChoices&&!!options.shuffleChoices,this.shuffleChoices=tmp,options.width){if("string"!=typeof options.width)throw new TypeError("Dropdownn.init:width must be string or undefined. Found: "+options.width);this.inputWidth=options.width}if(void 0!==options.validationSpeed){if(!1===(tmp=J.isInt(options.valiadtionSpeed,0,void 0,!0)))throw new TypeError("Dropdownn.init: validationSpeed must a non-negative number or undefined. Found: "+options.validationSpeed);this.validationSpeed=tmp}},Dropdown.prototype.append=function(){if(W.gid(this.id))throw new Error("Dropdown.append: id is not unique: "+this.id);var text=this.text,label=this.label;(text=W.get("p")).innerHTML=this.mainText,text.id="p",this.bodyDiv.appendChild(text),(label=W.get("label")).innerHTML=this.labelText,this.bodyDiv.appendChild(label),this.setChoices(this.choices,!0),this.errorBox=W.append("div",this.bodyDiv,{className:"errbox",id:"errbox"})},Dropdown.prototype.setChoices=function(choices,append){var tag=this.tag,option=this.option,placeHolder=this.placeHolder,order=this.order;if(this.choices=choices,append){var create=!1;if(this.menu?this.menu.innerHTML="":create=!0,create)if("datalist"===(tag=this.tag)||void 0===tag){var datalist=this.datalist,input=this.input;(datalist=W.get("datalist")).id="dropdown",(input=W.get("input")).setAttribute("list",datalist.id),input.id=this.id,input.autocomplete="off",placeHolder&&(input.placeholder=placeHolder),this.inputWidth&&(input.style.width=this.inputWidth),this.bodyDiv.appendChild(input),this.bodyDiv.appendChild(datalist),this.menu=input}else if("select"===tag){var select=this.select;(select=W.get("select")).id=this.id,this.inputWidth&&(select.style.width=this.inputWidth),placeHolder&&((option=W.get("option")).value="",option.innerHTML=placeHolder,option.setAttribute("disabled",""),option.setAttribute("selected",""),option.setAttribute("hidden",""),select.appendChild(option)),this.bodyDiv.appendChild(select),this.menu=select}var len=choices.length;order=J.seq(0,len-1),this.shuffleChoices&&(order=J.shuffle(order));for(var i=0;i=0}if(this.fixedChoice&&this.choices.indexOf(current)<0&&(res.value=!1),this.validation){if(void 0===typeof res)throw new TypeError("something");this.validation(this.currentChoice,res)}return res},Dropdown.prototype.setError=function(err){this.errorBox&&(this.errorBox.innerHTML=err||""),err?this.highlight():this.unhighlight()},Dropdown.prototype.highlight=function(border){if(border&&"string"!=typeof border)throw new TypeError("Dropdown.highlight: border must be string or undefined. Found: "+border);this.highlighted||(this.menu.style.border=border||"3px solid red",this.highlighted=!0,this.emit("highlighted",border))},Dropdown.prototype.unhighlight=function(){!0===this.highlighted&&(this.menu.style.border="",this.highlighted=!1,this.setError(),this.emit("unhighlighted"))},Dropdown.prototype.getValues=function(opts){var obj;opts=opts||{};var verif=this.verifyChoice().value;return obj={id:this.id,choice:this.fixedChoice?this.choices.indexOf(this.currentChoice):this.currentChoice,time:this.timeCurrentChoice,nChanges:this.numberOfChanges},void 0===opts.highlight&&(opts.highlight=!0),this.shuffleChoices&&(obj.order=this.order),!1!==opts.addValue&&!1!==opts.getValue&&(obj.value=this.currentChoice),null===this.correctChoice&&null===this.requiredChoice&&null===this.fixedChoice||(obj.isCorrect=verif,!obj.isCorrect&&opts.highlight&&this.highlight()),!1===obj.isCorrect&&this.setError(this.getText("error",obj.value)),obj},Dropdown.prototype.listeners=function(){var that=this;node.on("INPUT_DISABLE",(function(){that.disable()})),node.on("INPUT_ENABLE",(function(){that.enable()}))},Dropdown.prototype.disable=function(){!0!==this.disabled&&(this.disabled=!0,this.menu&&this.menu.removeEventListener("change",this.listener),this.emit("disabled"))},Dropdown.prototype.enable=function(){if(!1!==this.disabled){if(!this.menu)throw new Error("Dropdown.enable: menu is not defined");this.disabled=!1,this.menu.addEventListener("change",this.listener),this.emit("enabled")}}}(node),function(node){"use strict";function EmailForm(opts){if(opts.onsubmit){if("object"!=typeof opts.onsubmit)throw new TypeError("EmailForm constructor: opts.onsubmit must be object or undefined. Found: "+opts.onsubmit);this.onsubmit=opts.onsubmit}else this.onsubmit={emailOnly:!0,send:!0,updateUI:!0};this._email=opts.email||null,this.attempts=[],this.timeInput=null,this.formElement=null,this.inputElement=null,this.buttonElement=null,this.setMsg=!!opts.setMsg||!1,this.showSubmitBtn=void 0===opts.showSubmitBtn||!!opts.showSubmitBtn}function getEmail(){return this.inputElement?this.inputElement.value:this._email}node.widgets.register("EmailForm",EmailForm),EmailForm.version="0.13.1",EmailForm.description="Displays a configurable email form.",EmailForm.title=!1,EmailForm.className="emailform",EmailForm.texts={label:"Enter your email:",errString:"Not a valid email address, please correct it and submit it again.",sent:"Sent!"},EmailForm.prototype.createForm=function(){var that,formElement,labelElement,inputElement,buttonElement;return that=this,(formElement=document.createElement("form")).className="emailform-form",(labelElement=document.createElement("label")).innerHTML=this.getText("label"),(inputElement=document.createElement("input")).setAttribute("type","text"),inputElement.setAttribute("placeholder","Email"),inputElement.className="emailform-input form-control",formElement.appendChild(labelElement),formElement.appendChild(inputElement),this.formElement=formElement,this.inputElement=inputElement,this.showSubmitBtn&&((buttonElement=document.createElement("input")).setAttribute("type","submit"),buttonElement.setAttribute("value","Submit email"),buttonElement.className="btn btn-lg btn-primary emailform-submit",formElement.appendChild(buttonElement),J.addEvent(formElement,"submit",(function(event){event.preventDefault(),that.getValues(that.onsubmit)}),!0),J.addEvent(formElement,"input",(function(){that.timeInput||(that.timeInput=J.now()),that.isHighlighted()&&that.unhighlight()}),!0),this.buttonElement=buttonElement),this._email&&(this.formElement.value=this._email),this._email=null,formElement},EmailForm.prototype.verifyInput=function(markAttempt,updateUI){var email,res;return email=getEmail.call(this),(res=J.isEmail(email))&&updateUI?(this.inputElement&&(this.inputElement.disabled=!0),this.buttonElement&&(this.buttonElement.disabled=!0,this.buttonElement.value=this.getText("sent"))):(updateUI&&this.buttonElement&&(this.buttonElement.value=this.getText("errString")),(void 0===markAttempt||markAttempt)&&this.attempts.push(email)),res},EmailForm.prototype.append=function(){this.createForm(),this.bodyDiv.appendChild(this.formElement)},EmailForm.prototype.setValues=function(options){var email;email=(options=options||{}).email?options.email:J.randomEmail(),this.inputElement?this.inputElement.value=email:this._email=email,this.timeInput=J.now()},EmailForm.prototype.getValues=function(opts){var email,res;return void 0!==(opts=opts||{}).say&&(console.log("***EmailForm.getValues: option say is deprecated, use send.***"),opts.send=opts.say),void 0!==opts.sayAnyway&&(console.log("***EmailForm.getValues: option sayAnyway is deprecated, use sendAnyway.***"),opts.sendAnyway=opts.sayAnyway),void 0===opts.markAttempt&&(opts.markAttempt=!0),void 0===opts.highlight&&(opts.highlight=!0),email=getEmail.call(this),!1!==opts.verify&&(res=this.verifyInput(opts.markAttempt,opts.updateUI)),opts.emailOnly||(email={time:this.timeInput,email:email,attempts:this.attempts},opts.markAttempt&&(email.isCorrect=res)),!1===res&&((opts.updateUI||opts.highlight)&&this.highlight(),this.timeInput=null),(opts.send&&res||opts.sendAnyway)&&this.sendValues({values:email}),opts.reset&&this.reset(),email},EmailForm.prototype.sendValues=function(opts){var values;return values=(opts=opts||{emailOnly:!0}).values||this.getValues(opts),this.setMsg?("string"==typeof values&&(values={email:values}),node.set(values,opts.to||"SERVER")):node.say("email",opts.to||"SERVER",values),values},EmailForm.prototype.highlight=function(border){if(border&&"string"!=typeof border)throw new TypeError("EmailForm.highlight: border must be string or undefined. Found: "+border);this.inputElement&&!0!==this.highlighted&&(this.inputElement.style.border=border||"3px solid red",this.highlighted=!0,this.emit("highlighted",border))},EmailForm.prototype.unhighlight=function(){this.inputElement&&!0===this.highlighted&&(this.inputElement.style.border="",this.highlighted=!1,this.emit("unhighlighted"))},EmailForm.prototype.reset=function(){this.attempts=[],this.timeInput=null,this._email=null,this.inputElement&&(this.inputElement.value=""),this.isHighlighted()&&this.unhighlight()}}(node),function(node){"use strict";function EndScreen(options){this.showEmailForm=!0,this.showFeedbackForm=!0,this.showTotalWin=!0,this.showExitCode=!0,this.totalWinCurrency="USD",this.totalWinCb=null,this.emailForm=null,this.feedback=null,this.endScreenHTML=null,this.askServer=options.askServer||!1}node.widgets.register("EndScreen",EndScreen),EndScreen.version="0.7.2",EndScreen.description="Game end screen. With end game message, email form, and exit code.",EndScreen.title=!1,EndScreen.className="endscreen",EndScreen.texts={headerMessage:"Thank you for participating!",message:"You have now completed this task and your data has been saved. Please go back to the Amazon Mechanical Turk web site and submit the HIT.",totalWin:"Your total win:",exitCode:"Your exit code:",errTotalWin:"Error: invalid total win.",errExitCode:"Error: invalid exit code.",copyButton:"Copy",exitCopyMsg:"Exit code copied to clipboard.",exitCopyError:"Failed to copy exit code. Please copy it manually."},EndScreen.dependencies={Feedback:{},EmailForm:{}},EndScreen.prototype.init=function(options){if(!1===options.email)this.showEmailForm=!1;else if("boolean"==typeof options.showEmailForm)this.showEmailForm=options.showEmailForm;else if(void 0!==options.showEmailForm)throw new TypeError("EndScreen.init: options.showEmailForm must be boolean or undefined. Found: "+options.showEmailForm);if(!1===options.feedback)this.showFeedbackForm=!1;else if("boolean"==typeof options.showFeedbackForm)this.showFeedbackForm=options.showFeedbackForm;else if(void 0!==options.showFeedbackForm)throw new TypeError("EndScreen.init: options.showFeedbackForm must be boolean or undefined. Found: "+options.showFeedbackForm);if(!1===options.totalWin)this.showTotalWin=!1;else if("boolean"==typeof options.showTotalWin)this.showTotalWin=options.showTotalWin;else if(void 0!==options.showTotalWin)throw new TypeError("EndScreen.init: options.showTotalWin must be boolean or undefined. Found: "+options.showTotalWin);if(!1===options.exitCode)options.showExitCode;else if("boolean"==typeof options.showExitCode)this.showExitCode=options.showExitCode;else if(void 0!==options.showExitCode)throw new TypeError("EndScreen.init: options.showExitCode must be boolean or undefined. Found: "+options.showExitCode);if("string"==typeof options.totalWinCurrency&&""!==options.totalWinCurrency.trim())this.totalWinCurrency=options.totalWinCurrency;else if(void 0!==options.totalWinCurrency)throw new TypeError("EndScreen.init: options.totalWinCurrency must be undefined or a non-empty string. Found: "+options.totalWinCurrency);if(options.totalWinCb){if("function"!=typeof options.totalWinCb)throw new TypeError("EndScreen.init: options.totalWinCb must be function or undefined. Found: "+options.totalWinCb);this.totalWinCb=options.totalWinCb}this.showEmailForm&&!this.emailForm&&(this.emailForm=node.widgets.get("EmailForm",J.mixin({onsubmit:{send:!0,emailOnly:!0,updateUI:!0},storeRef:!1,texts:{label:"If you would like to be contacted for future studies, please enter your email (optional):",errString:"Please enter a valid email and retry"},setMsg:!0},options.email))),this.showFeedbackForm&&(this.feedback=node.widgets.get("Feedback",J.mixin({storeRef:!1,minChars:50,setMsg:!0},options.feedback)))},EndScreen.prototype.append=function(){this.endScreenHTML=this.makeEndScreen(),this.bodyDiv.appendChild(this.endScreenHTML),this.askServer&&setTimeout((function(){node.say("WIN")}))},EndScreen.prototype.makeEndScreen=function(){var endScreenElement,headerElement,messageElement,totalWinElement,totalWinParaElement,totalWinInputElement,exitCodeElement,exitCodeParaElement,exitCodeInputElement,exitCodeBtn,exitCodeGroup,that=this;return(endScreenElement=document.createElement("div")).className="endscreen",(headerElement=document.createElement("h1")).innerHTML=this.getText("headerMessage"),endScreenElement.appendChild(headerElement),(messageElement=document.createElement("p")).innerHTML=this.getText("message"),endScreenElement.appendChild(messageElement),this.showTotalWin&&(totalWinElement=document.createElement("div"),(totalWinParaElement=document.createElement("p")).innerHTML=""+this.getText("totalWin")+"",(totalWinInputElement=document.createElement("input")).className="endscreen-total form-control",totalWinInputElement.setAttribute("disabled","true"),totalWinParaElement.appendChild(totalWinInputElement),totalWinElement.appendChild(totalWinParaElement),endScreenElement.appendChild(totalWinElement),this.totalWinInputElement=totalWinInputElement),this.showExitCode&&((exitCodeElement=document.createElement("div")).className="input-group",(exitCodeParaElement=document.createElement("span")).innerHTML=""+this.getText("exitCode")+"",(exitCodeInputElement=document.createElement("input")).id="exit_code",exitCodeInputElement.className="endscreen-exit-code form-control",exitCodeInputElement.setAttribute("disabled","true"),(exitCodeGroup=document.createElement("span")).className="input-group-btn",(exitCodeBtn=document.createElement("button")).className="btn btn-default endscreen-copy-btn",exitCodeBtn.innerHTML=this.getText("copyButton"),exitCodeBtn.type="button",exitCodeBtn.onclick=function(){that.copy(exitCodeInputElement.value)},exitCodeGroup.appendChild(exitCodeBtn),endScreenElement.appendChild(exitCodeParaElement),exitCodeElement.appendChild(exitCodeGroup),exitCodeElement.appendChild(exitCodeInputElement),endScreenElement.appendChild(exitCodeElement),this.exitCodeInputElement=exitCodeInputElement),this.showEmailForm&&node.widgets.append(this.emailForm,endScreenElement,{title:!1,panel:!1}),this.showFeedbackForm&&node.widgets.append(this.feedback,endScreenElement,{title:!1,panel:!1}),endScreenElement},EndScreen.prototype.listeners=function(){var that;that=this,node.on.data("WIN",(function(message){that.updateDisplay(message.data)}))},EndScreen.prototype.copy=function(text){var inp=document.createElement("input");try{document.body.appendChild(inp),inp.value=text,inp.select(),document.execCommand("copy",!1),inp.remove(),alert(this.getText("exitCopyMsg"))}catch(err){alert(this.getText("exitCopyError"))}},EndScreen.prototype.updateDisplay=function(data){var preWin,totalWin,totalRaw,exitCode,totalHTML,exitCodeHTML,ex,err;if(this.totalWinCb)totalWin=this.totalWinCb(data,this);else{if(void 0===data.total&&void 0===data.totalRaw)throw new Error("EndScreen.updateDisplay: data.total and data.totalRaw cannot be both undefined.");void 0!==data.total&&!1===(totalWin=J.isNumber(data.total))&&(node.err("EndScreen.updateDisplay: invalid data.total: "+data.total),totalWin=this.getText("errTotalWin"),err=!0),preWin="",void 0!==data.basePay&&(preWin=data.basePay),void 0!==data.bonus&&!1!==data.showBonus&&(""!==preWin&&(preWin+=" + "),preWin+=data.bonus),data.partials&&(J.isArray(data.partials)?(""!==preWin&&(preWin+=" + "),preWin+=data.partials.join(" + ")):node.err("EndScreen error, invalid partials win: "+data.partials)),void 0!==data.totalRaw&&(preWin?preWin+=" = ":preWin="",preWin+=data.totalRaw,void 0!==(ex=void 0!==data.exchangeRate?data.exchangeRate:node.game.settings.EXCHANGE_RATE)&&(preWin+="*"+ex),void 0===totalWin&&(totalRaw=J.isNumber(data.totalRaw,0),totalWin=parseFloat(ex*totalRaw).toFixed(2),!1===(totalWin=J.isNumber(totalWin,0))&&(node.err("EndScreen.updateDisplay: invalid : totalWin calculation from totalRaw."),totalWin=this.getText("errTotalWin"),err=!0))),err||(totalWin!==preWin&""!==preWin&&(totalWin=preWin+" = "+totalWin),totalWin+=" "+this.totalWinCurrency)}"string"!=typeof(exitCode=data.exit)&&(node.err("EndScreen error, invalid exit code: "+exitCode),exitCode=this.getText("errExitCode")),totalHTML=this.totalWinInputElement,exitCodeHTML=this.exitCodeInputElement,totalHTML&&this.showTotalWin&&(totalHTML.value=totalWin),exitCodeHTML&&this.showExitCode&&(exitCodeHTML.value=exitCode)}}(node),function(node){"use strict";function Feedback(options){var tmp;if(void 0!==options.maxLength&&(console.log("***Feedback constructor: maxLength is deprecated, use maxChars instead***"),options.maxChars=options.maxLength),void 0!==options.minLength&&(console.log("***Feedback constructor: minLength is deprecated, use minChars instead***"),options.minChars=options.minLength),this.mainText=null,this.hint=null,this.spanMainText=null,void 0===options.maxChars)this.maxChars=0;else{if(!1===(tmp=J.isInt(options.maxChars,0)))throw new TypeError("Feedback constructor: maxChars must be an integer >= 0 or undefined. Found: "+options.maxChars);this.maxChars=tmp}if(void 0===options.minChars)this.minChars=0;else{if(!1===(tmp=J.isInt(options.minChars,0,void 0,!0)))throw new TypeError("Feedback constructor: minChars must be an integer >= 0 or undefined. Found: "+options.minChars);if(this.maxChars&&tmp>this.maxChars)throw new TypeError("Feedback constructor: minChars cannot be greater than maxChars. Found: "+tmp+" > "+this.maxChars);this.minChars=tmp}if(void 0===options.maxWords)this.maxWords=0;else{if(!1===(tmp=J.isInt(options.maxWords,0,void 0,!0)))throw new TypeError("Feedback constructor: maxWords must be an integer >= 0 or undefined. Found: "+options.maxWords);this.maxWords=options.maxWords}if(void 0===options.minWords)this.minWords=0;else{if(!1===(tmp=J.isInt(options.minWords,0,void 0,!0)))throw new TypeError("Feedback constructor: minWords must be an integer >= 0 or undefined. Found: "+options.minWords);if(this.minWords=options.minWords,this.maxChars&&(tmp=(this.maxChars+1)/2,this.minWords>tmp))throw new TypeError("Feedback constructor: minWords cannot be larger than (maxChars+1)/2. Found: "+this.minWords+" > "+tmp)}if(this.maxWords){if(this.maxChars&&this.maxChars "+this.maxWords);if(this.minChars>this.maxWords)throw new TypeError("Feedback constructor: minChars cannot be greater than maxWords. Found: "+this.minChars+" > "+this.maxWords)}if(void 0===options.rows)this.rows=3;else{if(!1===J.isInt(options.rows,0))throw new TypeError("Feedback constructor: rows must be an integer > 0 or undefined. Found: "+options.rows);this.rows=options.rows}if(void 0===options.maxAttemptLength)this.maxAttemptLength=0;else{if(!1===(tmp=J.isNumber(options.maxAttemptLength,0)))throw new TypeError("Feedback constructor: options.maxAttemptLength must be a number > 0 or undefined. Found: "+options.maxAttemptLength);this.maxAttemptLength=tmp}if(this.showSubmit=void 0===options.showSubmit||!!options.showSubmit,options.onsubmit){if("object"!=typeof options.onsubmit)throw new TypeError("Feedback constructor: onsubmit must be string or object. Found: "+options.onsubmit);this.onsubmit=options.onsubmit}else this.onsubmit={feedbackOnly:!0,send:!0,updateUI:!0};this._feedback=options.feedback||null,this.attempts=[],this.timeInputBegin=null,this.feedbackForm=null,this.textareaElement=null,this.charCounter=null,this.wordCounter=null,this.submitButton=null,this.setMsg=!!options.setMsg||!1}function getFeedback(){var out;return(out=this.textareaElement?this.textareaElement.value:this._feedback)?out.trim():out}node.widgets.register("Feedback",Feedback),Feedback.version="1.6.0",Feedback.description="Displays a configurable feedback form",Feedback.title="Feedback",Feedback.className="feedback",Feedback.texts={autoHint:function(w){var res,res2;return w.minChars&&w.maxChars?res="between "+w.minChars+" and "+w.maxChars+" characters":w.minChars?(res="at least "+w.minChars+" character",w.minChars>1&&(res+="s")):w.maxChars&&(res="at most "+w.maxChars+" character",w.maxChars>1&&(res+="s")),w.minWords&&w.maxWords?res2="beetween "+w.minWords+" and "+w.maxWords+" words":w.minWords?(res2="at least "+w.minWords+" word",w.minWords>1&&(res2+="s")):w.maxWords&&(res2="at most "+w.maxWords+" word",w.maxWords>1&&(res2+="s")),res?(res="("+res,res2&&(res+=", and "+res2),res+")"):!!res2&&"("+res2+")"},submit:"Submit feedback",label:"Any feedback? Let us know here:",sent:"Sent!",counter:function(w,param){var res;return res=param.chars?" character":" word",1!==param.len&&(res+="s"),param.needed?res+=" needed":param.over?res+=" over":param.justcount||(res+=" remaining"),res}},Feedback.dependencies={JSUS:{}},Feedback.prototype.init=function(options){if("string"==typeof options.mainText)this.mainText=options.mainText;else{if(void 0!==options.mainText)throw new TypeError("Feedback.init: options.mainText must be string or undefined. Found: "+options.mainText);this.mainText=this.getText("label")}if("string"==typeof options.hint||!1===options.hint)this.hint=options.hint;else{if(void 0!==options.hint)throw new TypeError("Feedback.init: options.hint must be a string, false, or undefined. Found: "+options.hint);this.hint=this.getText("autoHint")}},Feedback.prototype.verifyFeedback=function(markAttempt,updateUI){var feedback,length,res,submitButton,charCounter,wordCounter,tmp,updateCharCount,updateCharColor,updateWordCount,updateWordColor;return length=(feedback=getFeedback.call(this))?feedback.length:0,submitButton=this.submitButton,charCounter=this.charCounter,wordCounter=this.wordCounter,res=!0,lengththis.maxChars?(res=!1,updateCharCount=(tmp=length-this.maxChars)+this.getText("counter",{chars:!0,over:!0,len:tmp}),updateCharColor="#a32020"):(updateCharCount=(tmp=this.maxChars?this.maxChars-length:length)+this.getText("counter",{chars:!0,len:tmp,justcount:!this.maxChars}),updateCharColor="#78b360"),wordCounter&&((length=(tmp=feedback?feedback.match(/\b[-?(\w+)?]+\b/gi):0)?tmp.length:0)this.maxWords?(res=!1,updateWordCount=(tmp=length-this.maxWords)+this.getText("counter",{over:!0,len:tmp}),updateWordColor="#a32020"):(updateWordCount=(tmp=this.maxWords?this.maxWords-length:length)+this.getText("counter",{len:tmp,justcount:!this.maxWords}),updateWordColor="#78b360")),updateUI&&(submitButton&&(submitButton.disabled=!res),charCounter&&(charCounter.style.backgroundColor=updateCharColor,charCounter.innerHTML=updateCharCount),wordCounter&&(wordCounter.style.backgroundColor=updateWordColor,wordCounter.innerHTML=updateWordCount)),res||void 0!==markAttempt&&!markAttempt||(this.maxAttemptLength&&length>this.maxAttemptLength&&(feedback=feedback.substr(0,this.maxAttemptLength)),this.attempts.push(feedback)),res},Feedback.prototype.append=function(){var that;that=this,this.feedbackForm=W.append("form",this.bodyDiv,{className:"feedback-form"}),this.mainText&&(this.spanMainText=W.append("span",this.feedbackForm,{className:"feedback-maintext",innerHTML:this.mainText})),this.hint&&W.append("span",this.spanMainText||this.feedbackForm,{className:"feedback-hint",innerHTML:this.hint}),this.textareaElement=W.append("textarea",this.feedbackForm,{className:"form-control feedback-textarea",type:"text",rows:this.rows}),this.showSubmit&&(this.submitButton=W.append("input",this.feedbackForm,{className:"btn btn-lg btn-primary",type:"submit",value:this.getText("submit")}),J.addEvent(this.feedbackForm,"submit",(function(event){event.preventDefault(),that.getValues(that.onsubmit)}))),this.showCounters(),J.addEvent(this.feedbackForm,"input",(function(){that.isHighlighted()&&that.unhighlight(),that.verifyFeedback(!1,!0)})),J.addEvent(this.feedbackForm,"click",(function(){that.isHighlighted()&&that.unhighlight()})),this.verifyFeedback(!1,!0)},Feedback.prototype.setValues=function(options){var feedback,maxChars,minChars,nWords,i;if((options=options||{}).feedback)feedback=options.feedback;else if(minChars=this.minChars||0,maxChars=this.maxChars?this.maxChars:this.maxWords?4*this.maxWords:minChars?minChars+80:80,feedback=J.randomString(J.randomInt(minChars,maxChars),"aA_1"),this.minWords&&(nWords=this.minWords-feedback.split(" ").length)>0)for(i=0;i")),!1!==opts.verify&&(res=this.verifyFeedback(opts.markAttempt,opts.updateUI)),!1===res&&(opts.updateUI||opts.highlight)&&this.highlight(),opts.feedbackOnly||(feedback={timeBegin:this.timeInputBegin,feedback:feedback,attempts:this.attempts,valid:res},opts.markAttempt&&(feedback.isCorrect=res)),""!==feedback&&(opts.send&&res||opts.sendAnyway)&&(this.sendValues({values:feedback}),opts.updateUI&&(this.submitButton.setAttribute("value",this.getText("sent")),this.submitButton.disabled=!0,this.textareaElement.disabled=!0)),opts.reset&&this.reset(),feedback},Feedback.prototype.sendValues=function(opts){var values;return values=(opts=opts||{feedbackOnly:!0}).values||this.getValues(opts),this.setMsg?("string"==typeof values&&(values={feedback:values}),node.set(values,opts.to||"SERVER")):node.say("feedback",opts.to||"SERVER",values),values},Feedback.prototype.highlight=function(border){if(border&&"string"!=typeof border)throw new TypeError("Feedback.highlight: border must be string or undefined. Found: "+border);this.isAppended()&&!0!==this.highlighted&&(this.textareaElement.style.border=border||"3px solid red",this.highlighted=!0,this.emit("highlighted",border))},Feedback.prototype.unhighlight=function(){this.isAppended()&&!0===this.highlighted&&(this.textareaElement.style.border="",this.highlighted=!1,this.emit("unhighlighted"))},Feedback.prototype.reset=function(){this.attempts=[],this.timeInputBegin=null,this._feedback=null,this.textareaElement&&(this.textareaElement.value=""),this.isHighlighted()&&this.unhighlight()},Feedback.prototype.disable=function(){this.textareaElement&&!this.textareaElement.disabled&&(this.disabled=!0,this.submitElement&&(this.submitElement.disabled=!0),this.textareaElement.disabled=!0,this.emit("disabled"))},Feedback.prototype.enable=function(){this.textareaElement&&this.textareaElement.disabled&&(this.disabled=!1,this.submitElement&&(this.submitElement.disabled=!1),this.textareaElement.disabled=!1,this.emit("enabled"))},Feedback.prototype.showCounters=function(){this.charCounter?this.charCounter.style.display="":(this.minChars||this.maxChars)&&(this.charCounter=W.append("span",this.feedbackForm,{className:"feedback-char-count badge",innerHTML:this.maxChars})),this.wordCounter?this.wordCounter.style.display="":(this.minWords||this.maxWords)&&(this.wordCounter=W.append("span",this.feedbackForm,{className:"feedback-char-count badge",innerHTML:this.maxWords}),this.charCounter&&(this.wordCounter.style["margin-left"]="10px"))},Feedback.prototype.hideCounters=function(){this.charCounter&&(this.charCounter.style.display="none"),this.wordCounter&&(this.wordCounter.style.display="none")}}(node),function(node){"use strict";node.widgets.register("GroupMalleability",GroupMalleability),GroupMalleability.version="0.1.0",GroupMalleability.description="Displays an interface to measure perception for group malleability.",GroupMalleability.title="Group Malleability",GroupMalleability.className="group-malleability";var items=["As hard as it is to admit, it is impossible to change the central characteristics of nationalities and groups.","Groups that are characterized by extreme and violent traits will never change as these traits are inherently ingrained in their nature.","Groups can sometimes change their outward behavior, but can never change who they really are.","Every nationality or group has a fixed set of beliefs and values that cannot be changed.","Social and political processes can lead to changes in a group's values and morality."],choices=[1,2,3,4,5,6,7],header=["Strongly Oppose","Somewhat Oppose","Slightly Oppose","Neutral","Slightly Favor","Somewhat Favor","Strongly Favor"];function GroupMalleability(){this.ctg=null,this.choices=choices,this.header=header,this.mainText=null}GroupMalleability.texts={mainText:"Show how much you favor or oppose each idea below by selecting a number from 1 to 7 on the scale below. You can work quickly, your first feeling is generally best."},GroupMalleability.dependencies={},GroupMalleability.prototype.init=function(opts){if((opts=opts||{}).choices){if(!J.isArray(opts.choices)||opts.choices.length<2)throw new Error("GroupMalleability.init: choices must be an array of length > 1 or undefined. Found: "+opts.choices);this.choices=opts.choices}if(opts.header){if(!J.isArray(opts.header)||opts.header.length!==this.choices.length)throw new Error("GroupMalleability.init: header must be an array of length equal to the number of choices or undefined. Found: "+opts.header);this.header=opts.header}if(opts.mainText){if("string"!=typeof opts.mainText&&!1!==opts.mainText)throw new Error("GroupMalleability.init: mainText must be string, false, or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}else!1!==opts.mainText&&(this.mainText=this.getText("mainText"))},GroupMalleability.prototype.append=function(){this.ctg=node.widgets.add("ChoiceTableGroup",this.panelDiv,{id:this.id||"groupmalleability_choicetable",items:items.map((function(item,i){return["GM_"+(i+1),item]})),choices:this.choices,mainText:this.mainText,title:!1,panel:!1,requiredChoice:this.required,header:this.header})},GroupMalleability.prototype.getValues=function(opts){return opts=opts||{},this.ctg.getValues(opts)},GroupMalleability.prototype.setValues=function(opts){return opts=opts||{},this.ctg.setValues(opts)},GroupMalleability.prototype.enable=function(opts){return this.ctg.enable(opts)},GroupMalleability.prototype.disable=function(opts){return this.ctg.disable(opts)},GroupMalleability.prototype.highlight=function(opts){return this.ctg.highlight(opts)},GroupMalleability.prototype.unhighlight=function(opts){return this.ctg.unhighlight(opts)}}(node),function(node){"use strict";function LanguageSelector(options){var that=this;this.options=options,this.availableLanguages={en:{name:"English",nativeName:"English",shortName:"en"}},this.currentLanguage=null,this.buttonListLength=null,this.displayForm=null,this.optionsLabel={},this.optionsDisplay={},this.loadingDiv=null,this.languagesLoaded=!1,this.usingButtons=!0,this.updatePlayer="ondone",this.setUriPrefix=!0,this.notifyServer=!0,this.onLangCallback=function(msg){for(var language;that.displayForm.firstChild;)that.displayForm.removeChild(that.displayForm.firstChild);if(that.availableLanguages=msg.data,that.usingButtons)for(language in msg.data)msg.data.hasOwnProperty(language)&&(that.optionsLabel[language]=W.get("label",{id:language+"Label",for:language+"RadioButton"}),that.optionsDisplay[language]=W.get("input",{id:language+"RadioButton",type:"radio",name:"languageButton",value:msg.data[language].name}),that.optionsDisplay[language].onclick=makeSetLanguageOnClick(language),that.optionsLabel[language].appendChild(that.optionsDisplay[language]),that.optionsLabel[language].appendChild(document.createTextNode(msg.data[language].nativeName)),W.add("br",that.displayForm),that.optionsLabel[language].className="unselectedButtonLabel",that.displayForm.appendChild(that.optionsLabel[language]));else{for(language in that.displaySelection=W.get("select","selectLanguage"),msg.data)that.optionsLabel[language]=document.createTextNode(msg.data[language].nativeName),that.optionsDisplay[language]=W.get("option",{id:language+"Option",value:language}),that.optionsDisplay[language].appendChild(that.optionsLabel[language]),that.displaySelection.appendChild(that.optionsDisplay[language]);that.displayForm.appendChild(that.displaySelection),that.displayForm.onchange=function(){that.setLanguage(that.displaySelection.value,"onselect"===that.updatePlayer)}}function makeSetLanguageOnClick(langStr){return function(){that.setLanguage(langStr,"onselect"===that.updatePlayer)}}that.loadingDiv.style.display="none",that.languagesLoaded=!0,that.setLanguage(node.player.lang.shortName||"en",!1),that.onLangCallbackExtension&&(that.onLangCallbackExtension(msg),that.onLangCallbackExtension=null)},this.onLangCallbackExtension=null}node.widgets.register("LanguageSelector",LanguageSelector),LanguageSelector.version="0.6.2",LanguageSelector.description="Display information about the current language and allows to change language.",LanguageSelector.title="Language",LanguageSelector.className="languageselector",LanguageSelector.texts.loading="Loading language information...",LanguageSelector.dependencies={JSUS:{}},LanguageSelector.prototype.init=function(options){if(J.mixout(options,this.options),this.options=options,void 0!==this.options.usingButtons&&(this.usingButtons=!!this.options.usingButtons),void 0!==this.options.notifyServer)if(!1===this.options.notifyServer)this.options.notifyServer="never";else{if("string"!=typeof this.options.notifyServer)throw new Error("LanguageSelector.init: options.notifyServer must be "+this.options.notifyServer);if("never"!==this.options.notifyServer&&"onselect"!==this.options.notifyServer&&"ondone"!==this.options.notifyServer)throw new Error('LanguageSelector.init: invalid value for notifyServer: "'+this.options.notifyServer+'". Valid values: "never","onselect", "ondone".');this.notifyServer=this.options.notifyServer}void 0!==this.options.setUriPrefix&&(this.setUriPrefix=!!this.options.setUriPrefix),node.on.lang(this.onLangCallback),this.displayForm=W.get("form","radioButtonForm"),this.loadingDiv=W.add("div",this.displayForm),this.loadingDiv.innerHTML=this.getText("loading"),this.loadLanguages()},LanguageSelector.prototype.append=function(){this.bodyDiv.appendChild(this.displayForm)},LanguageSelector.prototype.setLanguage=function(langName,updatePlayer){this.usingButtons&&null!==this.currentLanguage&&this.currentLanguage!==this.availableLanguages[langName]&&(this.optionsDisplay[this.currentLanguage].checked="unchecked",this.optionsLabel[this.currentLanguage].className="unselectedButtonLabel"),this.currentLanguage=langName,this.usingButtons?(this.optionsDisplay[this.currentLanguage].checked="checked",this.optionsLabel[this.currentLanguage].className="selectedButtonLabel"):this.displaySelection.value=this.currentLanguage,!1!==updatePlayer&&node.setLanguage(this.availableLanguages[this.currentLanguage],this.setUriPrefix,this.notifyServer)},LanguageSelector.prototype.updateAvalaibleLanguages=function(options){options&&options.callback&&(this.onLangCallbackExtension=options.callback),node.socket.send(node.msg.create({target:"LANG",to:"SERVER",action:"get"}))},LanguageSelector.prototype.loadLanguages=function(options){this.languagesLoaded?options&&options.callback&&options.callback():this.updateAvalaibleLanguages(options)},LanguageSelector.prototype.listeners=function(){var that;that=this,node.events.step.on("REALLY_DONE",(function(){"ondone"===that.updatePlayer&&node.setLanguage(that.availableLanguages[that.currentLanguage],that.setUriPrefix,that.notifyServer)}))}}(node),function(node){"use strict";function MoneyTalks(){this.spanCurrency=null,this.spanMoney=null,this.currency="ECU",this.money=0,this.precision=2,this.showCurrency=!0,this.classnameCurrency="moneytalkscurrency",this.classnameMoney="moneytalksmoney"}node.widgets.register("MoneyTalks",MoneyTalks),MoneyTalks.version="0.5.0",MoneyTalks.description="Displays the earnings of a player.",MoneyTalks.title="Earnings",MoneyTalks.className="moneytalks",MoneyTalks.dependencies={JSUS:{}},MoneyTalks.prototype.init=function(options){"string"==typeof(options=options||{}).currency&&(this.currency=options.currency),void 0!==options.showCurrency&&(this.showCurrency=!!options.showCurrency),"number"==typeof options.money&&(this.money=options.money),"number"==typeof options.precision&&(this.precision=options.precision),"string"==typeof options.MoneyClassName&&(this.classnameMoney=options.MoneyClassName),"string"==typeof options.currencyClassName&&(this.classnameCurrency=options.currencyClassName)},MoneyTalks.prototype.append=function(){this.spanMoney||(this.spanMoney=document.createElement("span")),this.spanCurrency||(this.spanCurrency=document.createElement("span")),this.showCurrency||(this.spanCurrency.style.display="none"),this.spanMoney.className=this.classnameMoney,this.spanCurrency.className=this.classnameCurrency,this.spanCurrency.innerHTML=this.currency,this.spanMoney.innerHTML=this.money,this.bodyDiv.appendChild(this.spanMoney),this.bodyDiv.appendChild(this.spanCurrency)},MoneyTalks.prototype.listeners=function(){var that=this;node.on("MONEYTALKS",(function(amount,clear){that.update(amount,clear)}))},MoneyTalks.prototype.update=function(amount,clear){var parsedAmount;if(!1!==(parsedAmount=J.isNumber(amount)))return clear&&(this.money=0),this.money+=parsedAmount,this.spanMoney.innerHTML=this.money.toFixed(this.precision),this.money;node.err("MoneyTalks.update: invalid amount: "+amount)},MoneyTalks.prototype.getValues=function(){return this.money}}(node),function(node){"use strict";function MoodGauge(options){this.methods={},this.method="I-PANAS-SF",this.mainText=null,this.gauge=null,this.addMethod("I-PANAS-SF",I_PANAS_SF)}function I_PANAS_SF(options){var items,emotions,choices,right,i,len;for(choices=options.choices||["1","2","3","4","5"],emotions=options.emotions||["Upset","Hostile","Alert","Ashamed","Inspired","Nervous","Determined","Attentive","Afraid","Active"],options.left||"never",right=options.right||"always",len=emotions.length,items=new Array(len),i=-1;++i'+emotions[i]+": never",right:right,choices:choices};return node.widgets.get("ChoiceTableGroup",{id:options.id||"ipnassf",items:items,mainText:this.mainText||this.getText("mainText"),title:!1,requiredChoice:!0,storeRef:!1})}node.widgets.register("MoodGauge",MoodGauge),MoodGauge.version="0.4.0",MoodGauge.description="Displays an interface to measure mood and emotions.",MoodGauge.title="Mood Gauge",MoodGauge.className="moodgauge",MoodGauge.texts.mainText="Thinking about yourself and how you normally feel, to what extent do you generally feel: ",MoodGauge.dependencies={JSUS:{}},MoodGauge.prototype.init=function(opts){var gauge;if(void 0!==opts.method){if("string"!=typeof opts.method)throw new TypeError("MoodGauge.init: method must be string or undefined: "+opts.method);if(!this.methods[opts.method])throw new Error("MoodGauge.init: method is invalid: "+opts.method);this.method=opts.method}if(opts.mainText){if("string"!=typeof opts.mainText)throw new TypeError("MoodGauge.init: mainText must be string or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}gauge=this.methods[this.method].call(this,opts),function(method,gauge){if(!gauge)throw new Error("MoodGauge.init: method "+method+"did not create element gauge.");if("function"!=typeof gauge.getValues)throw new Error("MoodGauge.init: method "+method+": gauge missing function getValues.");if("function"!=typeof gauge.enable)throw new Error("MoodGauge.init: method "+method+": gauge missing function enable.");if("function"!=typeof gauge.disable)throw new Error("MoodGauge.init: method "+method+": gauge missing function disable.");if("function"!=typeof gauge.append)throw new Error("MoodGauge.init: method "+method+": gauge missing function append.")}(this.method,gauge),this.gauge=gauge,this.on("enabled",(function(){gauge.enable()})),this.on("disabled",(function(){gauge.disable()})),this.on("highlighted",(function(){gauge.highlight()})),this.on("unhighlighted",(function(){gauge.unhighlight()}))},MoodGauge.prototype.append=function(){node.widgets.append(this.gauge,this.bodyDiv,{panel:!1})},MoodGauge.prototype.addMethod=function(name,cb){if("string"!=typeof name)throw new Error("MoodGauge.addMethod: name must be string: "+name);if("function"!=typeof cb)throw new Error("MoodGauge.addMethod: cb must be function: "+cb);if(this.methods[name])throw new Error("MoodGauge.addMethod: name already existing: "+name);this.methods[name]=cb},MoodGauge.prototype.getValues=function(opts){return this.gauge.getValues(opts)},MoodGauge.prototype.setValues=function(opts){return this.gauge.setValues(opts)}}(node),function(node){"use strict";function Requirements(options){this.requirements=[],this.stillChecking=0,this.withTimeout=options.withTimeout||!0,this.timeoutTime=options.timeoutTime||1e4,this.timeoutId=null,this.summary=null,this.summaryUpdate=null,this.summaryResults=null,this.dots=null,this.hasFailed=!1,this.results=[],this.completed={},this.sayResults=options.sayResults||!1,this.sayResultsLabel=options.sayResultLabel||"requirements",this.addToResults=options.addToResults||null,this.onComplete=null,this.onSuccess=null,this.onFailure=null,this.callbacksExecuted=!1,this.list=new W.List({render:{pipeline:function(o){var imgPath,img,span,text;imgPath="/images/"+(o.content.success?"success-icon.png":"delete-icon.png"),(img=document.createElement("img")).src=imgPath,"object"==typeof o.content.text&&(o.content.text=extractErrorMsg(o.content.text));return text=document.createTextNode(o.content.text),(span=document.createElement("span")).className="requirement",span.appendChild(img),span.appendChild(text),span},returnAt:"first"}})}function resultCb(that,name,i){var req,update,res;if(update=function(success,errors,data){if(that.completed[name])throw new Error("Requirements.checkRequirements: test already completed: "+name);if(that.completed[name]=!0,that.updateStillChecking(-1),success||(that.hasFailed=!0),"string"==typeof errors&&(errors=[errors]),errors){if(!J.isArray(errors))throw new Error("Requirements.checkRequirements: errors must be array or undefined. Found: "+errors);that.displayResults(errors)}that.results.push({name:name,success:success,errors:errors,data:data}),that.isCheckingFinished()&&that.checkingFinished()},"function"==typeof(req=that.requirements[i]))res=req(update);else{if("object"!=typeof req)throw new TypeError("Requirements.checkRequirements: invalid requirement: "+name+".");res=req.cb(update,req.params||{})}res&&update(res.success,res.errors,res.data)}function extractErrorMsg(e){var errMsg;return errMsg=e.msg?e.msg:e.message?e.message:e.description?errMsg.description:e.toString()}node.widgets.register("Requirements",Requirements),Requirements.version="0.7.2",Requirements.description="Checks a set of requirements and display the results",Requirements.title="Requirements",Requirements.className="requirements",Requirements.texts.errStr="One or more function is taking too long. This is likely to be due to a compatibility issue with your browser or to bad network connectivity.",Requirements.texts.testPassed="All tests passed.",Requirements.dependencies={JSUS:{},List:{}},Requirements.prototype.init=function(conf){if("object"!=typeof conf)throw new TypeError("Requirements.init: conf must be object. Found: "+conf);if(conf.requirements){if(!J.isArray(conf.requirements))throw new TypeError("Requirements.init: conf.requirements must be array or undefined. Found: "+conf.requirements);this.requirements=conf.requirements}if(void 0!==conf.onComplete){if(null!==conf.onComplete&&"function"!=typeof conf.onComplete)throw new TypeError("Requirements.init: conf.onComplete must be function, null or undefined. Found: "+conf.onComplete);this.onComplete=conf.onComplete}if(void 0!==conf.onSuccess){if(null!==conf.onSuccess&&"function"!=typeof conf.onSuccess)throw new TypeError("Requirements.init: conf.onSuccess must be function, null or undefined. Found: "+conf.onSuccess);this.onSuccess=conf.onSuccess}if(void 0!==conf.onFailure){if(null!==conf.onFailure&&"function"!=typeof conf.onFailure)throw new TypeError("Requirements.init: conf.onFailure must be function, null or undefined. Found: "+conf.onFailure);this.onFailure=conf.onFailure}if(conf.maxExecTime){if(null!==conf.maxExecTime&&"number"!=typeof conf.maxExecTime)throw new TypeError("Requirements.init: conf.onMaxExecTime must be number, null or undefined. Found: "+conf.maxExecTime);this.withTimeout=!!conf.maxExecTime,this.timeoutTime=conf.maxExecTime}},Requirements.prototype.addRequirements=function(){var i,len;for(i=-1,len=arguments.length;++i0&&that.displayResults([that.getText("errStr")]),that.timeoutId=null,that.hasFailed=!0,that.checkingFinished()}),this.timeoutTime)},Requirements.prototype.clearTimeout=function(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null)},Requirements.prototype.updateStillChecking=function(update,absolute){var total,remaining;this.stillChecking=absolute?update:this.stillChecking+update,remaining=(total=this.requirements.length)-this.stillChecking,this.summaryUpdate.innerHTML=" ("+remaining+" / "+total+")"},Requirements.prototype.isCheckingFinished=function(){return this.stillChecking<=0},Requirements.prototype.checkingFinished=function(force){var results;this.callbacksExecuted&&!force||(this.callbacksExecuted=!0,this.timeoutId&&clearTimeout(this.timeoutId),this.dots.stop(),this.sayResults&&(results={success:!this.hasFailed,results:this.results},this.addToResults&&J.mixin(results,this.addToResults()),node.say(this.sayResultsLabel,"SERVER",results)),this.onComplete&&this.onComplete(),this.hasFailed?this.onFailure&&this.onFailure():this.onSuccess&&this.onSuccess())},Requirements.prototype.displayResults=function(results){var i,len;if(!this.list)throw new Error("Requirements.displayResults: list not found. Have you called .append() first?");if(!J.isArray(results))throw new TypeError("Requirements.displayResults: results must be array. Found: "+results);if(!this.hasFailed&&this.stillChecking<=0)this.list.addDT({success:!0,text:this.getText("testPassed")});else for(i=-1,len=results.length;++iand',out=p1+of,out+=opts.currencyAfter?v1+cur:cur+v1,(out+=sep+p2+of)+(opts.currencyAfter?v2+cur:cur+v2)}function holtLaury(options){var items,i,j,tmp,v1,v2,v3,v4,p1,p2;for(tmp=options.values||[2,1.6,3.85,.1],options.scale&&(tmp=tmp.map((function(i){return i*options.scale}))),v1=tmp[0].toFixed(2),v2=tmp[1].toFixed(2),v3=tmp[2].toFixed(2),v4=tmp[3].toFixed(2),10,items=new Array(10),i=0;i<10;i++)p1=(j=i+1)+"/10",p2=10-j+"/10",items[i]={id:"hl_"+j,left:j+". ",choices:[makeProbString(p1,v1,p2,v2,options),makeProbString(p1,v3,p2,v4,options)]};return node.widgets.get("ChoiceTableGroup",{id:options.id||"holt_laury",items:items,mainText:this.mainText||this.getText("holt_laury_mainText"),title:!1,requiredChoice:!0,storeRef:!1})}function bomb(opts){var that,probBomb,bombBox,infoDiv,bombResult,slider,button,isWinner,finalValue;if(that=this,opts.boxHeight){if("string"!=typeof opts.boxHeight)throw new Error("Bomb.init: boxHeight must be string or undefined. Found: "+opts.boxHeight);W.cssRule("div.riskgauge .bomb-box { height: "+opts.boxHeight+"}")}if(void 0!==opts.probBomb){if(!1===J.isNumber(opts.probBomb,0,1,!0,!0))throw new Error("Bomb.init: probBomb must be a number between 0 and 1 or undefined. Found: "+opts.probBomb);probBomb=opts.probBomb}else probBomb=1;if(this._highlight=this.highlight,this._unhighlight=this.unhighlight,void 0!==opts.boxValue){if(this.boxValue=J.isNumber(opts.boxValue,0),!this.boxValue)throw new TypeError("Bomb.init: boxValue must be an a number > 0 or undefined. Found: "+opts.boxValue)}else this.boxValue=.01;if(this.currency=opts.currency||"USD",this.revealProbBomb=void 0===opts.revealProbBomb||!!opts.revealProbBomb,void 0!==opts.totBoxes){if(!J.isInt(opts.totBoxes,0,1e4,!1,!0))throw new TypeError("Bomb.init: maxBoxes must be an integer > 0 and <= 10000 or undefined. Found: "+opts.totBoxes);this.totBoxes=opts.totBoxes}else this.totBoxes=100;if(void 0!==opts.maxBoxes){if(!J.isInt(opts.maxBoxes,0,this.totBoxes))throw new TypeError("Bomb.init: maxBoxes must be a positive integer <= "+this.totBoxes+" or undefined. Found: "+opts.maxBoxes);this.maxBoxes=opts.maxBoxes}else this.maxBoxes=1===probBomb?this.totBoxes-1:this.totBoxes;if(void 0!==opts.boxesInRow){if(!J.isInt(opts.boxesInRow,0))throw new TypeError("Bomb.init: boxesInRow must be a positive integer or undefined. Found: "+opts.boxesInRow);this.boxesInRow=opts.boxesInRow>this.totBoxes?this.totBoxes:opts.boxesInRow}else this.boxesInRow=this.totBoxes<10?this.totBoxes:10;return this.withPrize=void 0===opts.withPrize||!!opts.withPrize,bombBox=Math.random()>=probBomb?-1:Math.ceil(Math.random()*this.totBoxes),{setValues:function(opts){slider.setValues(opts)},getValues:function(opts){var out,values,nb,ic;return opts=opts||{},values=slider.getValues(),void 0!==finalValue?(nb=finalValue,ic=!0):(nb=parseInt(slider.slider.value,10),ic=!1),(out={value:nb,isCorrect:ic,totalMove:values.totalMove,isWinner:isWinner,time:values.time,reward:0}).isCorrect||void 0!==opts.highlight&&!opts.highlight||slider.highlight(),!0===isWinner&&(out.reward=finalValue*that.boxValue),out},highlight:function(){slider.highlight()},unhighlight:function(){slider.unhighlight()},append:function(){var nRows;W.add("div",that.bodyDiv,{innerHTML:that.mainText||that.getText("bomb_mainText",probBomb)}),slider=node.widgets.add("Slider",that.bodyDiv,{min:0,max:that.maxBoxes,hint:that.getText("bomb_sliderHint"),title:!1,initialValue:0,displayValue:!1,displayNoChange:!1,type:"flat",required:!0,panel:!1,onmove:function(value){var i,c,v;for(that._unhighlight(),value>0?(button.style.display="",button.disabled=!1,bombResult.innerHTML=""):(button.style.display="none",bombResult.innerHTML=that.getText("bomb_warn"),button.disabled=!0),i=0;ii?"#1be139":"#000000";W.gid("bomb_numBoxes").innerText=value,c=that.currency,v=that.boxValue,that.withPrize&&(W.gid("bomb_boxValue").innerText=v+c,W.gid("bomb_totalWin").innerText=Number(value*v).toFixed(2)+c)},storeRef:!1,width:"100%"}),nRows=Math.ceil(that.totBoxes/that.boxesInRow),W.add("div",that.bodyDiv,{innerHTML:makeTable(nRows,that.boxesInRow,that.totBoxes)}),infoDiv=W.add("div",that.bodyDiv,{className:"risk-info"}),W.add("p",infoDiv,{innerHTML:that.getText("bomb_numBoxes")+' 0'}),that.withPrize&&(W.add("p",infoDiv,{innerHTML:that.getText("bomb_boxValue")+' '+this.boxValue+""}),W.add("p",infoDiv,{innerHTML:that.getText("bomb_totalWin")+' 0'})),bombResult=W.add("p",infoDiv,{id:"bomb_result"}),(button=W.add("button",that.bodyDiv,{className:"btn-danger",innerHTML:that.getText("bomb_openButton")})).style.display="none",button.onclick=function(){var cl;finalValue=parseInt(slider.slider.value,10),bombBox>-1?(W.gid(getBoxId(bombBox-1)).style.background="#fa0404",isWinner=finalValuecolSpan){out=out+'';break}out=out+'
'}return out+=""}function makeTable(nRows,boxesInRow,totBoxes){var rowId,out,colSpan;for(out='',rowId=0;rowIdtotBoxes&&(colSpan=totBoxes-rowId*boxesInRow-1),out+=makeBoxRow(rowId,boxesInRow,colSpan);return out+="

"}node.widgets.register("RiskGauge",RiskGauge),RiskGauge.version="0.8.0",RiskGauge.description="Displays an interface to measure risk preferences with different methods.",RiskGauge.title="Risk Gauge",RiskGauge.className="riskgauge",RiskGauge.texts={holt_laury_mainText:"Below you find a series of hypothetical lotteries, each contains two lotteries with different probabalities of winning. In each row, select the lottery you would rather take part in.",bomb_mainText:function(widget,probBomb){var str;return str='

',str+="Below there are "+widget.totBoxes+" black boxes. ",str+="Every box contains a prize of "+widget.boxValue+" "+widget.currency+", but ",1===probBomb?str+="one random box contains a bomb.":widget.revealProbBomb?str+="with probability "+probBomb+" one random box contains a bomb.":str+="one random box might contain a bomb.",str+=" You must decide how many boxes you want to open.",str+="

",widget.withPrize&&(str+='

',str+="You will receive a reward equal to the sum of all the prizes in every opened box. However, if you open the box with the bomb, you get nothing.

"),str+='

',str+="How many boxes do you want to open ",str+="between 1 and "+widget.maxBoxes+"?

"},bomb_sliderHint:'Move the slider to choose the number of boxes to open, then click "Open Boxes"',bomb_boxValue:"Prize per box: ",bomb_numBoxes:"Number of boxes: ",bomb_totalWin:"Total reward: ",bomb_openButton:"Open Boxes",bomb_warn:"Open at least one box.",bomb_won:"You won! You did not open the box with the bomb.",bomb_lost:"You lost! You opened the box with the bomb."},RiskGauge.texts.mainText=RiskGauge.texts.holt_laury_mainText,RiskGauge.dependencies={JSUS:{}},RiskGauge.prototype.init=function(opts){var gauge,that;if(void 0!==opts.method){if("string"!=typeof opts.method)throw new TypeError("RiskGauge.init: method must be string or undefined: "+opts.method);if(!this.methods[opts.method])throw new Error("RiskGauge.init: method is invalid: "+opts.method);this.method=opts.method}if(opts.mainText){if("string"!=typeof opts.mainText)throw new TypeError("RiskGauge.init: mainText must be string or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}if(gauge=this.methods[this.method].call(this,opts),that=this,gauge.isHidden=function(){return that.isHidden()},gauge.isCollapsed=function(){return that.isCollapsed()},!node.widgets.isWidget(gauge))throw new Error("RiskGauge.init: method "+this.method+" created invalid gauge: missing default widget methods.");this.gauge=gauge,this.on("enabled",(function(){gauge.enable&&gauge.enable()})),this.on("disabled",(function(){gauge.disable&&gauge.disable()})),this.on("highlighted",(function(){gauge.highlight&&gauge.highlight()})),this.on("unhighlighted",(function(){gauge.unhighlight&&gauge.unhighlight()}))},RiskGauge.prototype.append=function(){node.widgets.append(this.gauge,this.bodyDiv,{panel:!1})},RiskGauge.prototype.addMethod=function(name,cb){if("string"!=typeof name)throw new TypeError("RiskGauge.addMethod: name must be string: "+name);if("function"!=typeof cb)throw new TypeError("RiskGauge.addMethod: cb must be function: "+cb);if(this.methods[name])throw new Error("RiskGauge.addMethod: name already existing: "+name);this.methods[name]=cb},RiskGauge.prototype.getValues=function(opts){return this.gauge.getValues(opts)},RiskGauge.prototype.setValues=function(opts){return this.gauge.setValues(opts)}}(node),function(node){"use strict";node.widgets.register("SDO",SDO),SDO.version="0.3.0",SDO.description="Displays an interface to measure Social Dominance Orientation (S.D.O.).",SDO.title="SDO",SDO.className="SDO";var scales={SDO7:["Some groups of people must be kept in their place.","It's probably a good thing that certain groups are at the top and other groups are at the bottom.","An ideal society requires some groups to be on top and others to be on the bottom.","Some groups of people are simply inferior to other groups.","Groups at the bottom are just as deserving as groups at the top.","No one group should dominate in society.","Groups at the bottom should not have to stay in their place.","Group dominance is a poor principle.","We should not push for group equality.","We shouldn't try to guarantee that every group has the same quality of life.","It is unjust to try to make groups equal.","Group equality should not be our primary goal.","We should work to give all groups an equal chance to succeed.","We should do what we can to equalize conditions for different groups.","No matter how much effort it takes, we ought to strive to ensure that all groups have the same chance in life.","Group equality should be our ideal."],SDO16:["Some groups of people are simply inferior to other groups.","In getting what you want, it is sometimes necessary to use force against other groups.","It's OK if some groups have more of a chance in life than others.","To get ahead in life, it is sometimes necessary to step on other groups.","If certain groups stayed in their place, we would have fewer problems.","It's probably a good thing that certain groups are at the top and other groups are at the bottom.","Inferior groups should stay in their place.","Sometimes other groups must be kept in their place.","It would be good if groups could be equal.","Group equality should be our ideal.","All groups should be given an equal chance in life.","We should do what we can to equalize conditions for different groups.","Increased social equality is beneficial to society.","We would have fewer problems if we treated people more equally.","We should strive to make incomes as equal as possible.","No group should dominate in society."]};scales.SDO7s=[scales.SDO7[2],scales.SDO7[3],scales.SDO7[5],scales.SDO7[6],scales.SDO7[11],scales.SDO7[10],scales.SDO7[13],scales.SDO7[12]];var choices=[1,2,3,4,5,6,7],header=["Strongly Oppose","Somewhat Oppose","Slightly Oppose","Neutral","Slightly Favor","Somewhat Favor","Strongly Favor"];function SDO(){this.sdo=null,this.scale="SDO7s",this.choices=choices,this.header=header,this.mainText=null}SDO.texts={mainText:"Show how much you favor or oppose each idea below by selecting a number from 1 to 7 on the scale below. You can work quickly, your first feeling is generally best."},SDO.dependencies={},SDO.prototype.init=function(opts){if((opts=opts||{}).scale){if("SDO16"!==opts.scale&&"SDO7"!==opts.scale&&"SDO7s"!==opts.scale)throw new Error("SDO.init: scale must be SDO16, SDO7, SDO7s or undefined. Found: "+opts.scale);this.scale=opts.scale}if(opts.choices){if(!J.isArray(opts.choices)||opts.choices.length<2)throw new Error("SDO.init: choices must be an array of length > 1 or undefined. Found: "+opts.choices);this.choices=opts.choices}if(opts.header){if(!J.isArray(opts.header)||opts.header.length!==this.choices.length)throw new Error("SDO.init: header must be an array of length equal to the number of choices or undefined. Found: "+opts.header);this.header=opts.header}if(opts.mainText){if("string"!=typeof opts.mainText&&!1!==opts.mainText)throw new Error("SDO.init: mainText must be string, false, or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}},SDO.prototype.append=function(){this.sdo=node.widgets.add("ChoiceTableGroup",this.panelDiv,{id:this.id||"SDO_choicetable",items:this.getItems(this.scale),choices:this.choices,mainText:this.mainText||this.getText("mainText"),title:!1,panel:!1,requiredChoice:this.required,header:this.header})},SDO.prototype.getItems=function(){var s=this.scale;return scales[s].map((function(item,idx){return[s+"_"+(idx+1),item]}))},SDO.prototype.getValues=function(opts){return opts=opts||{},this.sdo.getValues(opts)},SDO.prototype.setValues=function(opts){return opts=opts||{},this.sdo.setValues(opts)},SDO.prototype.enable=function(opts){return this.sdo.enable(opts)},SDO.prototype.disable=function(opts){return this.sdo.disable(opts)},SDO.prototype.highlight=function(opts){return this.sdo.highlight(opts)},SDO.prototype.unhighlight=function(opts){return this.sdo.unhighlight(opts)}}(node),function(node){"use strict";function Slider(){var that;that=this,this.slider=null,this.rangeFill=null,this.scale=1,this.currentValue=50,this.initialValue=50,this.mainText=null,this.required=null,this.requiredChoice=null,this.hint=null,this.min=0,this.max=100,this.correctValue=null,this.displayValue=!0,this.valueSpan=null,this.displayNoChange=!0,this.noChangeSpan=null,this.totalMove=0,this.type="volume",this.hoverColor="#2076ea";var timeOut=null;this.listener=function(noChange){!noChange&&timeOut||(that.isHighlighted()&&that.unhighlight(),timeOut=setTimeout((function(){var percent,diffPercent;diffPercent=(percent=(that.slider.value-that.min)*that.scale)-that.currentValue,that.currentValue=percent,"volume"===that.type?(percent>99&&(percent=99),that.rangeFill.style.width=percent+"%"):that.rangeFill.style.width="99%",that.displayValue&&(that.valueSpan.innerHTML=that.getText("currentValue",that.slider.value)),that.displayNoChange&&!0!==noChange&&that.noChangeCheckbox.checked&&(that.noChangeCheckbox.checked=!1,J.removeClass(that.noChangeSpan,"italic")),that.totalMove+=Math.abs(diffPercent),that.onmove&&that.onmove.call(that,that.slider.value,diffPercent),timeOut=null}),0))},this.onmove=null,this.timeFrom="step"}node.widgets.register("Slider",Slider),Slider.version="0.4.0",Slider.description="Creates a configurable slider",Slider.title=!1,Slider.className="slider",Slider.texts={currentValue:function(widget,value){return"Value: "+value},noChange:"No change"},Slider.prototype.init=function(opts){var tmp,e;if(e="Slider.init: ",void 0!==opts.min){if("number"!=typeof(tmp=J.isInt(opts.min)))throw new TypeError(e+"min must be an integer or undefined. Found: "+opts.min);this.min=tmp}if(void 0!==opts.max){if("number"!=typeof(tmp=J.isInt(opts.max)))throw new TypeError(e+"max must be an integer or undefined. Found: "+opts.max);this.max=tmp}if(this.scale=100/(this.max-this.min),void 0!==(tmp=opts.initialValue)){if("random"===tmp)tmp=J.randomInt(this.min-1,this.max);else if("number"!=typeof(tmp=J.isInt(tmp,this.min,this.max,!0,!0)))throw new TypeError(e+"initialValue must be an integer >= "+this.min+" and =< "+this.max+" or undefined. Found: "+opts.initialValue);this.initialValue=this.currentValue=tmp}if(void 0!==opts.displayValue&&(this.displayValue=!!opts.displayValue),void 0!==opts.displayNoChange&&(this.displayNoChange=!!opts.displayNoChange),opts.type){if("volume"!==opts.type&&"flat"!==opts.type)throw new TypeError(e+'type must be "volume", "flat", or undefined. Found: '+opts.type);this.type=opts.type}if(void 0!==(tmp=opts.requiredChoice)?console.log("***Slider.init: requiredChoice is deprecated. Use required instead.***"):void 0!==opts.required&&(tmp=opts.required),void 0!==tmp&&(this.requiredChoice=this.required=!!tmp),opts.mainText){if("string"!=typeof opts.mainText)throw new TypeError(e+"mainText must be string or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}if(void 0!==opts.hint){if(!1!==opts.hint&&"string"!=typeof opts.hint)throw new TypeError(e+"hint must be a string, false, or undefined. Found: "+opts.hint);this.hint=opts.hint}if(this.required&&!1!==this.hint&&(this.hint||(this.hint="Movement required"),this.hint+=" *"),opts.onmove){if("function"!=typeof opts.onmove)throw new TypeError(e+"onmove must be a function or undefined. Found: "+opts.onmove);this.onmove=opts.onmove}if(opts.width){if("string"!=typeof opts.width)throw new TypeError(e+"width must be string or undefined. Found: "+opts.width);this.sliderWidth=opts.width}if(opts.hoverColor){if("string"!=typeof opts.hoverColor)throw new TypeError(e+"hoverColor must be string or undefined. Found: "+opts.hoverColor);this.hoverColor=opts.hoverColor}if(void 0!==opts.correctValue){if(!1===J.isNumber(opts.correctValue,this.min,this.max,!0,!0))throw new Error(e+"correctValue must be a number between "+this.min+" and "+this.max+". Found: "+opts.correctValue);this.correctValue=opts.correctValue}},Slider.prototype.append=function(){var container,tmpColor,that=this;this.mainText&&(this.spanMainText=W.append("span",this.bodyDiv,{className:"slider-maintext",innerHTML:this.mainText})),this.hint&&W.append("span",this.bodyDiv,{className:"slider-hint",innerHTML:this.hint}),container=W.add("div",this.bodyDiv,{className:"container-slider"}),this.rangeFill=W.add("div",container,{className:"fill-slider"}),this.slider=W.add("input",container,{className:"volume-slider",name:"rangeslider",type:"range",min:this.min,max:this.max}),this.slider.onmouseover=function(){tmpColor=that.rangeFill.style.background||"black",that.rangeFill.style.background=that.hoverColor},this.slider.onmouseout=function(){that.rangeFill.style.background=tmpColor},this.sliderWidth&&(this.slider.style.width=this.sliderWidth),this.displayValue&&(this.valueSpan=W.add("span",this.bodyDiv,{className:"slider-display-value"})),this.displayNoChange&&(this.noChangeSpan=W.add("span",this.bodyDiv,{className:"slider-display-nochange",innerHTML:this.getText("noChange")+" "}),this.noChangeCheckbox=W.add("input",this.noChangeSpan,{type:"checkbox"}),this.noChangeCheckbox.onclick=function(){if(that.noChangeCheckbox.checked){if(that.slider.value===that.initialValue)return;that.slider.value=that.initialValue,that.listener(!0),J.addClass(that.noChangeSpan,"italic")}else J.removeClass(that.noChangeSpan,"italic")}),this.slider.oninput=this.listener,this.slider.value=this.initialValue,this.slider.oninput()},Slider.prototype.getValues=function(opts){var res,value,nochange;return res=!0,void 0===(opts=opts||{}).highlight&&(opts.highlight=!0),value=this.currentValue,nochange=this.noChangeCheckbox&&this.noChangeCheckbox.checked,(this.required&&0===this.totalMove&&!nochange||null!==this.correctValue&&this.correctValue!==value)&&(opts.highlight&&this.highlight(),res=!1),{value:value,noChange:!!nochange,initialValue:this.initialValue,totalMove:this.totalMove,isCorrect:res,time:node.timer.getTimeSince(this.timeFrom)}},Slider.prototype.setValues=function(opts){opts=opts||{},this.slider.value=opts.value,this.slider.oninput()}}(node),function(node){"use strict";function SVOGauge(){this.methods={},this.method="Slider",this.mainText=null,this.gauge=null,this.addMethod("Slider",SVO_Slider)}function SVO_Slider(options){var items,sliders,mainText,i,len,renderer;for(sliders=options.sliders||[[[85,85],[85,76],[85,68],[85,59],[85,50],[85,41],[85,33],[85,24],[85,15]],[[85,15],[87,19],[89,24],[91,28],[93,33],[94,37],[96,41],[98,46],[100,50]],[[50,100],[54,98],[59,96],[63,94],[68,93],[72,91],[76,89],[81,87],[85,85]],[[50,100],[54,89],[59,79],[63,68],[68,58],[72,47],[76,36],[81,26],[85,15]],[[100,50],[94,56],[88,63],[81,69],[75,75],[69,81],[63,88],[56,94],[50,100]],[[100,50],[98,54],[96,59],[94,63],[93,68],[91,72],[89,76],[87,81],[85,85]]],this.sliders=sliders,renderer=options.renderer||function(td,choice,idx){td.innerHTML=choice[0]+"
"+choice[1]},len=sliders.length,items=new Array(len),i=-1;++iextra bonus
.
Choose the preferred bonus amounts (in cents) for you and the other participant in each row.
We will select one row at random and add the bonus to your and the other participant's payment. Your choice will remain anonymous.",left:"Your Bonus:
Other's Bonus:"},SVOGauge.dependencies={},SVOGauge.prototype.init=function(opts){var gauge,that;if(void 0!==opts.method){if("string"!=typeof opts.method)throw new TypeError("SVOGauge.init: method must be string or undefined. Found: "+opts.method);if(!this.methods[opts.method])throw new Error("SVOGauge.init: method is invalid: "+opts.method);this.method=opts.method}if(void 0!==opts.mainText){if(!1!==opts.mainText&&"string"!=typeof opts.mainText)throw new TypeError("SVOGauge.init: mainText must be string false, or undefined. Found: "+opts.mainText);this.mainText=opts.mainText}if(gauge=this.methods[this.method].call(this,opts),that=this,gauge.isHidden=function(){return that.isHidden()},gauge.isCollapsed=function(){return that.isCollapsed()},!node.widgets.isWidget(gauge))throw new Error("SVOGauge.init: method "+this.method+" created invalid gauge: missing default widget methods.");this.gauge=gauge,this.on("enabled",(function(){gauge.enable()})),this.on("disabled",(function(){gauge.disable()})),this.on("highlighted",(function(){gauge.highlight()})),this.on("unhighlighted",(function(){gauge.unhighlight()}))},SVOGauge.prototype.append=function(){node.widgets.append(this.gauge,this.bodyDiv)},SVOGauge.prototype.addMethod=function(name,cb){if("string"!=typeof name)throw new Error("SVOGauge.addMethod: name must be string: "+name);if("function"!=typeof cb)throw new Error("SVOGauge.addMethod: cb must be function: "+cb);if(this.methods[name])throw new Error("SVOGauge.addMethod: name already existing: "+name);this.methods[name]=cb},SVOGauge.prototype.getValues=function(opts){return void 0===(opts=opts||{}).processChoice&&(opts.processChoice=function(choice){return null===choice?null:this.choices[choice]}),this.gauge.getValues(opts)},SVOGauge.prototype.setValues=function(opts){return this.gauge.setValues(opts)}}(node),function(node){"use strict";function VisualRound(){this.options=null,this.displayMode=null,this.stager=null,this.gamePlot=null,this.curStage=null,this.totStage=null,this.curRound=null,this.totRound=null,this.stageOffset=null,this.totStageOffset=null,this.oldStageId=null,this.separator=" / ",this.layout=null}function CountUpStages(visualRound,options){generalConstructor(this,visualRound,"COUNT_UP_STAGES",options),generalInit(this,"stagediv",this.visualRound.getText("stage"))}function CountDownStages(visualRound,options){generalConstructor(this,visualRound,"COUNT_DOWN_STAGES",options),generalInit(this,"stagediv",visualRound.getText("stageLeft"))}function CountUpSteps(visualRound,options){generalConstructor(this,visualRound,"COUNT_UP_STEPS",options),generalInit(this,"stepdiv",this.visualRound.getText("step"))}function CountDownSteps(visualRound,options){generalConstructor(this,visualRound,"COUNT_DOWN_STEPS",options),generalInit(this,"stepdiv",this.visualRound.getText("stepLeft"))}function CountUpRounds(visualRound,options){generalConstructor(this,visualRound,"COUNT_UP_ROUNDS",options),generalInit(this,"rounddiv",visualRound.getText("round"))}function CountDownRounds(visualRound,options){generalConstructor(this,visualRound,"COUNT_DOWN_ROUNDS",options),generalInit(this,"rounddiv",visualRound.getText("roundLeft"))}function CompoundDisplayMode(visualRound,displayModes,options){this.visualRound=visualRound,this.displayModes=displayModes,this.name=displayModes.join("&"),this.options=options||{},this.displayDiv=null,this.init(options)}function setLayout(d,layout,lastDisplay){return"vertical"===layout||"multimode_vertical"===layout||"all_vertical"===layout?(d.displayDiv.style.float="none",d.titleDiv.style.float="none",d.titleDiv.style["margin-right"]="0px",d.contentDiv.style.float="none",!0):"horizontal"===layout?(d.displayDiv.style.float="none",d.titleDiv.style.float="left",d.titleDiv.style["margin-right"]="6px",d.contentDiv.style.float="right",!0):"multimode_horizontal"===layout?(d.displayDiv.style.float="left",d.titleDiv.style.float="none",d.titleDiv.style["margin-right"]="0px",d.contentDiv.style.float="none",lastDisplay||(d.displayDiv.style["margin-right"]="10px"),!0):"all_horizontal"===layout&&(d.displayDiv.style.float="left",d.titleDiv.style.float="left",d.titleDiv.style["margin-right"]="6px",d.contentDiv.style.float="right",lastDisplay||(d.displayDiv.style["margin-right"]="10px"),!0)}function generalConstructor(that,visualRound,name,options){options=options||{},that.visualRound=visualRound,that.name=name,options.toTotal&&(that.name+="_TO_TOTAL"),that.options=options,that.displayDiv=null,that.titleDiv=null,that.contentDiv=null,that.current=null,that.textDiv=null,that.total=null}function generalInit(that,containerName,title){that.displayDiv=W.get("div",{className:containerName}),that.titleDiv=W.add("div",that.displayDiv,{className:"title",innerHTML:title}),that.contentDiv=W.add("div",that.displayDiv,{className:"content"}),that.current=W.append("span",that.contentDiv,{className:"number"}),that.options.toTotal&&(that.textDiv=W.append("span",that.contentDiv,{className:"text",innerHTML:that.visualRound.separator}),that.total=W.append("span",that.contentDiv,{className:"number"})),that.updateDisplay()}node.widgets.register("VisualRound",VisualRound),VisualRound.version="0.9.0",VisualRound.description="Displays current/total/left round/stage/step. ",VisualRound.title=!1,VisualRound.className="visualround",VisualRound.texts={round:"Round",step:"Step",stage:"Stage",roundLeft:"Rounds Left",stepLeft:"Steps Left",stageLeft:"Stages Left"},VisualRound.dependencies={GamePlot:{}},VisualRound.prototype.init=function(options){if(options=options||{},J.mixout(options,this.options),this.options=options,this.stageOffset=this.options.stageOffset||0,this.totStageOffset=void 0===this.options.totStageOffset?this.stageOffset:this.options.totStageOffset,this.options.flexibleMode&&(this.curStage=this.options.curStage||1,this.curStage-=this.options.stageOffset||0,this.curStep=this.options.curStep||1,this.curRound=this.options.curRound||1,this.totStage=this.options.totStage,this.totRound=this.options.totRound,this.totStep=this.options.totStep,this.oldStageId=this.options.oldStageId),this.gamePlot||(this.gamePlot=node.game.plot),this.stager||(this.stager=this.gamePlot.stager),this.updateInformation(),!this.options.displayMode&&this.options.displayModeNames&&(console.log("***VisualTimer.init: options.displayModeNames is deprecated. Use options.displayMode instead.***"),this.options.displayMode=this.options.displayModeNames),this.options.displayMode?this.setDisplayMode(this.options.displayMode):this.setDisplayMode(["COUNT_UP_ROUNDS_TO_TOTAL_IFNOT1","COUNT_UP_STAGES_TO_TOTAL"]),void 0!==options.separator&&(this.separator=options.separator),void 0!==options.layout&&(this.layout=options.layout),void 0!==options.preprocess){if("function"!=typeof options.preprocess)throw new TypeError("VisualRound.init: preprocess must function or undefined. Found: "+options.preprocess);this.preprocess=options.preprocess}this.updateDisplay()},VisualRound.prototype.append=function(){this.activate(this.displayMode),this.updateDisplay()},VisualRound.prototype.updateDisplay=function(){this.displayMode&&this.displayMode.updateDisplay()},VisualRound.prototype.setDisplayMode=function(displayMode){var i,len,displayModes;if("string"==typeof displayMode)displayMode=[displayMode];else if(!J.isArray(displayMode))throw new TypeError("VisualRound.setDisplayMode: displayMode must be array or string. Found: "+displayMode);if(0===(len=displayMode.length))throw new Error("VisualRound.setDisplayMode: displayMode is empty");if(this.displayMode){if(displayMode.join("&")===this.displayMode.name)return;this.deactivate(this.displayMode)}for(displayModes=[],i=-1;++i'+that.getText(tmp)+""+str),W.add("span",that.div,{innerHTML:str,className:"visualstage-"+tmp}))}node.widgets.register("VisualStage",VisualStage),VisualStage.version="0.11.0",VisualStage.description="Displays the name of the current, previous and next step of the game.",VisualStage.title=!1,VisualStage.className="visualstage",VisualStage.texts={miss:"",current:"Stage: ",previous:"Prev: ",next:"Next: "},VisualStage.dependencies={Table:{}},VisualStage.prototype.init=function(opts){var order,arr,i;if(void 0!==opts.displayMode){if("inline"!==opts.displayMode&&"table"!==opts.displayMode)throw new TypeError('VisualStage.init: displayMode must be "inline", "table" or undefined. Found: '+opts.displayMode);this.displayMode=opts.displayMode}if(void 0!==opts.addRound&&(this.addRound=!!opts.addRound),void 0!==opts.previous&&(this.showPrevious=!!opts.previous),void 0!==opts.next&&(this.showNext=!!opts.next),void 0!==opts.current&&(this.showCurrent=!!opts.current),void 0!==opts.order){if(!J.isArray(opts.order)||3!==opts.order.length)throw new TypeError("VisualStage.init: order must be an array of length 3 or undefined. Found: "+opts.order);if(order=opts.order,arr=this.order.slice(0),-1===(i=arr.indexOf(order[0]))?"unknown item: "+order[0]:(arr.splice(i,1),-1===(i=arr.indexOf(order[1]))?"unknown item: "+order[1]:(arr.splice(i,1),-1===(i=arr.indexOf(order[2]))?"unknown item: "+order[2]:(arr.splice(i,1),arr.length?"duplicated entry: "+arr[0]:void 0))))throw new TypeError("VisualStage.init: order contains errors: "+opts.order);this.order=opts.order}else"inline"===this.displayMode&&(this.order=["previous","current","next"]);if(void 0!==opts.preprocess){if("function"!=typeof opts.preprocess)throw new TypeError("VisualStage.init: preprocess must be function or undefined. Found: "+opts.preprocess);this.preprocess=opts.preprocess}void 0!==opts.capitalize&&(this.capitalize=!!opts.capitalize),void 0!==opts.replaceUnderscore&&(this.replaceUnderscore=!!opts.replaceUnderscore)},VisualStage.prototype.append=function(){"table"===this.displayMode?(this.table=new Table,this.bodyDiv.appendChild(this.table.table)):this.div=W.append("div",this.bodyDiv),this.updateDisplay()},VisualStage.prototype.listeners=function(){var that=this;node.on("STEP_CALLBACK_EXECUTED",(function(){that.updateDisplay()}))},VisualStage.prototype.updateDisplay=function(){var curStep,nextStep,prevStep,curStepName,nextStepName,prevStepName,order;order={},(curStep=node.game.getCurrentGameStage())&&(this.showCurrent&&(curStepName=this.getStepName(curStep,curStep,"current"),order.current=curStepName),this.showNext&&(nextStep=node.game.plot.next(curStep))&&(nextStepName=this.getStepName(nextStep,curStep,"next"),order.next=nextStepName),this.showPrevious&&(prevStep=node.game.plot.previous(curStep))&&(prevStepName=this.getStepName(prevStep,curStep,"previous"),order.previous=prevStepName)),"table"===this.displayMode?(this.table.clear(!0),addRow(this,0,order),addRow(this,1,order),addRow(this,2,order),this.table.selexec("y","=",0).addClass("strong"),this.table.parse()):(this.div.innerHTML="",addSpan(this,0,order),addSpan(this,1,order),addSpan(this,2,order))},VisualStage.prototype.getStepName=function(gameStage,curStage,mod){var name,round,preprocess,addRound;return"function"==typeof(name=node.game.plot.getProperty(gameStage,"name"))?(preprocess=name,name=null):"object"==typeof name&&null!==name&&(preprocess=name.preprocess,addRound=name.addRound,name=name.name),name||((name=node.game.plot.getStep(gameStage))?(name=name.id,this.replaceUnderscore&&(name=name.replace(/_/g," ")),this.capitalize&&(name=function(str){var tks,i,len;tks=str.split(" "),str=capWord(tks[0]),(len=tks.length)>1&&(str+=" "+capWord(tks[1]));if(len>2)for(i=2;igameStage.stage?totRounds:1;return round}(gameStage,curStage,mod),preprocess&&(name=preprocess.call(node.game,name,mod,round)),addRound&&round&&(name+=" "+round),name}}(node),function(node){"use strict";function VisualTimer(){this.gameTimer=null,this.mainBox=null,this.waitBox=null,this.activeBox=null,this.isInitialized=!1,this.options={},this.internalTimer=null}function TimerBox(options){this.boxDiv=null,this.titleDiv=null,this.bodyDiv=null,this.timeLeft=null,this.boxDiv=W.get("div"),this.titleDiv=W.add("div",this.boxDiv),this.bodyDiv=W.add("div",this.boxDiv),this.init(options)}function destroyTimer(that){that.internalTimer?(that.gameTimer.isDestroyed()||node.timer.destroyTimer(that.gameTimer),that.internalTimer=null):that.gameTimer.removeHook("VisualTimer_"+that.wid)}node.widgets.register("VisualTimer",VisualTimer),VisualTimer.version="0.9.3",VisualTimer.description="Display a configurable timer for the game. Can trigger events. Only for countdown smaller than 1h.",VisualTimer.title="Time Left",VisualTimer.className="visualtimer",VisualTimer.dependencies={GameTimer:{}},VisualTimer.prototype.init=function(options){var gameTimerOptions;if("object"!=typeof(options=options||{}))throw new TypeError("VisualTimer.init: options must be object or undefined. Found: "+options);if(gameTimerOptions={},void 0!==options.gameTimer){if(this.gameTimer)throw new Error("GameTimer.init: options.gameTimer cannot be set if a gameTimer is already existing: "+this.name);if("object"!=typeof options.gameTimer)throw new TypeError("VisualTimer.init: options.gameTimer must be object or undefined. Found: "+options.gameTimer);this.gameTimer=options.gameTimer}else this.isInitialized||(this.internalTimer=!0,this.gameTimer=node.timer.createTimer({name:options.name||"VisualTimer_"+J.randomInt(1e7)}));if(options.hooks){if(!this.internalTimer)throw new Error("VisualTimer.init: cannot add hooks on external gameTimer.");J.isArray(options.hooks)||(gameTimerOptions.hooks=[options.hooks])}else gameTimerOptions.hooks=[];this.isInitialized||gameTimerOptions.hooks.push({name:"VisualTimer_"+this.wid,hook:this.updateDisplay,ctx:this}),void 0!==options.milliseconds&&(gameTimerOptions.milliseconds=node.timer.parseInput("milliseconds",options.milliseconds)),void 0!==options.update?gameTimerOptions.update=node.timer.parseInput("update",options.update):gameTimerOptions.update=1e3,void 0!==options.timeup&&(gameTimerOptions.timeup=options.timeup),this.gameTimer.init(gameTimerOptions),this.gameTimer,this.options=gameTimerOptions,void 0===this.options.stopOnDone&&(this.options.stopOnDone=!0),void 0===this.options.startOnPlaying&&(this.options.startOnPlaying=!0),this.options.mainBoxOptions||(this.options.mainBoxOptions={}),this.options.waitBoxOptions||(this.options.waitBoxOptions={}),J.mixout(this.options.mainBoxOptions,{classNameBody:options.className,hideTitle:!0}),J.mixout(this.options.waitBoxOptions,{title:"Max. wait timer",classNameTitle:"waitTimerTitle",classNameBody:"waitTimerBody",hideBox:!0}),this.mainBox?this.mainBox.init(this.options.mainBoxOptions):this.mainBox=new TimerBox(this.options.mainBoxOptions),this.waitBox?this.waitBox.init(this.options.waitBoxOptions):this.waitBox=new TimerBox(this.options.waitBoxOptions),this.activeBox=this.options.activeBox||this.mainBox,this.isInitialized=!0},VisualTimer.prototype.append=function(){this.bodyDiv.appendChild(this.mainBox.boxDiv),this.bodyDiv.appendChild(this.waitBox.boxDiv),this.activeBox=this.mainBox,this.updateDisplay()},VisualTimer.prototype.clear=function(options){var oldOptions;return options=options||{},oldOptions=this.options,destroyTimer(this),this.gameTimer=null,this.activeBox=null,this.isInitialized=!1,this.init(options),oldOptions},VisualTimer.prototype.updateDisplay=function(){var time,minutes,seconds;this.gameTimer.milliseconds&&0!==this.gameTimer.milliseconds?(time=this.gameTimer.milliseconds-this.gameTimer.timePassed,minutes=(time=J.parseMilliseconds(time))[2]<10?"0"+time[2]:time[2],seconds=time[3]<10?"0"+time[3]:time[3],this.activeBox.bodyDiv.innerHTML=minutes+":"+seconds):this.activeBox.bodyDiv.innerHTML="00:00"},VisualTimer.prototype.start=function(){this.updateDisplay(),this.gameTimer.start()},VisualTimer.prototype.restart=function(options){this.stop(),"number"==typeof options&&(options={milliseconds:options}),this.init(options),this.start()},VisualTimer.prototype.stop=function(){this.gameTimer.isStopped()||(this.activeBox.timeLeft=this.gameTimer.timeLeft,this.gameTimer.stop())},VisualTimer.prototype.switchActiveBoxTo=function(box){this.activeBox.timeLeft=this.gameTimer.timeLeft||0,this.activeBox=box,this.updateDisplay()},VisualTimer.prototype.startWaiting=function(options){void 0===options&&(options={}),void 0===options.milliseconds&&(options.milliseconds=this.gameTimer.timeLeft),void 0===options.mainBoxOptions&&(options.mainBoxOptions={}),void 0===options.waitBoxOptions&&(options.waitBoxOptions={}),options.mainBoxOptions.classNameBody="strike",options.mainBoxOptions.timeLeft=this.gameTimer.timeLeft||0,options.activeBox=this.waitBox,options.waitBoxOptions.hideBox=!1,this.restart(options)},VisualTimer.prototype.startTiming=function(options){void 0===options&&(options={}),void 0===options.mainBoxOptions&&(options.mainBoxOptions={}),void 0===options.waitBoxOptions&&(options.waitBoxOptions={}),options.activeBox=this.mainBox,options.waitBoxOptions.timeLeft=this.gameTimer.timeLeft||0,options.waitBoxOptions.hideBox=!0,options.mainBoxOptions.classNameBody="",this.restart(options)},VisualTimer.prototype.resume=function(){this.gameTimer.resume()},VisualTimer.prototype.setToZero=function(){this.stop(),this.activeBox.bodyDiv.innerHTML="00:00",this.activeBox.setClassNameBody("strike")},VisualTimer.prototype.isTimeup=function(){return this.gameTimer.isTimeup()},VisualTimer.prototype.doTimeUp=function(){this.gameTimer.doTimeUp()},VisualTimer.prototype.listeners=function(){var that=this;this.internalTimer&&(node.on("PLAYING",(function(){var options;that.options.startOnPlaying&&((options=that.gameTimer.getStepOptions())?(options.update=that.update,options.timeup=void 0,that.startTiming(options)):that.gameTimer.isRunning()||that.setToZero())})),node.on("REALLY_DONE",(function(){that.options.stopOnDone&&(that.gameTimer.isStopped()||that.stop())})),this.on("destroyed",(function(){destroyTimer(that),that.bodyDiv.removeChild(that.mainBox.boxDiv),that.bodyDiv.removeChild(that.waitBox.boxDiv)})))},TimerBox.prototype.init=function(options){options&&(options.hideTitle?this.hideTitle():this.unhideTitle(),options.hideBody?this.hideBody():this.unhideBody(),options.hideBox?this.hideBox():this.unhideBox()),this.setTitle(options.title||""),this.setClassNameTitle(options.classNameTitle||""),this.setClassNameBody(options.classNameBody||""),options.timeLeft&&(this.timeLeft=options.timeLeft)},TimerBox.prototype.hideBox=function(){this.boxDiv.style.display="none"},TimerBox.prototype.unhideBox=function(){this.boxDiv.style.display=""},TimerBox.prototype.hideTitle=function(){this.titleDiv.style.display="none"},TimerBox.prototype.unhideTitle=function(){this.titleDiv.style.display=""},TimerBox.prototype.hideBody=function(){this.bodyDiv.style.display="none"},TimerBox.prototype.unhideBody=function(){this.bodyDiv.style.display=""},TimerBox.prototype.setTitle=function(title){this.titleDiv.innerHTML=title},TimerBox.prototype.setClassNameTitle=function(className){this.titleDiv.className=className},TimerBox.prototype.setClassNameBody=function(className){this.bodyDiv.className=className}}(node),function(node){"use strict";function WaitingRoom(){this.connected=0,this.poolSize=0,this.nGames=void 0,this.groupSize=0,this.waitTime=null,this.executionMode=null,this.startDate=null,this.timeoutId=null,this.execModeDiv=null,this.playerCount=null,this.startDateDiv=null,this.msgDiv=null,this.timerDiv=null,this.timer=null,this.dots=null,this.onTimeout=null,this.disconnectIfNotSelected=null,this.playWithBotOption=null,this.playBotBtn=null,this.selectTreatmentOption=null,this.selectedTreatment=null}node.widgets.register("WaitingRoom",WaitingRoom),WaitingRoom.version="1.3.0",WaitingRoom.description="Displays a waiting room for clients.",WaitingRoom.title="Waiting Room",WaitingRoom.className="waitingroom",WaitingRoom.dependencies={VisualTimer:{}},WaitingRoom.sounds={dispatch:"/sounds/doorbell.ogg"},WaitingRoom.texts={blinkTitle:"GAME STARTS!",waitingForConf:"Waiting to receive data",executionMode:function(w){return"WAIT_FOR_N_PLAYERS"===w.executionMode?"Waiting for All Players to Connect: ":"WAIT_FOR_DISPATCH"===w.executionMode?"Task will start soon. Please be patient.":"Task will start at:
"+w.startDate},disconnect:'You have been disconnected. Please try again later.

',waitedTooLong:"Waiting for too long. Please look for a HIT called Trouble Ticket and file a new trouble ticket reporting your experience.",notEnoughPlayers:'

Thank you for your patience.
Unfortunately, there are not enough participants in your group to start the experiment.
',roomClosed:' The waiting room is CLOSED. You have been disconnected. Please try again later.

',tooManyPlayers:function(widget,data){var str;return str="There are more players in this waiting room than playslots in the game. ",1===widget.poolSize?str+="Each player will play individually.":str+="Only "+data.nGames+" players will be selected to play the game.",str},notSelectedClosed:'

Unfortunately, you were not selected to join the game this time. Thank you for your participation.



',notSelectedOpen:'

Unfortunately, you were not selected to join the game this time, but you may join the next one.Ok, I got it.



Thank you for your participation.

',exitCode:function(widget,data){return"
You have been disconnected. "+(void 0!==data.exit?"Please report this exit code: "+data.exit:"")+"
"},playBot:function(widget){return widget.poolSize===widget.groupSize&&1===widget.groupSize?"Play":2===widget.groupSize?"Play With Bot":"Play With Bots"},connectingBots:function(widget){return console.log(widget.poolSize,widget.groupSize),widget.poolSize===widget.groupSize&&1===widget.groupSize?"Starting, Please Wait...":2===widget.groupSize?"Connecting Bot, Please Wait...":"Connecting Bot/s, Please Wait..."},selectTreatment:"Select Treatment ",gameTreatments:"Game:",defaultTreatments:"Defaults:"},WaitingRoom.prototype.init=function(conf){var that=this;if("object"!=typeof conf)throw new TypeError("WaitingRoom.init: conf must be object. Found: "+conf);if(conf.executionMode){if(this.executionMode=conf.executionMode,conf.onTimeout){if("function"!=typeof conf.onTimeout)throw new TypeError("WaitingRoom.init: conf.onTimeout must be function, null or undefined. Found: "+conf.onTimeout);this.onTimeout=conf.onTimeout}if(conf.waitTime){if(null!==conf.waitTime&&"number"!=typeof conf.waitTime)throw new TypeError("WaitingRoom.init: conf.waitTime must be number, null or undefined. Found: "+conf.waitTime);this.waitTime=conf.waitTime}if(conf.startDate&&(this.startDate=new Date(conf.startDate).toString()),conf.poolSize){if(conf.poolSize&&"number"!=typeof conf.poolSize)throw new TypeError("WaitingRoom.init: conf.poolSize must be number or undefined. Found: "+conf.poolSize);this.poolSize=conf.poolSize}if(conf.groupSize){if(conf.groupSize&&"number"!=typeof conf.groupSize)throw new TypeError("WaitingRoom.init: conf.groupSize must be number or undefined. Found: "+conf.groupSize);this.groupSize=conf.groupSize}if(conf.nGames){if(conf.nGames&&"number"!=typeof conf.nGames)throw new TypeError("WaitingRoom.init: conf.nGames must be number or undefined. Found: "+conf.nGames);this.nGames=conf.nGames}if(conf.connected){if(conf.connected&&"number"!=typeof conf.connected)throw new TypeError("WaitingRoom.init: conf.connected must be number or undefined. Found: "+conf.connected);this.connected=conf.connected}if(conf.disconnectIfNotSelected){if("boolean"!=typeof conf.disconnectIfNotSelected)throw new TypeError("WaitingRoom.init: conf.disconnectIfNotSelected must be boolean or undefined. Found: "+conf.disconnectIfNotSelected);this.disconnectIfNotSelected=conf.disconnectIfNotSelected}else this.disconnectIfNotSelected=!1;conf.playWithBotOption?this.playWithBotOption=!0:this.playWithBotOption=!1,conf.selectTreatmentOption?this.selectTreatmentOption=!0:this.selectTreatmentOption=!1,this.displayExecMode(),this.playWithBotOption&&!document.getElementById("bot_btn")&&function(w){var btnGroup=document.createElement("div");btnGroup.role="group",btnGroup["aria-label"]="Play Buttons",btnGroup.className="btn-group";var playBotBtn=document.createElement("input");if(playBotBtn.className="btn btn-primary btn-lg",playBotBtn.value=w.getText("playBot"),playBotBtn.id="bot_btn",playBotBtn.type="button",playBotBtn.onclick=function(){w.playBotBtn.value=w.getText("connectingBots"),w.playBotBtn.disabled=!0,node.say("PLAYWITHBOT","SERVER",w.selectedTreatment),setTimeout((function(){w.playBotBtn.value=w.getText("playBot"),w.playBotBtn.disabled=!1}),5e3)},btnGroup.appendChild(playBotBtn),w.playBotBtn=playBotBtn,w.selectTreatmentOption){var btnGroupTreatments=document.createElement("div");btnGroupTreatments.role="group",btnGroupTreatments["aria-label"]="Select Treatment",btnGroupTreatments.className="btn-group";var btnTreatment=document.createElement("button");btnTreatment.className="btn btn-default btn-lg dropdown-toggle",btnTreatment["data-toggle"]="dropdown",btnTreatment["aria-haspopup"]="true",btnTreatment["aria-expanded"]="false",btnTreatment.innerHTML=w.getText("selectTreatment");var span=document.createElement("span");span.className="caret",btnTreatment.appendChild(span);var li,a,t,liT1,liT2,liT3,ul=document.createElement("ul");if(ul.className="dropdown-menu",ul.style["text-align"]="left",conf.availableTreatments){for(t in(li=document.createElement("li")).innerHTML=w.getText("gameTreatments"),li.className="dropdown-header",ul.appendChild(li),conf.availableTreatments)conf.availableTreatments.hasOwnProperty(t)&&((li=document.createElement("li")).id=t,(a=document.createElement("a")).href="#",a.innerHTML=""+t+": "+conf.availableTreatments[t],li.appendChild(a),"treatment_latin_square"===t?liT3=li:"treatment_rotate"===t?liT1=li:"treatment_random"===t?liT2=li:ul.appendChild(li));(li=document.createElement("li")).role="separator",li.className="divider",ul.appendChild(li),(li=document.createElement("li")).innerHTML=w.getText("defaultTreatments"),li.className="dropdown-header",ul.appendChild(li),ul.appendChild(liT1),ul.appendChild(liT2),ul.appendChild(liT3)}btnGroupTreatments.appendChild(btnTreatment),btnGroupTreatments.appendChild(ul),btnGroup.appendChild(btnGroupTreatments),btnTreatment.onclick=function(){""===ul.style.display?ul.style.display="block":ul.style.display=""},ul.onclick=function(eventData){var t;t=eventData.target,ul.style.display="",(t=t.parentNode.id)||(t=eventData.target.parentNode.parentNode.id),t&&(btnTreatment.innerHTML=t+" ",btnTreatment.appendChild(span),w.selectedTreatment=t)},w.treatmentBtn=btnTreatment}w.bodyDiv.appendChild(document.createElement("br")),w.bodyDiv.appendChild(btnGroup)}(this),this.on("destroyed",(function(){that.dots&&that.dots.stop(),node.deregisterSetup("waitroom")}))}},WaitingRoom.prototype.startTimer=function(){var that=this;this.timer||this.waitTime&&(this.timerDiv||(this.timerDiv=document.createElement("div"),this.timerDiv.id="timer-div"),this.timerDiv.appendChild(document.createTextNode("Maximum Waiting Time: ")),this.timer=node.widgets.append("VisualTimer",this.timerDiv,{milliseconds:this.waitTime,timeup:function(){that.bodyDiv.innerHTML=that.getText("waitedTooLong")},update:1e3}),this.timer.setTitle(),this.timer.panelDiv.className="ng_widget visualtimer",this.bodyDiv.appendChild(this.timerDiv),this.timer.start())},WaitingRoom.prototype.clearTimeout=function(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null)},WaitingRoom.prototype.updateState=function(update){update&&("number"==typeof update.connected&&(this.connected=update.connected),"number"==typeof update.poolSize&&(this.poolSize=update.poolSize),"number"==typeof update.groupSize&&(this.groupSize=update.groupSize))},WaitingRoom.prototype.updateDisplay=function(){var numberOfGameSlots,numberOfGames;this.connected>this.poolSize?(numberOfGames=Math.floor(this.connected/this.groupSize),void 0!==this.nGames&&(numberOfGames=numberOfGames>this.nGames?this.nGames:numberOfGames),numberOfGameSlots=numberOfGames*this.groupSize,this.playerCount.innerHTML=''+this.connected+" / "+this.poolSize,this.playerCountTooHigh.style.display="",this.playerCountTooHigh.innerHTML=this.getText("tooManyPlayers",{nGames:numberOfGameSlots})):(this.playerCount.innerHTML=this.connected+" / "+this.poolSize,this.playerCountTooHigh.style.display="none")},WaitingRoom.prototype.displayExecMode=function(){this.bodyDiv.innerHTML="",this.execModeDiv=document.createElement("div"),this.execModeDiv.id="exec-mode-div",this.execModeDiv.innerHTML=this.getText("executionMode"),this.playerCount=document.createElement("p"),this.playerCount.id="player-count",this.execModeDiv.appendChild(this.playerCount),this.playerCountTooHigh=document.createElement("div"),this.playerCountTooHigh.style.display="none",this.execModeDiv.appendChild(this.playerCountTooHigh),this.startDateDiv=document.createElement("div"),this.startDateDiv.style.display="none",this.execModeDiv.appendChild(this.startDateDiv),this.dots=W.getLoadingDots(),this.execModeDiv.appendChild(this.dots.span),this.bodyDiv.appendChild(this.execModeDiv),this.msgDiv=document.createElement("div"),this.bodyDiv.appendChild(this.msgDiv),this.waitTime&&this.startTimer()},WaitingRoom.prototype.append=function(){this.bodyDiv.innerHTML=this.getText("waitingForConf")},WaitingRoom.prototype.listeners=function(){var that;that=this,node.registerSetup("waitroom",(function(conf){if(conf){if("object"==typeof conf)return conf.executionMode?that.init(conf):(that.setSounds(conf.sounds),that.setTexts(conf.texts)),conf;node.warn("waiting room widget: invalid setup object: "+conf)}})),node.on.data("PLAYERSCONNECTED",(function(msg){msg.data&&(that.connected=msg.data,that.updateDisplay())})),node.on.data("DISPATCH",(function(msg){var data,reportExitCode;data=(msg=msg||{}).data||{},that.dots&&that.dots.stop(),"allPlayersConnected"===data.action?that.alertPlayer():(reportExitCode=that.getText("exitCode",data),"notEnoughPlayers"===data.action?(that.bodyDiv.innerHTML=that.getText(data.action),that.onTimeout&&that.onTimeout(msg.data),that.disconnect(that.bodyDiv.innerHTML+reportExitCode)):"notSelected"===data.action?!1===data.shouldDispatchMoreGames||that.disconnectIfNotSelected?(that.bodyDiv.innerHTML=that.getText("notSelectedClosed"),that.disconnect(that.bodyDiv.innerHTML+reportExitCode)):that.msgDiv.innerHTML=that.getText("notSelectedOpen"):"disconnect"===data.action&&that.disconnect(that.bodyDiv.innerHTML+reportExitCode))})),node.on.data("TIME",(function(){node.info("waiting room: TIME IS UP!"),that.stopTimer()})),node.on.data("WAITTIME",(function(msg){that.updateState(msg.data),that.updateDisplay()})),node.on("SOCKET_DISCONNECT",(function(){that.stopTimer(),that.bodyDiv.innerHTML=that.getText("disconnect")})),node.on.data("ROOM_CLOSED",(function(){that.disconnect(that.getText("roomClosed"))}))},WaitingRoom.prototype.stopTimer=function(){this.timer&&(node.info("waiting room: STOPPING TIMER"),this.timer.destroy())},WaitingRoom.prototype.disconnect=function(msg){msg&&this.setText("disconnect",msg),node.socket.disconnect(),this.stopTimer()},WaitingRoom.prototype.alertPlayer=function(){var clearBlink,onFrame,blink,sound;blink=this.getText("blinkTitle"),(sound=this.getSound("dispatch"))&&J.playSound(sound),blink&&(document.hasFocus&&document.hasFocus()?J.blinkTitle(blink,{repeatFor:1}):(clearBlink=J.blinkTitle(blink,{stopOnFocus:!0,stopOnClick:window}),onFrame=function(){var frame;clearBlink(),(frame=W.getFrame())&&frame.removeEventListener("mouseover",onFrame,!1)},node.events.ng.once("FRAME_GENERATED",(function(frame){frame.addEventListener("mouseover",onFrame,!1)}))))}}(node); \ No newline at end of file diff --git a/public/stylesheets/nodegame.min.css b/public/stylesheets/nodegame.min.css index 834419e1..9fd07659 100644 --- a/public/stylesheets/nodegame.min.css +++ b/public/stylesheets/nodegame.min.css @@ -1 +1 @@ -body{margin:auto;padding:0 5px;font-family:Arial,Helvetica,sans-serif;font-size:16px;color:black}iframe#ng_mainframe{border:0;padding:10px}.ng_mainframe-header-vertical-r{height:100%;float:left;width:86%}.ng_mainframe-header-vertical-l{height:100%;float:right;width:86%}.ng_mainframe-header-horizontal{height:88%;width:98%;clear:both}div#ng_header{padding:2px 10px;color:black;border:0;margin:0}.ng_header_position-horizontal-t,.ng_header_position-horizontal-b{width:98%;height:10%}.ng_header_position-vertical-r{float:right;width:10%}.ng_header_position-vertical-l{float:left;width:10%}div#ng_waitScreen{z-index:10000;filter:alpha(opacity=50);filter:progid:DXImageTransform.Microsoft.Alpha(opacity=50);-moz-opacity:.50;-khtml-opacity:0.5;opacity:0.5;background-color:#000;position:fixed;top:0;left:0;width:100%;height:100%;color:#FFF;text-align:center;vertical-align:middle;font-weight:bold;font-size:30px;padding:20px}canvas{border:1px #CCC solid}label{display:block;float:left;min-width:200px}input[type="range"]{margin-bottom:5px;margin-left:5px}.strong{font-weight:bold}.underline{text-decoration:underline}.strike{text-decoration:line-through}.languageselector{float:center;width:160px}.languageselector > .panel-body > form > label{font-size:20px;font-weight:normal}.languageselector > .panel-body > form > label.selectedButtonLabel{font-weight:bold}.visualtimer{float:right;min-width:100px;width:auto}.visualtimer > .panel-body > div{font-size:40px;text-align:center}.visualtimer > .panel-body > div > div.waitTimerTitle{font-size:15px}.visualtimer > .panel-body > div > div.waitTimerBody{font-size:20px;text-align:center}.visualround{float:right;min-width:100px;width:auto}.visualround > .panel-body > div > div.rounddiv{font-size:40px;text-align:center}.visualround > .panel-body > div > div.stagediv{font-size:20px;text-align:center}.visualround > .panel-body > div > div > .number{}.visualround > .panel-body > div > div > span.text{font-size:40%;text-align:center}.visualround > .panel-body > div > div > div.title{font-size:50%;text-align:center}.visualstage{float:left;min-width:200px;width:auto}.statedisplay{float:left;width:300px}.statedisplay > .panel-body > div{width:auto;font-size:16px}.moneytalks{float:right;width:auto;min-width:100px}.moneytalks > .panel-body > span.moneytalksmoney{font-size:40px;text-align:center}.moneytalks > .panel-body > span.moneytalkscurrency{font-size:12px;text-align:center}.donebutton{float:right;width:auto;min-width:100px}.donebutton > .panel-body{font-size:20px;text-align:center}.chat{overflow-y:scroll;height:200px;width:450px;border:1px solid #CCC;padding:5px}.chat > .panel-body > textarea{height:100px;width:400px}.chat_me{font-weight:bold}.feedback > .panel-body > textarea{padding:5px;font-size:16px;width:98%;height:300px;border:1px solid #CCC}.requirements{font-size:1.2em}.requirements-success{font-weight:bold;color:green;padding-top:15px;padding-bottom:15px}.requirements-fail{font-weight:bold;color:red;padding-top:15px;padding-bottom:15px}.waitingroom{font-size:1.2em}.waitingroom > .panel-body{text-align:center}.waitingroom > .panel-body > div#timer-div{margin-top:30px}.waitingroom > .panel-body > div#player-count-div > p#player-count{font-size:40px;clear:both;margin-top:30px}.waitingroom > .panel-body > div > .visualtimer{float:none;display:inline;font-size:40px;margin:0}.waitingroom > .panel-body > div > span#span_dots{font-size:40px}div.choicetable,div.choicetable div.panel-heading,div.choicetable div.panel-body{border:0;padding:0}span.choicetable-maintext{margin:0;margin-top:20px!important;padding:0;display:block;text-align:left}textarea.choicetable-freetext{margin:0;margin-top:20px!important;padding:5px;text-align:left}table.choicetable td{word-wrap:break-word;border:solid 1px;text-align:center;padding:5px;width:40px;background:white}table.clickable td:hover{background:#FFE;cursor:pointer;cursor:hand}table.choicetable td.selected{border:3px solid #333!important;background:#FFE!important} \ No newline at end of file +noscript{background:#fff;border:1px dotted #a60000;color:red;font-family:Arial,Helvetica,sans-serif;font-size:16px;left:50%;margin-left:-15em;margin-top:-9em;padding:20px 30px;position:fixed;text-align:center;top:50%}html{margin:0;padding:0}body{font-family:Source Sans Pro,-apple-system,BlinkMacSystemFont,Roboto,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:20px;margin:0}body:after{clear:both;content:"";display:table}.ng-page-title{margin-bottom:20px;margin-top:10px;text-align:center}#ng_mainframe,.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6,p{font-family:Source Sans Pro,-apple-system,BlinkMacSystemFont,Roboto,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif}#ng_mainframe{display:block;font-size:20px;margin:0 auto;padding:0;width:100%}.ng_mainframe-header-vertical-l,.ng_mainframe-header-vertical-r{padding-bottom:0!important;padding-top:0!important}.ng_mainframe-header-horizontal-t{padding-bottom:0!important;padding-left:0!important;padding-right:0!important}.ng_mainframe-header-horizontal-b{padding-left:0!important;padding-right:0!important;padding-top:0!important}#ng_header{background-color:#fff;border-radius:0 0 5px 5px;box-shadow:0 0 15px #d3d3d3;font-size:20px;height:auto;left:0;margin:0 auto;max-width:42em;padding:10px 15px;position:fixed!important;right:0;width:100%;z-index:1000}#ng_header:after{clear:both;content:"";display:table}.ng_header_position-horizontal-b,.ng_header_position-horizontal-t{bottom:auto!important;height:auto!important;margin:0 auto!important;top:0!important;width:100%!important}.ng_header_position-horizontal-b{bottom:0!important;top:auto!important}.ng_header_position-vertical-l,.ng_header_position-vertical-r{height:100%!important;left:auto!important;margin:0!important;right:0!important;width:125px!important}.ng_header_position-vertical-l{left:0!important;right:auto!important}#ng_waitScreen{background-color:#000;color:#fff;filter:alpha(opacity=70);filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);font-size:30px;font-weight:700;height:100%;left:0;-moz-opacity:.7;-khtml-opacity:.7;opacity:.7;padding:40px;position:fixed;text-align:center;top:0;vertical-align:middle;width:100%;z-index:10000}#ng_info-panel{margin:0 auto;max-width:42em}.strong{font-weight:700}.italic{font-style:italic}.underline{text-decoration:underline}.strike{text-decoration:line-through}.hand{cursor:pointer;cursor:hand}.centered,.requirements,.waitingroom{margin:0 auto;max-width:42em}.requirements,.waitingroom{width:90%}#ng_header .ng_widget{border:none;box-shadow:none;float:left;margin-bottom:0;margin-right:20px;padding:10px}#ng_header .ng_widget .no-panel-heading,#ng_header .ng_widget .panel-heading{background-color:#fff;border:none;font-weight:700;padding:0}#ng_header .ng_widget .panel-body{padding:0}#ng_header .ng_widget:last-child{margin-right:0}#ng_header .backbutton,#ng_header .donebutton{float:right;margin:0 0 0 10px;padding:0}#ng_header .backbutton .no-panel-heading,#ng_header .backbutton .panel-heading,#ng_header .donebutton .no-panel-heading,#ng_header .donebutton .panel-heading{display:none}.ng_header_position-horizontal-b .visualround,.ng_header_position-horizontal-t .visualround{margin-right:10px}.ng_header_position-horizontal-b .visualround .rounddiv,.ng_header_position-horizontal-b .visualround .stagediv,.ng_header_position-horizontal-b .visualround .stepdiv,.ng_header_position-horizontal-t .visualround .rounddiv,.ng_header_position-horizontal-t .visualround .stagediv,.ng_header_position-horizontal-t .visualround .stepdiv{float:left}.ng_header_position-horizontal-b .visualround .rounddiv .title,.ng_header_position-horizontal-b .visualround .stagediv .title,.ng_header_position-horizontal-b .visualround .stepdiv .title,.ng_header_position-horizontal-t .visualround .rounddiv .title,.ng_header_position-horizontal-t .visualround .stagediv .title,.ng_header_position-horizontal-t .visualround .stepdiv .title{float:left;margin-right:6px}.ng_header_position-horizontal-b .visualround .rounddiv .content,.ng_header_position-horizontal-b .visualround .stagediv .content,.ng_header_position-horizontal-b .visualround .stepdiv .content,.ng_header_position-horizontal-t .visualround .rounddiv .content,.ng_header_position-horizontal-t .visualround .stagediv .content,.ng_header_position-horizontal-t .visualround .stepdiv .content{display:flex;float:right}.ng_header_position-horizontal-b .visualround .rounddiv,.ng_header_position-horizontal-b .visualround .stepdiv,.ng_header_position-horizontal-t .visualround .rounddiv,.ng_header_position-horizontal-t .visualround .stepdiv{margin-left:8px;margin-right:8px}.ng_header_position-horizontal-b .moneytalks .no-panel-heading,.ng_header_position-horizontal-b .visualstage .no-panel-heading,.ng_header_position-horizontal-b .visualtimer .no-panel-heading,.ng_header_position-horizontal-t .moneytalks .no-panel-heading,.ng_header_position-horizontal-t .visualstage .no-panel-heading,.ng_header_position-horizontal-t .visualtimer .no-panel-heading{float:left;margin-right:8px}.ng_header_position-horizontal-b .moneytalks .no-panel-body,.ng_header_position-horizontal-b .visualstage .no-panel-body,.ng_header_position-horizontal-b .visualtimer .no-panel-body,.ng_header_position-horizontal-t .moneytalks .no-panel-body,.ng_header_position-horizontal-t .visualstage .no-panel-body,.ng_header_position-horizontal-t .visualtimer .no-panel-body{float:right}.visualstage{padding:0 10px}.visualstage-current{font-weight:700;margin:0 15px}.visualstage-next,.visualstage-previous{font-size:13px;margin:0 15px}.visualround .title{font-weight:700}.languageselector{float:center;width:160px}.languageselector .panel-heading{font-size:18px}.languageselector>.panel-body>form>label{font-size:20px;font-weight:400}.languageselector>.panel-body>form>label.selectedButtonLabel{font-weight:700}.feedback-textarea{font-size:16px;padding:5px}.custominputgroup td{vertical-align:top}.custominputgroup .custominput-maintext{margin:20px 0 0 20px!important}.requirements,.waitingroom{box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19);font-size:1.2em}.requirements-success{color:green}.requirements-fail,.requirements-success{font-weight:700;padding-bottom:15px;padding-top:15px}.requirements-fail{color:red}.waitingroom .panel-body{text-align:center}.waitingroom .panel-body div#timer-div{margin-top:30px}.waitingroom .panel-body div#exec-mode-div>p#player-count{clear:both;font-size:40px;margin-top:30px}.waitingroom .panel-body .div>.visualtimer{display:inline;float:none;font-size:40px;margin:0}.waitingroom .panel-body div>span#span_dots{font-size:40px}div.choicetable,div.choicetable div.panel-body,div.choicetable div.panel-heading{border:0;padding:0}.choicetable-maintext,.custominput-maintext,.feedback-maintext,.slider-maintext{display:block;margin:20px 0 0!important;padding:0;text-align:left}.choicetable-maintext .choicetable-hint,.choicetable-maintext .custominput-hint,.choicetable-maintext .feedback-hint,.contentbox-maintext .contentbox-hint,.custominput-maintext .choicetable-hint,.custominput-maintext .custominput-hint,.custominput-maintext .feedback-hint,.custominputgroup-maintext .custominputgroup-hint,.feedback-maintext .choicetable-hint,.feedback-maintext .custominput-hint,.feedback-maintext .feedback-hint,.slider-maintext .slider-hint{margin-left:10px}.choicetable-hint,.contentbox-hint,.custominput-hint,.custominputgroup-hint,.feedback-hint,.slider-hint{font-color:gray;font-size:14px;font-weight:400;padding:0;text-align:left}textarea.choicemanager-freetext,textarea.choicetable-freetext,textarea.choicetablegroup-freetext{float:left;margin:20px 0 0!important;padding:5px;text-align:left;width:100%}table.choicetable{border-collapse:separate;border-spacing:20px;width:100%}table.choicetable td{word-wrap:break-word;background:#fff;border:1px solid #333;font-weight:400;padding:5px 5px 5px 10px;text-align:center;width:40px}table.choicetable td.selected{background:#333!important;border:1px solid #333!important;color:#fff}table.choicetable td.choicetable-left,table.choicetable td.choicetable-right,table.choicetable td.header{background:inherit;border:0}table.choicetable td.choicetable-left,table.choicetable td.choicetable-right{font-weight:700!important;width:200px!important}table.choicetable td.choicetable-left{padding-right:15px;text-align:right}table.choicetable td.choicetable-right{padding-left:15px;text-align:left}table.choicetable td.header{font-size:smaller;font-weight:700}table.choicetable td.choicetable-left:hover,table.choicetable td.choicetable-right:hover,table.choicetable td.header:hover{background:inherit;cursor:default}table.clickable td:hover{background:#ffe;cursor:pointer;cursor:hand}table.clickable td:focus{background:#ffe}table.choicetable-vertical td{text-align:left!important}.custominput input,dt.question,dt.question:first-of-type{margin-top:20px!important}table.choicetablegroup{border-collapse:separate;border-spacing:5px 12px!important;text-align:center!important}.custominput input,table.choicetable td{border:1px solid #999;border-radius:5px}.choicetable tr td{font-size:smaller;font-weight:400!important;padding:8px!important}.choicetable .errbox,.custominput .errbox,.custominputgroup .errbox{color:red;font-size:14px;font-weight:400;margin-left:20px;margin-top:5px}.custominput input{margin-left:20px;padding:5px}.custominput .panel-body{padding:0}.custominput-checkbox-text{font-size:14px;font-weight:400;margin-left:8px}div.moodgauge{margin:0 auto;text-align:center}div.moodgauge span.choicetable-maintext,div.moodgauge span.custominput-maintext,div.moodgauge span.feedback-maintext,div.moodgauge table.choicetable{text-align:center;width:auto}div.moodgauge span.choicetable-maintext,div.moodgauge span.custominput-maintext,div.moodgauge span.feedback-maintext{font-weight:700;margin-bottom:30px}div.moodgauge table.choicetable{border-collapse:separate;border-spacing:0 5px;margin:0 auto;text-align:center;width:auto}div.moodgauge table.choicetable td{width:80px!important}div.moodgauge table.choicetable td.choicetable-left{font-weight:400!important;min-width:260px!important}div.moodgauge table.choicetable span.emotion{font-weight:700;margin-right:10px}div.moodgauge table.choicetable td.choicetable-right{font-weight:400!important;width:100px}div.riskgauge span.choicetable-maintext,div.riskgauge span.custominput-maintext,div.riskgauge span.feedback-maintext,div.riskgauge table.choicetable{text-align:center;width:auto}div.riskgauge table.choicetable{border-collapse:separate;border-spacing:0 30px;margin:0 auto;text-align:center}div.riskgauge choicetable-maintext{font-size:20px;margin-bottom:10px}div.riskgauge span.choicetable-maintext,div.riskgauge span.custominput-maintext,div.riskgauge span.feedback-maintext,div.riskgauge table.choicetable,div.svogauge span.choicetable-maintext,div.svogauge span.custominput-maintext,div.svogauge span.feedback-maintext,div.svogauge table.choicetable{text-align:center;width:auto}div.riskgauge table.choicetable,div.svogauge table.choicetable{border-collapse:separate;border-spacing:0 30px;margin:0 auto;text-align:center}div.svogauge choicetable-maintext{font-size:20px;margin-bottom:10px}div.svogauge table td{width:60px!important}div.svogauge hr{margin:10px auto}div.svogauge td.choicetable-left hr{border-color:#000}div.riskgauge table td{width:350px!important}div.riskgauge td.choicetable-left{width:50px!important}div.riskgauge .sep{display:block;font-size:13px;margin:0 auto}div.riskgauge .bomb-table{margin-left:20%;margin-right:20%}div.riskgauge .bomb-box{background:#000;height:10px}@media (min-width:1900px){div.riskgauge .bomb-box{height:30px}div.riskgauge .bomb-table{margin-left:10%;margin-right:10%}}div.riskgauge #bomb_result{font-weight:700}div.riskgauge .bomb_lost{color:#fa0404}div.riskgauge .bomb_won{color:#1be139}div.riskgauge button.btn-danger{display:block;margin:auto;padding:.3em}div.riskgauge .risk-info{text-align:center}div.riskgauge .risk-info p{display:inline-flex;margin-right:20px}div.riskgauge .risk-info span{font-weight:700;margin-left:.3em}.emailform-input,.feedback-textarea{margin-bottom:5px}.feedback .btn{margin-right:5px}.endscreen .emailform,.endscreen .feedback{margin-top:30px}.endscreen .no-panel-body{margin:5px}.panel-collapse-link{cursor:pointer;display:inline-block;float:right;margin-left:8px}.docked{bottom:0;box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19);margin-left:20px;position:fixed;right:10px;z-index:100}.chat{font-size:16px}.chat .panel-body{height:380px;width:330px}.chat_chat{height:280px;overflow-y:scroll;padding:5px;width:100%}.chat_textarea{resize:none;width:100%}.chat_textarea_btn{display:inline;width:78%}.chat_submit{height:auto;max-width:300px;width:20%}.chat_inputgroup{display:inline-flex;width:100%}.chat_msg,.chat_msg_collapse,.chat_msg_incoming,.chat_msg_outgoing,.chat_msg_quit,.chat_time{clear:both;float:left;margin:1px;padding:5px 10px}.chat_msg_incoming{background:#f4f4f4;border-radius:5px;max-width:150px}.chat_msg_outgoing{background:#f2f7ff;border-radius:5px;float:right;max-width:150px}.chat_msg_collapse,.chat_msg_quit,.chat_time{font-size:13px;font-style:oblique}.container-slider{clear:both;display:inline-block;height:40px;position:relative;width:100%}.fill-slider{background:#000;border-radius:8px;border-bottom-right-radius:0;border-top-right-radius:0;display:inline-block;height:10px;top:15px;width:calc(100% - 10px)}.fill-slider,.volume-slider{box-sizing:border-box;left:0;position:absolute}.volume-slider{-webkit-appearance:none;background:transparent;cursor:pointer;height:40px;padding:0;top:0;width:100%}.volume-slider::-ms-track{border-color:transparent}.volume-slider:focus{outline:none}.volume-slider::-moz-focus-outer{border:0}.volume-slider::-webkit-slider-thumb{-webkit-appearance:none;background:#fff;border:3px solid #282d32;border-radius:50%;cursor:pointer;height:30px;margin-top:-11px;width:30px}.volume-slider::-webkit-slider-runnable-track{background:transparent;border:1px solid #fff;border-radius:8px;cursor:pointer;height:10px;width:300px}.volume-slider::-moz-range-thumb{background:#fff;border:3px solid #282d32;border-radius:50%;cursor:pointer;height:30px;width:30px}.volume-slider::-moz-range-track{background:transparent;border:1px solid #fff;border-radius:8px;box-sizing:border-box;cursor:pointer;height:10px;width:100%}.volume-slider:hover~.fill-slider{background:#00ced1!important}@media (-ms-high-contrast:active),(-ms-high-contrast:none){.fill-slider{display:none}}.volume-slider::-ms-thumb{background:#fff;border:0;border-radius:50%;box-shadow:0 0 0 3px #282d32;box-sizing:border-box;cursor:pointer;height:30px;margin-top:2px;width:30px}.volume-slider:focus::-ms-thumb{border:0}.volume-slider::-ms-track{background:transparent;border:1px solid #fff;border-radius:8px;box-sizing:border-box;color:transparent;cursor:pointer;height:10px;width:100%}.volume-slider::-ms-fill-lower{background:#fff;border:1px solid #fff;border-radius:8px}.volume-slider::-ms-fill-upper{background:transparent}.volume-slider::-ms-tooltip{display:none}.slider-display-nochange,.slider-display-value{clear:both;font-size:14px}.slider-display-nochange{float:right} \ No newline at end of file diff --git a/views/homepage.jade b/views/homepage.jade index 510c116c..0aeba024 100644 --- a/views/homepage.jade +++ b/views/homepage.jade @@ -46,11 +46,11 @@ html5 i(class='material-icons') book if (game.external) li - a(href=game.demo, class='btn-floating btn-large green pulse tooltipped z-depth-2', target='_blank', data-delay="0", data-tooltip='Play Demo') + a(href=game.demo, class='btn-floating btn-large green pulse tooltipped z-depth-2', target='_blank', data-delay="0", data-tooltip='Play') i(class='large material-icons') play_circle_filled else li - a(href='/'+game.name, class='btn-floating btn-large green pulse tooltipped z-depth-2', target='_blank', data-delay="0", data-tooltip='Play Demo') + a(href='/'+game._name, class='btn-floating btn-large green pulse tooltipped z-depth-2', target='_blank', data-delay="0", data-tooltip='Play') i(class='large material-icons') play_circle_filled if nodeGameCard span(class='col s12 m6 l4 xl4 center')