<commit_before>/**
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter;
var small_screen = require('../is-small-screen');
var ocreate = require('../object-create');

var regex = require('../regex');
var i18n = require('../i18n');
var bind = require('../bind');
var _ = require('underscore');
var okeys = _.keys;

/**
 * Expose `OptionsManager`
 */

module.exports = OptionsManager;

/**
 * Create an `OptionsManager` from
 * instanceOptions and displayOptions
 *
 * @param {Auth0Lock} widget
 * @param {Object} displayOptions
 * @constructor
 */

function OptionsManager(widget, options) {
  if (!(this instanceof OptionsManager)) {
    return new OptionsManager(widget, options);
  }

  // Initiate `EventEmitter`
  EventEmitter.call(this);

  // Flag OptionsManager as `unloaded`
  this.state('loading');

  // holds widget as reference
  this.$widget = widget;

  // save widget's $client object reference
  this.$client = widget.$client;

  // save copy of widget's valid strategies
  this.$strategies = widget.$strategies;

  // save widget's `auth0-js` instance object
  this.$auth0 = widget.$auth0;

  // save widget instance options with `$` prepended
  _.each(okeys(widget.$options), function(key) {
    this['$' + key] = widget.$options[key];
  }, this);

  // copies all provided options to instance
  // filtering by allowed options `whitelist`
  _.each(okeys(options), function(key) {
    // we should whitelist options
    // so no OptionsManager method gets overriden
    // by user configurable object
    // XXX: Broken, fix it!
    // if (!~whitelist.indexOf(key) && !~supportedParams.indexOf(key)) return;
    this[key] = options[key];
  }, this);

  // Set `i18n` dictionary for templates
  this.i18n = i18n.getDict(this.dict);

  // default authParams to empty object
  this.authParams = _.extend({}, options.authParams);

  // enable/disable last login and AD discovery
  this.rememberLastLogin = null != options.rememberLastLogin ? !!options.rememberLastLogin : true;
  this.integratedWindowsLogin = null != options.integratedWindowsLogin ? !!options.integratedWindowsLogin : true;

  // If popupCallback, enable popup mode
  if ('function' === typeof options.popupCallback) {
    this.popup = true;
    // XXX: the following to should already come with
    // the options from constructor... right?
    this.popupOptions = _.extend({}, options.popupOptions);
    this.popupCallback = options.popupCallback;
  }

  // save default responseType
  if (options.responseType) {
    this.responseType = options.responseType;
  } else {
    this.responseType = (this.popup || !options.callbackURL) ? 'token' : 'code';
  }

  // Options moved from constructor and hacked into `auth0-js` instance
  this.$auth0._useJSONP = options.forceJSONP || this.$auth0._useJSONP;
  this.$auth0._callbackURL = options.callbackURL || this.$auth0._callbackURL;
  this.$auth0._callbackOnLocationHash = 'token' === this.responseType || !!this.$auth0._callbackOnLocationHash;

  // force `closable` when provided with `container`
  this.closable = null != options.closable ? !!options.closable : !this.container;

  // Delay options requiring $client configuration
  this.$widget.getClientConfiguration(bind(this._onclientloaded, this));
}

/**
 * Inherit from `EventEmitter`
 */

OptionsManager.prototype = ocreate(EventEmitter.prototype);

/**
 * Get or Set `$_state` for track
 * `OptionsManager`s ready state
 *
 * @param {String} state
 * @param {String} message
 * @return {OptionsManager}
 * @public
 */

OptionsManager.prototype.state = function(state, message) {
  if (0 === arguments.length) {
    return this.$_state;
  }

  // debug('state is now %s', state);
  this.$_state = state;
  this.emit(state, message);
  return this;
};

/**
 * Register `fn` for when `OptionsManager`
 * is ready (or `loaded`)
 *
 * @param {Function} fn
 * @return {OptionsManager}
 * @public
 */

OptionsManager.prototype.ready = function(fn) {
  function done() {
    if ('loaded' === this.state()) {
      return fn();
    }
  }

  if ('loaded' === this.state()) {
    setTimeout(bind(done, this), 0);
  } else {
    this.once('loaded', bind(done, this));
  }

  return this;
};

/**
 * Continue setup once client's configuration
 * is retrieved from assets url or S3
 *
 * @param {Object} client
 * @return {OptionsManager}
 * @private
 */

OptionsManager.prototype._onclientloaded = function(client) {

  // Refresh clients configuration with what's stored
  // on the Auth0's hash
  this.$client = _.extend(this.$client, client);

  // Enrich $client.strategies
  // then, continue setting up the mode
  if (this.connections) {
    this.$client.strategies = _.chain(this.$client.strategies)
      .map(strategiesConnectionsMapper(this.connections))
      .filter(hasConnectionsFilter)
      .value();
  }

  // merge strategies info
  for (var i = 0; i < this.$client.strategies.length; i++) {
    var sname = this.$client.strategies[i].name;
    this.$client.strategies[i] = _.extend({}, this.$client.strategies[i], this.$strategies[sname]);
  }

  // Holds auth0 strategies only
  this.auth0Strategies = _.chain(this.$client.strategies)
    .filter(auth0StrategiesFilter)
    .value();

  // show signup/forgot links
  var auth0Conn = this._getAuth0Connection() || {};

  // if booted on `signup` or `reset`, but not configured
  // on connection => override mode with `signin`
  if (this.mode === 'signup' && !auth0Conn.showSignup) { this.mode = 'signin'; }
  if (this.mode === 'reset' && !auth0Conn.showForgot) { this.mode = 'signin'; }

  // Resolve show action buttons or not
  this.showSignupAction = (this.disableSignupAction !== true) && ((auth0Conn && auth0Conn.showSignup) || this.signupLink);
  this.showResetAction = (this.disableResetAction !== true) && ((auth0Conn && auth0Conn.showForgot) || this.resetLink);

  // usernameStyle
  var auth0ConnStrategy = this._getClientStrategyByConnectionName(auth0Conn.name) || {};

  if (!this.usernameStyle && (auth0ConnStrategy.name === 'ad' || auth0ConnStrategy.name === 'auth0-adldap')) {
    this.usernameStyle = 'username';
  }

  this.state('loaded');

  return this;
};

/**
 * Resolve whether are there or not any
 * social connections within client
 * strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnySocialConnection = function () {
  var client = this.$client;
  var filter = { social: true };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * enterprise or Databse connection within
 * client strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyEnterpriseOrDbConnection = function() {
  var client = this.$client;
  var filter = { social: false };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * database connection within client strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyDBConnection = function() {
  var client = this.$client;
  var filter = { userAndPass: true };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * Active Directory connection within client
 * strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyADConnection = function() {
  return _.some(this.$client.strategies, function (s) {
    return (s.name === 'ad' || s.name === 'auth0-adldap') && s.connections.length > 0;
  });
};

/**
 * Given an email extracts it domain part.
 *
 * @param {String} email
 *
 * @return {String} domain of the email
 */
OptionsManager.prototype._extractEmailDomain = function (email) {
  var parser = regex.email_parser;
  var emailM = parser.exec(email.toLowerCase());
  return emailM ? emailM.slice(-2)[0] : null;
};

/**
 * Helper to filter AD connections by domain.
 *
 * @private
 */
OptionsManager.prototype._findConnectionByADDomain = function (domain, strategies) {
  return this._filterConnections(domain, strategies, {userAndPass: true});
};

/**
 * Helper to filter enterprise connections by domain.
 *
 * @private
 */
OptionsManager.prototype._findConnectionByDomain = function (domain, strategies) {
  return this._filterConnections(domain, strategies, {userAndPass: undefined});
};

/**
 * Get from the strategies list (filtered by criteria) connections and
 * filter those connections by a given domain.
 *
 * @param   {String}  domain      Domain to be found.
 * @param   {Array}   strategies  Array with all the existing strategies
 *                                for this client.
 * @param   {Object}  criteria    Criteria to filter strategies.
 *
 * @returns {Object} the connection matching the domain or undefined otherwise.
 *
 * @private
 */
OptionsManager.prototype._filterConnections = function (domain, strategies, criteria) {
  strategies = strategies || this.$client.strategies;
  var conn_obj = _.chain(strategies)
    .where(criteria)
    .pluck('connections')
    .flatten()
    .map(function (e) {
      var l = [];
      if (e.domain) {
        l.push(e.domain);
      }
      l = l.concat(e.domain_aliases || []);
      e.domains = l;
      return e;
    })
    .find(function (e) { return e.domains.indexOf(domain) !== -1; })
    .value();

  return conn_obj;
};

/**
 * Resolves wether `email`'s domain belongs to
 * an enterprise connection or not, and alters
 * `output` object in the way...
 *
 * @param {String} email
 * @param {Object} output
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isEnterpriseConnection = function (email, output) {
  var client = this.$client;
  var domain = this._extractEmailDomain(email);

  var conn = this._filterConnections(domain, client.strategies, {userAndPass: undefined});

  if (conn && output) {
    output.domain = conn.domain;
  }

  return !!conn;
};

OptionsManager.prototype._isFreeSubscription = function() {
  return this.$client.subscription && !~['free', 'dev'].indexOf(this.$client.subscription);
};

/**
 * Get resolved Auth0 connection to signin by `userName`
 * XXX: No idea what logic this follows...
 *
 * @param {String} userName
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getAuth0Connection = function(username) {

  // if specified, use it, otherwise return first
  if (null != this.defaultUserPasswordConnection) {
    return _.chain(this.auth0Strategies)
      .pluck('connections')
      .flatten()
      .findWhere({ name: this.defaultUserPasswordConnection })
      .value();
  }

  var domain = username && ~username.indexOf('@') ? username.split('@')[1] : '';

  if (username && domain && this.$client.strategies) {
    //there is still a chance that the connection might be
    //adldap and with domain
    var conn = _.chain(this.$client.strategies)
                .pluck('connections')
                .flatten()
                .findWhere({domain: domain})
                .value();
    if (conn) {
      return conn;
    }
  }

  // By default, if exists, return auth0 connection (db-conn) or first
  var defaultStrategy = _.findWhere(this.auth0Strategies, { name: 'auth0' });
  defaultStrategy = defaultStrategy || (this.auth0Strategies.length > 0 ? this.auth0Strategies[0] : null);

  return defaultStrategy && defaultStrategy.connections.length > 0 ? defaultStrategy.connections[0] : null;
};

/**
 * Get Loggedin auth parameters from `strategy` and `ssoData`
 *
 * @param {String} strategy
 * @param {Object} ssoData
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getLoggedInAuthParams = function (strategy, ssoData) {
  switch (strategy) {
    case 'google-oauth2':
      return { login_hint: ssoData.lastUsedUsername };
    default:
      return {};
  }
};

/**
 * Get client strategy by connection `connName`
 * XXX: Check that there may exist 2 connection with same name
 * but at different strategies... in that case this is wrong,
 * and it should also accept a strategy name as second parameter
 *
 * @param {String} connName
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getClientStrategyByConnectionName = function (connName) {
  return _.chain(this.$client.strategies)
    .filter(function (s) {
      return _.findWhere(s.connections, { name: connName });
    }).value()[0];
};

/**
 * Get configured client strategy by strategy `name`
 *
 * @param {String} name
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getClientStrategyByName = function (name) {
  return _.findWhere(this.$client.strategies, { name: name });
};

/**
 * Resolve whether use or don't use big social buttons
 *
 * @return {Boolean}
 * @public
 */

