<commit_before>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');
var flaverr = require('flaverr');
var parley = require('parley');
var forgeStageTwoQuery = require('../utils/query/forge-stage-two-query');
var getQueryModifierMethods = require('../utils/query/get-query-modifier-methods');
var verifyModelMethodContext = require('../utils/query/verify-model-method-context');

/**
 * Module constants
 */

var DEFERRED_METHODS = getQueryModifierMethods('findOrCreate');

/**
 * findOrCreate()
 *
 * Find the record matching the specified criteria.  If no record exists or more
 * than one record matches the criteria, an error will be returned.
 *
 * ```
 * // Ensure an a pet with type dog exists
 * PetType.findOrCreate({ type: 'dog' }, { name: 'Pretend pet type', type: 'dog' })
 * .exec(function(err, petType, wasCreated) {
 *   // ...
 * });
 * ```
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * Usage without deferred object:
 * ================================================
 *
 * @param {Dictionary?} criteria
 *
 * @param {Dictionary} newRecord
 *
 * @param {Function?} explicitCbMaybe
 *        Callback function to run when query has either finished successfully or errored.
 *        (If unspecified, will return a Deferred object instead of actually doing anything.)
 *
 * @param {Ref?} meta
 *     For internal use.
 *
 * @returns {Ref?} Deferred object if no `explicitCbMaybe` callback was provided
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * The underlying query keys:
 * ==============================
 *
 * @qkey {Dictionary?} criteria
 * @qkey {Dictionary?} newRecord
 *
 * @qkey {Dictionary?} meta
 * @qkey {String} using
 * @qkey {String} method
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */

module.exports = function findOrCreate( /* criteria?, newRecord?, explicitCbMaybe?, meta? */ ) {

  // Verify `this` refers to an actual Sails/Waterline model.
  verifyModelMethodContext(this);

  // Set up a few, common local vars for convenience / familiarity.
  var WLModel = this;
  var orm = this.waterline;
  var modelIdentity = this.identity;

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // FUTURE: Potentially build an omen here for potential use in an
  // asynchronous callback below if/when an error occurs.  This would
  // provide for a better stack trace, since it would be based off of
  // the original method call, rather than containing extra stack entries
  // from various utilities calling each other within Waterline itself.
  //
  // > Note that it'd need to be passed in to the other model methods that
  // > get called internally.
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  // Build query w/ initial, universal keys.
  var query = {
    method: 'findOrCreate',
    using: modelIdentity
  };

  //  ██╗   ██╗ █████╗ ██████╗ ██╗ █████╗ ██████╗ ██╗ ██████╗███████╗
  //  ██║   ██║██╔══██╗██╔══██╗██║██╔══██╗██╔══██╗██║██╔════╝██╔════╝
  //  ██║   ██║███████║██████╔╝██║███████║██║  ██║██║██║     ███████╗
  //  ╚██╗ ██╔╝██╔══██║██╔══██╗██║██╔══██║██║  ██║██║██║     ╚════██║
  //   ╚████╔╝ ██║  ██║██║  ██║██║██║  ██║██████╔╝██║╚██████╗███████║
  //    ╚═══╝  ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚═╝  ╚═╝╚═════╝ ╚═╝ ╚═════╝╚══════╝
  //

  // The `explicitCbMaybe` callback, if one was provided.
  var explicitCbMaybe;

  // Handle the various supported usage possibilities
  // (locate the `explicitCbMaybe` callback, and extend the `query` dictionary)
  //
  // > Note that we define `args` to minimize the chance of this "variadics" code
  // > introducing any unoptimizable performance problems.  For details, see:
  // > https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
  // > •=> `.length` is just an integer, this doesn't leak the `arguments` object itself
  // > •=> `i` is always valid index in the arguments object
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }

  // • findOrCreate(criteria, newRecord, explicitCbMaybe, ...)
  query.criteria = args[0];
  query.newRecord = args[1];
  explicitCbMaybe = args[2];
  query.meta = args[3];

  //  ██████╗ ███████╗███████╗███████╗██████╗
  //  ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗
  //  ██║  ██║█████╗  █████╗  █████╗  ██████╔╝
  //  ██║  ██║██╔══╝  ██╔══╝  ██╔══╝  ██╔══██╗
  //  ██████╔╝███████╗██║     ███████╗██║  ██║
  //  ╚═════╝ ╚══════╝╚═╝     ╚══════╝╚═╝  ╚═╝
  //
  //   ██╗███╗   ███╗ █████╗ ██╗   ██╗██████╗ ███████╗██╗
  //  ██╔╝████╗ ████║██╔══██╗╚██╗ ██╔╝██╔══██╗██╔════╝╚██╗
  //  ██║ ██╔████╔██║███████║ ╚████╔╝ ██████╔╝█████╗   ██║
  //  ██║ ██║╚██╔╝██║██╔══██║  ╚██╔╝  ██╔══██╗██╔══╝   ██║
  //  ╚██╗██║ ╚═╝ ██║██║  ██║   ██║   ██████╔╝███████╗██╔╝
  //   ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═════╝ ╚══════╝╚═╝
  //
  //  ┌┐ ┬ ┬┬┬  ┌┬┐   ┬   ┬─┐┌─┐┌┬┐┬ ┬┬─┐┌┐┌  ┌┐┌┌─┐┬ ┬  ┌┬┐┌─┐┌─┐┌─┐┬─┐┬─┐┌─┐┌┬┐
  //  ├┴┐│ │││   ││  ┌┼─  ├┬┘├┤  │ │ │├┬┘│││  │││├┤ │││   ││├┤ ├┤ ├┤ ├┬┘├┬┘├┤  ││
  //  └─┘└─┘┴┴─┘─┴┘  └┘   ┴└─└─┘ ┴ └─┘┴└─┘└┘  ┘└┘└─┘└┴┘  ─┴┘└─┘└  └─┘┴└─┴└─└─┘─┴┘
  //  ┌─    ┬┌─┐  ┬─┐┌─┐┬  ┌─┐┬  ┬┌─┐┌┐┌┌┬┐    ─┐
  //  │───  │├┤   ├┬┘├┤ │  ├┤ └┐┌┘├─┤│││ │   ───│
  //  └─    ┴└    ┴└─└─┘┴─┘└─┘ └┘ ┴ ┴┘└┘ ┴     ─┘
  // If an explicit callback function was specified, then immediately run the logic below
  // and trigger the explicit callback when the time comes.  Otherwise, build and return
  // a new Deferred now. (If/when the Deferred is executed, the logic below will run.)
  return parley(

    function (done){

      // Otherwise, IWMIH, we know that it's time to actually do some stuff.
      // So...
      //
      //  ███████╗██╗  ██╗███████╗ ██████╗██╗   ██╗████████╗███████╗
      //  ██╔════╝╚██╗██╔╝██╔════╝██╔════╝██║   ██║╚══██╔══╝██╔════╝
      //  █████╗   ╚███╔╝ █████╗  ██║     ██║   ██║   ██║   █████╗
      //  ██╔══╝   ██╔██╗ ██╔══╝  ██║     ██║   ██║   ██║   ██╔══╝
      //  ███████╗██╔╝ ██╗███████╗╚██████╗╚██████╔╝   ██║   ███████╗
      //  ╚══════╝╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═════╝    ╚═╝   ╚══════╝

      //  ╔═╗╔═╗╦═╗╔═╗╔═╗  ┌─┐┌┬┐┌─┐┌─┐┌─┐  ┌┬┐┬ ┬┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
      //  ╠╣ ║ ║╠╦╝║ ╦║╣   └─┐ │ ├─┤│ ┬├┤    │ ││││ │  │─┼┐│ │├┤ ├┬┘└┬┘
      //  ╚  ╚═╝╩╚═╚═╝╚═╝  └─┘ ┴ ┴ ┴└─┘└─┘   ┴ └┴┘└─┘  └─┘└└─┘└─┘┴└─ ┴
      //
      // Forge a stage 2 query (aka logical protostatement)
      try {
        forgeStageTwoQuery(query, orm);
      } catch (e) {
        switch (e.code) {
          case 'E_INVALID_CRITERIA':
            return done(
              flaverr(
                { name: 'UsageError' },
                new Error(
                  'Invalid criteria.\n' +
                  'Details:\n' +
                  '  ' + e.details + '\n'
                )
              )
            );

          case 'E_INVALID_NEW_RECORDS':
            return done(
              flaverr(
                { name: 'UsageError' },
                new Error(
                  'Invalid new record(s).\n'+
                  'Details:\n'+
                  '  '+e.details+'\n'
                )
              )
            );
          case 'E_NOOP':
            // If the criteria is deemed to be a no-op, then normalize it into a standard format.
            // This way, it will continue to represent a no-op as we proceed below, so the `findOne()`
            // call will also come back with an E_NOOP, and so then it will go on to do a `.create()`.
            // And most importantly, this way we don't have to worry about the case where the no-op
            // was caused by an edge case like `false` (we need to be able to munge the criteria --
            // i.e. deleting the `limit`).
            var STD_NOOP_CRITERIA = { where: { or: [] } };
            query.criteria = STD_NOOP_CRITERIA;
            break;

          default:
            return done(e);
        }
      }// >-•

      // Remove the `limit`, `skip`, and `sort` clauses so that our findOne query is valid.
      // (This is because they were automatically attached above.)
      delete query.criteria.limit;
      delete query.criteria.skip;
      delete query.criteria.sort;

      //  ╔═╗═╗ ╦╔═╗╔═╗╦ ╦╔╦╗╔═╗  ┌─┐┬┌┐┌┌┬┐  ┌─┐┌┐┌┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
      //  ║╣ ╔╩╦╝║╣ ║  ║ ║ ║ ║╣   ├┤ ││││ ││  │ ││││├┤   │─┼┐│ │├┤ ├┬┘└┬┘
      //  ╚═╝╩ ╚═╚═╝╚═╝╚═╝ ╩ ╚═╝  └  ┴┘└┘─┴┘  └─┘┘└┘└─┘  └─┘└└─┘└─┘┴└─ ┴
      // Note that we pass in `meta` here, which ensures we're on the same db connection.
      // (provided one was explicitly passed in!)
      WLModel.findOne(query.criteria, function _afterPotentiallyFinding(err, foundRecord) {
        if (err) {
          return done(err);
        }

        // Note that we pass through a flag as the third argument to our callback,
        // indicating whether a new record was created.
        if (foundRecord) {
          return done(undefined, foundRecord, false);
        }

        // So that the create query is valid, check if the primary key value was
        // automatically set to `null` by FS2Q (i.e. because it was unspecified.)
        // And if so, remove it.
        //
        // > IWMIH, we know this was automatic because, if `null` had been
        // > specified explicitly, it would have already caused an error in
        // > our call to FS2Q above (`null` is NEVER a valid PK value)
        var pkAttrName = WLModel.primaryKey;
        var wasPKValueCoercedToNull = _.isNull(query.newRecord[pkAttrName]);
        if (wasPKValueCoercedToNull) {
          delete query.newRecord[pkAttrName];
        }

        // Build a modified shallow clone of the originally-provided `meta`
        // that also has `fetch: true`.
        var modifiedMeta = _.extend({}, query.meta || {}, { fetch: true });

        //  ╔═╗═╗ ╦╔═╗╔═╗╦ ╦╔╦╗╔═╗  ┌─┐┬─┐┌─┐┌─┐┌┬┐┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
        //  ║╣ ╔╩╦╝║╣ ║  ║ ║ ║ ║╣   │  ├┬┘├┤ ├─┤ │ ├┤   │─┼┐│ │├┤ ├┬┘└┬┘
        //  ╚═╝╩ ╚═╚═╝╚═╝╚═╝ ╩ ╚═╝  └─┘┴└─└─┘┴ ┴ ┴ └─┘  └─┘└└─┘└─┘┴└─ ┴
        WLModel.create(query.newRecord, function _afterCreating(err, createdRecord) {
          if (err) {
            return done(err);
          }

          // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          // FUTURE: Instead of preventing projections (`omit`/`select`) for findOrCreate,
          // instead allow them and just modify the newly created record after the fact
          // (i.e. trim properties in-memory).
          // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

          // Pass the newly-created record to our callback.
          // > Note we set the `wasCreated` flag to `true` in this case.
          return done(undefined, createdRecord, true);

        }, modifiedMeta);//</.create()>
      }, query.meta);//</.findOne()>
    },

    explicitCbMaybe,

    _.extend(DEFERRED_METHODS, {

      // Provide access to this model for use in query modifier methods.
      _WLModel: WLModel,

      // Set up initial query metadata.
      _wlQueryInfo: query,

    })

  );//</parley>

};
<commit_msg>Better stack traces when usage error occurs in findOrCreate()<commit_after>/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');
var flaverr = require('flaverr');
var parley = require('parley');
var buildOmen = require('../utils/query/build-omen');
var forgeStageTwoQuery = require('../utils/query/forge-stage-two-query');
var getQueryModifierMethods = require('../utils/query/get-query-modifier-methods');
var verifyModelMethodContext = require('../utils/query/verify-model-method-context');

