<commit_before>var request = require('request'),
    JSONStream = require('JSONStream'),
    when = require('when'),
    util = require('util'),
    qs = require('querystring'),
    fs = require('fs'),
    os = require('os'),
    open = require('open'),
    imagemagick = require('imagemagick');

module.exports = function (config) {
    var apiToken = config.apiToken,
        baseUrl = config.url,
        workingDir = config.workingDir;

    function responseResolver(deferred, bodyParser) {
        return function (error, response, body) {
            if (error) {
                deferred.reject(error);

            } else if (response.statusCode > 299) {
                deferred.reject(new Error("Status code: " + response.statusCode));

            } else {
                if (bodyParser) {
                    console.debug(body);
                    deferred.resolve(bodyParser(body));
                } else {
                    deferred.resolve();
                }
            }
        };
    }

    this.dateFormat = "YYYY/MM/DD HH:mm:ss ZZ";

    this.downloadAvatarFor = function (user) {
        var deferred = when.defer(),
            filename = user.id;

        if (user.avatar_url) {
            var path = workingDir + filename,
                file = fs.createWriteStream(path);

            console.debug("Downloading avatar for user " + user.id + " to path " + path + "...");

            request.get(user.avatar_url)
                .pipe(file)
                .on('finish', function () {
                    var finalPath = path + ".png";
                    imagemagick.convert([ path, finalPath], function () {
                        deferred.resolve(finalPath);
                    });
                });

            return deferred.promise;

        } else {
            console.debug("User " + user.id + " does not have avatar.");
            deferred.reject();
        }

        return deferred.promise;
    };

    /**
     * Gets the details for the specified user. Returns a promise.
     */
    this.getUser = function (userId) {
        console.debug("Getting user " + userId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/users/%s.json', baseUrl, userId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).user;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the details for the specified room. Returns a promise.
     */
    this.getRoom = function (roomId) {
        console.debug("Getting room " + roomId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/room/%s.json', baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).room;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the details for all rooms visible to the user. Returns a promise.
     */
    this.getRooms = function () {
        console.debug("Getting rooms...");

        var deferred = when.defer();

        request.get(util.format('%s/rooms.json', baseUrl),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).rooms;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Sends a join request to the specified Campfire room. Returns a promise.
     */
    this.joinRoom = function (roomId) {
        console.debug("Joining room " + roomId + "...");

        var deferred = when.defer();

        request.post(util.format('%s/room/%s/join.json', baseUrl, roomId),
            responseResolver(deferred))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Sends a leave request to the specified Campfire room. Returns a promise.
     */
    this.leaveRoom = function (roomId) {
        console.debug("Leaving room " + roomId + "...");

        var deferred = when.defer();

        request.post(util.format('%s/room/%s/leave.json', baseUrl, roomId),
            responseResolver(deferred))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the most recent messages for the specified room. Returns a promise.
     */
    this.getRecentMessages = function (roomId) {
        console.debug("Getting recent messages from room " + roomId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/room/%s/recent.json', baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Posts the specified message to the specified room.
     */
    this.postMessage = function (roomId, message) {
        console.debug("Posting message to room " + roomId + "...");
        console.debug(JSON.stringify(message));

        var deferred = when.defer();

        request.post({
            url: util.format('%s/room/%s/speak.json', baseUrl, roomId),
            auth: {
                user: apiToken,
                pass: 'X'
            },
            json: {
                message: message
            }
        }, responseResolver(deferred));

        return deferred.promise;
    };

    /**
     * Searches all rooms for the specified term.
     */
    this.search = function (roomId, term) {
        console.debug("Searching room " + roomId + " with term '" + term + "'...");

        var deferred = when.defer(),
            url = util.format('%s/search?', baseUrl) + qs.stringify({
                q: term,
                format: "json"
            });

        request.get(url,
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages.filter(function (message) {
                    return message.room_id === parseInt(roomId);
                }).reverse();
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the room transcript for the specified day indicated by the specified moment.
     *
     * Returns a promise.
     */
    this.getTranscript = function (roomId, date) {

        var datePath = date.format("YYYY/M/D"),
            deferred = when.defer();

        console.debug("Getting messages for " + datePath + " from room " + roomId + "...");

        request.get(util.format('%s/room/%s/transcript/' + datePath + ".json", baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the upload details for the specified upload message.
     *
     * Returns a promise.
     */
    this.getUpload = function (roomId, messageId) {

        var deferred = when.defer();

        console.debug("Getting upload for message " + messageId + " from room " + roomId + "...");

        request.get(util.format('%s/room/%s/messages/%s/upload.json', baseUrl, roomId, messageId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).upload;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Opens a stream to the specified room.
     */
    this.openRoomStream = function (roomId) {
        console.debug("Opening stream to room " + roomId + "...");

        return request.get('https://streaming.campfirenow.com/room/' + roomId + '/live.json')
            .auth(apiToken, 'X')
            .pipe(JSONStream.parse());
    };

    /**
     * Opens a browser session for the specified room.
     */
    this.openRoomInBrowser = function (roomId) {
        var url = baseUrl + '/room/' + roomId;

        console.debug("Opening url " + url + " in browser...");
        open(url);
    };
};
<commit_msg>Added a bit of diagnostics to avatar downloading and converting.<commit_after>var request = require('request'),
    JSONStream = require('JSONStream'),
    when = require('when'),
    util = require('util'),
    qs = require('querystring'),
    fs = require('fs'),
    os = require('os'),
    open = require('open'),
    imagemagick = require('imagemagick');

module.exports = function (config) {
    var apiToken = config.apiToken,
        baseUrl = config.url,
        workingDir = config.workingDir;

    function responseResolver(deferred, bodyParser) {
        return function (error, response, body) {
            if (error) {
                deferred.reject(error);

            } else if (response.statusCode > 299) {
                deferred.reject(new Error("Status code: " + response.statusCode));

            } else {
                if (bodyParser) {
                    console.debug(body);
                    deferred.resolve(bodyParser(body));
                } else {
                    deferred.resolve();
                }
            }
        };
    }

    this.dateFormat = "YYYY/MM/DD HH:mm:ss ZZ";

    this.downloadAvatarFor = function (user) {
        var deferred = when.defer(),
            filename = user.id;

        if (user.avatar_url) {
            var path = workingDir + filename,
                file = fs.createWriteStream(path);

            console.debug("Downloading avatar for user " + user.id + " to path " + path + "...");

            request.get(user.avatar_url)
                .pipe(file)
                .on('finish', function () {
                    console.debug("Avatar downloaded. Converting...");
                    var finalPath = path + ".png";

                    try {
                        imagemagick.convert([ path, finalPath], function () {
                            deferred.resolve(finalPath);
                        });
                    } catch (e) {
                        deferred.reject(e);
                    }
                });

            return deferred.promise;

        } else {
            console.debug("User " + user.id + " does not have avatar.");
            deferred.reject();
        }

        return deferred.promise;
    };

    /**
     * Gets the details for the specified user. Returns a promise.
     */
    this.getUser = function (userId) {
        console.debug("Getting user " + userId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/users/%s.json', baseUrl, userId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).user;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the details for the specified room. Returns a promise.
     */
    this.getRoom = function (roomId) {
        console.debug("Getting room " + roomId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/room/%s.json', baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).room;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the details for all rooms visible to the user. Returns a promise.
     */
    this.getRooms = function () {
        console.debug("Getting rooms...");

        var deferred = when.defer();

        request.get(util.format('%s/rooms.json', baseUrl),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).rooms;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Sends a join request to the specified Campfire room. Returns a promise.
     */
    this.joinRoom = function (roomId) {
        console.debug("Joining room " + roomId + "...");

        var deferred = when.defer();

        request.post(util.format('%s/room/%s/join.json', baseUrl, roomId),
            responseResolver(deferred))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Sends a leave request to the specified Campfire room. Returns a promise.
     */
    this.leaveRoom = function (roomId) {
        console.debug("Leaving room " + roomId + "...");

        var deferred = when.defer();

        request.post(util.format('%s/room/%s/leave.json', baseUrl, roomId),
            responseResolver(deferred))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the most recent messages for the specified room. Returns a promise.
     */
    this.getRecentMessages = function (roomId) {
        console.debug("Getting recent messages from room " + roomId + "...");

        var deferred = when.defer();

        request.get(util.format('%s/room/%s/recent.json', baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Posts the specified message to the specified room.
     */
    this.postMessage = function (roomId, message) {
        console.debug("Posting message to room " + roomId + "...");
        console.debug(JSON.stringify(message));

        var deferred = when.defer();

        request.post({
            url: util.format('%s/room/%s/speak.json', baseUrl, roomId),
            auth: {
                user: apiToken,
                pass: 'X'
            },
            json: {
                message: message
            }
        }, responseResolver(deferred));

        return deferred.promise;
    };

    /**
     * Searches all rooms for the specified term.
     */
    this.search = function (roomId, term) {
        console.debug("Searching room " + roomId + " with term '" + term + "'...");

        var deferred = when.defer(),
            url = util.format('%s/search?', baseUrl) + qs.stringify({
                q: term,
                format: "json"
            });

        request.get(url,
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages.filter(function (message) {
                    return message.room_id === parseInt(roomId);
                }).reverse();
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the room transcript for the specified day indicated by the specified moment.
     *
     * Returns a promise.
     */
    this.getTranscript = function (roomId, date) {

        var datePath = date.format("YYYY/M/D"),
            deferred = when.defer();

        console.debug("Getting messages for " + datePath + " from room " + roomId + "...");

        request.get(util.format('%s/room/%s/transcript/' + datePath + ".json", baseUrl, roomId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).messages;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Gets the upload details for the specified upload message.
     *
     * Returns a promise.
     */
    this.getUpload = function (roomId, messageId) {

        var deferred = when.defer();

        console.debug("Getting upload for message " + messageId + " from room " + roomId + "...");

        request.get(util.format('%s/room/%s/messages/%s/upload.json', baseUrl, roomId, messageId),
            responseResolver(deferred, function (body) {
                return JSON.parse(body).upload;
            }))
            .auth(apiToken, 'X');

        return deferred.promise;
    };

    /**
     * Opens a stream to the specified room.
     */
    this.openRoomStream = function (roomId) {
        console.debug("Opening stream to room " + roomId + "...");

        return request.get('https://streaming.campfirenow.com/room/' + roomId + '/live.json')
            .auth(apiToken, 'X')
            .pipe(JSONStream.parse());
    };

    /**
     * Opens a browser session for the specified room.
     */
    this.openRoomInBrowser = function (roomId) {
        var url = baseUrl + '/room/' + roomId;

        console.debug("Opening url " + url + " in browser...");
        open(url);
    };
};
<|endoftext|>


<commit_before>#! /usr/bin/env node

var userArgs = process.argv.slice(2);

var command = userArgs[0];

var exec = require('child_process').exec;

switch (command) {
    case "seed":
        exec('gulp seed --gulpfile $PWD/node_modules/rest-hapi/gulpfile.js', function(err, stdout, stderr) {
            console.log(stdout);
            console.log(stderr);
        });
        break;
    case "test":
        exec('gulp test --gulpfile $PWD/node_modules/rest-hapi/gulpfile.js', function(err, stdout, stderr) {
            console.log(stdout);
            console.log(stderr);
        });
        break;
    default:
        console.error("error, unknown command:", command);
        break;
}

<commit_msg>CLI fix for windows users when executing rest-hapi-cli command in the terminal<commit_after>#! /usr/bin/env node

var userArgs = process.argv.slice(2);

var command = userArgs[0];

var exec = require('child_process').exec;

var isWindows = /^win/.test(process.platform);

var cmdString = '$PWD/node_modules/rest-hapi/gulpfile.js';

if (isWindows) {
	// This will fix the error "No gulpfile found" on windows OS
	cmdString = './node_modules/rest-hapi/gulpfile.js';
}

switch (command) {
	case "seed":
		exec('gulp seed --gulpfile ' + cmdString, function(err, stdout, stderr) {
			console.log(stdout);
			console.log(stderr);
		});
		break;
	case "test":
		exec('gulp test --gulpfile ' + cmdString, function(err, stdout, stderr) {
			console.log(stdout);
			console.log(stderr);
		});
		break;
	default:
		console.error("error, unknown command:", command);
		break;
}

<|endoftext|>


<commit_before>'use strict';

var Task            = require('./-task');
var CordovaRawTask  = require('../tasks/cordova-raw');

module.exports = Task.extend({
  project: undefined,
  ui: undefined,

  platform: undefined,
  isRelease: false,
  isEmulator: true,
  platformOpts: undefined,
  buildConfig: undefined,

  run: function() {
    var cordovaOpts = [];
    var platformOpts = [];
    var _platformOpts = Object.keys(platformOpts).map((key) => {
      var value = platformOpts[key];
      if (value !== undefined) {
        return '--' + key + '=' + value;
      }
    });

    cordovaOpts.push(this.isRelease ? '--release' : '--debug');
    cordovaOpts.push(this.isEmulator ? '--emulator' : '--device');

    if (this.buildConfig !== undefined) {
      cordovaOpts.push('--buildConfig=' + this.buildConfig);
    }

    if (_platformOpts !== undefined) {
      Object.keys(_platformOpts).forEach((key) => {
        var value = _platformOpts[key];

        if (value !== undefined) {
          platformOpts.push('--' + key + '=' + value);
        }
      });

      if (platformOpts.length > 0) {
        cordovaOpts.push('--');
        cordovaOpts = cordovaOpts.concat(platformOpts);
      }
    }

    var build = new CordovaRawTask({
      project: this.project,
      rawApi: 'build',
      ui: this.ui
    });

    return build.run({
      platforms: [this.platform],
      options: cordovaOpts
    });
  }
});
<commit_msg>fix(eslint): get eslint passing<commit_after>'use strict';

var Task            = require('./-task');
var CordovaRawTask  = require('../tasks/cordova-raw');

module.exports = Task.extend({
  project: undefined,
  ui: undefined,

  platform: undefined,
  isRelease: false,
  isEmulator: true,
  platformOpts: undefined,
  buildConfig: undefined,

  run: function() {
    var cordovaOpts = [];
    var platformOpts = [];
    var _platformOpts = Object.keys(platformOpts).map(function(key) {
      var value = platformOpts[key];
      if (value !== undefined) {
        return '--' + key + '=' + value;
      }
    });

    cordovaOpts.push(this.isRelease ? '--release' : '--debug');
    cordovaOpts.push(this.isEmulator ? '--emulator' : '--device');

    if (this.buildConfig !== undefined) {
      cordovaOpts.push('--buildConfig=' + this.buildConfig);
    }

    if (_platformOpts !== undefined) {
      Object.keys(_platformOpts).forEach(function(key) {
        var value = _platformOpts[key];

        if (value !== undefined) {
          platformOpts.push('--' + key + '=' + value);
        }
      });

      if (platformOpts.length > 0) {
        cordovaOpts.push('--');
        cordovaOpts = cordovaOpts.concat(platformOpts);
      }
    }

    var build = new CordovaRawTask({
      project: this.project,
      rawApi: 'build',
      ui: this.ui
    });

    return build.run({
      platforms: [this.platform],
      options: cordovaOpts
    });
  }
});
<|endoftext|>


<commit_before>/**
 * https://github.com/MarcDiethelm/terrificjs-extensions
 * Adds some sugar and enhancements to @brunschgi's excellent Terrificjs frontend framework.
 * @file terrificjs-extensions.js
 * @license MIT
 * @copyright 2014 Marc Diethelm
 */

(function ($) {

	'use strict';

	/**
	 * Select elements in the module context. Usage: this.$(selector)
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @param {string} selector
	 * @returns {object} - jQuery collection
	 */
	Tc.Module.prototype.$ = function $$(selector) {
		return this.$ctx.find(selector);
	};

	/**
	* Deprecated. Use Tc.Module.prototype.$
	* Select elements in the module context. Usage: this.$$(selector)
	* @deprecated Use Tc.Module.prototype.$
	* @see Tc.Module.prototype.$
	* @author Marc Diethelm <marc.diethelm@namics.com>
	* @param {string} selector
	* @returns {object} - jQuery collection
	*/
	Tc.Module.prototype.$$ = Tc.Module.prototype.$;

	/**
	 * Bind methods to Terrific module context.  Usage: this.bindAll(funcName [,funcName...])
	 * Inspired by Underscore's bindAll. http://underscorejs.org/#bindAll
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {...string} methods - Names of methods each as a param.
	 * @return {module} - Returns the module instance for chaining.
	 */
	Tc.Module.prototype.bindAll = function bindAll(methods) {
		var i = 0,
			args = arguments,
			argLen = args.length,
			methodName
		;

		for (i; i < argLen; i++) {
			methodName = args[i];
			if (typeof this[methodName] === 'function') {
				this[methodName] = $.proxy(this, methodName);
			} else if (typeof methodName === 'string') {
				throw new TypeError('bindAll: Tc.Module.' + this.getName() + '.' + methodName + ' is not a function');
			} else {
				throw new TypeError('Arguments to bindAll must be strings');
			}
		}

		return this;
	};

	/**
	 * Get the name of the Terrific module
	 * @author Remo Brunschwiler <remo.brunschwiler@namics.com>
	 * @author Mathias Hayoz <mathias.hayoz@namics.com>
	 * @returns {string} - Module name
	 */
	Tc.Module.prototype.getName = function getName() {
		var property;
		if (!this._modName) {
			for (property in Tc.Module) {
				if (Tc.Module.hasOwnProperty(property) && property !== 'constructor' && this instanceof Tc.Module[property]) {
					this._modName = property;
					break;
				}
			}
		}

		return this._modName;
	};

	/**
	 * Simplify connector channel subscription
	 *
	 * Because the second parameter to sandbox.subscribe `this` is often forgotten.
	 * Additionally this method allows connecting to multiple channels at once.
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {...string} channels - Connector channels to subscribe to
	 * @return {module} - Returns the module instance for chaining.
	 */
	Tc.Module.prototype.subscribe = function subscribe(channels) {
		var i = 0,
			args = arguments,
			argLen = args.length
		;

		for (i; i < argLen; i++) {
			this.sandbox.subscribe(args[i], this);
		}

		return this;
	};

	/**
	 * Get all channels the module is currently subscribed to
	 *
	 * @author Simon Harte <simon.harte@namics.com>
	 * @return {object, string} channels - Returns the array of connected channels
	 */
	Tc.Module.prototype.getConnectors = function getConnectors() {
		var channels = [],
			chan,
			curr;

		for (chan in this.connectors) {
			if (this.connectors.hasOwnProperty(chan)) {
				curr = this.connectors[chan];
				channels.push(curr.connectorId);
			}
		}

		return channels;
	};

	/**
	 * Fire on all channels the current module is subscribed to
	 *
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {string} method - Function to execute in connected modules
	 * @param {object} [data] - The data to provide to your connected modules (optional)
	 * @return {object} this - Returns the module instance for chaining
	 */
	Tc.Module.prototype.fireAll = function fireAll(method, data) {
		var channels = this.getConnectors();

		this.fire(method, data || {}, channels);

		return this;
	};

	var tplCache = {};
	/**
	 * Micro-templating for modules. Extrapolates {{= foo }} variables in strings from data.
	 * This function is a remix of
	 * - Simple JavaScript Templating – John Resig - http://ejohn.org/ - MIT Licensed
	 * - https://gist.github.com/topliceanu/1537847
	 * - http://weblog.west-wind.com/posts/2008/Oct/13/Client-Templating-with-jQuery
	 * This code incorporates a fix for single-quote usage.
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @param {string} str - Template
	 * @param {object} [data] - Optional, renders template immediately if present. Data to use as the template context for variable extrapolation.
	 * @returns {function|string} - Template function, to render template with data, or if data was supplied already the rendered template.
	 */
	Tc.Module.prototype.template = function template(str, data) {

		// Figure out if we're getting a template, or if we need to
		// load the template - and be sure to cache the result.
		var fn = !/\W/.test(str) ?
			tplCache[str] = tplCache[str] ||
				template(document.getElementById(str).innerHTML) :
			// Generate a reusable function that will serve as a template
			// generator (and which will be cached).
			/*jshint -W054, -W014 */
			new Function("obj",
					"var p=[],print=function(){p.push.apply(p,arguments);};" +
					// Introduce the data as local variables using with(){}
					"with(obj){p.push('" +
					// Convert the template into pure JavaScript
					str.replace(/[\r\t\n]/g, " ")
						.replace(/'(?=[^%]*\}\}>)/g, "\t")
						.split("'").join("\\'")
						.split("\t").join("'")
						.replace(/\{\{=(.+?)\}\}/g, "',$1,'")
						.split("{{").join("');")
						.split("}}").join("p.push('")
					+ "');}return p.join('');");
		/*jshint +W054, +W014 */
		// Provide some basic currying to the user
		return data ? fn(data) : fn;
	};

})($ || jQuery);
<commit_msg>module is no valid type in jsdoc<commit_after>/**
 * https://github.com/MarcDiethelm/terrificjs-extensions
 * Adds some sugar and enhancements to @brunschgi's excellent Terrificjs frontend framework.
 * @file terrificjs-extensions.js
 * @license MIT
 * @copyright 2014 Marc Diethelm
 */

(function ($) {

	'use strict';

	/**
	 * Select elements in the module context. Usage: this.$(selector)
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @param {string} selector
	 * @returns {object} - jQuery collection
	 */
	Tc.Module.prototype.$ = function $$(selector) {
		return this.$ctx.find(selector);
	};

	/**
	 * Deprecated. Use Tc.Module.prototype.$
	 * Select elements in the module context. Usage: this.$$(selector)
	 * @deprecated Use Tc.Module.prototype.$
	 * @see Tc.Module.prototype.$
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @param {string} selector
	 * @returns {object} - jQuery collection
	 */
	Tc.Module.prototype.$$ = Tc.Module.prototype.$;

	/**
	 * Bind methods to Terrific module context.  Usage: this.bindAll(funcName [,funcName...])
	 * Inspired by Underscore's bindAll. http://underscorejs.org/#bindAll
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {...string} methods - Names of methods each as a param.
	 * @return {object} - Returns the module instance for chaining.
	 */
	Tc.Module.prototype.bindAll = function bindAll(methods) {
		var i = 0,
			args = arguments,
			argLen = args.length,
			methodName
			;

		for (i; i < argLen; i++) {
			methodName = args[i];
			if (typeof this[methodName] === 'function') {
				this[methodName] = $.proxy(this, methodName);
			} else if (typeof methodName === 'string') {
				throw new TypeError('bindAll: Tc.Module.' + this.getName() + '.' + methodName + ' is not a function');
			} else {
				throw new TypeError('Arguments to bindAll must be strings');
			}
		}

		return this;
	};

	/**
	 * Get the name of the Terrific module
	 * @author Remo Brunschwiler <remo.brunschwiler@namics.com>
	 * @author Mathias Hayoz <mathias.hayoz@namics.com>
	 * @returns {string} - Module name
	 */
	Tc.Module.prototype.getName = function getName() {
		var property;
		if (!this._modName) {
			for (property in Tc.Module) {
				if (Tc.Module.hasOwnProperty(property) && property !== 'constructor' && this instanceof Tc.Module[property]) {
					this._modName = property;
					break;
				}
			}
		}

		return this._modName;
	};

	/**
	 * Simplify connector channel subscription
	 *
	 * Because the second parameter to sandbox.subscribe `this` is often forgotten.
	 * Additionally this method allows connecting to multiple channels at once.
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {...string} channels - Connector channels to subscribe to
	 * @return {object} - Returns the module instance for chaining
	 */
	Tc.Module.prototype.subscribe = function subscribe(channels) {
		var i = 0,
			args = arguments,
			argLen = args.length
			;

		for (i; i < argLen; i++) {
			this.sandbox.subscribe(args[i], this);
		}

		return this;
	};

	/**
	 * Get all channels the module is currently subscribed to
	 *
	 * @author Simon Harte <simon.harte@namics.com>
	 * @return {object, string} channels - Returns the array of connected channels
	 */
	Tc.Module.prototype.getConnectors = function getConnectors() {
		var channels = [],
			chan,
			curr
			;

		for (chan in this.connectors) {
			if (this.connectors.hasOwnProperty(chan)) {
				curr = this.connectors[chan];
				channels.push(curr.connectorId);
			}
		}

		return channels;
	};

	/**
	 * Fire on all channels the current module is subscribed to
	 *
	 * @author Simon Harte <simon.harte@namics.com>
	 * @param {string} method - Function to execute in connected modules
	 * @param {object} [data] - The data to provide to your connected modules (optional)
	 * @return {object} this - Returns the module instance for chaining
	 */
	Tc.Module.prototype.fireAll = function fireAll(method, data) {
		var channels = this.getConnectors();

		this.fire(method, data || {}, channels);

		return this;
	};

	var tplCache = {};
	/**
	 * Micro-templating for modules. Extrapolates {{= foo }} variables in strings from data.
	 * This function is a remix of
	 * - Simple JavaScript Templating – John Resig - http://ejohn.org/ - MIT Licensed
	 * - https://gist.github.com/topliceanu/1537847
	 * - http://weblog.west-wind.com/posts/2008/Oct/13/Client-Templating-with-jQuery
	 * This code incorporates a fix for single-quote usage.
	 * @author Marc Diethelm <marc.diethelm@namics.com>
	 * @param {string} str - Template
	 * @param {object} [data] - Optional, renders template immediately if present. Data to use as the template context for variable extrapolation.
	 * @returns {function|string} - Template function, to render template with data, or if data was supplied already the rendered template.
	 */
	Tc.Module.prototype.template = function template(str, data) {

		// Figure out if we're getting a template, or if we need to
		// load the template - and be sure to cache the result.
		var fn = !/\W/.test(str) ?
			tplCache[str] = tplCache[str] ||
				template(document.getElementById(str).innerHTML) :
			// Generate a reusable function that will serve as a template
			// generator (and which will be cached).
			/*jshint -W054, -W014 */
			new Function("obj",
					"var p=[],print=function(){p.push.apply(p,arguments);};" +
					// Introduce the data as local variables using with(){}
					"with(obj){p.push('" +
					// Convert the template into pure JavaScript
					str.replace(/[\r\t\n]/g, " ")
						.replace(/'(?=[^%]*\}\}>)/g, "\t")
						.split("'").join("\\'")
						.split("\t").join("'")
						.replace(/\{\{=(.+?)\}\}/g, "',$1,'")
						.split("{{").join("');")
						.split("}}").join("p.push('")
					+ "');}return p.join('');");
		/*jshint +W054, +W014 */
		// Provide some basic currying to the user
		return data ? fn(data) : fn;
	};

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


<commit_before>/*eslint-env mocha*/
/*global assert*/ // chai

define(['BlinkForms', 'BIC'], function (Forms) {

  suite('2: options', function () {
    var $page = $('[data-role=page]'),
      $content = $page.find('[data-role=content]');

    /**
     * execute once before everything else in this suite
     */
    suiteSetup(function () {
      $content.empty();
      delete Forms.current;
    });

    suite('Form', function () {

      test('BlinkForms global is an Object', function () {
        assert($.isPlainObject(Forms), 'BlinkForms is a JavaScript object');
      });

      test('initialise with form.json', function (done) {
        var form;

        Forms.getDefinition('form1', 'add').then(function (def) {
          Forms.initialize(def);
          form = Forms.current;
          assert.equal($.type(form), 'object');
          assert.equal(form.get('name'), 'form1');
          assert.equal(form.get('label'), 'Form 1');
          done();
        }, function () {
          assert.fail(true, false, 'getDefinition failed!');
          done();
        });
      });

      test('render form for jQuery Mobile', function () {
        var form = Forms.current;

        $content.append(form.$form);

        $.mobile.page({}, $page);
        $page.trigger('pagecreate');
        $page.show();
      });

      test('select-1 collapsed', function () {
        var form = Forms.current,
          element = form.getElement('selectc'),
          $fieldset = element.attributes._view.$el,
          $span = $fieldset.find('.ui-btn-text'),
          $select = $fieldset.find('select');

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');

        element.val('a');
        assert.equal(element.val(), 'a', 'model.value = "a"');
        assert.equal($span.text(), 'alpha', 'jQM shows "alpha"');

        element.val('b');
        assert.equal(element.val(), 'b', 'model.value = "b"');
        assert.equal($span.text(), 'beta', 'jQM shows "beta"');

        assert.notEqual($select.data("role"), "none", "data-role is none");
        // TODO: test UI causes side-effect in model
      });

      test('select-multi collapsed', function () {
        var form = Forms.current,
          element = form.getElement('multic'),
          $fieldset = element.attributes._view.$el,
          $span = $fieldset.find('.ui-btn-text'),
          $select = $fieldset.find('select');

        element.val([]);
        assert.deepEqual(element.val(), [], 'model.value is []');

        element.val(['a']);
        assert.deepEqual(element.val(), ['a'], 'model.value = ["a"]');
        assert.equal($span.text(), 'alpha', 'jQM shows "alpha"');

        element.val(['a', 'b']);
        assert.deepEqual(element.val(), ['a', 'b'], 'model.value = ["a", "b"]');
        assert.equal($span.text(), 'alpha, beta', 'jQM shows "alpha, beta"');

        assert.notEqual($select.data("role"), "none", "data-role is none");

        // TODO: test UI causes side-effect in model
      });

      test('select-1 expanded', function () {
        var form = Forms.current,
          element = form.getElement('selecte'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val('a');
        assert.equal(element.val(), 'a', 'model.value = "a"');

        element.val('b');
        assert.equal(element.val(), 'b', 'model.value = "b"');

        $fieldset.find('label:contains(gamma)').trigger('click');
        assert.equal(element.val(), 'g', 'model.value = "g"');
      });

      test('select-multi expanded', function () {
        var form = Forms.current,
          element = form.getElement('multie'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val(['a']);
        assert.deepEqual(element.val(), ['a'], 'model.value = ["a"]');

        element.val(['a', 'b']);
        assert.deepEqual(element.val(), ['a', 'b'], 'model.value = ["a", "b"]');

        $fieldset.find('.ui-btn-text:contains(beta)').trigger('click');
        $fieldset.find('.ui-btn-text:contains(gamma)').trigger('click');
        assert.deepEqual(element.val(), ['a', 'g'], 'model.value = ["a", "g"]');
      });

      test('Select-F native collapsed', function () {
        var form = Forms.current,
          element = form.getElement('selectf'),
          $fieldset = element.attributes._view.$el,
          $select = $fieldset.find('select');

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');

        element.val('a');
        assert.equal(element.val(), 'a', 'model.value = "a"');

        element.val('b');
        assert.equal(element.val(), 'b', 'model.value = "b"');

        assert.equal($select.data("role"), "none", "data-role is not none");

      });

      test('Multi-F native collapsed', function () {
        var form = Forms.current,
          element = form.getElement('multif'),
          $fieldset = element.attributes._view.$el,
          $select = $fieldset.find('select');

        element.val([]);
        assert.deepEqual(element.val(), [], 'model.value is []');

        element.val(['a']);
        assert.deepEqual(element.val(), ['a'], 'model.value = ["a"]');

        element.val(['a', 'b']);
        assert.deepEqual(element.val(), ['a', 'b'], 'model.value = ["a", "b"]');

        assert.equal($select.data("role"), "none", "data-role is not none");

      });

      test('boolean 0/1', function (done) {
        var form = Forms.current,
          element = form.getElement('boolean'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val(0);
        assert.equal(element.val(), 0, 'model.value = 0');

        setTimeout(function () {
          element.val(1);
          assert.equal(element.val(), 1, 'model.value = 1');

          setTimeout(function () {
            $fieldset.find('div.ui-slider-switch').trigger('mousedown').trigger('mouseup').trigger('click');
            assert.equal(element.val(), 0, 'model.value = 0');
            done();
          }, 500);

        }, 500);

      });

      test('boolean n/y', function (done) {
        var form = Forms.current,
          element = form.getElement('question'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val('n');
        assert.equal(element.val(), 'n', 'model.value = "n"');

        setTimeout(function () {
          element.val('y');
          assert.equal(element.val(), 'y', 'model.value = "y"');

          setTimeout(function () {
            $fieldset.find('div.ui-slider-switch').trigger('mousedown').trigger('mouseup').trigger('click');
            assert.equal(element.val(), 'n', 'model.value = "n"');
            done();
          }, 500);
        }, 500);

      });

    }); // END: suite('Form', ...)

  }); // END: suite('1', ...)

});
<commit_msg>Much updated Unit tests<commit_after>/*eslint-env mocha*/
/*global assert*/ // chai

define(['BlinkForms', 'BIC'], function (Forms) {

  suite('2: options', function () {
    var $page = $('[data-role=page]'),
      $content = $page.find('[data-role=content]');

    /**
     * execute once before everything else in this suite
     */
    suiteSetup(function () {
      $content.empty();
      delete Forms.current;
    });

    suite('Form', function () {

      test('BlinkForms global is an Object', function () {
        assert($.isPlainObject(Forms), 'BlinkForms is a JavaScript object');
      });

      test('initialise with form.json', function (done) {
        var form;

        Forms.getDefinition('form1', 'add').then(function (def) {
          Forms.initialize(def);
          form = Forms.current;
          assert.equal($.type(form), 'object');
          assert.equal(form.get('name'), 'form1');
          assert.equal(form.get('label'), 'Form 1');
          done();
        }, function () {
          assert.fail(true, false, 'getDefinition failed!');
          done();
        });
      });

      test('render form for jQuery Mobile', function () {
        var form = Forms.current;

        $content.append(form.$form);

        $.mobile.page({}, $page);
        $page.trigger('pagecreate');
        $page.show();
      });

      test('select-1 collapsed API -> UI bindings', function () {
        var form = Forms.current,
          element = form.getElement('selectc'),
          $fieldset = element.attributes._view.$el,
          $span = $fieldset.find('.ui-btn-text'),
          $select = $fieldset.find('select'),
          $other;

        element.val('');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'select one...', 'form element value is "select one"..."');
        assert.equal($other.length, 0, 'other box absent');

        element.val('a');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'a', 'form element value = "a"');
        assert.equal($span.text(), 'alpha', 'jQM shows "alpha"');
        assert.equal($other.length, 0, 'other box absent');

        element.val('b');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'b', 'form element value = "b"');
        assert.equal($span.text(), 'beta', 'jQM shows "beta"');
        assert.equal($other.length, 0, 'other box absent');

        element.val('other');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'other', 'form element value = "other"');
        assert.equal($other.length, 1, 'other box exists');
        assert.equal($other.val(), '', 'other box is empty');

        // Include this test here to make the other box dissapear
        // Then test what happens when an 'other' value is directly inserted
        // This pattern repeated in all test suites below for coverage
        element.val('');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'select one...', 'form element value is "select one"..."');
        assert.equal($other.length, 0, 'other box absent');

        element.val('cat');
        $other = $fieldset.find('input[type = text]');
        assert.equal($select.val(), 'other', 'form element value = "other"');
        assert.equal($other.length, 1, 'other box exists');
        assert.equal($other.val(), 'cat', 'other box is has value "cat"');
      });

      test('select-1 collapsed UI -> API bindings');

      test('select-1 expanded API -> UI bindings', function () {
        var form = Forms.current,
        element = form.getElement('selecte'),
        $fieldset = element.attributes._view.$el,
        $selected,
        $other;

        element.val('');
        $selected = $fieldset.find('input[type = radio]:checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 0, 'no form element selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val('a');
        $selected = $fieldset.find('input[type = radio]:checked').val();
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected, 'a', 'form element value = "a"');
        assert.equal($other.length, 0, 'other box absent');

        element.val('b');
        $selected = $fieldset.find('input[type = radio]:checked').val();
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected, 'b', 'form element value = "b"');
        assert.equal($other.length, 0, 'other box absent');

        element.val('other');
        $selected = $fieldset.find('input[type = radio]:checked').val();
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected, 'other', 'form element value = "other"');
        assert.equal($other.length, 1, 'other box exists');
        assert.equal($other.val(), '', 'other box is empty');

        element.val('');
        $selected = $fieldset.find('input[type = radio]:checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 0, 'no form element selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val('cat');
        $selected = $fieldset.find('input[type = radio]:checked').val();
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected, 'other', 'form element value = "other"');
        assert.equal($other.length, 1, 'other box exists');
        assert.equal($other.val(), 'cat', 'other box is "cat"');
      });

      test('select-1 expanded UI -> API bindings', function () {
        // UI -> API bindings
        var form = Forms.current,
        element = form.getElement('selecte'),
        $fieldset = element.attributes._view.$el;

        $fieldset.find('label:contains(gamma)').trigger('click');
        assert.equal(element.val(), 'g', 'model.value = "g"');
      });

      test('select-multi collapsed API -> UI bindings', function () {
        var form = Forms.current,
          element = form.getElement('multic'),
          $fieldset = element.attributes._view.$el,
          $span = $fieldset.find('.ui-btn-text'),
          $select = $fieldset.find('select'),
          $selected,
          $other,
          val;

        element.val([]);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'select one or more...', 'jQM shows "select one or more..."');
        assert.equal($selected.length, 0, 'no elements selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a']);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'alpha', 'jQM shows "alpha"');
        assert.equal($selected.length, 1, '1 element selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a'], 'element has a selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b']);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'alpha, beta', 'jQM shows "alpha, beta"');
        assert.equal($selected.length, 2, '2 elements selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b'], 'element has a & b selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b', 'other']);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'alpha, beta, other', 'jQM shows "alpha, beta, other"');
        assert.equal($selected.length, 3, '3 elements selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b', 'other'], 'element has a, b & other selected');
        assert.equal($other.length, 1, 'other box present');
        assert.equal($other.val(), '', 'other box empty');

        element.val([]);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'select one or more...', 'jQM shows "select one or more..."');
        assert.equal($selected.length, 0, 'no elements selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b', 'cat']);
        $selected = $select.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($span.text(), 'alpha, beta, other', 'jQM shows "alpha, beta, other"');
        assert.equal($selected.length, 3, '3 elements selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b', 'other'], 'element has a, b & other selected');
        assert.equal($other.length, 1, 'other box present');
        assert.equal($other.val(), 'cat', 'other box contains "cat"');

        assert.notEqual($select.data("role"), "none", "data-role is none");
      });

      test('select-multi expanded API -> UI bindings', function () {
        var form = Forms.current,
          element = form.getElement('multie'),
          $fieldset = element.attributes._view.$el,
          $selected,
          $other,
          val;

        element.val('');
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 0, 'no items selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a']);
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 1, '1 item selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a'], 'element has a selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b']);
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 2, '2 items selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b'], 'element has a & b selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b', 'other']);
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 3, '3 items selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b', 'other'], 'element has a, b & other selected');
        assert.equal($other.length, 1, 'other box present');
        assert.equal($other.val(), '', 'other box empty');

        element.val('');
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 0, 'no items selected');
        assert.equal($other.length, 0, 'other box absent');

        element.val(['a', 'b', 'cat']);
        $selected = $fieldset.find(':checked');
        $other = $fieldset.find('input[type = text]');
        assert.equal($selected.length, 3, '3 items selected');
        val = _.map($selected, function (input) {
          return $(input).val();
        });
        assert.deepEqual(val, ['a', 'b', 'other'], 'element has a, b, other selected');
        assert.equal($other.length, 1, 'other box present');
        assert.equal($other.val(), 'cat', 'other box contains "cat"');

        $fieldset.find('.ui-btn-text:contains(beta)').trigger('click');
        $fieldset.find('.ui-btn-text:contains(gamma)').trigger('click');
      });

      test('Select-F native collapsed', function () {
        var form = Forms.current,
          element = form.getElement('selectf'),
          $fieldset = element.attributes._view.$el,
          $select = $fieldset.find('select');

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');

        element.val('a');
        assert.equal(element.val(), 'a', 'model.value = "a"');

        element.val('b');
        assert.equal(element.val(), 'b', 'model.value = "b"');

        assert.equal($select.data("role"), "none", "data-role is not none");

      });

      test('Multi-F native collapsed', function () {
        var form = Forms.current,
          element = form.getElement('multif'),
          $fieldset = element.attributes._view.$el,
          $select = $fieldset.find('select');

        element.val([]);
        assert.deepEqual(element.val(), [], 'model.value is []');

        element.val(['a']);
        assert.deepEqual(element.val(), ['a'], 'model.value = ["a"]');

        element.val(['a', 'b']);
        assert.deepEqual(element.val(), ['a', 'b'], 'model.value = ["a", "b"]');

        assert.equal($select.data("role"), "none", "data-role is not none");

      });

      test('boolean 0/1', function (done) {
        var form = Forms.current,
          element = form.getElement('boolean'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val(0);
        assert.equal(element.val(), 0, 'model.value = 0');

        setTimeout(function () {
          element.val(1);
          assert.equal(element.val(), 1, 'model.value = 1');

          setTimeout(function () {
            $fieldset.find('div.ui-slider-switch').trigger('mousedown').trigger('mouseup').trigger('click');
            assert.equal(element.val(), 0, 'model.value = 0');
            done();
          }, 500);

        }, 500);

      });

      test('boolean n/y', function (done) {
        var form = Forms.current,
          element = form.getElement('question'),
          $fieldset = element.attributes._view.$el;

        element.val('');
        assert.equal(element.val(), '', 'model.value is ""');
        assert.equal($fieldset.find('ui-btn-active').length, 0, 'jQM is blank');

        element.val('n');
        assert.equal(element.val(), 'n', 'model.value = "n"');

        setTimeout(function () {
          element.val('y');
          assert.equal(element.val(), 'y', 'model.value = "y"');

          setTimeout(function () {
            $fieldset.find('div.ui-slider-switch').trigger('mousedown').trigger('mouseup').trigger('click');
            assert.equal(element.val(), 'n', 'model.value = "n"');
            done();
          }, 500);
        }, 500);

      });

    }); // END: suite('Form', ...)

  }); // END: suite('1', ...)

});

/*
TODO
SelectC ...chose one bugs out
*/
<|endoftext|>


<commit_before>var GoalTimes = require('../js/GoalTimes');
var assert = require('chai').assert;

var decimalGoalTimes = [[0.5, 0.6], , [0.2]];
var periodTimes = [10, 5, 10];
var playablePeriods = [true, false, true];
var startTime = Date.now();

var goalTimes = new GoalTimes(decimalGoalTimes, periodTimes, startTime);

describe('GoalTimes', function () {
    describe('#getMinuteTimes', function () {
        it('should convert to minutes correctly', function () {
            var minuteTimes = goalTimes.getMinuteTimes();

            assert.deepEqual(minuteTimes, [[5, 6], , [17]]);
        });
    });

    describe('#getMilliTimes', function () {
        it('should convert to milliseconds correctly', function () {
            var milliTimes = goalTimes.getMilliTimes();
            var times = [
                [
                    calculateTime(300000),
                    calculateTime(360000)
                ],
                ,
                [
                    calculateTime(912000)
                ]
            ];

            assert.deepEqual(milliTimes, times);
        });
    });
});

function calculateTime(time) {
    return time + startTime;
}
<commit_msg>Updates tests<commit_after>var GoalTimes = require('../js/GoalTimes');
var assert = require('chai').assert;

var decimalGoalTimes = [[0.5, 0.6], , [0.2]];
var periodTimes = [10, 5, 10];
var playablePeriods = [true, false, true];
var startTime = Date.now();

var goalTimes = new GoalTimes(decimalGoalTimes, periodTimes, startTime);

describe('GoalTimes', function () {
    describe('#getMinuteTimes', function () {
        it('should convert to minutes correctly', function () {
            var minuteTimes = goalTimes.getMinuteTimes();

            assert.deepEqual(minuteTimes, [[5, 6], , [17]]);
        });
    });

    describe('#getMilliTimes', function () {
        it('should convert to milliseconds correctly', function () {
            var milliTimes = goalTimes.getMilliTimes();
            var times = [
                [
                    calculateTime(300000),
                    calculateTime(360000)
                ],
                ,
                [
                    calculateTime(912000)
                ]
            ];

            assert.deepEqual(milliTimes, times);
        });
    });

    describe('#_totalTime', function () {
        it('should total up all the previous in play times', function () {
            var time = goalTimes._totalTime(2);

            assert.equal(time, 15);
        });
    });

    describe('#_totalTimeInPlay', function () {
        it('should total up all the previous times that are in play', function () {
            var time = goalTimes_totalTimeInPlay(2);

            assert.equal(time, 10);
        });
    });

    describe('#_totalTimeNonPlay', function () {
        it('should total up all the previous times that are non play', function () {
            var time = goalTimes._totalTimeNonPlay(2);

            assert.equal(time, 5);
        });
    });
});

function calculateTime(time) {
    return time + startTime;
}
<|endoftext|>


<commit_before>const { assert } = require('chai');

describe('Array', () => {
 describe('#indexOf()', () => {
   it('should return -1 when the value is not present', function() {
     assert.equal(-1, [1,2,3].indexOf(4));
   });
 });
});
<commit_msg>Delete HelloWord.test.js<commit_after><|endoftext|>


<commit_before>import React from 'react';
import { shallow } from 'enzyme';
import TextInput from '../src/TextInput';

describe('<TextInput />', () => {
  let wrapper;

  test('handles layout classes', () => {
    wrapper = shallow(<TextInput s={4} m={6} />);

    expect(wrapper.hasClass('input-field')).toBeTruthy();
    expect(wrapper.hasClass('col')).toBeTruthy();
    expect(wrapper.hasClass('s4')).toBeTruthy();
    expect(wrapper.hasClass('m6')).toBeTruthy();
  });

  test('handles removing layout classes', () => {
    wrapper = shallow(<TextInput s={4} m={6} noLayout />);

    expect(wrapper.hasClass('input-field')).toBeTruthy();
    expect(wrapper.hasClass('col')).toBeFalsy();
    expect(wrapper.hasClass('s4')).toBeFalsy();
    expect(wrapper.hasClass('m6')).toBeFalsy();
  });

  test('renders placeholder', () => {
    wrapper = shallow(<TextInput placeholder="Name" />);
    expect(wrapper.find('input').prop('placeholder')).toEqual('Name');
  });

  test('renders label', () => {
    wrapper = shallow(<TextInput label="Name" />);
    expect(wrapper.find('label').text()).toEqual('Name');
  });

  test('handles validate', () => {
    wrapper = shallow(<TextInput validate />);
    expect(wrapper.find('input.validate')).toHaveLength(1);
  });

  test('handles inputClassName', () => {
    wrapper = shallow(<TextInput validate inputClassName={'hello red'} />);
    expect(wrapper.find('input.hello.red.validate')).toHaveLength(1);
  });

  test('handles other types', () => {
    wrapper = shallow(<TextInput password />);
    expect(wrapper.find('input').prop('type')).toEqual('password');
  });

  test('with icon', () => {
    wrapper = shallow(<TextInput icon="cloud" />);
    expect(wrapper.find('i.material-icons.prefix')).toHaveLength(1);
  });
});
<commit_msg>Add test for onChange event to textinput<commit_after>import React from 'react';
import { shallow } from 'enzyme';
import TextInput from '../src/TextInput';

describe('<TextInput />', () => {
  let wrapper;

  test('handles layout classes', () => {
    wrapper = shallow(<TextInput s={4} m={6} />);

    expect(wrapper.hasClass('input-field')).toBeTruthy();
    expect(wrapper.hasClass('col')).toBeTruthy();
    expect(wrapper.hasClass('s4')).toBeTruthy();
    expect(wrapper.hasClass('m6')).toBeTruthy();
  });

  test('handles removing layout classes', () => {
    wrapper = shallow(<TextInput s={4} m={6} noLayout />);

    expect(wrapper.hasClass('input-field')).toBeTruthy();
    expect(wrapper.hasClass('col')).toBeFalsy();
    expect(wrapper.hasClass('s4')).toBeFalsy();
    expect(wrapper.hasClass('m6')).toBeFalsy();
  });

  test('renders placeholder', () => {
    wrapper = shallow(<TextInput placeholder="Name" />);
    expect(wrapper.find('input').prop('placeholder')).toEqual('Name');
  });

  test('renders label', () => {
    wrapper = shallow(<TextInput label="Name" />);
    expect(wrapper.find('label').text()).toEqual('Name');
  });

  test('handles validate', () => {
    wrapper = shallow(<TextInput validate />);
    expect(wrapper.find('input.validate')).toHaveLength(1);
  });

  test('handles inputClassName', () => {
    wrapper = shallow(<TextInput validate inputClassName={'hello red'} />);
    expect(wrapper.find('input.hello.red.validate')).toHaveLength(1);
  });

  test('handles other types', () => {
    wrapper = shallow(<TextInput password />);
    expect(wrapper.find('input').prop('type')).toEqual('password');
  });

  test('with icon', () => {
    wrapper = shallow(<TextInput icon="cloud" />);
    expect(wrapper.find('i.material-icons.prefix')).toHaveLength(1);
  });

  test('handles other props', () => {
    const mockOnChange = jest.fn();
    wrapper = shallow(<TextInput onChange={mockOnChange} />);
    wrapper.find('input').simulate('change', { target: { value: '7' } });

    expect(mockOnChange).toHaveBeenCalledTimes(1);
  });
});
<|endoftext|>


<commit_before>require('../support/test_helper');

var assert = require('../support/assert');
var TestClient = require('../support/test-client');
var serverOptions = require('../../lib/cartodb/server_options');

function createMapConfig(sql = TestClient.SQL.ONE_POINT) {
    return {
        version: '1.6.0',
        layers: [{
            type: "cartodb",
            options: {
                sql: sql,
                cartocss: TestClient.CARTOCSS.POINTS,
                cartocss_version: '2.3.0',
                interactivity: 'cartodb_id'
            }
        }]
    };
}

describe('mvt (mapnik)', mvt(false));
if (process.env.POSTGIS_VERSION >= '20400') {
    describe('mvt (postgis)', mvt(true));
}

function mvt(usePostGIS) {
return function () {
    const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
    before(function () {
        serverOptions.renderer.mvt.usePostGIS = usePostGIS;
    });
    after(function (){
        serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS;
    });

    describe('named map tile', function () {
        it('should get default named vector tile', function (done) {
            const apikeyToken = 1234;
            const templateName = `mvt-template-${usePostGIS ? 'postgis' : 'mapnik'}`;
            const template = {
                version: '0.0.1',
                name: templateName,
                placeholders: {
                    buffersize: {
                        type: 'number',
                        default: 0
                    }
                },
                layergroup: {
                    version: '1.7.0',
                    layers: [{
                        type: 'cartodb',
                        options: {
                            sql: 'select * from populated_places_simple_reduced limit 10',
                            cartocss: TestClient.CARTOCSS.POINTS,
                            cartocss_version: '2.3.0',
                        }
                    }]
                }
            };

            const testClient = new TestClient(template, apikeyToken);
            testClient.keysToDelete['map_tpl|localhost'] = 0;

            testClient.getNamedTile(templateName, 0, 0, 0, 'mvt', {}, (err, res, tile) => {
                if (err) {
                    return done(err);
                }

                const tileJSON = tile.toJSON();

                assert.equal(tileJSON[0].features.length, 10);

                testClient.drain(done);
            });
        });
    });

    describe('analysis-layers-dataviews-mvt', function () {

        function createMapConfig(layers, dataviews, analysis) {
            return {
                version: '1.5.0',
                layers: layers,
                dataviews: dataviews || {},
                analyses: analysis || []
            };
        }

        var CARTOCSS = [
            "#points {",
            "  marker-fill-opacity: 1.0;",
            "  marker-line-color: #FFF;",
            "  marker-line-width: 0.5;",
            "  marker-line-opacity: 1.0;",
            "  marker-placement: point;",
            "  marker-type: ellipse;",
            "  marker-width: 8;",
            "  marker-fill: red;",
            "  marker-allow-overlap: true;",
            "}"
        ].join('\n');

        var mapConfig = createMapConfig(
            [
                {
                    "type": "cartodb",
                    "options": {
                        "source": {
                            "id": "2570e105-7b37-40d2-bdf4-1af889598745"
                        },
                        "cartocss": CARTOCSS,
                        "cartocss_version": "2.3.0"
                    }
                }
            ],
            {
                pop_max_histogram: {
                    source: {
                        id: '2570e105-7b37-40d2-bdf4-1af889598745'
                    },
                    type: 'histogram',
                    options: {
                        column: 'pop_max'
                    }
                }
            },
            [
                {
                    "id": "2570e105-7b37-40d2-bdf4-1af889598745",
                    "type": "source",
                    "params": {
                        "query": "select * from populated_places_simple_reduced"
                    }
                }
            ]
        );

        it('should get pop_max column from dataview', function (done) {
            var testClient = new TestClient(mapConfig);

            testClient.getTile(0, 0, 0, { format: 'mvt', layers: 0 }, function (err, res, MVT) {
                var geojsonTile = JSON.parse(MVT.toGeoJSONSync(0));
                assert.ok(!err, err);

                assert.ok(Array.isArray(geojsonTile.features));
                assert.ok(geojsonTile.features.length > 0);
                var feature = geojsonTile.features[0];
                assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property');

                testClient.drain(done);
            });
        });

    });

    const testCases = [
        {
            desc: 'should get empty mvt with code 204 (no content)',
            coords: { z: 0, x: 0, y: 0 },
            format: 'mvt',
            response: {
                status: 204,
                headers: {
                    'Content-Type': undefined
                }
            },
            mapConfig: createMapConfig(TestClient.SQL.EMPTY)
        },
        {
            desc: 'should get mvt tile with code 200 (ok)',
            coords: { z: 0, x: 0, y: 0 },
            format: 'mvt',
            response: {
                status: 200,
                headers: {
                    'Content-Type': 'application/x-protobuf'
                }
            },
            mapConfig: createMapConfig()
        }
    ];

    testCases.forEach(function (test) {
        it(test.desc, done => {
            var testClient = new TestClient(test.mapConfig);
            const { z, x, y } = test.coords;
            const { format, response } = test;

            testClient.getTile(z, x, y, { format, response }, err => {
                assert.ifError(err);
                testClient.drain(done);
            });
        });
    });

    describe('overviews-mvt', function () {
        function createMapConfig(layers, dataviews, analysis) {
            return {
                version: '1.8.0',
                layers: layers,
                dataviews: dataviews || {},
                analyses: analysis || []
            };
        }

        it('should use overviews to fetch mvt data', function (done) {
            const mapConfig = createMapConfig(
                [
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table_overviews',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    }
                ]
            );

            const testClient = new TestClient(mapConfig);

            testClient.getTile(0, 0, 0, { format: 'mvt', layers: 0 }, function (err, res, mvt) {
                assert.ifError(err);

                const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0));

                assert.ok(Array.isArray(geojsonTile.features));
                assert.ok(geojsonTile.features.length > 0);

                const feature = geojsonTile.features[0];

                assert.ok(feature.properties.hasOwnProperty('_feature_count'), 'Missing _feature_count property');
                assert.equal(feature.properties.cartodb_id, 1);
                assert.equal(feature.properties.name, 'Hawai');
                assert.equal(feature.properties._feature_count, 5); // original table has _feature_count = 1
                assert.equal(feature.properties.value, 3); // original table has value = 1.0

                testClient.drain(done);
            });
        });

        it('two layers, first should use overviews, second shouldn\'t', function (done) {
            const mapConfig = createMapConfig(
                [
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table_overviews',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    },
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    }
                ]
            );

            var testClient = new TestClient(mapConfig);

            testClient.getTile(0, 0, 0, { format: 'mvt' }, function (err, res, mvt) {
                assert.ifError(err);

                const tileWithOverviews = JSON.parse(mvt.toGeoJSONSync(0));
                const tileWithoutOverviews = JSON.parse(mvt.toGeoJSONSync(1));

                assert.ok(Array.isArray(tileWithOverviews.features));
                assert.equal(tileWithOverviews.features.length, 1);

                assert.ok(Array.isArray(tileWithoutOverviews.features));
                assert.equal(tileWithoutOverviews.features.length, 5);

                testClient.drain(done);
            });
        });
    });
};
}
<commit_msg>Organize params<commit_after>require('../support/test_helper');

var assert = require('../support/assert');
var TestClient = require('../support/test-client');
var serverOptions = require('../../lib/cartodb/server_options');

function createMapConfig(sql = TestClient.SQL.ONE_POINT) {
    return {
        version: '1.6.0',
        layers: [{
            type: "cartodb",
            options: {
                sql: sql,
                cartocss: TestClient.CARTOCSS.POINTS,
                cartocss_version: '2.3.0',
                interactivity: 'cartodb_id'
            }
        }]
    };
}

describe('mvt (mapnik)', mvt(false));
if (process.env.POSTGIS_VERSION >= '20400') {
    describe('mvt (postgis)', mvt(true));
}

function mvt(usePostGIS) {
return function () {
    const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
    before(function () {
        serverOptions.renderer.mvt.usePostGIS = usePostGIS;
    });
    after(function (){
        serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS;
    });

    describe('named map tile', function () {
        it('should get default named vector tile', function (done) {
            const apikeyToken = 1234;
            const templateName = `mvt-template-${usePostGIS ? 'postgis' : 'mapnik'}`;
            const template = {
                version: '0.0.1',
                name: templateName,
                placeholders: {
                    buffersize: {
                        type: 'number',
                        default: 0
                    }
                },
                layergroup: {
                    version: '1.7.0',
                    layers: [{
                        type: 'cartodb',
                        options: {
                            sql: 'select * from populated_places_simple_reduced limit 10',
                            cartocss: TestClient.CARTOCSS.POINTS,
                            cartocss_version: '2.3.0',
                        }
                    }]
                }
            };

            const testClient = new TestClient(template, apikeyToken);
            testClient.keysToDelete['map_tpl|localhost'] = 0;

            testClient.getNamedTile(templateName, 0, 0, 0, 'mvt', {}, (err, res, tile) => {
                if (err) {
                    return done(err);
                }

                const tileJSON = tile.toJSON();

                assert.equal(tileJSON[0].features.length, 10);

                testClient.drain(done);
            });
        });
    });

    describe('analysis-layers-dataviews-mvt', function () {

        function createMapConfig(layers, dataviews, analysis) {
            return {
                version: '1.5.0',
                layers: layers,
                dataviews: dataviews || {},
                analyses: analysis || []
            };
        }

        var CARTOCSS = [
            "#points {",
            "  marker-fill-opacity: 1.0;",
            "  marker-line-color: #FFF;",
            "  marker-line-width: 0.5;",
            "  marker-line-opacity: 1.0;",
            "  marker-placement: point;",
            "  marker-type: ellipse;",
            "  marker-width: 8;",
            "  marker-fill: red;",
            "  marker-allow-overlap: true;",
            "}"
        ].join('\n');

        var mapConfig = createMapConfig(
            [
                {
                    "type": "cartodb",
                    "options": {
                        "source": {
                            "id": "2570e105-7b37-40d2-bdf4-1af889598745"
                        },
                        "cartocss": CARTOCSS,
                        "cartocss_version": "2.3.0"
                    }
                }
            ],
            {
                pop_max_histogram: {
                    source: {
                        id: '2570e105-7b37-40d2-bdf4-1af889598745'
                    },
                    type: 'histogram',
                    options: {
                        column: 'pop_max'
                    }
                }
            },
            [
                {
                    "id": "2570e105-7b37-40d2-bdf4-1af889598745",
                    "type": "source",
                    "params": {
                        "query": "select * from populated_places_simple_reduced"
                    }
                }
            ]
        );

        it('should get pop_max column from dataview', function (done) {
            var testClient = new TestClient(mapConfig);

            testClient.getTile(0, 0, 0, { format: 'mvt', layers: 0 }, function (err, res, MVT) {
                var geojsonTile = JSON.parse(MVT.toGeoJSONSync(0));
                assert.ok(!err, err);

                assert.ok(Array.isArray(geojsonTile.features));
                assert.ok(geojsonTile.features.length > 0);
                var feature = geojsonTile.features[0];
                assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property');

                testClient.drain(done);
            });
        });

    });

    const testCases = [
        {
            desc: 'should get empty mvt with code 204 (no content)',
            coords: { z: 0, x: 0, y: 0 },
            format: 'mvt',
            response: {
                status: 204,
                headers: {
                    'Content-Type': undefined
                }
            },
            mapConfig: createMapConfig(TestClient.SQL.EMPTY)
        },
        {
            desc: 'should get mvt tile with code 200 (ok)',
            coords: { z: 0, x: 0, y: 0 },
            format: 'mvt',
            response: {
                status: 200,
                headers: {
                    'Content-Type': 'application/x-protobuf'
                }
            },
            mapConfig: createMapConfig()
        }
    ];

    testCases.forEach(function (test) {
        it(test.desc, done => {
            var testClient = new TestClient(test.mapConfig);
            const { z, x, y } = test.coords;
            const { format, response } = test;

            testClient.getTile(z, x, y, { format, response }, err => {
                assert.ifError(err);
                testClient.drain(done);
            });
        });
    });

    describe('overviews', function () {
        function createMapConfig(layers, dataviews, analysis) {
            return {
                version: '1.8.0',
                layers: layers,
                dataviews: dataviews || {},
                analyses: analysis || []
            };
        }

        it('should use overviews to fetch mvt data', function (done) {
            const mapConfig = createMapConfig(
                [
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table_overviews',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    }
                ]
            );

            const testClient = new TestClient(mapConfig);
            const [ z, x, y ] = [ 0, 0, 0 ];
            const options = { format: 'mvt' };

            testClient.getTile(z, x, y, options, function (err, res, mvt) {
                assert.ifError(err);

                const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0));

                assert.ok(Array.isArray(geojsonTile.features));
                assert.ok(geojsonTile.features.length > 0);

                const feature = geojsonTile.features[0];

                assert.ok(feature.properties.hasOwnProperty('_feature_count'), 'Missing _feature_count property');
                assert.equal(feature.properties.cartodb_id, 1);
                assert.equal(feature.properties.name, 'Hawai');
                assert.equal(feature.properties._feature_count, 5); // original table has _feature_count = 1
                assert.equal(feature.properties.value, 3); // original table has value = 1.0

                testClient.drain(done);
            });
        });

        it('first layer should use overviews, second layer shouldn\'t', function (done) {
            const mapConfig = createMapConfig(
                [
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table_overviews',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    },
                    {
                        "type": "cartodb",
                        "options": {
                            "sql": 'SELECT * FROM test_table',
                            "cartocss": TestClient.CARTOCSS.POINTS,
                            "cartocss_version": "2.3.0"
                        }
                    }
                ]
            );

            const testClient = new TestClient(mapConfig);
            const [ z, x, y ] = [ 0, 0, 0 ];
            const options = { format: 'mvt' };

            testClient.getTile(z, x, y, options, function (err, res, mvt) {
                assert.ifError(err);

                const tileWithOverviews = JSON.parse(mvt.toGeoJSONSync(0));
                const tileWithoutOverviews = JSON.parse(mvt.toGeoJSONSync(1));

                assert.ok(Array.isArray(tileWithOverviews.features));
                assert.equal(tileWithOverviews.features.length, 1);

                assert.ok(Array.isArray(tileWithoutOverviews.features));
                assert.equal(tileWithoutOverviews.features.length, 5);

                testClient.drain(done);
            });
        });
    });
};
}
<|endoftext|>


<commit_before>'use strict';

const http = require('http');
const Immutable = require('immutable');

/**
 * Walk a properties object looking for transformable values
 *
 * @param {Object} properties  an object to search for transformable values
 * @param {Array} keyPath  accumulated path of keys where transformable value was found
 * @return {Array<Immutable.Map>} transformable data with injected key path
 */
function collectTransformables(properties, keyPath) {
  let results = [];

  // Ensure we're walking an Object. `== null` covers both null and undefined.
  if (properties == null || Object.getPrototypeOf(properties) !== Object.prototype) { // eslint-disable-line eqeqeq
    return results;
  }

  // If we're walking a $tokend object, pass it to the callback.
  const keys = Object.keys(properties);

  if (keys.length === 1 && keys[0] === '$tokend') {
    return results.concat(Immutable.Map(properties.$tokend).set('keyPath', keyPath));
  }

  Object.keys(properties).forEach((key) => {
    const value = properties[key];

    // Don't walk anything that's not an Object. `!= null` covers both null and undefined.
    if (value != null && Object.getPrototypeOf(value) === Object.prototype) { // eslint-disable-line eqeqeq
      results = results.concat(collectTransformables(value, keyPath.concat(key)));
    }
  });

  return results;
}

/**
 * @param {Object}  options
 */
class TokendTransformer {
  constructor(options) {
    let defaultOptions = Immutable.Map({
      host: '127.0.0.1',
      port: '4500'
    });

    defaultOptions = defaultOptions.mergeDeep(options);

    this.host = defaultOptions.get('host');
    this.port = parseInt(defaultOptions.get('port'), 10);
  }

  /**
   * Transform properties by fetching secrets from tokend
   *
   * @param  {Object} properties  properties that may contain $tokend values
   * @return {Promise<Properties>} properties that had $tokend values transformed
   */
  transform(properties) {
    const promises = collectTransformables(properties, []).map((info) => {
      return new Promise((resolve, reject) => {
        let data = '';

        const req = http.get({
          host: this.host,
          port: this.port,
          path: info.get('resource')
        }, (res) => {
          res.setEncoding('utf8');
          res.on('data', (chunk) => {
            data += chunk;
          });
          res.on('end', () => {
            data = JSON.parse(data);
            resolve(Immutable.Map().setIn(info.get('keyPath'), data.secret));
          });
        });

        req.on('error', (e) => {
          reject(e);
        });
      });
    });

    return Promise.all(promises).then((values) => {
      let transformedProperties = Immutable.Map();

      values.forEach((value) => {
        transformedProperties = transformedProperties.mergeDeep(value);
      });

      return transformedProperties.toJS();
    });
  }
}

module.exports = TokendTransformer;
<commit_msg>Check they $tokend "type" before trying to fetch the secret.<commit_after>'use strict';

const http = require('http');
const Immutable = require('immutable');

/**
 * Walk a properties object looking for transformable values
 *
 * @param {Object} properties  an object to search for transformable values
 * @param {Array} keyPath  accumulated path of keys where transformable value was found
 * @return {Array<Immutable.Map>} transformable data with injected key path
 */
function collectTransformables(properties, keyPath) {
  let results = [];

  // Ensure we're walking an Object. `== null` covers both null and undefined.
  if (properties == null || Object.getPrototypeOf(properties) !== Object.prototype) { // eslint-disable-line eqeqeq
    return results;
  }

  // If we're walking a $tokend object, pass it to the callback.
  const keys = Object.keys(properties);

  if (keys.length === 1 && keys[0] === '$tokend') {
    return results.concat(Immutable.Map(properties.$tokend).set('keyPath', keyPath));
  }

  Object.keys(properties).forEach((key) => {
    const value = properties[key];

    // Don't walk anything that's not an Object. `!= null` covers both null and undefined.
    if (value != null && Object.getPrototypeOf(value) === Object.prototype) { // eslint-disable-line eqeqeq
      results = results.concat(collectTransformables(value, keyPath.concat(key)));
    }
  });

  return results;
}

/**
 * @param {Object}  options
 */
class TokendTransformer {
  constructor(options) {
    let defaultOptions = Immutable.Map({
      host: '127.0.0.1',
      port: '4500'
    });

    defaultOptions = defaultOptions.mergeDeep(options);

    this.host = defaultOptions.get('host');
    this.port = parseInt(defaultOptions.get('port'), 10);
  }

  /**
   * Transform properties by fetching secrets from tokend
   *
   * @param  {Object} properties  properties that may contain $tokend values
   * @return {Promise<Properties>} properties that had $tokend values transformed
   */
  transform(properties) {
    const promises = collectTransformables(properties, []).map((info) => {
      return new Promise((resolve, reject) => {
        if (info.get('type') !== 'secret') {
          return reject(new Error(`Invalid $tokend.type ${info.get('type')} for ${info.get('keyPath').join('.')}`));
        }

        let data = '';

        const req = http.get({
          host: this.host,
          port: this.port,
          path: info.get('resource')
        }, (res) => {
          res.setEncoding('utf8');
          res.on('data', (chunk) => {
            data += chunk;
          });
          res.on('end', () => {
            data = JSON.parse(data);
            resolve(Immutable.Map().setIn(info.get('keyPath'), data.secret));
          });
        });

        req.on('error', (e) => {
          reject(e);
        });
      });
    });

    return Promise.all(promises).then((values) => {
      let transformedProperties = Immutable.Map();

      values.forEach((value) => {
        transformedProperties = transformedProperties.mergeDeep(value);
      });

      return transformedProperties.toJS();
    });
  }
}

module.exports = TokendTransformer;
<|endoftext|>