OptionsManager.prototype._useBigSocialButtons = function() {
  return null != this.socialBigButtons ? !!this.socialBigButtons : !this._isThereAnyEnterpriseOrDbConnection();
};

/**
 * Retrieve `$client` strategies by `social: true`
 *
 * @return {Array}
 * @public
 */

OptionsManager.prototype._getSocialStrategies = function() {
  return _.where(this.$client.strategies, { social: true });
};

/**
 * Resolve disable the focus on `is_small_screen`
 * or at embeded mode in `container`. Or override
 * by user preferences
 *
 * @return {Boolean}
 * @public
 */

OptionsManager.prototype._focusDisabled = function() {
  return null != this.focusInput ? !this.focusInput : (small_screen() || !!this.container);
};

/**
 * Private helpers
 */

function auth0StrategiesFilter(strategy) {
  return strategy.userAndPass && strategy.connections.length > 0;
}

function hasConnectionsFilter(strategy) {
  return strategy.connections.length > 0;
}

function strategiesConnectionsMapper(connections) {
  return function (strategy) {
    // XXX: We need to replace with Lodash
    // no deep clone/extend is a pain for referential objects...
    var cloned = _.extend({}, strategy);
    cloned.connections = _.filter(cloned.connections, function (connection) {
      return _.contains(connections, connection.name);
    });
    return cloned;
  };
}
<commit_msg>Remove alt+space characters<commit_after>/**
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter;
var small_screen = require('../is-small-screen');
var ocreate = require('../object-create');

var regex = require('../regex');
var i18n = require('../i18n');
var bind = require('../bind');
var _ = require('underscore');
var okeys = _.keys;

/**
 * Expose `OptionsManager`
 */

module.exports = OptionsManager;

/**
 * Create an `OptionsManager` from
 * instanceOptions and displayOptions
 *
 * @param {Auth0Lock} widget
 * @param {Object} displayOptions
 * @constructor
 */

function OptionsManager(widget, options) {
  if (!(this instanceof OptionsManager)) {
    return new OptionsManager(widget, options);
  }

  // Initiate `EventEmitter`
  EventEmitter.call(this);

  // Flag OptionsManager as `unloaded`
  this.state('loading');

  // holds widget as reference
  this.$widget = widget;

  // save widget's $client object reference
  this.$client = widget.$client;

  // save copy of widget's valid strategies
  this.$strategies = widget.$strategies;

  // save widget's `auth0-js` instance object
  this.$auth0 = widget.$auth0;

  // save widget instance options with `$` prepended
  _.each(okeys(widget.$options), function(key) {
    this['$' + key] = widget.$options[key];
  }, this);

  // copies all provided options to instance
  // filtering by allowed options `whitelist`
  _.each(okeys(options), function(key) {
    // we should whitelist options
    // so no OptionsManager method gets overriden
    // by user configurable object
    // XXX: Broken, fix it!
    // if (!~whitelist.indexOf(key) && !~supportedParams.indexOf(key)) return;
    this[key] = options[key];
  }, this);

  // Set `i18n` dictionary for templates
  this.i18n = i18n.getDict(this.dict);

  // default authParams to empty object
  this.authParams = _.extend({}, options.authParams);

  // enable/disable last login and AD discovery
  this.rememberLastLogin = null != options.rememberLastLogin ? !!options.rememberLastLogin : true;
  this.integratedWindowsLogin = null != options.integratedWindowsLogin ? !!options.integratedWindowsLogin : true;

  // If popupCallback, enable popup mode
  if ('function' === typeof options.popupCallback) {
    this.popup = true;
    // XXX: the following to should already come with
    // the options from constructor... right?
    this.popupOptions = _.extend({}, options.popupOptions);
    this.popupCallback = options.popupCallback;
  }

  // save default responseType
  if (options.responseType) {
    this.responseType = options.responseType;
  } else {
    this.responseType = (this.popup || !options.callbackURL) ? 'token' : 'code';
  }

  // Options moved from constructor and hacked into `auth0-js` instance
  this.$auth0._useJSONP = options.forceJSONP || this.$auth0._useJSONP;
  this.$auth0._callbackURL = options.callbackURL || this.$auth0._callbackURL;
  this.$auth0._callbackOnLocationHash = 'token' === this.responseType || !!this.$auth0._callbackOnLocationHash;

  // force `closable` when provided with `container`
  this.closable = null != options.closable ? !!options.closable : !this.container;

  // Delay options requiring $client configuration
  this.$widget.getClientConfiguration(bind(this._onclientloaded, this));
}

/**
 * Inherit from `EventEmitter`
 */

OptionsManager.prototype = ocreate(EventEmitter.prototype);

/**
 * Get or Set `$_state` for track
 * `OptionsManager`s ready state
 *
 * @param {String} state
 * @param {String} message
 * @return {OptionsManager}
 * @public
 */

OptionsManager.prototype.state = function(state, message) {
  if (0 === arguments.length) {
    return this.$_state;
  }

  // debug('state is now %s', state);
  this.$_state = state;
  this.emit(state, message);
  return this;
};

/**
 * Register `fn` for when `OptionsManager`
 * is ready (or `loaded`)
 *
 * @param {Function} fn
 * @return {OptionsManager}
 * @public
 */

OptionsManager.prototype.ready = function(fn) {
  function done() {
    if ('loaded' === this.state()) {
      return fn();
    }
  }

  if ('loaded' === this.state()) {
    setTimeout(bind(done, this), 0);
  } else {
    this.once('loaded', bind(done, this));
  }

  return this;
};

/**
 * Continue setup once client's configuration
 * is retrieved from assets url or S3
 *
 * @param {Object} client
 * @return {OptionsManager}
 * @private
 */

OptionsManager.prototype._onclientloaded = function(client) {

  // Refresh clients configuration with what's stored
  // on the Auth0's hash
  this.$client = _.extend(this.$client, client);

  // Enrich $client.strategies
  // then, continue setting up the mode
  if (this.connections) {
    this.$client.strategies = _.chain(this.$client.strategies)
      .map(strategiesConnectionsMapper(this.connections))
      .filter(hasConnectionsFilter)
      .value();
  }

  // merge strategies info
  for (var i = 0; i < this.$client.strategies.length; i++) {
    var sname = this.$client.strategies[i].name;
    this.$client.strategies[i] = _.extend({}, this.$client.strategies[i], this.$strategies[sname]);
  }

  // Holds auth0 strategies only
  this.auth0Strategies = _.chain(this.$client.strategies)
    .filter(auth0StrategiesFilter)
    .value();

  // show signup/forgot links
  var auth0Conn = this._getAuth0Connection() || {};

  // if booted on `signup` or `reset`, but not configured
  // on connection => override mode with `signin`
  if (this.mode === 'signup' && !auth0Conn.showSignup) { this.mode = 'signin'; }
  if (this.mode === 'reset' && !auth0Conn.showForgot) { this.mode = 'signin'; }

  // Resolve show action buttons or not
  this.showSignupAction = (this.disableSignupAction !== true) && ((auth0Conn && auth0Conn.showSignup) || this.signupLink);
  this.showResetAction = (this.disableResetAction !== true) && ((auth0Conn && auth0Conn.showForgot) || this.resetLink);

  // usernameStyle
  var auth0ConnStrategy = this._getClientStrategyByConnectionName(auth0Conn.name) || {};

  if (!this.usernameStyle && (auth0ConnStrategy.name === 'ad' || auth0ConnStrategy.name === 'auth0-adldap')) {
    this.usernameStyle = 'username';
  }

  this.state('loaded');

  return this;
};

/**
 * Resolve whether are there or not any
 * social connections within client
 * strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnySocialConnection = function () {
  var client = this.$client;
  var filter = { social: true };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * enterprise or Databse connection within
 * client strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyEnterpriseOrDbConnection = function() {
  var client = this.$client;
  var filter = { social: false };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * database connection within client strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyDBConnection = function() {
  var client = this.$client;
  var filter = { userAndPass: true };
  return !!_.findWhere(client.strategies, filter);
};

/**
 * Resolve whether are there or not any
 * Active Directory connection within client
 * strategies
 *
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isThereAnyADConnection = function() {
  return _.some(this.$client.strategies, function (s) {
    return (s.name === 'ad' || s.name === 'auth0-adldap') && s.connections.length > 0;
  });
};

/**
 * Given an email extracts it domain part.
 *
 * @param {String} email
 *
 * @return {String} domain of the email
 */
OptionsManager.prototype._extractEmailDomain = function (email) {
  var parser = regex.email_parser;
  var emailM = parser.exec(email.toLowerCase());
  return emailM ? emailM.slice(-2)[0] : null;
};