/**
 * Module constants
 */

var DEFERRED_METHODS = getQueryModifierMethods('findOrCreate');

/**
 * findOrCreate()
 *
 * Find the record matching the specified criteria.  If no record exists or more
 * than one record matches the criteria, an error will be returned.
 *
 * ```
 * // Ensure an a pet with type dog exists
 * PetType.findOrCreate({ type: 'dog' }, { name: 'Pretend pet type', type: 'dog' })
 * .exec(function(err, petType, wasCreated) {
 *   // ...
 * });
 * ```
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * Usage without deferred object:
 * ================================================
 *
 * @param {Dictionary?} criteria
 *
 * @param {Dictionary} newRecord
 *
 * @param {Function?} explicitCbMaybe
 *        Callback function to run when query has either finished successfully or errored.
 *        (If unspecified, will return a Deferred object instead of actually doing anything.)
 *
 * @param {Ref?} meta
 *     For internal use.
 *
 * @returns {Ref?} Deferred object if no `explicitCbMaybe` callback was provided
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *
 * The underlying query keys:
 * ==============================
 *
 * @qkey {Dictionary?} criteria
 * @qkey {Dictionary?} newRecord
 *
 * @qkey {Dictionary?} meta
 * @qkey {String} using
 * @qkey {String} method
 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */

module.exports = function findOrCreate( /* criteria?, newRecord?, explicitCbMaybe?, meta? */ ) {

  // Verify `this` refers to an actual Sails/Waterline model.
  verifyModelMethodContext(this);

  // Set up a few, common local vars for convenience / familiarity.
  var WLModel = this;
  var orm = this.waterline;
  var modelIdentity = this.identity;

  // Build an omen for potential use in the asynchronous callback below.
  var omen = buildOmen(findOrCreate);

  // Build query w/ initial, universal keys.
  var query = {
    method: 'findOrCreate',
    using: modelIdentity
  };

  //  ██╗   ██╗ █████╗ ██████╗ ██╗ █████╗ ██████╗ ██╗ ██████╗███████╗
  //  ██║   ██║██╔══██╗██╔══██╗██║██╔══██╗██╔══██╗██║██╔════╝██╔════╝
  //  ██║   ██║███████║██████╔╝██║███████║██║  ██║██║██║     ███████╗
  //  ╚██╗ ██╔╝██╔══██║██╔══██╗██║██╔══██║██║  ██║██║██║     ╚════██║
  //   ╚████╔╝ ██║  ██║██║  ██║██║██║  ██║██████╔╝██║╚██████╗███████║
  //    ╚═══╝  ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚═╝  ╚═╝╚═════╝ ╚═╝ ╚═════╝╚══════╝
  //

  // The `explicitCbMaybe` callback, if one was provided.
  var explicitCbMaybe;

  // Handle the various supported usage possibilities
  // (locate the `explicitCbMaybe` callback, and extend the `query` dictionary)
  //
  // > Note that we define `args` to minimize the chance of this "variadics" code
  // > introducing any unoptimizable performance problems.  For details, see:
  // > https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
  // > •=> `.length` is just an integer, this doesn't leak the `arguments` object itself
  // > •=> `i` is always valid index in the arguments object
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }

  // • findOrCreate(criteria, newRecord, explicitCbMaybe, ...)
  query.criteria = args[0];
  query.newRecord = args[1];
  explicitCbMaybe = args[2];
  query.meta = args[3];

  //  ██████╗ ███████╗███████╗███████╗██████╗
  //  ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗
  //  ██║  ██║█████╗  █████╗  █████╗  ██████╔╝
  //  ██║  ██║██╔══╝  ██╔══╝  ██╔══╝  ██╔══██╗
  //  ██████╔╝███████╗██║     ███████╗██║  ██║
  //  ╚═════╝ ╚══════╝╚═╝     ╚══════╝╚═╝  ╚═╝
  //
  //   ██╗███╗   ███╗ █████╗ ██╗   ██╗██████╗ ███████╗██╗
  //  ██╔╝████╗ ████║██╔══██╗╚██╗ ██╔╝██╔══██╗██╔════╝╚██╗
  //  ██║ ██╔████╔██║███████║ ╚████╔╝ ██████╔╝█████╗   ██║
  //  ██║ ██║╚██╔╝██║██╔══██║  ╚██╔╝  ██╔══██╗██╔══╝   ██║
  //  ╚██╗██║ ╚═╝ ██║██║  ██║   ██║   ██████╔╝███████╗██╔╝
  //   ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═════╝ ╚══════╝╚═╝
  //
  //  ┌┐ ┬ ┬┬┬  ┌┬┐   ┬   ┬─┐┌─┐┌┬┐┬ ┬┬─┐┌┐┌  ┌┐┌┌─┐┬ ┬  ┌┬┐┌─┐┌─┐┌─┐┬─┐┬─┐┌─┐┌┬┐
  //  ├┴┐│ │││   ││  ┌┼─  ├┬┘├┤  │ │ │├┬┘│││  │││├┤ │││   ││├┤ ├┤ ├┤ ├┬┘├┬┘├┤  ││
  //  └─┘└─┘┴┴─┘─┴┘  └┘   ┴└─└─┘ ┴ └─┘┴└─┘└┘  ┘└┘└─┘└┴┘  ─┴┘└─┘└  └─┘┴└─┴└─└─┘─┴┘
  //  ┌─    ┬┌─┐  ┬─┐┌─┐┬  ┌─┐┬  ┬┌─┐┌┐┌┌┬┐    ─┐
  //  │───  │├┤   ├┬┘├┤ │  ├┤ └┐┌┘├─┤│││ │   ───│
  //  └─    ┴└    ┴└─└─┘┴─┘└─┘ └┘ ┴ ┴┘└┘ ┴     ─┘
  // If an explicit callback function was specified, then immediately run the logic below
  // and trigger the explicit callback when the time comes.  Otherwise, build and return
  // a new Deferred now. (If/when the Deferred is executed, the logic below will run.)
  return parley(

    function (done){

      // Otherwise, IWMIH, we know that it's time to actually do some stuff.
      // So...
      //
      //  ███████╗██╗  ██╗███████╗ ██████╗██╗   ██╗████████╗███████╗
      //  ██╔════╝╚██╗██╔╝██╔════╝██╔════╝██║   ██║╚══██╔══╝██╔════╝
      //  █████╗   ╚███╔╝ █████╗  ██║     ██║   ██║   ██║   █████╗
      //  ██╔══╝   ██╔██╗ ██╔══╝  ██║     ██║   ██║   ██║   ██╔══╝
      //  ███████╗██╔╝ ██╗███████╗╚██████╗╚██████╔╝   ██║   ███████╗
      //  ╚══════╝╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═════╝    ╚═╝   ╚══════╝

      //  ╔═╗╔═╗╦═╗╔═╗╔═╗  ┌─┐┌┬┐┌─┐┌─┐┌─┐  ┌┬┐┬ ┬┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
      //  ╠╣ ║ ║╠╦╝║ ╦║╣   └─┐ │ ├─┤│ ┬├┤    │ ││││ │  │─┼┐│ │├┤ ├┬┘└┬┘
      //  ╚  ╚═╝╩╚═╚═╝╚═╝  └─┘ ┴ ┴ ┴└─┘└─┘   ┴ └┴┘└─┘  └─┘└└─┘└─┘┴└─ ┴
      //
      // Forge a stage 2 query (aka logical protostatement)
      try {
        forgeStageTwoQuery(query, orm);
      } catch (e) {
        switch (e.code) {
          case 'E_INVALID_CRITERIA':
            return done(
              flaverr({
                name: 'UsageError',
                message:
                'Invalid criteria.\n' +
                'Details:\n' +
                '  ' + e.details + '\n'
              }, omen)
            );

          case 'E_INVALID_NEW_RECORDS':
            return done(
              flaverr({
                name: 'UsageError',
                message:
                'Invalid new record(s).\n'+
                'Details:\n'+
                '  '+e.details+'\n'
              }, omen)
            );
          case 'E_NOOP':
            // If the criteria is deemed to be a no-op, then normalize it into a standard format.
            // This way, it will continue to represent a no-op as we proceed below, so the `findOne()`
            // call will also come back with an E_NOOP, and so then it will go on to do a `.create()`.
            // And most importantly, this way we don't have to worry about the case where the no-op
            // was caused by an edge case like `false` (we need to be able to munge the criteria --
            // i.e. deleting the `limit`).
            var STD_NOOP_CRITERIA = { where: { or: [] } };
            query.criteria = STD_NOOP_CRITERIA;
            break;

          default:
            return done(e);
        }
      }// >-•

      // Remove the `limit`, `skip`, and `sort` clauses so that our findOne query is valid.
      // (This is because they were automatically attached above.)
      delete query.criteria.limit;
      delete query.criteria.skip;
      delete query.criteria.sort;

      //  ╔═╗═╗ ╦╔═╗╔═╗╦ ╦╔╦╗╔═╗  ┌─┐┬┌┐┌┌┬┐  ┌─┐┌┐┌┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
      //  ║╣ ╔╩╦╝║╣ ║  ║ ║ ║ ║╣   ├┤ ││││ ││  │ ││││├┤   │─┼┐│ │├┤ ├┬┘└┬┘
      //  ╚═╝╩ ╚═╚═╝╚═╝╚═╝ ╩ ╚═╝  └  ┴┘└┘─┴┘  └─┘┘└┘└─┘  └─┘└└─┘└─┘┴└─ ┴
      // Note that we pass in `meta` here, which ensures we're on the same db connection.
      // (provided one was explicitly passed in!)
      WLModel.findOne(query.criteria, function _afterPotentiallyFinding(err, foundRecord) {
        if (err) {
          return done(err);
        }

        // Note that we pass through a flag as the third argument to our callback,
        // indicating whether a new record was created.
        if (foundRecord) {
          return done(undefined, foundRecord, false);
        }

        // So that the create query is valid, check if the primary key value was
        // automatically set to `null` by FS2Q (i.e. because it was unspecified.)
        // And if so, remove it.
        //
        // > IWMIH, we know this was automatic because, if `null` had been
        // > specified explicitly, it would have already caused an error in
        // > our call to FS2Q above (`null` is NEVER a valid PK value)
        var pkAttrName = WLModel.primaryKey;
        var wasPKValueCoercedToNull = _.isNull(query.newRecord[pkAttrName]);
        if (wasPKValueCoercedToNull) {
          delete query.newRecord[pkAttrName];
        }

        // Build a modified shallow clone of the originally-provided `meta`
        // that also has `fetch: true`.
        var modifiedMeta = _.extend({}, query.meta || {}, { fetch: true });

        //  ╔═╗═╗ ╦╔═╗╔═╗╦ ╦╔╦╗╔═╗  ┌─┐┬─┐┌─┐┌─┐┌┬┐┌─┐  ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
        //  ║╣ ╔╩╦╝║╣ ║  ║ ║ ║ ║╣   │  ├┬┘├┤ ├─┤ │ ├┤   │─┼┐│ │├┤ ├┬┘└┬┘
        //  ╚═╝╩ ╚═╚═╝╚═╝╚═╝ ╩ ╚═╝  └─┘┴└─└─┘┴ ┴ ┴ └─┘  └─┘└└─┘└─┘┴└─ ┴
        WLModel.create(query.newRecord, function _afterCreating(err, createdRecord) {
          if (err) {
            return done(err);
          }

          // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          // FUTURE: Instead of preventing projections (`omit`/`select`) for findOrCreate,
          // instead allow them and just modify the newly created record after the fact
          // (i.e. trim properties in-memory).
          // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

          // Pass the newly-created record to our callback.
          // > Note we set the `wasCreated` flag to `true` in this case.
          return done(undefined, createdRecord, true);

        }, modifiedMeta);//</.create()>
      }, query.meta);//</.findOne()>
    },

    explicitCbMaybe,

    _.extend(DEFERRED_METHODS, {

      // Provide access to this model for use in query modifier methods.
      _WLModel: WLModel,

      // Set up initial query metadata.
      _wlQueryInfo: query,

    })

  );//</parley>

};
<|endoftext|>


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