/**
 * Helper to filter AD connections by domain.
 *
 * @private
 */
OptionsManager.prototype._findConnectionByADDomain = function (domain, strategies) {
  return this._filterConnections(domain, strategies, {userAndPass: true});
};

/**
 * Helper to filter enterprise connections by domain.
 *
 * @private
 */
OptionsManager.prototype._findConnectionByDomain = function (domain, strategies) {
  return this._filterConnections(domain, strategies, {userAndPass: undefined});
};

/**
 * Get from the strategies list (filtered by criteria) connections and
 * filter those connections by a given domain.
 *
 * @param   {String}  domain      Domain to be found.
 * @param   {Array}   strategies  Array with all the existing strategies
 *                                for this client.
 * @param   {Object}  criteria    Criteria to filter strategies.
 *
 * @returns {Object} the connection matching the domain or undefined otherwise.
 *
 * @private
 */
OptionsManager.prototype._filterConnections = function (domain, strategies, criteria) {
  strategies = strategies || this.$client.strategies;
  var conn_obj = _.chain(strategies)
    .where(criteria)
    .pluck('connections')
    .flatten()
    .map(function (e) {
      var l = [];
      if (e.domain) {
        l.push(e.domain);
      }
      l = l.concat(e.domain_aliases || []);
      e.domains = l;
      return e;
    })
    .find(function (e) { return e.domains.indexOf(domain) !== -1; })
    .value();

  return conn_obj;
};

/**
 * Resolves wether `email`'s domain belongs to
 * an enterprise connection or not, and alters
 * `output` object in the way...
 *
 * @param {String} email
 * @param {Object} output
 * @return {Boolean}
 * @private
 */

OptionsManager.prototype._isEnterpriseConnection = function (email, output) {
  var client = this.$client;
  var domain = this._extractEmailDomain(email);

  var conn = this._filterConnections(domain, client.strategies, {userAndPass: undefined});

  if (conn && output) {
    output.domain = conn.domain;
  }

  return !!conn;
};

OptionsManager.prototype._isFreeSubscription = function() {
  return this.$client.subscription && !~['free', 'dev'].indexOf(this.$client.subscription);
};

/**
 * Get resolved Auth0 connection to signin by `userName`
 * XXX: No idea what logic this follows...
 *
 * @param {String} userName
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getAuth0Connection = function(username) {

  // if specified, use it, otherwise return first
  if (null != this.defaultUserPasswordConnection) {
    return _.chain(this.auth0Strategies)
      .pluck('connections')
      .flatten()
      .findWhere({ name: this.defaultUserPasswordConnection })
      .value();
  }

  var domain = username && ~username.indexOf('@') ? username.split('@')[1] : '';

  if (username && domain && this.$client.strategies) {
    //there is still a chance that the connection might be
    //adldap and with domain
    var conn = _.chain(this.$client.strategies)
                .pluck('connections')
                .flatten()
                .findWhere({domain: domain})
                .value();
    if (conn) {
      return conn;
    }
  }

  // By default, if exists, return auth0 connection (db-conn) or first
  var defaultStrategy = _.findWhere(this.auth0Strategies, { name: 'auth0' });
  defaultStrategy = defaultStrategy || (this.auth0Strategies.length > 0 ? this.auth0Strategies[0] : null);

  return defaultStrategy && defaultStrategy.connections.length > 0 ? defaultStrategy.connections[0] : null;
};

/**
 * Get Loggedin auth parameters from `strategy` and `ssoData`
 *
 * @param {String} strategy
 * @param {Object} ssoData
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getLoggedInAuthParams = function (strategy, ssoData) {
  switch (strategy) {
    case 'google-oauth2':
      return { login_hint: ssoData.lastUsedUsername };
    default:
      return {};
  }
};

/**
 * Get client strategy by connection `connName`
 * XXX: Check that there may exist 2 connection with same name
 * but at different strategies... in that case this is wrong,
 * and it should also accept a strategy name as second parameter
 *
 * @param {String} connName
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getClientStrategyByConnectionName = function (connName) {
  return _.chain(this.$client.strategies)
    .filter(function (s) {
      return _.findWhere(s.connections, { name: connName });
    }).value()[0];
};

/**
 * Get configured client strategy by strategy `name`
 *
 * @param {String} name
 * @return {Object}
 * @private
 */

OptionsManager.prototype._getClientStrategyByName = function (name) {
  return _.findWhere(this.$client.strategies, { name: name });
};

/**
 * Resolve whether use or don't use big social buttons
 *
 * @return {Boolean}
 * @public
 */

OptionsManager.prototype._useBigSocialButtons = function() {
  return null != this.socialBigButtons ? !!this.socialBigButtons : !this._isThereAnyEnterpriseOrDbConnection();
};

/**
 * Retrieve `$client` strategies by `social: true`
 *
 * @return {Array}
 * @public
 */

OptionsManager.prototype._getSocialStrategies = function() {
  return _.where(this.$client.strategies, { social: true });
};

/**
 * Resolve disable the focus on `is_small_screen`
 * or at embeded mode in `container`. Or override
 * by user preferences
 *
 * @return {Boolean}
 * @public
 */

OptionsManager.prototype._focusDisabled = function() {
  return null != this.focusInput ? !this.focusInput : (small_screen() || !!this.container);
};

/**
 * Private helpers
 */

function auth0StrategiesFilter(strategy) {
  return strategy.userAndPass && strategy.connections.length > 0;
}

function hasConnectionsFilter(strategy) {
  return strategy.connections.length > 0;
}

function strategiesConnectionsMapper(connections) {
  return function (strategy) {
    // XXX: We need to replace with Lodash
    // no deep clone/extend is a pain for referential objects...
    var cloned = _.extend({}, strategy);
    cloned.connections = _.filter(cloned.connections, function (connection) {
      return _.contains(connections, connection.name);
    });
    return cloned;
  };
}
<|endoftext|>


<commit_before>import {
  closest,
  domify,
  query
} from '../lib';

describe('closest', function() {

  it('should get closest parent', function() {

    var node = domify('
' +
                        '
' +
                          '

' +
                        '
' +
                      '
');

    var child = query('.child', node);

    // when
    expect(closest(child, '.root')).to.equal(node);
    expect(closest(node, '.root', true)).to.equal(node);
  });

});<commit_msg>feat(lib): closest Shadow DOM and Document Fragment tests<commit_after>import {
  closest,
  domify,
  query
} from '../lib';

describe('closest', function() {

  it('should get closest parent', function() {

    // given
    var node = domify('
' +
                        '
' +
                          '

' +
                        '
' +
                      '
');

    var child = query('.child', node);

    // then
    expect(closest(child, '.root')).to.equal(node);
    expect(closest(node, '.root', true)).to.equal(node);
  });

  it('should work with document fragments', function() {

    // given
    var node = domify('
' +
                        '
' +
                          '

' +
                        '
' +
                      '
');
    var child = query('.child', node);

    var fragment = document.createDocumentFragment();
    fragment.appendChild(node);

    // then
    expect(closest(child, '.root')).to.equal(node);
    expect(closest(node, '.root', true)).to.equal(node);
    expect(closest(node, '.outside')).to.be.null;
  });

  // Shadow DOM is not supported by PhantomJS headless browser. In order to
  // execute this test, use 'karma-chrome-launcher' and set the browser to
  // 'Chrome' in karma.conf.js
  (window.HTMLShadowElement ? it : it.skip)('should work with shadow dom', function() {

    //  .root
    //    | -> (shadow - This is not a HTML document nor HTML element)
    //          | -> .innerShadowRoot
    //                    | -> .innerShadowChild

    // given
    var root = createDivWithClassname('root');
    var shadow = root.attachShadow({ mode: 'open' });

    var innerShadowRoot = createDivWithClassname('innerShadowRoot');
    shadow.appendChild(innerShadowRoot);
    var innerShadowChild = createDivWithClassname('innerShadowChild');
    innerShadowRoot.appendChild(innerShadowChild);

    // then
    expect(closest(innerShadowChild, '.innerShadowRoot')).to.equal(innerShadowRoot);
    expect(closest(innerShadowRoot, '.innerShadowRoot', true)).to.equal(innerShadowRoot);
    expect(closest(innerShadowChild, '.outside')).to.be.null;
  });
});

// helper ////
function createDivWithClassname(className) {
  var div = document.createElement('div');
  div.className = className;
  return div;
}
<|endoftext|>


<commit_before>var fsUtil = require('../lib/fs-util'),
    should = require('should'),
    mockFs = require('mock-fs');

describe('lib/fs-util', function() {
    beforeEach(function() {
        mockFs({
            'foo': {
                'bar.tpl': 'hello Edi'
            }
        });
    });

    it('should read "hello Edi"', function(done) {
        fsUtil.readFileOrReturnData('foo/bar.tpl')
            .then(function(data) {
                data.should.equal('hello Edi');
                done();
            });
    });

    it('should throw an error if file doesn\'t exist', function(done) {
        fsUtil.readFileOrReturnData('not/existing.tpl')
            .fail(function(error) {
                error.should.be.ok;
                done();
            });
    });
});
<commit_msg>adds missing test case<commit_after>var fsUtil = require('../lib/fs-util'),
    should = require('should'),
    mockFs = require('mock-fs');

describe('lib/fs-util', function() {
    beforeEach(function() {
        mockFs({
            'foo': {
                'bar.tpl': 'hello Edi'
            }
        });
    });

    it('should read "hello Edi"', function(done) {
        fsUtil.readFileOrReturnData('foo/bar.tpl')
            .then(function(data) {
                data.should.equal('hello Edi');
                done();
            });
    });

    it('should throw an error if file doesn\'t exist', function(done) {
        fsUtil.readFileOrReturnData('not/existing.tpl')
            .fail(function(error) {
                error.should.be.ok;
                done();
            });
    });

    it('should return the object if not a file and typeof object', function(done) {
        fsUtil.readFileOrReturnData({
            foo: 'bar'
        }).then(function(obj) {
            obj.should.have.property('foo');
            done();
        });
    });
});
<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 */
var utils = require('../utils'),
	Template = require('../template'),
	Context = require('../context'),
	stringEngine = require('./string'),
	SOD = stringEngine.SOD;

var firstMethods = {
	//_________________________________ local context management
	newContext: function(context, args) {
		var data = args[0],
			parent = args[1] || context,
			path = args[2],
			ctx = new Context(data, parent, path);
		(context.firstPassObjects = context.firstPassObjects || []).push(ctx);
		return ctx;
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		var path = args[0],
			// produce local context and store it in parent
			ctx = new Context(typeof path === 'string' ? context.get(path) : path, context, path);
		(context.firstPassObjects = context.firstPassObjects || []).push(ctx);
	},
	//________________________________ Conditonal node rendering
	agoraView: function(context, args) {
		var channel = args[0],
			template = args[1];

		throw new Error('agoraView has not been implemented yet for twopass engine.');

		context.onAgora(channel, function(message) {
			firstPass(template, context);
		});

	},

	mountIf: function(context, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		var exec = function(ok, type, path) {
			if (ok)
				firstPass(successTempl, context);
			else if (failTempl)
				firstPass(failTempl, context);
		};
		if (condition && condition.__interpolable__) {
			ok = condition.output(context);
			condition.subscribeTo(context, exec);
		} else if (typeof condition === 'function')
			ok = condition.call(this, context);
		exec(ok, 'set');
	},
	if: function(context, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__) {
			ok = condition.output(context);
		} else if (typeof condition === 'function')
			ok = condition.call(this, context);
		if (ok)
			firstPass(successTempl, context);
		else if (failTempl)
			firstPass(failTempl, context);
	},
	switch: function(context, args) {
		var expression = args[0],
			dico = args[1],
			seen = {};

		function switchTempl(value) {
			var templ = dico[value] || dico['default'];
			if (templ && !seen[value]) {
				seen[value] = true;
				firstPass(templ, context);
			}
		}
		if (expression.__interpolable__) {
			expression.subscribeTo(context, function(value) {
				switchTempl(value);
			});
			switchTempl(expression.output(context));
		} else if (typeof expression === 'function')
			switchTempl(expression(context));
		else
			switchTempl(expression);
	},
	//_________________________________________ EACH
	each: function(context, args) {
		var path = args[0],
			template = args[1],
			emptyTemplate = args[2],
			emptyInitialised = false,
			data = path,
			contexts = [];

		var updateArray = function(value, type, path, index) {
			// on array update : produce or maintain associated local contexts array
			var ctx, ctxs = contexts;
			switch (type) {
				case 'reset':
				case 'set':

					if (!value.length && !emptyInitialised)
						firstPass(emptyTemplate, context); // traverse empty template with firstPass

					var j = 0;
					for (var len = value.length; j < len; ++j) // reset existing or create new ctx
					{
						if (ctxs[j]) // reset existing
							ctxs[j].reset(value[j]);
						else { // create new ctx
							ctx = new Context(value[j], context);
							ctxs.push(ctx);
							firstPass(template, ctx); // traverse child template with firstPass
						}
					}
					if (j < ctxs.length) // remove additional ctx that is not used any more
					{
						for (var i = j, len = ctxs.length; i < len; ++i)
							ctxs[i].destroy();
						ctxs.splice(j);
					}
					break;
				case 'removeAt':
					ctxs[index].destroy();
					ctxs.splice(index, 1);
					break;
				case 'push':
					ctx = new Context(value, context)
					ctxs.push(ctx);
					firstPass(template, ctx);
					break;
			}
		};

		if (typeof path === 'string') {
			context.subscribe(path, updateArray);
			context.subscribe(path + '.*', function(value, type, path, key) {
				// on array's item update
				var ctx = contexts[key];
				if (ctx)
					return ctx.reset(value); // update associated context
			});
			data = context.get(path);
		}
		if (data)
			updateArray(data, 'set');
		// store local contexts array in parent
		(context.firstPassObjects = context.firstPassObjects || []).push(contexts);
	},
	eachTemplates: function(context, descriptor, args) {
		var templates = args[0],
			handler = args[1];
		templates.forEach(function(templ) {
			firstPass(handler ? handler(templ) : templ, context);
		});
	},
	//________________________________ TAGS
	tag: function(context, args) {
		var name = args[0],
			template = args[1];
		if (template)
			firstPass(template, context); // traverse tag template with frstPass
	},
	//_________________________________ CLIENT/SERVER
	client: function(context, args) {
		if (context.env.data.isServer)
			return;
		firstPass(args[0], context); // traverse client template with frstPass
	},
	server: function(context, args) {
		if (!context.env.data.isServer)
			return;
		firstPass(args[0], context); // traverse server template with frstPass
	},
	//_________________ CONTAINER
	container: function(context, node, args) {
		firstPass(args[0], context);
	}
};

var secondMethods = {
	container: function(context, descriptor, args) {
		var sod = new SOD();
		secondPass(args[0], context, sod);
		descriptor.children += sod.children;
	},
	//_________________________________ local context management
	newContext: function(context, descriptor) {
		if (context.firstPassObjects) // catch context produced in firstPass
			descriptor.context = context.firstPassObjects.shift();
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		if (!context.firstPassObjects)
			return;
		var path = args[0],
			template = args[1],
			ctx = context.firstPassObjects.shift(); // catch context produced in firstPass
		secondPass(template, ctx, descriptor);
	},
	//_________________________________________ EACH
	each: function(context, descriptor, args) {
		if (!context.firstPassObjects)
			return;
		var contexts = context.firstPassObjects.shift(); // catch contexts array produced in firstPass
		if (contexts && contexts.length) {
			var template = args[1],
				emptyTemplate = args[2];
			if (!contexts.length)
				secondPass(emptyTemplate, context, descriptor);
			else
				for (var i = 0, len = contexts.length; i < len; ++i)
					secondPass(template, contexts[i], descriptor);
		}
	},
	eachTemplates: function(context, descriptor, args) {
		var templates = args[0],
			handler = args[1];
		templates.forEach(function(templ) {
			secondPass(handler ? handler(templ) : templ, context, descriptor);
		});
	},
	switch: function(context, descriptor, args) {
		var expression = args[0],
			dico = args[1],
			value;
		if (expression.__interpolable__)
			value = expression.output(context);
		else if (typeof expression === 'function')
			value = expression(context);
		else
			value = expression;
		templ = dico[value] || dico['default'];
		if (templ) {
			var sod = new SOD();
			templ.toHTMLString(context, sod);
			if (sod.firstPassObjects)
				descriptor.firstPassObjects += sod.firstPassObjects;
		}
	},
	//________________________________ TAGS
	tag: function(context, descriptor, args) {
		var name = args[0],
			template = args[1],
			newDescriptor = new SOD();
		if (template)
			secondPass(template, context, newDescriptor);
		utils.tagOutput(descriptor, newDescriptor, name);
	},
	//________________________________ Conditonal node rendering
	if: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (type === 'function')
			ok = condition.call(this, context);
		if (ok)
			secondPass(successTempl, context, descriptor);
		else if (failTempl)
			secondPass(failTempl, context, descriptor);
	},
	mountIf: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (type === 'function')
			ok = condition.call(this, context);
		var sod = new SOD();
		if (ok)
			secondPass(successTempl, context, sod);
		else if (failTempl)
			secondPass(failTempl, context, sod);
		if (sod.children)
			descriptor.children += sod.children;
	},
	//_________________________________ CLIENT/SERVER
	client: function(context, descriptor, args) {
		if (context.env.data.isServer)
			return;
		secondPass(args[0], context, descriptor);
	},
	server: function(context, descriptor, args) {
		if (!context.env.data.isServer)
			return;
		secondPass(args[0], context, descriptor);
	}
};

function secondPass(queue, context, descriptor) {
	descriptor = descriptor ||  new SOD();
	var handler = queue[0],
		index = 0,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = secondMethods[handler.handler] || stringEngine[handler.handler];
				break;
			case 'string':
			case 'secondPass':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.secondPass;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		f(descriptor.context || context, descriptor, handler.args);
		if (handler.suspendAfter)
			break;
		handler = queue[++index];
	}
}

function firstPass(queue, context) {
	var handler = queue[0],
		newContext,
		index = 0,
		ctx,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = firstMethods[handler.handler];
				break;
			case 'context':
			case 'firstPass':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.firstPass;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		ctx = f(newContext || context, handler.args);
		if (ctx && ctx.__yContext__)
			newContext = ctx;
		if (handler.suspendAfter)
			break;
		handler = queue[++index];
	}
}

Template.prototype.twopass = View.prototype.twopass = function(context) {
	context = context || new Context();
	firstPass(this._queue, context); // apply first pass : construct contexts
	var self = this;
	// wait for context stabilisation
	return context.stabilised().then(function(context) {
		// then apply second pass : render to string
		var descriptor = new SOD();
		secondPass(self._queue, context, descriptor);
		return descriptor.firstPassObjects;
	});
};

module.exports = {
	firstMethods: firstMethods,
	secondMethods: secondMethods,
	firstPass: firstPass,
	secondPass: secondPass
};
<commit_msg>twopass :remove last View ref<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 */
var utils = require('../utils'),
	Template = require('../template'),
	Context = require('../context'),
	stringEngine = require('./string'),
	SOD = stringEngine.SOD;