/*
 * assetman
 * https://github.com/miningold/assetman
 *
 * Copyright (c) 2013 Tylor Reynolds
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path'),
    fs = require('fs'),
    glob = require('glob'),
    ninjaGen = require('ninja-build-gen'),
    _ = require('lodash'),
    srcCache = {},
    buildCache = {},
    checkHelp,
    showHelp,
    help,
    parse;

// check argv for -h or --help
checkHelp = function(argv) {
  var len = argv.length,
      arg,
      i;

  for (i = 0; i < len; i++) {
    arg = argv[i];

    if ('-h' == arg || '--help' == arg) {
      help();
    }
  }
};

// Show usage for this command
showHelp = function() {
  console.log();
  console.log('  Usage: assetman [src_path]');
  console.log();
  console.log('  [src_path]  Path to source direcctory containing assets.json');
  console.log('              defaults to current directory');
  console.log();
  console.log('  -h, --help  Show usage information');
  console.log();
};

// Show help message, exit 0
help = function() {
  showHelp();
  process.exit();
};

// var OneBuilder = (function() {
//   function OneBuilder()
// });

// // Parse agv for arguments, recurse for sub-commands
// parse = function(settings, argv) {
//   var commands = settings.commands,
//       len = argv.length,
//       arg, i;

//   // parse first command found, ignore the rest
//   if (commands) {
//     for (i = 0; i < len; i++) {
//       arg = argv[i];

//       if (commands[arg]) {

//         // pass arguments to sub-command
//         argv.splice(i, 1);
//         return parse(commands[arg], argv);
//       }
//     }
//   }

//   // If a command was not found and an action exist, call it.
//   if (settings.action) {
//     settings.action.apply(this, argv);
//   } else {
//     // No action for this command, this is an error, show help
//     showHelp();
//     process.exit(1);
//   }
// };

// var getConfig = function(absSrcPath) {
//   var configPath = path.join(absSrcPath, 'assets.json');

//   if (fs.existsSync(configPath)) {
//     return require(configPath);
//   } else {
//     console.error('ERROR: The source directory "' + srcPath + '" does not appear to contain assets.json.');
//     process.exit(1);
//   }
// };

var RuleBuilder = (function() {
  function RuleBuilder(name) {
    this.name = name;
  }

  RuleBuilder.prototype.command = function(command) {
    this.command = command;
    return this;
  }

  return RuleBuilder;
})();

var OneBuilder = (function() {
  function OneBuilder(pattern) {
    this.pattern = pattern;
    this.buildRelative = false;
  }

  OneBuilder.prototype.fromBuild = function(fromBuild) {
    this.buildRelative = fromBuild;
    return this;
  };

  OneBuilder.prototype.to = function(ext) {
    this.ext = ext;
    return this;
  };

  OneBuilder.prototype.using = function(rule) {
    this.rule = rule;
    return this;
  };

  return OneBuilder
})();

var ManyBuilder = (function() {
  function ManyBuilder (pattern) {
    this.pattern = pattern;
    this.buildRelative = false;
    this.assignments = {};
    this.targets = [];
  }

  ManyBuilder.prototype.fromBuild = function(fromBuild) {
    this.buildRelative = fromBuild;
    return this;
  };

  ManyBuilder.prototype.to = function(files) {
    this.targets = this.targets.concat(files);
    return this;
  };

  ManyBuilder.prototype.assign = function(key, value) {
    this.assignments[key] = value;
    return this;
  };

  ManyBuilder.prototype.using = function(rule) {
    this.rule = rule;
  };

  return ManyBuilder;
})();

var setupUtils = function(ninja, srcPath) {
  // Setup rule for building file list file
  var compareEchoPath = path.join(__dirname, 'compare_echo.js'),
      command = 'node ' + compareEchoPath + ' "$glob" $out ' + srcPath;
  ninja.rule('COMPARE_ECHO')
    .restat(true)
    .description('Updating file list...')
    .run(command);

   // Setup rule for generating build.ninja
  ninja.rule('GENERATE')
    .generator(true)
    .description('Re-running assetman...')
    .run('assetman.cmd ' + srcPath);

  ninja.rule('CLEAN')
    .run('ninja -t clean')
    .description('Cleaning built files...');
};

var compileRules = function(ninja, rules) {
  rules.forEach(function(rule) {
    ninja.rule(rule.name).run(rule.command);
  });
};

var compileOnes = function(ninja, ones, srcPath) {
  ones.forEach(function(one) {
    var filepath  = one.buildRelative ? '.' : srcPath,
        cache = one.buildRelative ? buildCache : srcCache,
        files = glob.sync(one.pattern, {cwd: filepath, cache: cache});

    files.forEach(function(file) {

      // convert OS specific
      file = path.join(file);

      var inputPath = path.join(filepath, file),
          ext = path.extname(file),
          noExt = file.replace(new RegExp(ext + '$'), ''),
          outputPath = noExt + one.ext,
          inputPath;

      ninja.edge(outputPath).from(inputPath).using(one.rule);
    });
  });
};

var compileMany = function(ninja, manys, srcPath) {
  manys.forEach(function(many) {
    var filepath = many.buildRelative ? '.' : srcPath,
        cache = many.buildRelative ? buildCache : srcCache,
        files = glob.sync(many.pattern, {cwd: filepath, cache: cache});

    if (!many.buildRelative) {
      files = _.map(files, function(file) {
        return path.join(srcPath, file);
      });
    }

    if (many.targets.length == 0) {
      console.warn('WARN: No targets specified for many clause with pattern: ' + many.pattern);
    }

    ninja.edge(many.targets).from(files).using(many.rule);
  });
};

var generate = function(srcPath) {
  srcPath = srcPath || '.';
  srcPath = path.join(srcPath);

  var ninja = ninjaGen(),
      assetConfigPath = path.join(srcPath, 'assets.js'),
      assetConfigStr = fs.readFileSync(assetConfigPath, {encoding:'utf8'});

  setupUtils(ninja, srcPath);

  var rules = [],
      ones = [],
      many = [];

  var listBuild = function(list, Type) {
    return function(arg) {
      var obj = new Type(arg);
      list.push(obj);
      return obj;
    };
  };

  // shield config script from global node commands
  var mask = {
    global: undefined,
    process: undefined,
    require: undefined,
    module: undefined,
    exports: undefined,
    setTimeout: undefined,
    clearTimeout: undefined,
    setInterval: undefined,
    clearInterval: undefined,

    rule: listBuild(rules, RuleBuilder),
    one: listBuild(ones, OneBuilder),
    many: listBuild(many, ManyBuilder)
  };

  (new Function('with(this) {' + assetConfigStr + '}')).apply(mask);

  compileRules(ninja, rules);
  compileOnes(ninja, ones, srcPath);
  compileMany(ninja, many, srcPath);

  ninja.save('build.ninja');
  // console.log(many.length);
  // var mask = _.pick(global, 'console')
  // console.log(global);

  // console.log(assetConfigStr);

      // assetConfig = getConfig(absSrcPath);

  // // Generate rules from assets.json
  // for (var rule in assetConfig.rules) {
  //   ninja.rule(rule).run(assetConfig.rules[rule]);
  // }

  // var outputs = [];
  // for (var pattern in assetConfig.edges) {

  //   // find files that match each pattern
  //   var files = glob.sync(pattern, {cwd: srcPath});

  //   // create build edge for each file found
  //   files.forEach(function(file) {

  //     // use path.join to convert path seperator to OS specific
  //     file = path.join(file);

  //     var inputPath = path.join(srcPath, file),
  //         ext = path.extname(file),
  //         noExt = file.replace(new RegExp(ext + '$'), '');

  //     // Create edge from each output postfix
  //     var outputRules = assetConfig.edges[pattern];
  //     for (var postfix in outputRules) {
  //       var rule = outputRules[postfix];
  //       var outputPath = noExt + postfix;

  //       ninja.edge(outputPath).from(inputPath).using(rule);

  //       // collect outputs
  //       outputs.push(outputPath);
  //     }
  //   });
  // }

  // // Setup edge for building file list
  // var globs = Object.keys(assetConfig.edges).join(' ');
  // ninja.edge('.dirty');
  // ninja.edge('.files').from('.dirty').using('COMPARE_ECHO').assign('glob', globs);

  // // Setup edge for building build.ninja
  // var assetConfigPath = path.join(srcPath, 'assets.json');
  // ninja.edge('build.ninja').from(['.files', assetConfigPath]).using('GENERATE');

  // ninja.edge('clean').using('CLEAN');

  // // Setup defaults
  // ninja.byDefault(outputs.join(' '));

  // ninja.save('build.ninja');
};

// var commandSettings = {
//   action: generate
// };

var argv = process.argv.slice(2);
checkHelp(argv);
// parse(commandSettings, argv);
generate.apply(this, argv);
<commit_msg>add assign support to compileMany<commit_after>#!/usr/bin/env node

/*
 * assetman
 * https://github.com/miningold/assetman
 *
 * Copyright (c) 2013 Tylor Reynolds
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path'),
    fs = require('fs'),
    glob = require('glob'),
    ninjaGen = require('ninja-build-gen'),
    _ = require('lodash'),
    srcCache = {},
    buildCache = {},
    checkHelp,
    showHelp,
    help,
    parse;

// check argv for -h or --help
checkHelp = function(argv) {
  var len = argv.length,
      arg,
      i;

  for (i = 0; i < len; i++) {
    arg = argv[i];

    if ('-h' == arg || '--help' == arg) {
      help();
    }
  }
};

// Show usage for this command
showHelp = function() {
  console.log();
  console.log('  Usage: assetman [src_path]');
  console.log();
  console.log('  [src_path]  Path to source direcctory containing assets.json');
  console.log('              defaults to current directory');
  console.log();
  console.log('  -h, --help  Show usage information');
  console.log();
};

// Show help message, exit 0
help = function() {
  showHelp();
  process.exit();
};

// var OneBuilder = (function() {
//   function OneBuilder()
// });

// // Parse agv for arguments, recurse for sub-commands
// parse = function(settings, argv) {
//   var commands = settings.commands,
//       len = argv.length,
//       arg, i;

//   // parse first command found, ignore the rest
//   if (commands) {
//     for (i = 0; i < len; i++) {
//       arg = argv[i];

//       if (commands[arg]) {

//         // pass arguments to sub-command
//         argv.splice(i, 1);
//         return parse(commands[arg], argv);
//       }
//     }
//   }

//   // If a command was not found and an action exist, call it.
//   if (settings.action) {
//     settings.action.apply(this, argv);
//   } else {
//     // No action for this command, this is an error, show help
//     showHelp();
//     process.exit(1);
//   }
// };

// var getConfig = function(absSrcPath) {
//   var configPath = path.join(absSrcPath, 'assets.json');

//   if (fs.existsSync(configPath)) {
//     return require(configPath);
//   } else {
//     console.error('ERROR: The source directory "' + srcPath + '" does not appear to contain assets.json.');
//     process.exit(1);
//   }
// };

var RuleBuilder = (function() {
  function RuleBuilder(name) {
    this.name = name;
  }

  RuleBuilder.prototype.command = function(command) {
    this.command = command;
    return this;
  }

  return RuleBuilder;
})();

var OneBuilder = (function() {
  function OneBuilder(pattern) {
    this.pattern = pattern;
    this.buildRelative = false;
  }

  OneBuilder.prototype.fromBuild = function(fromBuild) {
    this.buildRelative = fromBuild;
    return this;
  };

  OneBuilder.prototype.to = function(ext) {
    this.ext = ext;
    return this;
  };

  OneBuilder.prototype.using = function(rule) {
    this.rule = rule;
    return this;
  };

  return OneBuilder
})();

var ManyBuilder = (function() {
  function ManyBuilder (pattern) {
    this.pattern = pattern;
    this.buildRelative = false;
    this.assignments = {};
    this.targets = [];
  }

  ManyBuilder.prototype.fromBuild = function(fromBuild) {
    this.buildRelative = fromBuild;
    return this;
  };

  ManyBuilder.prototype.to = function(files) {
    this.targets = this.targets.concat(files);
    return this;
  };

  ManyBuilder.prototype.assign = function(key, value) {
    this.assignments[key] = value;
    return this;
  };

  ManyBuilder.prototype.using = function(rule) {
    this.rule = rule;
  };

  return ManyBuilder;
})();

var setupUtils = function(ninja, srcPath) {
  // Setup rule for building file list file
  var compareEchoPath = path.join(__dirname, 'compare_echo.js'),
      command = 'node ' + compareEchoPath + ' "$glob" $out ' + srcPath;
  ninja.rule('COMPARE_ECHO')
    .restat(true)
    .description('Updating file list...')
    .run(command);

   // Setup rule for generating build.ninja
  ninja.rule('GENERATE')
    .generator(true)
    .description('Re-running assetman...')
    .run('assetman.cmd ' + srcPath);

  ninja.rule('CLEAN')
    .run('ninja -t clean')
    .description('Cleaning built files...');
};

var compileRules = function(ninja, rules) {
  rules.forEach(function(rule) {
    ninja.rule(rule.name).run(rule.command);
  });
};

var compileOnes = function(ninja, ones, srcPath) {
  ones.forEach(function(one) {
    var filepath  = one.buildRelative ? '.' : srcPath,
        cache = one.buildRelative ? buildCache : srcCache,
        files = glob.sync(one.pattern, {cwd: filepath, cache: cache});

    files.forEach(function(file) {

      // convert OS specific
      file = path.join(file);

      var inputPath = path.join(filepath, file),
          ext = path.extname(file),
          noExt = file.replace(new RegExp(ext + '$'), ''),
          outputPath = noExt + one.ext,
          inputPath;

      ninja.edge(outputPath).from(inputPath).using(one.rule);
    });
  });
};

var compileMany = function(ninja, manys, srcPath) {
  manys.forEach(function(many) {
    var filepath = many.buildRelative ? '.' : srcPath,
        cache = many.buildRelative ? buildCache : srcCache,
        files = glob.sync(many.pattern, {cwd: filepath, cache: cache});

    if (!many.buildRelative) {
      files = _.map(files, function(file) {
        return path.join(srcPath, file);
      });
    }

    if (many.targets.length == 0) {
      console.warn('WARN: No targets specified for many clause with pattern: ' + many.pattern);
      return;
    }

    var edge = ninja.edge(many.targets);

    edge.from(files).using(many.rule);

    var value;
    for (var key in many.assignments) {
      value = many.assignments[key];
      edge.assign(key, value);
    }
  });
};

var generate = function(srcPath) {
  srcPath = srcPath || '.';
  srcPath = path.join(srcPath);

  var ninja = ninjaGen(),
      assetConfigPath = path.join(srcPath, 'assets.js'),
      assetConfigStr = fs.readFileSync(assetConfigPath, {encoding:'utf8'});

  setupUtils(ninja, srcPath);

  var rules = [],
      ones = [],
      many = [];

  var listBuild = function(list, Type) {
    return function(arg) {
      var obj = new Type(arg);
      list.push(obj);
      return obj;
    };
  };

  // shield config script from global node commands
  var mask = {
    global: undefined,
    process: undefined,
    require: undefined,
    module: undefined,
    exports: undefined,
    setTimeout: undefined,
    clearTimeout: undefined,
    setInterval: undefined,
    clearInterval: undefined,

    rule: listBuild(rules, RuleBuilder),
    one: listBuild(ones, OneBuilder),
    many: listBuild(many, ManyBuilder)
  };

  (new Function('with(this) {' + assetConfigStr + '}')).apply(mask);

  compileRules(ninja, rules);
  compileOnes(ninja, ones, srcPath);
  compileMany(ninja, many, srcPath);

  ninja.save('build.ninja');
  // console.log(many.length);
  // var mask = _.pick(global, 'console')
  // console.log(global);

  // console.log(assetConfigStr);

      // assetConfig = getConfig(absSrcPath);

  // // Generate rules from assets.json
  // for (var rule in assetConfig.rules) {
  //   ninja.rule(rule).run(assetConfig.rules[rule]);
  // }

  // var outputs = [];
  // for (var pattern in assetConfig.edges) {

  //   // find files that match each pattern
  //   var files = glob.sync(pattern, {cwd: srcPath});

  //   // create build edge for each file found
  //   files.forEach(function(file) {

  //     // use path.join to convert path seperator to OS specific
  //     file = path.join(file);

  //     var inputPath = path.join(srcPath, file),
  //         ext = path.extname(file),
  //         noExt = file.replace(new RegExp(ext + '$'), '');

  //     // Create edge from each output postfix
  //     var outputRules = assetConfig.edges[pattern];
  //     for (var postfix in outputRules) {
  //       var rule = outputRules[postfix];
  //       var outputPath = noExt + postfix;

  //       ninja.edge(outputPath).from(inputPath).using(rule);

  //       // collect outputs
  //       outputs.push(outputPath);
  //     }
  //   });
  // }

  // // Setup edge for building file list
  // var globs = Object.keys(assetConfig.edges).join(' ');
  // ninja.edge('.dirty');
  // ninja.edge('.files').from('.dirty').using('COMPARE_ECHO').assign('glob', globs);

  // // Setup edge for building build.ninja
  // var assetConfigPath = path.join(srcPath, 'assets.json');
  // ninja.edge('build.ninja').from(['.files', assetConfigPath]).using('GENERATE');

  // ninja.edge('clean').using('CLEAN');

  // // Setup defaults
  // ninja.byDefault(outputs.join(' '));

  // ninja.save('build.ninja');
};

// var commandSettings = {
//   action: generate
// };

var argv = process.argv.slice(2);
checkHelp(argv);
// parse(commandSettings, argv);
generate.apply(this, argv);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
 * FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
 * is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
 * obligations to provide maintenance, support, updates, enhancements or
 * modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
 * liable to any party for direct, indirect, special, incidental or
 * consequential damages, including lost profits, arising out of the use of this
 * software and its documentation, even if Memorial Sloan-Kettering Cancer
 * Center has been advised of the possibility of such damage.
 */