var firstMethods = {
	//_________________________________ local context management
	newContext: function(context, args) {
		var data = args[0],
			parent = args[1] || context,
			path = args[2],
			ctx = new Context(data, parent, path);
		(context.firstPassObjects = context.firstPassObjects || []).push(ctx);
		return ctx;
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		var path = args[0],
			// produce local context and store it in parent
			ctx = new Context(typeof path === 'string' ? context.get(path) : path, context, path);
		(context.firstPassObjects = context.firstPassObjects || []).push(ctx);
	},
	//________________________________ Conditonal node rendering
	agoraView: function(context, args) {
		var channel = args[0],
			template = args[1];

		throw new Error('agoraView has not been implemented yet for twopass engine.');

		context.onAgora(channel, function(message) {
			firstPass(template, context);
		});

	},

	mountIf: function(context, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		var exec = function(ok, type, path) {
			if (ok)
				firstPass(successTempl, context);
			else if (failTempl)
				firstPass(failTempl, context);
		};
		if (condition && condition.__interpolable__) {
			ok = condition.output(context);
			condition.subscribeTo(context, exec);
		} else if (typeof condition === 'function')
			ok = condition.call(this, context);
		exec(ok, 'set');
	},
	if: function(context, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__) {
			ok = condition.output(context);
		} else if (typeof condition === 'function')
			ok = condition.call(this, context);
		if (ok)
			firstPass(successTempl, context);
		else if (failTempl)
			firstPass(failTempl, context);
	},
	switch: function(context, args) {
		var expression = args[0],
			dico = args[1],
			seen = {};

		function switchTempl(value) {
			var templ = dico[value] || dico['default'];
			if (templ && !seen[value]) {
				seen[value] = true;
				firstPass(templ, context);
			}
		}
		if (expression.__interpolable__) {
			expression.subscribeTo(context, function(value) {
				switchTempl(value);
			});
			switchTempl(expression.output(context));
		} else if (typeof expression === 'function')
			switchTempl(expression(context));
		else
			switchTempl(expression);
	},
	//_________________________________________ EACH
	each: function(context, args) {
		var path = args[0],
			template = args[1],
			emptyTemplate = args[2],
			emptyInitialised = false,
			data = path,
			contexts = [];

		var updateArray = function(value, type, path, index) {
			// on array update : produce or maintain associated local contexts array
			var ctx, ctxs = contexts;
			switch (type) {
				case 'reset':
				case 'set':

					if (!value.length && !emptyInitialised)
						firstPass(emptyTemplate, context); // traverse empty template with firstPass

					var j = 0;
					for (var len = value.length; j < len; ++j) // reset existing or create new ctx
					{
						if (ctxs[j]) // reset existing
							ctxs[j].reset(value[j]);
						else { // create new ctx
							ctx = new Context(value[j], context);
							ctxs.push(ctx);
							firstPass(template, ctx); // traverse child template with firstPass
						}
					}
					if (j < ctxs.length) // remove additional ctx that is not used any more
					{
						for (var i = j, len = ctxs.length; i < len; ++i)
							ctxs[i].destroy();
						ctxs.splice(j);
					}
					break;
				case 'removeAt':
					ctxs[index].destroy();
					ctxs.splice(index, 1);
					break;
				case 'push':
					ctx = new Context(value, context)
					ctxs.push(ctx);
					firstPass(template, ctx);
					break;
			}
		};

		if (typeof path === 'string') {
			context.subscribe(path, updateArray);
			context.subscribe(path + '.*', function(value, type, path, key) {
				// on array's item update
				var ctx = contexts[key];
				if (ctx)
					return ctx.reset(value); // update associated context
			});
			data = context.get(path);
		}
		if (data)
			updateArray(data, 'set');
		// store local contexts array in parent
		(context.firstPassObjects = context.firstPassObjects || []).push(contexts);
	},
	eachTemplates: function(context, descriptor, args) {
		var templates = args[0],
			handler = args[1];
		templates.forEach(function(templ) {
			firstPass(handler ? handler(templ) : templ, context);
		});
	},
	//________________________________ TAGS
	tag: function(context, args) {
		var name = args[0],
			template = args[1];
		if (template)
			firstPass(template, context); // traverse tag template with frstPass
	},
	//_________________________________ CLIENT/SERVER
	client: function(context, args) {
		if (context.env.data.isServer)
			return;
		firstPass(args[0], context); // traverse client template with frstPass
	},
	server: function(context, args) {
		if (!context.env.data.isServer)
			return;
		firstPass(args[0], context); // traverse server template with frstPass
	},
	//_________________ CONTAINER
	container: function(context, node, args) {
		firstPass(args[0], context);
	}
};

var secondMethods = {
	container: function(context, descriptor, args) {
		var sod = new SOD();
		secondPass(args[0], context, sod);
		descriptor.children += sod.children;
	},
	//_________________________________ local context management
	newContext: function(context, descriptor) {
		if (context.firstPassObjects) // catch context produced in firstPass
			descriptor.context = context.firstPassObjects.shift();
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		if (!context.firstPassObjects)
			return;
		var path = args[0],
			template = args[1],
			ctx = context.firstPassObjects.shift(); // catch context produced in firstPass
		secondPass(template, ctx, descriptor);
	},
	//_________________________________________ EACH
	each: function(context, descriptor, args) {
		if (!context.firstPassObjects)
			return;
		var contexts = context.firstPassObjects.shift(); // catch contexts array produced in firstPass
		if (contexts && contexts.length) {
			var template = args[1],
				emptyTemplate = args[2];
			if (!contexts.length)
				secondPass(emptyTemplate, context, descriptor);
			else
				for (var i = 0, len = contexts.length; i < len; ++i)
					secondPass(template, contexts[i], descriptor);
		}
	},
	eachTemplates: function(context, descriptor, args) {
		var templates = args[0],
			handler = args[1];
		templates.forEach(function(templ) {
			secondPass(handler ? handler(templ) : templ, context, descriptor);
		});
	},
	switch: function(context, descriptor, args) {
		var expression = args[0],
			dico = args[1],
			value;
		if (expression.__interpolable__)
			value = expression.output(context);
		else if (typeof expression === 'function')
			value = expression(context);
		else
			value = expression;
		templ = dico[value] || dico['default'];
		if (templ) {
			var sod = new SOD();
			templ.toHTMLString(context, sod);
			if (sod.firstPassObjects)
				descriptor.firstPassObjects += sod.firstPassObjects;
		}
	},
	//________________________________ TAGS
	tag: function(context, descriptor, args) {
		var name = args[0],
			template = args[1],
			newDescriptor = new SOD();
		if (template)
			secondPass(template, context, newDescriptor);
		utils.tagOutput(descriptor, newDescriptor, name);
	},
	//________________________________ Conditonal node rendering
	if: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (type === 'function')
			ok = condition.call(this, context);
		if (ok)
			secondPass(successTempl, context, descriptor);
		else if (failTempl)
			secondPass(failTempl, context, descriptor);
	},
	mountIf: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (type === 'function')
			ok = condition.call(this, context);
		var sod = new SOD();
		if (ok)
			secondPass(successTempl, context, sod);
		else if (failTempl)
			secondPass(failTempl, context, sod);
		if (sod.children)
			descriptor.children += sod.children;
	},
	//_________________________________ CLIENT/SERVER
	client: function(context, descriptor, args) {
		if (context.env.data.isServer)
			return;
		secondPass(args[0], context, descriptor);
	},
	server: function(context, descriptor, args) {
		if (!context.env.data.isServer)
			return;
		secondPass(args[0], context, descriptor);
	}
};

function secondPass(queue, context, descriptor) {
	descriptor = descriptor ||  new SOD();
	var handler = queue[0],
		index = 0,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = secondMethods[handler.handler] || stringEngine[handler.handler];
				break;
			case 'string':
			case 'secondPass':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.secondPass;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		f(descriptor.context || context, descriptor, handler.args);
		if (handler.suspendAfter)
			break;
		handler = queue[++index];
	}
}

function firstPass(queue, context) {
	var handler = queue[0],
		newContext,
		index = 0,
		ctx,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = firstMethods[handler.handler];
				break;
			case 'context':
			case 'firstPass':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.firstPass;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		ctx = f(newContext || context, handler.args);
		if (ctx && ctx.__yContext__)
			newContext = ctx;
		if (handler.suspendAfter)
			break;
		handler = queue[++index];
	}
}

Template.prototype.twopass = function(context) {
	context = context || new Context();
	firstPass(this._queue, context); // apply first pass : construct contexts
	var self = this;
	// wait for context stabilisation
	return context.stabilised().then(function(context) {
		// then apply second pass : render to string
		var descriptor = new SOD();
		secondPass(self._queue, context, descriptor);
		return descriptor.firstPassObjects;
	});
};

module.exports = {
	firstMethods: firstMethods,
	secondMethods: secondMethods,
	firstPass: firstPass,
	secondPass: secondPass
};
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');

var protectedStrings = {
  scss: "// <?== generator.vizabi.style ==?>"
};

var VizabiGenerator = yeoman.generators.Base.extend({
  init: function () {
  },

  askFor: function () {
    var done = this.async();

    // Have Yeoman greet the user.
    this.log(yosay('Welcome to the marvelous Vizabi generator!'));

    var vizabiPrompt = [{
      name: 'vizabiName',
      message: 'Name your new visualization:'
    }];

    var widgetPrompt = [{
      name: 'widgetName',
      message: 'Name your new widget:'
    }];

    var prompts = [{
      type: 'list',
      name: 'generateWhat',
      message: 'What do you want to create?',
      choices: [
        { name: 'A new Vizabi visualization', value: 'vizabi' },
        { name: 'A new Vizabi widget', value: 'widget' }
      ]
    }];

    this.prompt(prompts, function (props) {
      var that = this;
      this.generateWhat = props.generateWhat;

      if (this.generateWhat === 'vizabi') {
        this.prompt(vizabiPrompt, function (props2) {
          this.vizabiName = props2.vizabiName;
          done();
        }.bind(this));
      } else if (this.generateWhat === 'widget') {
        this.prompt(widgetPrompt, function (props2) {
          this.widgetName = props2.widgetName;
          done();
        }.bind(this));
      }
    }.bind(this));
  },

  app: function () {
    if (this.vizabiName) {
      var name = this._.slugify(this.vizabiName);
      var namePath = name + '/' + name;

      var mainStylePath = 'visualizations/vizabi.scss';
      var mainStyle = this.readFileAsString(mainStylePath);

      this.mkdir('visualizations/' + name);
      this.template('_vizabi_plain.js', 'visualizations/' + namePath + '.js');
      this.template('_vizabi_plain.scss', 'visualizations/' + namePath + '.scss');

      if (mainStyle) {
        this.write(mainStylePath,
          mainStyle.replace(protectedStrings.scss,
            '@import \'' + name + '/' + '_' + name + '\';\n    ' + protectedStrings.scss));
      }
    } else if (this.widgetName) {
      var name = this._.slugify(this.widgetName);
      var namePath = name + '/' + name;

      var mainStylePath = 'widgets/_widgets.scss';
      var mainStyle = this.readFileAsString(mainStylePath);

      this.mkdir('widgets/' + name);
      this.template('_widget_plain.js', 'widgets/' + namePath + '.js');
      this.template('_widget_plain.scss', 'widgets/' + namePath + '.scss');

      if (mainStyle) {
        this.write(mainStylePath,
          mainStyle.replace(protectedStrings.scss,
            '@import \'' + name + '/' + '_' + name + '\';\n    ' + protectedStrings.scss));
      }
    }
  },

  projectfiles: function () {
  }
});

module.exports = VizabiGenerator;
<commit_msg>generator fix #2<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');

var protectedStrings = {
  scss: "// <?== generator.vizabi.style ==?>"
};

var VizabiGenerator = yeoman.generators.Base.extend({
  init: function () {
  },

  askFor: function () {
    var done = this.async();

    // Have Yeoman greet the user.
    this.log(yosay('Welcome to the marvelous Vizabi generator!'));

    var vizabiPrompt = [{
      name: 'vizabiName',
      message: 'Name your new visualization:'
    }];

    var widgetPrompt = [{
      name: 'widgetName',
      message: 'Name your new widget:'
    }];

    var prompts = [{
      type: 'list',
      name: 'generateWhat',
      message: 'What do you want to create?',
      choices: [
        { name: 'A new Vizabi visualization', value: 'vizabi' },
        { name: 'A new Vizabi widget', value: 'widget' }
      ]
    }];

    this.prompt(prompts, function (props) {
      var that = this;
      this.generateWhat = props.generateWhat;

      if (this.generateWhat === 'vizabi') {
        this.prompt(vizabiPrompt, function (props2) {
          this.vizabiName = props2.vizabiName;
          done();
        }.bind(this));
      } else if (this.generateWhat === 'widget') {
        this.prompt(widgetPrompt, function (props2) {
          this.widgetName = props2.widgetName;
          done();
        }.bind(this));
      }
    }.bind(this));
  },

  app: function () {
    if (this.vizabiName) {
      var name = this._.slugify(this.vizabiName);
      var namePath = name + '/' + name;

      var mainStylePath = 'visualizations/vizabi.scss';
      var mainStyle = this.readFileAsString(mainStylePath);

      this.mkdir('visualizations/' + name);
      this.template('_vizabi_plain.js', 'visualizations/' + namePath + '.js');
      this.template('_vizabi_plain.scss', 'visualizations/_' + namePath + '.scss');

      if (mainStyle) {
        this.write(mainStylePath,
          mainStyle.replace(protectedStrings.scss,
            '@import \'' + name + '/' + '_' + name + '\';\n    ' + protectedStrings.scss));
      }
    } else if (this.widgetName) {
      var name = this._.slugify(this.widgetName);
      var namePath = name + '/' + name;

      var mainStylePath = 'widgets/_widgets.scss';
      var mainStyle = this.readFileAsString(mainStylePath);

      this.mkdir('widgets/' + name);
      this.template('_widget_plain.js', 'widgets/' + namePath + '.js');
      this.template('_widget_plain.scss', 'widgets/_' + namePath + '.scss');

      if (mainStyle) {
        this.write(mainStylePath,
          mainStyle.replace(protectedStrings.scss,
            '@import \'' + name + '/' + '_' + name + '\';\n    ' + protectedStrings.scss));
      }
    }
  },

  projectfiles: function () {
  }
});

module.exports = VizabiGenerator;
<|endoftext|>


<commit_before>'use strict';

require('./polyfills');
var Q = require('q');
var fs = require('fs');
var regex = require('./regex').getRegex();
var ROOT = './tests/sampleProject/';
var inquirer = require('inquirer');
var chalk = require('chalk');
var npm = require('npm');

module.exports = function () {
  return {
    isJavaScript: isJavaScript,
    userAction: userAction,
    readAndExtract: readAndExtract,
    isFile: isFile,
    flatten: flatten,
    readDir: readDir
  };

}();

//Takes a multi-dimensional array and returns
//a single array
function flatten(arr) {
  return arr.reduce(function (prevArr, currArr) {
    return prevArr.concat(currArr);
  });
}

var pckgJson = require('.' + ROOT + 'package');

function promptUser(pckgs) {
  return prompt('save', pckgs).then(function (depAnswers) {

    var selectedDeps = nonIntersect(depAnswers);
    var remaining = pckgs.filter(selectedDeps);

    if (remaining) {
      return prompt('save-dev', remaining).then(function (
        devDepAnswers) {

        var allSelected = nonIntersect(depAnswers.concat(
          devDepAnswers));
        var stillRemaining = pckgs.filter(allSelected);
        if (stillRemaining.length) {

          //TODO
          return confirmInstall();
        } else {
          installDeps(depAnswers).then(function () {
            installDevDeps(devDepAnswers);
          });
        }
      });
    } else {
      return installDeps(pckgs);
    }
  });
}

function nonIntersect(arr) {
  return function (b) {
    return arr.indexOf(b) === -1;
  };
}

function prompt(option, pckgs) {
  var type;
  if (option === 'save-dev') {
    type = 'devDependencies';
  } else {
    type = 'dependencies';
  }
  var defer = Q.defer();
  var question = {
    type: 'checkbox',
    message: chalk.red('Found ' + pckgs.length + ' missing packages.') +
      '\nSelect packages you want to install as ' + type + ':',
    name: 'selected',
    choices: pckgs.map(makeCheckboxObject)
  };

  inquirer.prompt(question, function (answer) {
    defer.resolve(answer.selected);
  });

  return defer.promise;
}

function confirmInstall(type, pckgs) {
  var defer = Q.defer();
  var questions = {
    type: 'confirm',
    name: 'toInstall',
    message: 'npm install --' + type + ' :\n ' + chalk.blue('* ' +
      pckgs.join(
        '\n * ')) + '\n Continue?',
    default: false
  };

  inquirer.prompt(questions,
    function (answer) {
      if (!answer.toInstall) {
        defer.reject();
      }
      defer.resolve(pckgs);

    });
  return defer.promise;
}

function userAction(argv) {
  return function (pckgs) {

    if (!argv.saveDev && !argv.save && argv.i) {
      return 'Error';
    }
    //No flags
    if (Object.keys(argv).length === 2) {
      return displayMissing(pckgs);
    }

    if (argv.saveDev && argv.save) {
      return promptUser(pckgs);
    }

    if (argv.saveDev && argv.i) {

      return confirmInstall('save-dev', pckgs).then(installDevDeps);
    }

    if (argv.saveDev) {
      return installDevDeps(pckgs);
    }

    if (argv.save && argv.i) {
      return confirmInstall('save', pckgs).then(installDeps);
    }

    if (argv.save) {
      return installDeps(pckgs);
    }

  };

}

function displayMissing(pckgs) {
    /*eslint-disable no-console*/
    console.log(chalk.red('Found ' + pckgs.length + ' missing packages:\n'));
    pckgs.map(function (pckg) {
      console.log(chalk.blue('* ' + pckg));
    });
    console.log('\n');
  }
  /*eslint-enable no-console*/

function installDevDeps(pckgs) {
  return install('save-dev')(pckgs);
}

function installDeps(pckgs) {
  return install('save')(pckgs);
}

//Installs all pckgs
function install(type) {
  return function (pckgs) {
    var defer = Q.defer();
    var config = {};
    config[type] = true;

    npm.load(config, function (err) {
      if (err) {
        defer.reject(err);
      }
      npm.commands.install(pckgs, function (errMsg) {
        if (errMsg) {
          defer.reject(err);
        }
        defer.resolve();
      });
    });

    return defer.promise;
  };
}

function makeCheckboxObject(pckg) {
  return {
    name: pckg,
    checked: false
  };

}

/*
 * Reads all files in Jsfiles,
 * extracts all packages in each file
 * and returns a list of package names
 */

function readAndExtract(jsFiles) {
  return Q.all(jsFiles.map(function (jsFile) {
    //read Js files
    return readFile(jsFile).then(
      extractPackages);

  })).then(flatten);

}

function readFile(file) {
  return Q.nfcall(fs.readFile, file, 'utf-8');
}

function readDir(dir) {
  return Q.nfcall(fs.readdir, dir);
}

function extractPackages(data) {
  // //Store all matching packages
  var packages = data.match(regex).map(
    replaceWithName);
  var uniqueDeps = isNotObjProp(pckgJson.dependencies);
  var uniqueDevDeps = isNotObjProp(pckgJson.devDependencies);

  //Only track packages that need to be installed
  return packages.filter(uniqueDeps).filter(uniqueDevDeps).filter(
    installablePckg);

}

//Replaces the regex with the name of the package.
function replaceWithName(file) {
  return file.replace(regex, '$7');
}

//Returns true if pckg is a property of obj.
function isObjProp(obj, pckg) {
  return obj.hasOwnProperty(pckg);

}

//Returns true if package is not a built in node package
//and therefore installable.
function installablePckg(pckg) {
  var packages = ['assert', 'buffer', 'child_process', 'cluster',
    'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
    'net',
    'os', 'path', 'punycode', 'querystring', 'readline', 'stream',
    'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc'
  ];
  return packages.indexOf(pckg) === -1;

}

/*Returns a function
 * that returns false if
 * pckg is an object property of obj.
 */
function isNotObjProp(obj) {
  return function (pckg) {
    return !isObjProp(obj, pckg);
  };

}

//Returns true if file has a js extension
function isJavaScript(file) {
  return file.endsWith('.js');
}