/*
 * This file is part of cBioPortal.
 *
 * cBioPortal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

$(document).ready(function(){

    //setUpPopEye();
    setUpTabs();
    setUpTestimonials();

});

/*
 * Set up results tabs
 */
function setUpTabs() {
     // generate tabs for results page; set cookies to preserve
    // state of tabs when user navigates away from page and back
    $('#tabs').tabs({cookie:{expires:1, name:("results-tab-" +
                    (typeof cancer_study_id_selected === 'undefined'? "" : cancer_study_id_selected))}});
    $('#tabs').show();
}

/*
 * Determine position and behavior of testimonials
 * based on current page
 */
function setUpTestimonials() {
    // If we are on 'view all' page (what_people_are_saying.jsp),
    // hide testimonial section in right column
    if ($('#all_testimonials').length > 0){
        $('#rotating_testimonials').hide();
    } else {
        // If we are not on 'view all' page, testimonials appear
        // in right column. Append link to 'view all' to each
        // blockquote. This is done to ensure link falls
        // directly beneath each quote, as quote lengths differ
        $('#testimonials blockquote').append("
View All");
        //rotateTestimonials();
	displayRandomTestimonial();
    }
}

/*
 * Rotate testimonials in right column
 */
function rotateTestimonials() {
    // use quovolver plugin to rotate testimonials

    // set animation speed to 400; quovolver default is 500
    var animationSpeed = 400;
    // set duration of each testimonial; quovolver default is 6000
    var duration = 8000;
    $('#testimonials > blockquote').quovolver(animationSpeed, duration);
}

function displayRandomTestimonial() {
    $('#testimonials blockquote').hide()

    var numTestimonials = $('#testimonials > blockquote').length;
    var ran = Math.floor(Math.random()*numTestimonials) + 1;
    $('#testimonials blockquote:nth-child(' + ran + ')').show();

}

/*
 * Set up preview images on home page
 * TODO not used anymore (we removed popeye lib)
 */

function setUpPopEye(){

    var hovering=false;
    var maxNextClicks = $('#ppy2 li').length * 2;

    $(".ppy").hover(
        function() {
            hovering = true;
            $('.ppy-caption').show();
        },
        function() {
            hovering = false;
        }
    );

    setInterval(function(){
        if(!$("#custom_case_set_dialog").dialog("isOpen") &&
        		!hovering && maxNextClicks >0)
        {
            maxNextClicks--;
            $('a.ppy-next').click();
            $('.ppy-caption').hide();
        }
    }, 3000);
}

function clinical(){
    $('#tabs ul li:eq(3) a').click(function(){
        $('#clinical img').hide();
        $('#clinical img').each(function(){
            $(this).load(function(){
                $('#clinical img').fadeIn('normal', hideClinicalLoader());
            });
        });

        function hideClinicalLoader() {
            //hide loader image and remove load div
            $('#load').delay(500).fadeOut('normal').$('#clinical div#load').remove();
        }

    });
}

/*
This function accepts as arguments the URL to be shortened,
our bitly user name and bitly API key (user and key are
stored in properties file)
 */
function bitlyURL(fullURL){

    /*
        when testing locally use 127.0.0.1 instead of localhost
        in your browser location bar.
        bitly: can not encode URI component when localhost is in URL
     */

    var defaults = {
        version: '3.0',
        history: '0',
        longURL: encodeURIComponent(fullURL)
    };

    //build call to web API
    var qurl = "api/proxy/bitly?"
    +"version="+defaults.version
    +"&longUrl="+defaults.longURL
    +"&history="+defaults.history
    +"&format=json&callback=?";

    // get JSON data, extract from it the new short URL and
    // append the short URL to div with id 'bitly'
    $.getJSON(qurl, function(data){
        if (data.results == null){
            $('#bitly').html("An unknown error occurred. Unable to shorten your URL.");
        }  else {
            $('#bitly').html("
" +
                    data.results[fullURL].shortUrl + "
");
        }
    }).fail(function() {
        $('#bitly').html("An unknown error occurred. Unable to shorten your URL.");
    });
}

function addURLBookmark() {
    displayBookmark(window.location.href, window.location.href.split("?")[0] + "?...");
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function getSessionServiceBookmark(fullURL, sessionJSON, callback) {
    // if user got here with a bookmark, just return that, don't create a bookmark of a bookmark
    var bookmarkPattern = /session-id=/
    if (bookmarkPattern.test(fullURL)) {
        callback(fullURL);
    } else {
        // cross_cancer.do has additional information in URL as #crosscancer/:tab/:priority/:genes/:study_list
        // check for that
        var additional_info = fullURL.split("#");
        if (additional_info.length == 2) {
            sessionJSON["url_hash_data"] = [additional_info[1]]; // must be an array like rest of parameter map
        }
        var bookmark = null;
        $.ajax({
            type: 'POST',
            url: 'api/proxy/session-service/main_session',
            dataType: 'json',
            contentType: 'application/json',
            data: JSON.stringify(sessionJSON)
        }).done(function(data) {
            if (data['id'] !== null) {
                var bookmark = fullURL.split("?")[0] + "?session_id=" + data['id'];
                callback(bookmark);
            }
        });
    }
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function addSessionServiceBookmark(fullURL, sessionJSON) {
    getSessionServiceBookmark(fullURL, sessionJSON, displayBookmark);
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function changeURLToSessionServiceURL(fullURL, pageTitle, sessionJSON) {
    getSessionServiceBookmark(fullURL, sessionJSON, function(bookmark) {
        window.history.pushState({ "html": fullURL, "pageTitle": pageTitle }, "", bookmark);
    });
}

function displayBookmark(bookmarkURL) {
    if (bookmarkURL === null){
        $('#session-id').html("An unknown error occurred. Unable to store your session.");
    } else {
        $("#session-id").html("" + bookmarkURL + "");
        bitlyURL(bookmarkURL);
    }
}
<commit_msg>does not call bookmark API if URL is already bookmark<commit_after>/*
 * Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
 * FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
 * is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
 * obligations to provide maintenance, support, updates, enhancements or
 * modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
 * liable to any party for direct, indirect, special, incidental or
 * consequential damages, including lost profits, arising out of the use of this
 * software and its documentation, even if Memorial Sloan-Kettering Cancer
 * Center has been advised of the possibility of such damage.
 */

/*
 * This file is part of cBioPortal.
 *
 * cBioPortal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

$(document).ready(function(){

    //setUpPopEye();
    setUpTabs();
    setUpTestimonials();

});

/*
 * Set up results tabs
 */
function setUpTabs() {
     // generate tabs for results page; set cookies to preserve
    // state of tabs when user navigates away from page and back
    $('#tabs').tabs({cookie:{expires:1, name:("results-tab-" +
                    (typeof cancer_study_id_selected === 'undefined'? "" : cancer_study_id_selected))}});
    $('#tabs').show();
}

/*
 * Determine position and behavior of testimonials
 * based on current page
 */
function setUpTestimonials() {
    // If we are on 'view all' page (what_people_are_saying.jsp),
    // hide testimonial section in right column
    if ($('#all_testimonials').length > 0){
        $('#rotating_testimonials').hide();
    } else {
        // If we are not on 'view all' page, testimonials appear
        // in right column. Append link to 'view all' to each
        // blockquote. This is done to ensure link falls
        // directly beneath each quote, as quote lengths differ
        $('#testimonials blockquote').append("
View All");
        //rotateTestimonials();
	displayRandomTestimonial();
    }
}

/*
 * Rotate testimonials in right column
 */
function rotateTestimonials() {
    // use quovolver plugin to rotate testimonials

    // set animation speed to 400; quovolver default is 500
    var animationSpeed = 400;
    // set duration of each testimonial; quovolver default is 6000
    var duration = 8000;
    $('#testimonials > blockquote').quovolver(animationSpeed, duration);
}

function displayRandomTestimonial() {
    $('#testimonials blockquote').hide()

    var numTestimonials = $('#testimonials > blockquote').length;
    var ran = Math.floor(Math.random()*numTestimonials) + 1;
    $('#testimonials blockquote:nth-child(' + ran + ')').show();

}

/*
 * Set up preview images on home page
 * TODO not used anymore (we removed popeye lib)
 */

function setUpPopEye(){

    var hovering=false;
    var maxNextClicks = $('#ppy2 li').length * 2;

    $(".ppy").hover(
        function() {
            hovering = true;
            $('.ppy-caption').show();
        },
        function() {
            hovering = false;
        }
    );

    setInterval(function(){
        if(!$("#custom_case_set_dialog").dialog("isOpen") &&
        		!hovering && maxNextClicks >0)
        {
            maxNextClicks--;
            $('a.ppy-next').click();
            $('.ppy-caption').hide();
        }
    }, 3000);
}

function clinical(){
    $('#tabs ul li:eq(3) a').click(function(){
        $('#clinical img').hide();
        $('#clinical img').each(function(){
            $(this).load(function(){
                $('#clinical img').fadeIn('normal', hideClinicalLoader());
            });
        });

        function hideClinicalLoader() {
            //hide loader image and remove load div
            $('#load').delay(500).fadeOut('normal').$('#clinical div#load').remove();
        }

    });
}

/*
This function accepts as arguments the URL to be shortened,
our bitly user name and bitly API key (user and key are
stored in properties file)
 */
function bitlyURL(fullURL){

    /*
        when testing locally use 127.0.0.1 instead of localhost
        in your browser location bar.
        bitly: can not encode URI component when localhost is in URL
     */

    var defaults = {
        version: '3.0',
        history: '0',
        longURL: encodeURIComponent(fullURL)
    };

    //build call to web API
    var qurl = "api/proxy/bitly?"
    +"version="+defaults.version
    +"&longUrl="+defaults.longURL
    +"&history="+defaults.history
    +"&format=json&callback=?";

    // get JSON data, extract from it the new short URL and
    // append the short URL to div with id 'bitly'
    $.getJSON(qurl, function(data){
        if (data.results == null){
            $('#bitly').html("An unknown error occurred. Unable to shorten your URL.");
        }  else {
            $('#bitly').html("
" +
                    data.results[fullURL].shortUrl + "
");
        }
    }).fail(function() {
        $('#bitly').html("An unknown error occurred. Unable to shorten your URL.");
    });
}

function addURLBookmark() {
    displayBookmark(window.location.href, window.location.href.split("?")[0] + "?...");
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function getSessionServiceBookmark(fullURL, sessionJSON, callback) {
    // if user got here with a bookmark, just return that, don't create a bookmark of a bookmark
    var bookmarkPattern = /session_id=/
    if (bookmarkPattern.test(fullURL)) {
        callback(fullURL);
    } else {
        // cross_cancer.do has additional information in URL as #crosscancer/:tab/:priority/:genes/:study_list
        // check for that
        var additional_info = fullURL.split("#");
        if (additional_info.length == 2) {
            sessionJSON["url_hash_data"] = [additional_info[1]]; // must be an array like rest of parameter map
        }
        var bookmark = null;
        $.ajax({
            type: 'POST',
            url: 'api/proxy/session-service/main_session',
            dataType: 'json',
            contentType: 'application/json',
            data: JSON.stringify(sessionJSON)
        }).done(function(data) {
            if (data['id'] !== null) {
                var bookmark = fullURL.split("?")[0] + "?session_id=" + data['id'];
                callback(bookmark);
            }
        });
    }
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function addSessionServiceBookmark(fullURL, sessionJSON) {
    getSessionServiceBookmark(fullURL, sessionJSON, displayBookmark);
}

/*
This function accepts as an argument the session
to be saved as a JSON string
*/
function changeURLToSessionServiceURL(fullURL, pageTitle, sessionJSON) {
    getSessionServiceBookmark(fullURL, sessionJSON, function(bookmark) {
        window.history.pushState({ "html": fullURL, "pageTitle": pageTitle }, "", bookmark);
    });
}

function displayBookmark(bookmarkURL) {
    if (bookmarkURL === null){
        $('#session-id').html("An unknown error occurred. Unable to store your session.");
    } else {
        $("#session-id").html("" + bookmarkURL + "");
        bitlyURL(bookmarkURL);
    }
}
<|endoftext|>


<commit_before>import axios from 'axios';
import qs from 'querystring';
import path from 'path';

export default function(req, res) {
  const term = req.query.text.trim();
  // CREATE QUERY STRING AND MAKE REQUEST TO OPEN WEATHER MAP API
  const searchUrl = 'http://api.openweathermap.org/data/2.5/weather?';
  const parameters = {
    q: term,
    units: 'imperial',
    appid: process.env.OPEN_WEATHER_MAP_KEY
  };
  const paramUrl = qs.stringify(parameters);
  const apiUrl = searchUrl + paramUrl;
  axios.get(apiUrl)
    .then((response) => {
      const data = response.data;
      const icon = data.weather[0].icon + 'png';
      const width = 600;
      const imageUrl = '';
      const html = ` Temp: ${data.main.temp} High: ${data.main.temp_max} Low: ${data.main.temp_min} Description: ${data.weather[0].description}`;
      res.json({
        body: ' \n' + data.main.temp + '\n' + data.weather[0].description
      });
    })
    .catch((err) => { console.log(`Error: ${err}`); });
}<commit_msg>chores/ updated template<commit_after>import axios from 'axios';
import qs from 'querystring';
import path from 'path';

export default function(req, res) {
  const term = req.query.text.trim();
  // CREATE QUERY STRING AND MAKE REQUEST TO OPEN WEATHER MAP API
  const searchUrl = 'http://api.openweathermap.org/data/2.5/weather?';
  const parameters = {
    q: term,
    units: 'imperial',
    appid: process.env.OPEN_WEATHER_MAP_KEY
  };
  const paramUrl = qs.stringify(parameters);
  const apiUrl = searchUrl + paramUrl;
  axios.get(apiUrl)
    .then((response) => {
      const data = response.data;
      const icon = data.weather[0].icon + 'png';
      const width = 600;
      const imageUrl = '';
      const html = ` Temp: ${data.main.temp} High: ${data.main.temp_max} Low: ${data.main.temp_min} Description: ${data.weather[0].description}`;
      res.json({
        body: ' \n' + 'Temp: ' + data.main.temp + '\nDescription: ' + data.weather[0].description
      });
    })
    .catch((err) => { console.log(`Error: ${err}`); });
}<|endoftext|>


<commit_before>'use babel';
/* @flow */

/**
* Compile Data With Template
*
* The MIT License (MIT)
* Copyright (c) 2014 Equan Pr.
*/
'use strict';

var TEMPLATE_INDEX = 'template/index.hbs';
var STATIC_FOLDER = 'static';

var fs = require('fs');
var handlebars = require('handlebars');
var mkdirp = require('mkdirp');
var root = require('../util').path();
var static_folder = `${root}/${STATIC_FOLDER}/`;
var { genFilename } = require('./helper');

import type { Post, PostCreated, PostDocument } from './types.js';

function compile(docData:Post): Promise {
    return new Promise((resolve, reject) => {

        var { title, postCreated } = docData;

        fs.readFile(`${root}/${TEMPLATE_INDEX}`, 'utf-8', (err, data) => {
            var pageBuilder = handlebars.compile(data);

            var dateCreated:PostCreated = {
                year: postCreated.getFullYear(),
                month: postCreated.getMonth(),
                date: postCreated.getDate()
            };

            var docContent:PostDocument = {
                filename: `${genFilename(title)}.html`,
                compiledContent: pageBuilder(docData),
                postCreated: dateCreated,
                post: docData
            };

            saveCompiled(docContent).then((status) => {
                resolve(status);
            }, (err) => {
                reject(err);
            })
        });
    });
}

function saveCompiled(data: PostDocument): Promise {
    var { filename, postCreated: { year: y, month: m, date: d}, compiledContent, post:{title:postTitle, status: postStatus, postCreated: pCreated}} = data;
    var postDir = `${static_folder}/${y}/${m}/${d}`;
    var filepath = `${postDir}/${filename}`;

    return new Promise((resolve, reject) => {
        mkdirp(postDir, (err) => {
            if(!err) {
                fs.writeFile(filepath, compiledContent, (err) => {
                    if(err) {
                        reject(err);
                    } else {
                        resolve({
                            title: postTitle,
                            status: postStatus,
                            created: pCreated
                        });
                    }
                });
            } else {
                console.log(err);
                return null;
            }
       });
    });
}

module.exports = { compile, saveCompiled };<commit_msg>add filename key to output<commit_after>'use babel';
/* @flow */

/**
* Compile Data With Template
*
* The MIT License (MIT)
* Copyright (c) 2014 Equan Pr.
*/
'use strict';

var TEMPLATE_INDEX = 'template/index.hbs';
var STATIC_FOLDER = 'static';

var fs = require('fs');
var handlebars = require('handlebars');
var mkdirp = require('mkdirp');
var root = require('../util').path();
var static_folder = `${root}/${STATIC_FOLDER}/`;
var { genFilename, cleanHtmlTags } = require('./helper');

import type { Post, PostCreated, PostDocument } from './types.js';

function compile(docData:Post): Promise {
    return new Promise((resolve, reject) => {

        var { title, postCreated } = docData;

        fs.readFile(`${root}/${TEMPLATE_INDEX}`, 'utf-8', (err, data) => {
            var pageBuilder = handlebars.compile(data);

            var dateCreated:PostCreated = {
                year: postCreated.getFullYear(),
                month: postCreated.getMonth(),
                date: postCreated.getDate()
            };

            var docContent:PostDocument = {
                filename: `${genFilename(title)}.html`,
                compiledContent: pageBuilder(docData),
                postCreated: dateCreated,
                post: docData
            };

            saveCompiled(docContent).then((status) => {
                resolve(status);
            }, (err) => {
                reject(err);
            })
        });
    });
}

function saveCompiled(data: PostDocument): Promise {
    var { filename, postCreated: { year: y, month: m, date: d}, compiledContent, post:{title:postTitle, status: postStatus, postCreated: pCreated}} = data;
    var postDir = `${static_folder}/${y}/${m}/${d}`;
    var filepath = `${postDir}/${filename}`;

    return new Promise((resolve, reject) => {
        mkdirp(postDir, (err) => {
            if(!err) {
                fs.writeFile(filepath, compiledContent, (err) => {
                    if(err) {
                        reject(err);
                    } else {
                        resolve({
                            title: cleanHtmlTags(postTitle),
                            status: postStatus,
                            created: pCreated,
                            filename: filename
                        });
                    }
                });
            } else {
                console.log(err);
                return null;
            }
       });
    });
}

module.exports = { compile, saveCompiled };<|endoftext|>


<commit_before>var urlJoin = Npm.require('url-join');

// Global for tests.
parseMacDownloadUrl = function(electronSettings) {
  if (!electronSettings || !electronSettings.downloadUrls || !electronSettings.downloadUrls.darwin) return;

  return electronSettings.downloadUrls.darwin.replace('{{version}}', electronSettings.version);
};

// Global for tests.
parseWindowsDownloadUrls = function(electronSettings) {
  if (!electronSettings || !electronSettings.downloadUrls || !electronSettings.downloadUrls.win32) return;

  // The default value here is what `createBinaries` writes into the app's package.json, which is
  // what is read by `grunt-electron-installer` to name the installer.
  var appName = electronSettings.name || 'electron';

  var releasesUrl, installerUrl;
  var installerUrlIsVersioned = false;

  if (_.isString(electronSettings.downloadUrls.win32)) {
    if (electronSettings.downloadUrls.win32.indexOf('{{version}}') > -1) {
      console.error('Only the Windows installer URL may be versioned. Specify `downloadUrls.win32.installer`.');
      return;
    }
    releasesUrl = electronSettings.downloadUrls.win32;
    // 'AppSetup.exe' refers to the output of `grunt-electron-installer`.
    installerUrl = urlJoin(electronSettings.downloadUrls.win32, appName + 'Setup.exe');
  } else {
    releasesUrl = electronSettings.downloadUrls.win32.releases;
    if (releasesUrl.indexOf('{{version}}') > -1) {
      console.error('Only the Windows installer URL may be versioned.');
      return;
    }
    installerUrl = electronSettings.downloadUrls.win32.installer;
    if (installerUrl.indexOf('{{version}}') > -1) {
      installerUrl = installerUrl.replace('{{version}}', electronSettings.version);
      installerUrlIsVersioned = true;
    }
  }

  // Cachebust the installer URL if it's not versioned.
  // (The releases URL will also be cachebusted, but by `serveDownloadUrl` since we've got to append
  // the particular paths requested by the client).
  if (!installerUrlIsVersioned) {
    installerUrl = cachebustedUrl(installerUrl);
  }

  return {
    releases: releasesUrl,
    installer: installerUrl
  };
};

function cachebustedUrl(url) {
  var querySeparator = (url.indexOf('?') > -1) ? '&' : '?';
  return url + querySeparator + 'cb=' + Date.now();
}

DOWNLOAD_URLS = {
  darwin: parseMacDownloadUrl(Meteor.settings.electron),
  win32: parseWindowsDownloadUrls(Meteor.settings.electron)
};
<commit_msg>Fix typo<commit_after>var urlJoin = Npm.require('url-join');

// Global for tests.
parseMacDownloadUrl = function(electronSettings) {
  if (!electronSettings || !electronSettings.downloadUrls || !electronSettings.downloadUrls.darwin) return;

  return electronSettings.downloadUrls.darwin.replace('{{version}}', electronSettings.version);
};

// Global for tests.
parseWindowsDownloadUrls = function(electronSettings) {
  if (!electronSettings || !electronSettings.downloadUrls || !electronSettings.downloadUrls.win32) return;

  // The default value here is what `createBinaries` writes into the app's package.json, which is
  // what is read by `grunt-electron-installer` to name the installer.
  var appName = electronSettings.name || 'electron';

  var releasesUrl, installerUrl;
  var installerUrlIsVersioned = false;

  if (_.isString(electronSettings.downloadUrls.win32)) {
    if (electronSettings.downloadUrls.win32.indexOf('{{version}}') > -1) {
      console.error('Only the Windows installer URL may be versioned. Specify `downloadUrls.win32.installer`.');
      return;
    }
    releasesUrl = electronSettings.downloadUrls.win32;
    // 'AppSetup.exe' refers to the output of `grunt-electron-installer`.
    installerUrl = urlJoin(electronSettings.downloadUrls.win32, appName + 'Setup.exe');
  } else {
    releasesUrl = electronSettings.downloadUrls.win32.releases;
    if (releasesUrl.indexOf('{{version}}') > -1) {
      console.error('Only the Windows installer URL may be versioned.');
      return;
    }
    installerUrl = electronSettings.downloadUrls.win32.installer;
    if (installerUrl.indexOf('{{version}}') > -1) {
      installerUrl = installerUrl.replace('{{version}}', electronSettings.version);
      installerUrlIsVersioned = true;
    }
  }

  // Cachebust the installer URL if it's not versioned.
  // (The releases URL will also be cachebusted, but by `serveUpdateFeed` since we've got to append
  // the particular paths requested by the client).
  if (!installerUrlIsVersioned) {
    installerUrl = cachebustedUrl(installerUrl);
  }

  return {
    releases: releasesUrl,
    installer: installerUrl
  };
};

function cachebustedUrl(url) {
  var querySeparator = (url.indexOf('?') > -1) ? '&' : '?';
  return url + querySeparator + 'cb=' + Date.now();
}

DOWNLOAD_URLS = {
  darwin: parseMacDownloadUrl(Meteor.settings.electron),
  win32: parseWindowsDownloadUrls(Meteor.settings.electron)
};
<|endoftext|>


<commit_before>/**********************************************************************
Game Session

The game session has slots for players and steps through the phases of
a game.

//********************************************************************/

function GameSession(original_images) {
    this.slots = [undefined];
    this.available_slots = [0];
    // let's just always use this.original_images[0] as the real original image
    this.original_images = original_images;
};

GameSession.prototype = {
    get_available_slots: function() {
        return this.available_slots;
    },
    get_next_available_slot: function() {
        return this.available_slots.length > 0 ? this.available_slots[0] : -1;
        //for (var i = 0; i < this.slots.length; ++i) {
        //    if (!this.slots[i]) {
        //        return i;
        //    }
        //}
        //return -1;
    },
    player_is_in_slot: function(player, slot_idx) {
        return this.slots[slot_idx] && this.slots[slot_idx].player == player;
    },
    assign_player_to_slot: function(player, slot_idx) {
        if (slot_idx in this.slots && slot_idx in this.get_available_slots()) {
            this.slots[slot_idx] = { player: player };
            // remove available_slot at idx
            this.available_slots.splice(this.available_slots.indexOf(slot_idx), 1);
        }
        return this.player_is_in_slot(player, slot_idx);
    },
    // expand: function(num_new_slots) {
    //     for (var i = 0; i < num_new_slots; i++) {
    //         this.available_slots.push(this.slots.length + i);
    //     }
    //     this.slots.length += num_new_slots;
    // },
    // expand_row: function() {
    //     this.expand(this.slots.length);
    // },
    expand_children: function(slotIdx) {
        var first_child_index = this.get_index_of_first_child(slotIdx);
        this.available_slots.push(first_child_index);
        console.log('this.slots: ' + this.slots)
        // console.log('this.slots[first_child_index]: ' + this.slots[first_child_index])
        this.slots[first_child_index] = {};
        this.slots[first_child_index] = null;
        this.available_slots.push(first_child_index + 1);
        this.slots[first_child_index + 1] = {};
        this.slots[first_child_index + 1] = null;
    },
    get_index_of_parent: function(slotIdx) {
        return Math.ceil(slotIdx/2) - 1;
    },
    get_index_of_first_child: function(slotIdx) {
        return slotIdx*2 + 1;
    },
    get_index_of_grandparent: function(slotIdx) {
        parent_index = this.get_index_of_parent(slotIdx);
        return this.get_index_of_parent(parent_index);
    },
    get_index_of_first_grandchild: function(slotIdx) {
        child_index = this.get_index_of_first_child(slotIdx);
        return this.get_index_of_first_child(child_index);
    },
    has_player_in_slot: function(player) {
        for (var slotIdx = 0; slotIdx < this.slots.length; ++slotIdx) {
            if (this.slots[slotIdx] && this.slots[slotIdx].player == player) {
                return true;
            }
        }
        return false;
    },
    get_player_slot_index: function(player) {
        for (var slotIdx = 0; slotIdx < this.slots.length; ++slotIdx) {
            if (this.slots[slotIdx] && this.slots[slotIdx].player == player) {
                return slotIdx;
            }
        }
        return -1;
    },
    save_image_to_slot: function(slot_idx, image_path) {
        this.slots[slot_idx].image_path = image_path;
        console.log('this.slots', this.slots);
        this.expand_children(slot_idx);
    }
};

module.exports = GameSession;
<commit_msg>Removed some log spam.<commit_after>/**********************************************************************
Game Session

The game session has slots for players and steps through the phases of
a game.

//********************************************************************/

function GameSession(original_images) {
    this.slots = [undefined];
    this.available_slots = [0];
    // let's just always use this.original_images[0] as the real original image
    this.original_images = original_images;
};

GameSession.prototype = {
    get_available_slots: function() {
        return this.available_slots;
    },
    get_next_available_slot: function() {
        return this.available_slots.length > 0 ? this.available_slots[0] : -1;
        //for (var i = 0; i < this.slots.length; ++i) {
        //    if (!this.slots[i]) {
        //        return i;
        //    }
        //}
        //return -1;
    },
    player_is_in_slot: function(player, slot_idx) {
        return this.slots[slot_idx] && this.slots[slot_idx].player == player;
    },
    assign_player_to_slot: function(player, slot_idx) {
        if (slot_idx in this.slots && slot_idx in this.get_available_slots()) {
            this.slots[slot_idx] = { player: player };
            // remove available_slot at idx
            this.available_slots.splice(this.available_slots.indexOf(slot_idx), 1);
        }
        return this.player_is_in_slot(player, slot_idx);
    },
    // expand: function(num_new_slots) {
    //     for (var i = 0; i < num_new_slots; i++) {
    //         this.available_slots.push(this.slots.length + i);
    //     }
    //     this.slots.length += num_new_slots;
    // },
    // expand_row: function() {
    //     this.expand(this.slots.length);
    // },
    expand_children: function(slotIdx) {
        var first_child_index = this.get_index_of_first_child(slotIdx);
        this.available_slots.push(first_child_index);
        // console.log('this.slots: ' + this.slots)
        // console.log('this.slots[first_child_index]: ' + this.slots[first_child_index])
        this.slots[first_child_index] = {};
        this.slots[first_child_index] = null;
        this.available_slots.push(first_child_index + 1);
        this.slots[first_child_index + 1] = {};
        this.slots[first_child_index + 1] = null;
    },
    get_index_of_parent: function(slotIdx) {
        return Math.ceil(slotIdx/2) - 1;
    },
    get_index_of_first_child: function(slotIdx) {
        return slotIdx*2 + 1;
    },
    get_index_of_grandparent: function(slotIdx) {
        parent_index = this.get_index_of_parent(slotIdx);
        return this.get_index_of_parent(parent_index);
    },
    get_index_of_first_grandchild: function(slotIdx) {
        child_index = this.get_index_of_first_child(slotIdx);
        return this.get_index_of_first_child(child_index);
    },
    has_player_in_slot: function(player) {
        for (var slotIdx = 0; slotIdx < this.slots.length; ++slotIdx) {
            if (this.slots[slotIdx] && this.slots[slotIdx].player == player) {
                return true;
            }
        }
        return false;
    },
    get_player_slot_index: function(player) {
        for (var slotIdx = 0; slotIdx < this.slots.length; ++slotIdx) {
            if (this.slots[slotIdx] && this.slots[slotIdx].player == player) {
                return slotIdx;
            }
        }
        return -1;
    },
    save_image_to_slot: function(slot_idx, image_path) {
        this.slots[slot_idx].image_path = image_path;
        // console.log('this.slots', this.slots);
        this.expand_children(slot_idx);
    }
};

module.exports = GameSession;
<|endoftext|>


<commit_before>var
  _ = require('lodash'),
  q = require('q'),
  InternalError = require('../../errors/internalError'),
  RequestObject = require('../requestObject'),
  ResponseObject = require('../responseObject');

function Repository (kuzzle, options) {
  this.collection = options.collection;
  this.ttl = options.ttl || kuzzle.config.repositories.cacheTTL;
  this.ObjectConstructor = options.ObjectConstructor;

  this.readEngine = options.readEngine || kuzzle.services.list.readEngine;
  this.writeEngine = options.writeEngine || kuzzle.services.list.writeEngine;
  this.cacheEngine = options.cacheEngine || kuzzle.services.list.internalCache;
}

/**
 *
 * @param {string} id
 * @returns {Promise} resolves on a new ObjectConstructor()
 */
Repository.prototype.loadOneFromDatabase = function (id) {
  var
    deferred = q.defer(),
    requestObject,
    result;

  requestObject = new RequestObject({
    controller: 'read',
    action: 'get',
    collection: this.collection,
    body: {
      _id: id
    }
  });

  this.readEngine.get(requestObject)
    .then(function (response) {
      if (response.data) {
        result = new this.ObjectConstructor();
        deferred.resolve(this.hydrate(result, response));
      }
      else {
        deferred.resolve(null);
      }
    }.bind(this))
    .catch(function (error) {
      if (error.status === 404) {
        // no content found, we return null without failing
        deferred.resolve(null);
      }
      else {
        deferred.reject(error);
      }
    });

  return deferred.promise;
};

/**
 *
 * @param ids
 * @returns {*|promise}
 */
Repository.prototype.loadMultiFromDatabase = function (ids) {
  var
    deferred = q.defer(),
    requestObject,
    promises;

  requestObject = new RequestObject({
    controller: 'read',
    action: 'mget',
    collection: this.collection,
    body: {
      ids: ids
    }
  });

  this.readEngine.mget(requestObject)
    .then(function (response) {
      promises = [];

      response.data.docs.forEach(function (document) {
        var
          object,
          data;

        if (document.found) {
          object = new this.ObjectConstructor();
          data = _.extend({}, document._source);
          data._id = document._id;

          promises.push(this.hydrate(object, data));
        }
      }.bind(this));

      deferred.resolve(q.all(promises));
    }.bind(this))
    .catch(function (error) {
      deferred.reject(error);
    });

  return deferred.promise;
};

/**
 * Loads an object from Cache. Returns a promise that resolves either to the
 * retrieved object of null in case it is not found.
 *
 * The opts object currently accepts one optional parameter: key, which forces
 * the cache key to fetch.
 * In case the key is not provided, it defauls to <collection>/id, i.e.: _kuzzle/users/12
 *
 * @param {String} id The id of the object to get
 * @param {Object} opts Optional options.
 * @returns {Promise}
 */
Repository.prototype.loadFromCache = function (id, opts) {
  var
    deferred = q.defer(),
    options = opts || {},
    key = options.key || this.collection + '/' + id;

  this.cacheEngine.get(key)
    .then(function (response) {
      var object = new this.ObjectConstructor();

      if (response === null) {
        deferred.resolve(null);
        return;
      }

      this.hydrate(object, response)
        .then(function (result) {
          deferred.resolve(result);
        })
        .catch(function (error) {
          deferred.reject(error);
        });
    }.bind(this))
    .catch(function (error) {
      deferred.reject(error);
    });

  return deferred.promise;
};

/**
 * From a poco object, hydrate an ObjectConstructor one.
 *
 * @param {Object} object The Object to be hydrated
 * @param {Object} data The Plain object to  take the values from
 * @returns {Promise}
 */
Repository.prototype.hydrate = function (object, data) {
  var
    deferred = q.defer(),
    o = {};

  if (data instanceof ResponseObject) {
    o = _.extend(o, data.toJson()._source);
    Object.keys(data.data).forEach(function (key) {
      if (key !== 'body') {
        o[key] = data.data[key];
      }
    });
  }
  else {
    o = data;
  }

  if (!_.isObject(o)) {
    deferred.reject(new InternalError('Error hydrating object ' + object.toString() + '. Data parameter is not an object'));
  }

  Object.keys(o).forEach(function (key) {
    object[key] = o[key];
  });
  deferred.resolve(object);

  return deferred.promise;
};

/**
 * Persists the given object in the collection that is attached to the repository.
 *
 * @param {ObjectConstructor} object The object to persist
 * @returns {Promise}
 */
Repository.prototype.persistToDatabase = function (object) {
  var requestObject = new RequestObject({
    controller: 'write',
    action: 'createOrUpdate',
    collection: this.collection,
    body: this.serializeToDatabase(object)
  });

  return this.writeEngine.createOrUpdate(requestObject);
};

/**
 * Persists the given ObjectConstructor object in cache.
 * The opts optional parameters currently accept 2 options:
 *   key: if provided, stores the object to the given key instead of the default one (<collection>/<id>)
 *   ttl: if provided, overrides the default ttl set on the repository for the current operation.
 *
 * @param {Object} object the object to persist
 * @param {Object} opts optional options for the current operation
 * @returns {Promise}
 */
Repository.prototype.persistToCache = function (object, opts) {
  var
    options = opts || {},
    key = options.key || this.collection + '/' + object._id,
    ttl = this.ttl;

  if (options.ttl !== undefined) {
    ttl = options.ttl;
  }

  if (ttl === false) {
    return this.cacheEngine.set(key, this.serializeToCache(object));
  }

  return this.cacheEngine.volatileSet(key, this.serializeToCache(object), ttl);
};

Repository.prototype.refreshCacheTTL = function (object, opts) {
  var
    options = opts || {},
    key = options.key || this.collection + '/' + object._id,
    ttl = this.ttl;

  if (options.ttl !== undefined) {
    ttl = options.ttl;
  }

  if (ttl === false) {
    return this.cacheEngine.persist(key);
  }

  return this.cacheEngine.expire(key, ttl);
};

/**
 * Serializes the object before being persisted to cache.
 *
 * @param {Object} object The object to serialize
 * @returns {Object}
 */
Repository.prototype.serializeToCache = function (object) {
  return object;
};

/**
 * Serializes the object before being persisted to the database.
 *
 * @param {Object} object The object to serialize
 * @returns {Object}
 */
Repository.prototype.serializeToDatabase = function (object) {
  return object;
};

module.exports = Repository;
<commit_msg>Add a global "load" function in asbtract repository<commit_after>var
  _ = require('lodash'),
  q = require('q'),
  InternalError = require('../../errors/internalError'),
  RequestObject = require('../requestObject'),
  ResponseObject = require('../responseObject');

function Repository (kuzzle, options) {
  this.collection = options.collection;
  this.ttl = options.ttl || kuzzle.config.repositories.cacheTTL;
  this.ObjectConstructor = options.ObjectConstructor;

  this.readEngine = options.readEngine || kuzzle.services.list.readEngine;
  this.writeEngine = options.writeEngine || kuzzle.services.list.writeEngine;
  this.cacheEngine = options.cacheEngine || kuzzle.services.list.internalCache;
}

/**
 *
 * @param {string} id
 * @returns {Promise} resolves on a new ObjectConstructor()
 */
Repository.prototype.loadOneFromDatabase = function (id) {
  var
    deferred = q.defer(),
    requestObject,
    result;

  requestObject = new RequestObject({
    controller: 'read',
    action: 'get',
    collection: this.collection,
    body: {
      _id: id
    }
  });

  this.readEngine.get(requestObject)
    .then(function (response) {
      if (response.data) {
        result = new this.ObjectConstructor();
        deferred.resolve(this.hydrate(result, response));
      }
      else {
        deferred.resolve(null);
      }
    }.bind(this))
    .catch(function (error) {
      if (error.status === 404) {
        // no content found, we return null without failing
        deferred.resolve(null);
      }
      else {
        deferred.reject(error);
      }
    });

  return deferred.promise;
};

/**
 *
 * @param ids
 * @returns {*|promise}
 */
Repository.prototype.loadMultiFromDatabase = function (ids) {
  var
    deferred = q.defer(),
    requestObject,
    promises;

  requestObject = new RequestObject({
    controller: 'read',
    action: 'mget',
    collection: this.collection,
    body: {
      ids: ids
    }
  });

  this.readEngine.mget(requestObject)
    .then(function (response) {
      promises = [];

      response.data.docs.forEach(function (document) {
        var
          object,
          data;

        if (document.found) {
          object = new this.ObjectConstructor();
          data = _.extend({}, document._source);
          data._id = document._id;

          promises.push(this.hydrate(object, data));
        }
      }.bind(this));

      deferred.resolve(q.all(promises));
    }.bind(this))
    .catch(function (error) {
      deferred.reject(error);
    });

  return deferred.promise;
};

/**
 * Loads an object from Cache. Returns a promise that resolves either to the
 * retrieved object of null in case it is not found.
 *
 * The opts object currently accepts one optional parameter: key, which forces
 * the cache key to fetch.
 * In case the key is not provided, it defauls to <collection>/id, i.e.: _kuzzle/users/12
 *
 * @param {String} id The id of the object to get
 * @param {Object} opts Optional options.
 * @returns {Promise}
 */
Repository.prototype.loadFromCache = function (id, opts) {
  var
    deferred = q.defer(),
    options = opts || {},
    key = options.key || this.collection + '/' + id;

  this.cacheEngine.get(key)
    .then(function (response) {
      var object = new this.ObjectConstructor();

      if (response === null) {
        deferred.resolve(null);
        return;
      }

      this.hydrate(object, response)
        .then(function (result) {
          deferred.resolve(result);
        })
        .catch(function (error) {
          deferred.reject(error);
        });
    }.bind(this))
    .catch(function (error) {
      deferred.reject(error);
    });

  return deferred.promise;
};

/**
 * Loads an object from Cache or from the Database if not available in Cache.
 * Returns a promise that resolves either to the
 * retrieved object of null in case it is not found.
 *
 * If the object is not found in Cache and found in the Database,
 * it will be written to cache also.
 *
 * The opts object currently accepts one optional parameter: key, which forces
 * the cache key to fetch.
 * In case the key is not provided, it defauls to <collection>/id, i.e.: _kuzzle/users/12
 *
 * @param {String} id The id of the object to get
 * @param {Object} opts Optional options.
 * @returns {Promise}
 */
Repository.prototype.load = function (id, opts) {
  var
    deferred = q.defer(),
    error;

  try {
    this.loadFromCache(id, opts)
      .then(function (object) {
        if (object === null) {
          this.loadOneFromDatabase(id)
            .then(function (objectFromDatabase) {
              if (objectFromDatabase !== null) {
                this.persistToCache(objectFromDatabase);
              }
              deferred.resolve(objectFromDatabase);
            }.bind(this))
            .catch(function (err) {
              deferred.reject(err);
            });
        }
        else {
          this.refreshCacheTTL(object);
          deferred.resolve(object);
        }
      }.bind(this))
      .catch(function (err) {
        deferred.reject(err);
      });
  }
  catch (err) {
    error = new InternalError('Error loading Object');
    error.details = err;
    deferred.reject(error);
  }
  return deferred.promise;
};

/**
 * From a poco object, hydrate an ObjectConstructor one.
 *
 * @param {Object} object The Object to be hydrated
 * @param {Object} data The Plain object to  take the values from
 * @returns {Promise}
 */
Repository.prototype.hydrate = function (object, data) {
  var
    deferred = q.defer(),
    o = {};

  if (data instanceof ResponseObject) {
    o = _.extend(o, data.toJson()._source);
    Object.keys(data.data).forEach(function (key) {
      if (key !== 'body') {
        o[key] = data.data[key];
      }
    });
  }
  else {
    o = data;
  }

  if (!_.isObject(o)) {
    deferred.reject(new InternalError('Error hydrating object ' + object.toString() + '. Data parameter is not an object'));
  }

  Object.keys(o).forEach(function (key) {
    object[key] = o[key];
  });
  deferred.resolve(object);

  return deferred.promise;
};

/**
 * Persists the given object in the collection that is attached to the repository.
 *
 * @param {ObjectConstructor} object The object to persist
 * @returns {Promise}
 */
Repository.prototype.persistToDatabase = function (object) {
  var requestObject = new RequestObject({
    controller: 'write',
    action: 'createOrUpdate',
    collection: this.collection,
    body: this.serializeToDatabase(object)
  });

  return this.writeEngine.createOrUpdate(requestObject);
};

/**
 * Persists the given ObjectConstructor object in cache.
 * The opts optional parameters currently accept 2 options:
 *   key: if provided, stores the object to the given key instead of the default one (<collection>/<id>)
 *   ttl: if provided, overrides the default ttl set on the repository for the current operation.
 *
 * @param {Object} object the object to persist
 * @param {Object} opts optional options for the current operation
 * @returns {Promise}
 */
Repository.prototype.persistToCache = function (object, opts) {
  var
    options = opts || {},
    key = options.key || this.collection + '/' + object._id,
    ttl = this.ttl;

  if (options.ttl !== undefined) {
    ttl = options.ttl;
  }

  if (ttl === false) {
    return this.cacheEngine.set(key, this.serializeToCache(object));
  }

  return this.cacheEngine.volatileSet(key, this.serializeToCache(object), ttl);
};

Repository.prototype.refreshCacheTTL = function (object, opts) {
  var
    options = opts || {},
    key = options.key || this.collection + '/' + object._id,
    ttl = this.ttl;

  if (options.ttl !== undefined) {
    ttl = options.ttl;
  }

  if (ttl === false) {
    return this.cacheEngine.persist(key);
  }

  return this.cacheEngine.expire(key, ttl);
};

/**
 * Serializes the object before being persisted to cache.
 *
 * @param {Object} object The object to serialize
 * @returns {Object}
 */
Repository.prototype.serializeToCache = function (object) {
  return object;
};

/**
 * Serializes the object before being persisted to the database.
 *
 * @param {Object} object The object to serialize
 * @returns {Object}
 */
Repository.prototype.serializeToDatabase = function (object) {
  return object;
};

module.exports = Repository;
<|endoftext|>


<commit_before>(function (win) {

  function stripControlSequences(text) {
    return text.replace(/\x1B\[[0-9]{0,5}m/g, '');
  }

  function createStartFn(karma) {
    return function () {
      win.startTests();
      console.log(win.stdout_buffer.map(stripControlSequences).join("\n"));

      karma.complete({});
    };
  }

  function createDumpFn(karma, serialize) {
    return function () {
      karma.info({dump: [].slice.call(arguments) });
    };
  }

  win.__karma__.start = createStartFn(win.__karma__);
  win.dump = createDumpFn(win.__karma__, function (value) {
    return value;
  });
})(window);
<commit_msg>One step closer to parsing results into Karma<commit_after>(function (win) {

  function stripControlSequences(text) {
    return text.replace(/\x1B\[[0-9]{0,5}m/g, '');
  }

  function parseResults(karma, resultBuffer) {
  }

  function createStartFn(karma) {
    return function () {
      win.startTests();
      parseResults(karma, win.stdout_buffer);

      karma.complete({});
    };
  }

  function createDumpFn(karma, serialize) {
    return function () {
      karma.info({dump: [].slice.call(arguments) });
    };
  }

  win.__karma__.start = createStartFn(win.__karma__);
  win.dump = createDumpFn(win.__karma__, function (value) {
    return value;
  });
})(window);
<|endoftext|>