function isFile(file) {
  return Q.nfcall(fs.stat, file)
    .then(function (stats, error) {
      if (error) {
        return error;
      }
      return stats.isFile();
    });
}
<commit_msg>remove duplicate packages<commit_after>'use strict';

require('./polyfills');
var Q = require('q');
var fs = require('fs');
var regex = require('./regex').getRegex();
var ROOT = './tests/sampleProject/';
var inquirer = require('inquirer');
var chalk = require('chalk');
var npm = require('npm');

module.exports = function () {
  return {
    isJavaScript: isJavaScript,
    userAction: userAction,
    readAndExtract: readAndExtract,
    isFile: isFile,
    flatten: flatten,
    readDir: readDir
  };

}();

//Takes a multi-dimensional array and returns
//a single array
function flatten(arr) {
  return arr.reduce(function (prevArr, currArr) {
    return prevArr.concat(currArr);
  });
}

var pckgJson = require('.' + ROOT + 'package');

function promptUser(pckgs) {
  return prompt('save', pckgs).then(function (depAnswers) {

    var selectedDeps = nonIntersect(depAnswers);
    var remaining = pckgs.filter(selectedDeps);

    if (remaining) {
      return prompt('save-dev', remaining).then(function (
        devDepAnswers) {

        var allSelected = nonIntersect(depAnswers.concat(
          devDepAnswers));
        var stillRemaining = pckgs.filter(allSelected);
        if (stillRemaining.length) {

          //TODO
          return confirmInstall();
        } else {
          installDeps(depAnswers).then(function () {
            installDevDeps(devDepAnswers);
          });
        }
      });
    } else {
      return installDeps(pckgs);
    }
  });
}

function nonIntersect(arr) {
  return function (b) {
    return arr.indexOf(b) === -1;
  };
}

function makeUnique(arr) {
  return arr.filter(function (elem, pos) {
    return arr.indexOf(elem) === pos;
  });

}

function prompt(option, pckgs) {
  var type;
  if (option === 'save-dev') {
    type = 'devDependencies';
  } else {
    type = 'dependencies';
  }
  var defer = Q.defer();
  var question = {
    type: 'checkbox',
    message: chalk.red('Found ' + pckgs.length + ' missing packages.') +
      '\nSelect packages you want to install as ' + type + ':',
    name: 'selected',
    choices: pckgs.map(makeCheckboxObject)
  };

  inquirer.prompt(question, function (answer) {
    defer.resolve(answer.selected);
  });

  return defer.promise;
}

function confirmInstall(type, pckgs) {
  var defer = Q.defer();
  var questions = {
    type: 'confirm',
    name: 'toInstall',
    message: 'npm install --' + type + ' :\n ' + chalk.blue('* ' +
      pckgs.join(
        '\n * ')) + '\n Continue?',
    default: false
  };

  inquirer.prompt(questions,
    function (answer) {
      if (!answer.toInstall) {
        defer.reject();
      }
      defer.resolve(pckgs);

    });
  return defer.promise;
}

function userAction(argv) {
  return function (pckgs) {

    if (!argv.saveDev && !argv.save && argv.i) {
      return 'Error';
    }
    //No flags
    if (Object.keys(argv).length === 2) {
      return displayMissing(pckgs);
    }

    if (argv.saveDev && argv.save) {
      return promptUser(pckgs);
    }

    if (argv.saveDev && argv.i) {

      return confirmInstall('save-dev', pckgs).then(installDevDeps);
    }

    if (argv.saveDev) {
      return installDevDeps(pckgs);
    }

    if (argv.save && argv.i) {
      return confirmInstall('save', pckgs).then(installDeps);
    }

    if (argv.save) {
      return installDeps(pckgs);
    }

  };

}

function displayMissing(pckgs) {
    /*eslint-disable no-console*/
    console.log(chalk.red('Found ' + pckgs.length + ' missing packages:\n'));
    pckgs.map(function (pckg) {
      console.log(chalk.blue('* ' + pckg));
    });
    console.log('\n');
  }
  /*eslint-enable no-console*/

function installDevDeps(pckgs) {
  return install('save-dev')(pckgs);
}

function installDeps(pckgs) {
  return install('save')(pckgs);
}

//Installs all pckgs
function install(type) {
  return function (pckgs) {
    var defer = Q.defer();
    var config = {};
    config[type] = true;

    npm.load(config, function (err) {
      if (err) {
        defer.reject(err);
      }
      npm.commands.install(pckgs, function (errMsg) {
        if (errMsg) {
          defer.reject(err);
        }
        defer.resolve();
      });
    });

    return defer.promise;
  };
}

function makeCheckboxObject(pckg) {
  return {
    name: pckg,
    checked: false
  };

}

/*
 * Reads all files in Jsfiles,
 * extracts all packages in each file
 * and returns a list of package names
 */

function readAndExtract(jsFiles) {
  return Q.all(jsFiles.map(function (jsFile) {
      //read Js files
      return readFile(jsFile)
        .then(extractPackages);
    })).then(flatten)
    .then(makeUnique);

}

function readFile(file) {
  return Q.nfcall(fs.readFile, file, 'utf-8');
}

function readDir(dir) {
  return Q.nfcall(fs.readdir, dir);
}

function extractPackages(data) {
  // //Store all matching packages
  var packages = data.match(regex).map(
    replaceWithName);
  var uniqueDeps = isNotObjProp(pckgJson.dependencies);
  var uniqueDevDeps = isNotObjProp(pckgJson.devDependencies);

  //Only track packages that need to be installed
  return packages.filter(uniqueDeps).filter(uniqueDevDeps).filter(
    installablePckg);

}

//Replaces the regex with the name of the package.
function replaceWithName(file) {
  return file.replace(regex, '$7');
}

//Returns true if pckg is a property of obj.
function isObjProp(obj, pckg) {
  return obj.hasOwnProperty(pckg);

}

//Returns true if package is not a built in node package
//and therefore installable.
function installablePckg(pckg) {
  var packages = ['assert', 'buffer', 'child_process', 'cluster',
    'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
    'net',
    'os', 'path', 'punycode', 'querystring', 'readline', 'stream',
    'string_decoder', 'tls', 'tty', 'url', 'util', 'vm', 'zlib', 'smalloc'
  ];
  return packages.indexOf(pckg) === -1;

}

/*Returns a function
 * that returns false if
 * pckg is an object property of obj.
 */
function isNotObjProp(obj) {
  return function (pckg) {
    return !isObjProp(obj, pckg);
  };

}

//Returns true if file has a js extension
function isJavaScript(file) {
  return file.endsWith('.js');
}

function isFile(file) {
  return Q.nfcall(fs.stat, file)
    .then(function (stats, error) {
      if (error) {
        return error;
      }
      return stats.isFile();
    });
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright 2013-2014 Aerospike, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

// we want to test the built aerospike module
var aerospike = require('../build/Release/aerospike');
var options = require('./util/options');
var assert = require('assert');
var expect = require('expect.js');

var keygen = require('./generators/key');
var metagen = require('./generators/metadata');
var recgen = require('./generators/record');
var putgen = require('./generators/put');

var status = aerospike.status;
var policy = aerospike.policy;
var op = aerospike.operator;

describe('client.operate()', function() {

    var client = aerospike.client({
        hosts: [
            { addr: options.host, port: options.port }
        ],
        log: {
            level: options.log
        },
        policies: {
            timeout: options.timeout
        }
    });

    before(function(done) {
        client.connect(function(err){
            done();
        });
    });

    after(function(done) {
        client.close();
        client = null;
        done();
    });

    it('should increment a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.incr('i', 432)
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i'] + 432).to.equal(record2['i']);
                    expect(record['s']).to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });

    it('should append a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.append('s', 'def')
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i']).to.equal(record2['i']);
                    expect(record['s'] + 'def').to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });

    it('should prepend and read a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.prepend('s', 'def'),
                op.read('s'),
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);
                expect(record1['i']).to.equal(undefined);
                expect('def' + record['s']).to.equal(record1['s']);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i']).to.equal(record2['i']);
                    expect('def'+record['s'] ).to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });
    it('should touch a record(refresh ttl) ', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // TEST LOGIC
        // 1.Write a record to an aerospike server.
        // 2.Read the record, to get the ttl and calculate
        //   the difference in the ttl written and the ttl returned by server.
        // 3.Touch the record with a definite ttl.
        // 4.Read the record and calculate the difference in the ttl between the
        //  touch ttl value and read ttl value.
        // 5.Compare the difference with the earlier difference calculated.
        // 6.This is to account for the clock asynchronicity between
        //   the client and the server machines.
        // 7.Server returns a number, at which the record expires according the server clock.
        // 8.The client calculates the time in seconds, and gives back ttl. In the case , where
        //   clocks are not synchronous between server and client, the ttl client calculates may not
        //   be accurate to the user. Nevertheless server expires the record in the correct time.

        // write the record then check
        client.put(key, record, meta, function(err, key) {
            var ops = [
                op.touch(2592000)
            ];
            client.get(key, function(err, record3, metadata3, key3){
                expect(err).to.be.ok();
                ttl_diff = metadata3.ttl - meta.ttl;
                client.operate(key, ops, function(err, record1, metadata1, key1) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    client.get(key1, function(err, record2, metadata2, key2) {
                        expect(err).to.be.ok();
                        expect(err.code).to.equal(status.AEROSPIKE_OK);
                        expect(record['i']).to.equal(record2['i']);
                        expect(record['s']).to.equal(record2['s']);
                        expect(2592000 + ttl_diff+10).to.be.above(metadata2.ttl);
                        expect(2592000 + ttl_diff-10).to.be.below(metadata2.ttl);
						client.remove(key2, function(err, key){
							done();
						});
                    });

                });
            });
        });
    });

});
<commit_msg>Changing the operate test case dependency from aerospike.node to lib/aerospike.js<commit_after>/*******************************************************************************
 * Copyright 2013-2014 Aerospike, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

// we want to test the built aerospike module
var aerospike = require('../lib/aerospike');
var options = require('./util/options');
var assert = require('assert');
var expect = require('expect.js');

var keygen = require('./generators/key');
var metagen = require('./generators/metadata');
var recgen = require('./generators/record');
var putgen = require('./generators/put');

var status = aerospike.status;
var policy = aerospike.policy;
var op = aerospike.operator;

describe('client.operate()', function() {

    var client = aerospike.client({
        hosts: [
            { addr: options.host, port: options.port }
        ],
        log: {
            level: options.log
        },
        policies: {
            timeout: options.timeout
        }
    });

    before(function(done) {
        client.connect(function(err){
            done();
        });
    });

    after(function(done) {
        client.close();
        client = null;
        done();
    });

    it('should increment a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.incr('i', 432)
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i'] + 432).to.equal(record2['i']);
                    expect(record['s']).to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });

    it('should append a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.append('s', 'def')
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i']).to.equal(record2['i']);
                    expect(record['s'] + 'def').to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });

    it('should prepend and read a bin', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // write the record then check
        client.put(key, record, meta, function(err, key) {

            var ops = [
                op.prepend('s', 'def'),
                op.read('s'),
            ];

            client.operate(key, ops, function(err, record1, metadata1, key1) {
                expect(err).to.be.ok();
                expect(err.code).to.equal(status.AEROSPIKE_OK);
                expect(record1['i']).to.equal(undefined);
                expect('def' + record['s']).to.equal(record1['s']);

                client.get(key, function(err, record2, metadata2, key2) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    expect(record['i']).to.equal(record2['i']);
                    expect('def'+record['s'] ).to.equal(record2['s']);
					client.remove(key2, function(err, key){
						done();
					});
                });

            });
        });
    });
    it('should touch a record(refresh ttl) ', function(done) {

        // generators
        var kgen = keygen.string(options.namespace, options.set, {prefix: "test/get/"});
        var mgen = metagen.constant({ttl: 1000});
        var rgen = recgen.constant({i: 123, s: "abc"});

        // values
        var key     = kgen();
        var meta    = mgen(key);
        var record  = rgen(key, meta);

        // TEST LOGIC
        // 1.Write a record to an aerospike server.
        // 2.Read the record, to get the ttl and calculate
        //   the difference in the ttl written and the ttl returned by server.
        // 3.Touch the record with a definite ttl.
        // 4.Read the record and calculate the difference in the ttl between the
        //  touch ttl value and read ttl value.
        // 5.Compare the difference with the earlier difference calculated.
        // 6.This is to account for the clock asynchronicity between
        //   the client and the server machines.
        // 7.Server returns a number, at which the record expires according the server clock.
        // 8.The client calculates the time in seconds, and gives back ttl. In the case , where
        //   clocks are not synchronous between server and client, the ttl client calculates may not
        //   be accurate to the user. Nevertheless server expires the record in the correct time.

        // write the record then check
        client.put(key, record, meta, function(err, key) {
            var ops = [
                op.touch(2592000)
            ];
            client.get(key, function(err, record3, metadata3, key3){
                expect(err).to.be.ok();
                ttl_diff = metadata3.ttl - meta.ttl;
                client.operate(key, ops, function(err, record1, metadata1, key1) {
                    expect(err).to.be.ok();
                    expect(err.code).to.equal(status.AEROSPIKE_OK);
                    client.get(key1, function(err, record2, metadata2, key2) {
                        expect(err).to.be.ok();
                        expect(err.code).to.equal(status.AEROSPIKE_OK);
                        expect(record['i']).to.equal(record2['i']);
                        expect(record['s']).to.equal(record2['s']);
                        expect(2592000 + ttl_diff+10).to.be.above(metadata2.ttl);
                        expect(2592000 + ttl_diff-10).to.be.below(metadata2.ttl);
						client.remove(key2, function(err, key){
							done();
						});
                    });

                });
            });
        });
    });

});
<|endoftext|>


<commit_before>/*
 * Copyright 2017 SideeX committers
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
import browser from "webextension-polyfill";
import TargetSelector from "./targetSelector";
import Selenium from "./selenium-api";
import BrowserBot from "./selenium-browserbot";
import { locatorBuilders } from "./record";

export const selenium = new Selenium(BrowserBot.createForWindow(window));
let contentSideexTabId = window.contentSideexTabId;
let targetSelector;

function doCommands(request, sender, sendResponse) {
  if (request.commands) {
    if (request.commands == "waitPreparation") {
      selenium["doWaitPreparation"]("", selenium.preprocessParameter(""));
      sendResponse({});
    } else if (request.commands == "prePageWait") {
      selenium["doPrePageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ new_page: window.sideex_new_page });
    } else if (request.commands == "pageWait") {
      selenium["doPageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ page_done: window.sideex_page_done });
    } else if (request.commands == "ajaxWait") {
      selenium["doAjaxWait"]("", selenium.preprocessParameter(""));
      sendResponse({ ajax_done: window.sideex_ajax_done });
    } else if (request.commands == "domWait") {
      selenium["doDomWait"]("", selenium.preprocessParameter(""));
      sendResponse({ dom_time: window.sideex_new_page });
    } else {
      const upperCase = request.commands.charAt(0).toUpperCase() + request.commands.slice(1);
      if (selenium["do" + upperCase] != null) {
        try {
          document.body.setAttribute("SideeXPlayingFlag", true);
          let returnValue = selenium["do"+upperCase](request.target,selenium.preprocessParameter(request.value));
          if (returnValue instanceof Promise) {
            // The command is a asynchronous function
            returnValue.then(function() {
              // Asynchronous command completed successfully
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: "success"});
            }).catch(function(reason) {
              // Asynchronous command failed
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: reason});
            });
          } else {
            // Synchronous command completed successfully
            document.body.removeAttribute("SideeXPlayingFlag");
            sendResponse({result: "success"});
          }
        } catch(e) {
          // Synchronous command failed
          document.body.removeAttribute("SideeXPlayingFlag");
          sendResponse({result: e.message});
        }
      } else {
        sendResponse({ result: "Unknown command: " + request.commands });
      }
    }

    //do every command need giving sideex id
    if (contentSideexTabId === -1) {
      contentSideexTabId = request.mySideexTabId;
    }
    return true;
  }
  if (request.selectMode) {
    if (request.selecting) {
      targetSelector = new TargetSelector(function (element, win) {
        if (element && win) {
          const target = locatorBuilders.buildAll(element);
          locatorBuilders.detach();
          if (target != null && target instanceof Array) {
            if (target) {
              //self.editor.treeView.updateCurrentCommand('targetCandidates', target);
              browser.runtime.sendMessage({
                selectTarget: true,
                target: target
              });
            }
          }
        }
        targetSelector = null;
      }, function () {
        browser.runtime.sendMessage({
          cancelSelectTarget: true
        });
      });

    } else {
      if (targetSelector) {
        targetSelector.cleanup();
        targetSelector = null;
        return;
      }
    }
  }
}

browser.runtime.onMessage.addListener(doCommands);
<commit_msg>add the listener only once<commit_after>/*
 * Copyright 2017 SideeX committers
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
import browser from "webextension-polyfill";
import TargetSelector from "./targetSelector";
import Selenium from "./selenium-api";
import BrowserBot from "./selenium-browserbot";
import { locatorBuilders } from "./record";

export const selenium = new Selenium(BrowserBot.createForWindow(window));
let contentSideexTabId = window.contentSideexTabId;
let targetSelector;

function doCommands(request, sender, sendResponse) {
  if (request.commands) {
    if (request.commands == "waitPreparation") {
      selenium["doWaitPreparation"]("", selenium.preprocessParameter(""));
      sendResponse({});
    } else if (request.commands == "prePageWait") {
      selenium["doPrePageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ new_page: window.sideex_new_page });
    } else if (request.commands == "pageWait") {
      selenium["doPageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ page_done: window.sideex_page_done });
    } else if (request.commands == "ajaxWait") {
      selenium["doAjaxWait"]("", selenium.preprocessParameter(""));
      sendResponse({ ajax_done: window.sideex_ajax_done });
    } else if (request.commands == "domWait") {
      selenium["doDomWait"]("", selenium.preprocessParameter(""));
      sendResponse({ dom_time: window.sideex_new_page });
    } else {
      const upperCase = request.commands.charAt(0).toUpperCase() + request.commands.slice(1);
      if (selenium["do" + upperCase] != null) {
        try {
          document.body.setAttribute("SideeXPlayingFlag", true);
          let returnValue = selenium["do"+upperCase](request.target,selenium.preprocessParameter(request.value));
          if (returnValue instanceof Promise) {
            // The command is a asynchronous function
            returnValue.then(function() {
              // Asynchronous command completed successfully
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: "success"});
            }).catch(function(reason) {
              // Asynchronous command failed
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: reason});
            });
          } else {
            // Synchronous command completed successfully
            document.body.removeAttribute("SideeXPlayingFlag");
            sendResponse({result: "success"});
          }
        } catch(e) {
          // Synchronous command failed
          document.body.removeAttribute("SideeXPlayingFlag");
          sendResponse({result: e.message});
        }
      } else {
        sendResponse({ result: "Unknown command: " + request.commands });
      }
    }

    //do every command need giving sideex id
    if (contentSideexTabId === -1) {
      contentSideexTabId = request.mySideexTabId;
    }
    return true;
  }
  if (request.selectMode) {
    if (request.selecting) {
      targetSelector = new TargetSelector(function (element, win) {
        if (element && win) {
          const target = locatorBuilders.buildAll(element);
          locatorBuilders.detach();
          if (target != null && target instanceof Array) {
            if (target) {
              //self.editor.treeView.updateCurrentCommand('targetCandidates', target);
              browser.runtime.sendMessage({
                selectTarget: true,
                target: target
              });
            }
          }
        }
        targetSelector = null;
      }, function () {
        browser.runtime.sendMessage({
          cancelSelectTarget: true
        });
      });

    } else {
      if (targetSelector) {
        targetSelector.cleanup();
        targetSelector = null;
        return;
      }
    }
  }
}

if (!window._listener) {
  window._listener = doCommands;
  browser.runtime.onMessage.addListener(doCommands);
}
<|endoftext|>