<commit_before>var _ = require('lodash'),

    nonObjectCriteriaTypes = { // object to validate types of wrapper fn
        string: true,
        number: true,
        boolean: true
    },

    E = '',
    H = '-',
    rnd = Math.random,

    util; // exports

util = {
    /**
     * Deep clone an object.
     *
     * @param {object} obj
     * @returns {object}
     */
    clone: function (obj) {
        return _.cloneDeep(obj);
    },

    /**
     * Performs shallow copy of one object into another.
     *
     * @param {object} recipient
     * @param {object} donor
     * @returns {object} - returns the seeded recipient parameter
     */
    extend: function (recipient, donor) {
        for (var prop in donor) {
            donor.hasOwnProperty(prop) && (recipient[prop] = donor[prop]);
        }
        return recipient;
    },

    /**
     * Shallow copies all non-existing properties from donor to recipient
     *
     * @param {object} recipient
     * @param {object} donor
     * @returns {object} - returns the seeded recipient parameter
     */
    fill: function (recipient, donor) {
        for (var prop in donor) {
            !recipient.hasOwnProperty(prop) && (recipient[prop] = donor[prop]);
        }
        return recipient;
    },

    /**
     * Useful function to iterate on array or object with almost same API.
     *
     * @param {object|array} obj
     * @param {function} iter
     * @param {object|function} [scope]
     * @returns {object|array} - the original object passed is returned for chaining.
     */
    each: function (obj, iter, scope) {
        var i,
            ii;

        !scope && (scope === obj);

        // proceed only when object passed is truly an object (array too is an object, in case it wasn't clear.)
        if (typeof obj !== 'object') {
            return obj;
        }

        if (_.isArray(obj) || _.isArguments(obj)) {
            for (i = 0, ii = obj.length; i < ii; i++) {
                if (iter.call(scope, obj[i], i, obj) === false) {
                    return obj;
                }
            }
        }
        else {
            for (i in obj) {
                if (obj.hasOwnProperty(i)) {
                    if (iter.call(scope, obj[i], i, obj) === false) {
                        return obj;
                    }
                }
            }
        }
        return obj;
    },

    /**
     * Returns unique GUID on every call as per pseudo-number RFC4122 standards.
     *
     * @type {function}
     * @returns {string}
     */
    uid: function () {
        var n, r; // r = result , n = numeric variable for positional checks

        // if "n" is not 9 or 14 or 19 or 24 return a random number or 4
        // if "n" is not 15 generate a random number from 0 to 15
        // `(n ^ 20 ? 16 : 4)` := unless "n" is 20, in which case a random number from 8 to 11 otherwise 4
        //
        // in other cases (if "n" is 9,14,19,24) insert "-"
        /* jshint noempty: false */// jscs:disable
        for (r = n = E; n++ < 36; r += n * 51 & 52 ? (n ^ 15 ? 8 ^ rnd() * (n ^ 20 ? 16 : 4) : 4).toString(16) : H) { }
        // jscs:enable
        return r;
    },

    /**
     * Use this function on the new instance of the transaction to mark a query as part of this transaction
     *
     * @param {*} query
     * @param {string} cid
     * @returns {*}
     *
     * @throws {Error} If failed to query the connection to start a transaction
     * @throws {Error} If query already has a `transactionId` field.
     */
    wrapquery: function (query, id) {
        // if query is string or number, we convert it to an object and store transaction id in them.
        query = nonObjectCriteriaTypes[typeof query] && {
            id: query
        } || query; // else inject transactionId.

        // save transaction id to query and return
        query && (query.transactionId = id);

        return query;
    },

    /**
     * This method allows one to extract transaction id from a critera object. The interesting thing is that it recovers
     * transaction id embedded within nested criteria and joins.
     * @private
     *
     * @param {object|array} criteria
     * @param {object=} [hash] - object to lookup validity of hash. in its absence simple lookup iis made
     * @returns {string}
     */
    unwrapquery: function (criteria, hash) {
        var transactionId;

        // if hash is absent, we have no option but to look for only the transaction key
        if (!hash) {
            return criteria && criteria.transactionId;
        }

        // if criteria is falsy, we have nothing further to work on.
        if (!criteria) {
            return;
        }

        // we do a crude check to see if transaction id has been sent as part of the criteria object.
        if (hash[criteria.transactionId]) {
            // @todo this is brought here because there is an extra transactionId coming from somewhere in the where
            // clause
            if (criteria.where && criteria.where.transactionId) {
                delete criteria.where.transactionId;
            }
            return ((transactionId = criteria.transactionId), (delete criteria.transactionId), transactionId);
        }

        // if the criteria object sent is an array, usually this is a result of recusrion from this
        // function itself, we then try and process every item in the array for existence of transaction id.
        if (Array.isArray(criteria)) {
            criteria.some(function (item) {
                // during recursion we are sure CRC will always pass as that has been ensured by waterline
                // schema.
                return (transactionId = util.unwrapquery(item));
            });
            // if trabsaction id was found in recursive criteria, we return the same, else proceed.
            if (transactionId) {
                return transactionId;
            }
        }

        // if the criteria object is a schema processed dql, we would possibly get the transaction id within the `where`
        // key.
        if (criteria.where && hash[criteria.where.transactionId]) {
            return ((transactionId = criteria.where.transactionId), (delete criteria.where.transactionId),
                transactionId);
        }

        // finally, we try to recurse into finding transaction id within joins
        Array.isArray(criteria.joins) && (transactionId = util.unwrapquery(criteria.joins));

        // finally, we return whatever transaction id we have received. could possibly be `undefined` as well.
        return transactionId;
    }
};

module.exports = util;
<commit_msg>Added utility function to convert arguments to real array<commit_after>var _ = require('lodash'),

    nonObjectCriteriaTypes = { // object to validate types of wrapper fn
        string: true,
        number: true,
        boolean: true
    },

    E = '',
    H = '-',
    rnd = Math.random,

    util; // exports

util = {
    /**
     * Deep clone an object.
     *
     * @param {object} obj
     * @returns {object}
     */
    clone: function (obj) {
        return _.cloneDeep(obj);
    },

    /**
     * Performs shallow copy of one object into another.
     *
     * @param {object} recipient
     * @param {object} donor
     * @returns {object} - returns the seeded recipient parameter
     */
    extend: function (recipient, donor) {
        for (var prop in donor) {
            donor.hasOwnProperty(prop) && (recipient[prop] = donor[prop]);
        }
        return recipient;
    },

    /**
     * Shallow copies all non-existing properties from donor to recipient
     *
     * @param {object} recipient
     * @param {object} donor
     * @returns {object} - returns the seeded recipient parameter
     */
    fill: function (recipient, donor) {
        for (var prop in donor) {
            !recipient.hasOwnProperty(prop) && (recipient[prop] = donor[prop]);
        }
        return recipient;
    },

    /**
     * Useful function to iterate on array or object with almost same API.
     *
     * @param {object|array} obj
     * @param {function} iter
     * @param {object|function} [scope]
     * @returns {object|array} - the original object passed is returned for chaining.
     */
    each: function (obj, iter, scope) {
        var i,
            ii;

        !scope && (scope === obj);

        // proceed only when object passed is truly an object (array too is an object, in case it wasn't clear.)
        if (typeof obj !== 'object') {
            return obj;
        }

        if (_.isArray(obj) || _.isArguments(obj)) {
            for (i = 0, ii = obj.length; i < ii; i++) {
                if (iter.call(scope, obj[i], i, obj) === false) {
                    return obj;
                }
            }
        }
        else {
            for (i in obj) {
                if (obj.hasOwnProperty(i)) {
                    if (iter.call(scope, obj[i], i, obj) === false) {
                        return obj;
                    }
                }
            }
        }
        return obj;
    },

    /**
     * Returns unique GUID on every call as per pseudo-number RFC4122 standards.
     *
     * @type {function}
     * @returns {string}
     */
    uid: function () {
        var n, r; // r = result , n = numeric variable for positional checks

        // if "n" is not 9 or 14 or 19 or 24 return a random number or 4
        // if "n" is not 15 generate a random number from 0 to 15
        // `(n ^ 20 ? 16 : 4)` := unless "n" is 20, in which case a random number from 8 to 11 otherwise 4
        //
        // in other cases (if "n" is 9,14,19,24) insert "-"
        /* jshint noempty: false */// jscs:disable
        for (r = n = E; n++ < 36; r += n * 51 & 52 ? (n ^ 15 ? 8 ^ rnd() * (n ^ 20 ? 16 : 4) : 4).toString(16) : H) { }
        // jscs:enable
        return r;
    },

    /**
     * Use this function on the new instance of the transaction to mark a query as part of this transaction
     *
     * @param {*} query
     * @param {string} cid
     * @returns {*}
     *
     * @throws {Error} If failed to query the connection to start a transaction
     * @throws {Error} If query already has a `transactionId` field.
     */
    wrapquery: function (query, id) {
        // if query is string or number, we convert it to an object and store transaction id in them.
        query = nonObjectCriteriaTypes[typeof query] && {
            id: query
        } || query; // else inject transactionId.

        // save transaction id to query and return
        query && (query.transactionId = id);

        return query;
    },

    /**
     * This method allows one to extract transaction id from a critera object. The interesting thing is that it recovers
     * transaction id embedded within nested criteria and joins.
     * @private
     *
     * @param {object|array} criteria
     * @param {object=} [hash] - object to lookup validity of hash. in its absence simple lookup iis made
     * @returns {string}
     */
    unwrapquery: function (criteria, hash) {
        var transactionId;

        // if hash is absent, we have no option but to look for only the transaction key
        if (!hash) {
            return criteria && criteria.transactionId;
        }

        // if criteria is falsy, we have nothing further to work on.
        if (!criteria) {
            return;
        }

        // we do a crude check to see if transaction id has been sent as part of the criteria object.
        if (hash[criteria.transactionId]) {
            // @todo this is brought here because there is an extra transactionId coming from somewhere in the where
            // clause
            if (criteria.where && criteria.where.transactionId) {
                delete criteria.where.transactionId;
            }
            return ((transactionId = criteria.transactionId), (delete criteria.transactionId), transactionId);
        }

        // if the criteria object sent is an array, usually this is a result of recusrion from this
        // function itself, we then try and process every item in the array for existence of transaction id.
        if (Array.isArray(criteria)) {
            criteria.some(function (item) {
                // during recursion we are sure CRC will always pass as that has been ensured by waterline
                // schema.
                return (transactionId = util.unwrapquery(item));
            });
            // if trabsaction id was found in recursive criteria, we return the same, else proceed.
            if (transactionId) {
                return transactionId;
            }
        }

        // if the criteria object is a schema processed dql, we would possibly get the transaction id within the `where`
        // key.
        if (criteria.where && hash[criteria.where.transactionId]) {
            return ((transactionId = criteria.where.transactionId), (delete criteria.where.transactionId),
                transactionId);
        }

        // finally, we try to recurse into finding transaction id within joins
        Array.isArray(criteria.joins) && (transactionId = util.unwrapquery(criteria.joins));

        // finally, we return whatever transaction id we have received. could possibly be `undefined` as well.
        return transactionId;
    },

    /**
     * Converts arguments object to real array
     *
     * @param {Arguments} args
     * @returns {Array}
     */
    args2arr: function (args) {
        return Array.prototype.slice.call(args);
    }
};

module.exports = util;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var Q = require('q');

var MEMO_DIR = './memos';

var memos = require('express').Router();

memos.get(/^(.*)$/, function (req, res) {
  var dir = path.join(MEMO_DIR, req.params[0]);

  getMemoList(dir).then(function (memoList) {
    res.send(memoList);
  }, function (error) {
    res.send(500, {error: error});
  });
});

function getMemoList (dir) {
  var deferred = Q.defer();

  var fs_readdir = Q.denodeify(fs.readdir);
  fs_readdir(dir).then(function (files) {
    Q.all(files.map(function (file) {
      return getFileInfo(dir, file);
    })).then(function (memoList) {
      deferred.resolve(memoList);
    });
  }, function (error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

function getFileInfo (dir, file) {
  var deferred = Q.defer();

  var fs_stat = Q.denodeify(fs.stat);
  fs_stat(path.join(dir, file)).then(function (stat) {
    var fileInfo = {
      name: file,
      type: stat.isFile() ? 'file' : 'dir',
      hidden: file.charAt(0) === '.'
    };
    deferred.resolve(fileInfo);
  });

  return deferred.promise;
}

memos.post(/^(.*)$/, function (req, res) {
  var file = req.params[0];

  var makeFunc = file.charAt(file.length - 1) === '/' ? makeDir : makeFile;
  makeFunc(file).then(function () {
    var lastIndex = file.lastIndexOf('/');
    var dir = path.join(MEMO_DIR, file.slice(0, lastIndex) + '/');

    return getMemoList(dir).then(function (memoList) {
      res.send(memoList);
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  });
});

function makeDir (file) {
  var deferred = Q.defer();

  fs.mkdir(path.join(MEMO_DIR, file), deferred.makeNodeResolver());

  return deferred.promise;
}

function makeFile (file) {
  var deferred = Q.defer();

  var fs_open = Q.denodeify(fs.open);
  fs_open(path.join(MEMO_DIR, file), 'wx').then(function (fd) {
    fs.close(fd, deferred.makeNodeResolver());
  }).fail(function (error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

function getDir (file) {
  var lastIndex = file.lastIndexOf('/');
  return lastIndex !== -1 ? file.slice(0, lastIndex) : '';
}

memos.put(/^(.*)$/, function (req, res) {
  var file = path.join(MEMO_DIR, req.params[0]);
  var dir = getDir(file);
  var newFile = path.join(dir, req.query.new);

  var fs_rename = Q.denodeify(fs.rename);
  fs_rename(file, newFile).then(function () {
    return getMemoList(dir).then(function (memoList) {
      res.send(memoList);
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  });
});

memos.delete(/^(.*)$/, function (req, res) {
  var file = path.join(MEMO_DIR, req.params[0]);
  var dir = getDir(file);

  var fs_stat = Q.denodeify(fs.stat);
  fs_stat(file).then(function (stat) {
    var removeFunc = Q.denodeify(stat.isFile() ? fs.unlink : fs.rmdir);
    removeFunc(file).then(function () {
      return getMemoList(dir).then(function (memoList) {
        res.send(memoList);
      });
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  })
});

module.exports.memos = memos;
<commit_msg>Minor change<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var Q = require('q');

var MEMO_DIR = './memos';

var memos = require('express').Router();

memos.get(/^(.*)$/, function (req, res) {
  var dir = path.join(MEMO_DIR, req.params[0]);

  getMemoList(dir).then(function (memoList) {
    res.send(memoList);
  }, function (error) {
    res.send(500, {error: error});
  });
});

function getMemoList (dir) {
  var deferred = Q.defer();

  var fs_readdir = Q.denodeify(fs.readdir);
  fs_readdir(dir).then(function (files) {
    Q.all(files.map(function (file) {
      return getFileInfo(dir, file);
    })).then(function (memoList) {
      deferred.resolve(memoList);
    });
  }, function (error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

function getFileInfo (dir, file) {
  var deferred = Q.defer();

  var fs_stat = Q.denodeify(fs.stat);
  fs_stat(path.join(dir, file)).then(function (stat) {
    var fileInfo = {
      name: file,
      type: stat.isFile() ? 'file' : 'dir',
      hidden: file.charAt(0) === '.'
    };
    deferred.resolve(fileInfo);
  });

  return deferred.promise;
}

memos.post(/^(.*)$/, function (req, res) {
  var file = req.params[0];

  var makeFunc;
  if (file.charAt(file.length - 1) === '/') {
    makeFunc = makeDir;
    file = file.slice(0, -1);
  } else {
    makeFunc = makeFile;
  }

  makeFunc(file).then(function () {
    var dir = path.join(MEMO_DIR, getDir(file));
    return getMemoList(dir).then(function (memoList) {
      res.send(memoList);
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  });
});

function makeDir (file) {
  var deferred = Q.defer();

  fs.mkdir(path.join(MEMO_DIR, file), deferred.makeNodeResolver());

  return deferred.promise;
}

function makeFile (file) {
  var deferred = Q.defer();

  var fs_open = Q.denodeify(fs.open);
  fs_open(path.join(MEMO_DIR, file), 'wx').then(function (fd) {
    fs.close(fd, deferred.makeNodeResolver());
  }).fail(function (error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

function getDir (file) {
  var lastIndex = file.lastIndexOf('/');
  return lastIndex !== -1 ? file.slice(0, lastIndex) : '';
}

memos.put(/^(.*)$/, function (req, res) {
  var file = path.join(MEMO_DIR, req.params[0]);
  var dir = getDir(file);
  var newFile = path.join(dir, req.query.new);

  var fs_rename = Q.denodeify(fs.rename);
  fs_rename(file, newFile).then(function () {
    return getMemoList(dir).then(function (memoList) {
      res.send(memoList);
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  });
});

memos.delete(/^(.*)$/, function (req, res) {
  var file = path.join(MEMO_DIR, req.params[0]);
  var dir = getDir(file);

  var fs_stat = Q.denodeify(fs.stat);
  fs_stat(file).then(function (stat) {
    var removeFunc = Q.denodeify(stat.isFile() ? fs.unlink : fs.rmdir);
    removeFunc(file).then(function () {
      return getMemoList(dir).then(function (memoList) {
        res.send(memoList);
      });
    });
  }).fail(function (error) {
    res.send(500, {error: error});
  })
});

module.exports.memos = memos;
<|endoftext|>


<commit_before>var mkdirp = require('mkdirp');
var clone = require('clone');

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var proc = require('child_process');
var util = require('util');
var assert = require('assert');

require('./object.js');

util.clone = clone;

// extends util with isFunction
util.isFunction = function(arg) {
  return typeof(arg) == 'function';
};

// extends util with exists
util.exists = function(obj) {
  return (obj !== undefined && obj !== null);
}

// extends util with zip
util.zip = function(arr) {
  var args = [].slice.call(arguments);
  return args[0].map(function(_, i) {
    return args.map(function(arr) {
      return arr[i];
    });
  });
}

util.__nextid = 0;
util.__pending = {};

// extends util with method to force single callback execution
util.force = function(cb, msg) {
  var id = ++util.__nextid;
  var wrapped = function() {
    delete util.__pending[id];
    return cb.apply(null, arguments);
  };
  util.__pending[id] = (msg ? msg + ' - ' : '') + 'initialized at ' + __marker;
  return wrapped;
}

process.on('exit', function() {
  assert(Object.keys(util.__pending).length === 0,
        'Unexecuted callbacks: ' + Object.values(util.__pending).reduce(function(prev, curr) { return prev + '\n' + curr.toString(); }, ''));
})

// pretty-printed json dump
util.dump = function(obj) {
  return JSON.stringify(obj, null, 2);
}

// serializes object to file
util.cache = function(file, obj, cb) {
  mkdirp.sync(path.dirname(file));
  if (util.exists(cb))
    fs.writeFile(file, dump(obj), cb);
  else
    fs.writeFileSync(file, dump(obj));
}

// retrieves object from file
util.retrieve = function(file, cb) {
  if (util.exists(cb)) {
    fs.readFile(file, function(err, data) {
      if (err)
        return cb(err);
      cb(null, JSON.parse(data));
    });
  }
  else
    return JSON.parse(fs.readFileSync(file));
}

// writes string to file
util.write = function(file, str, cb) {
  mkdirp.sync(path.dirname(file));
  if (util.exists(cb))
    fs.writeFile(file, str, cb);
  else
    fs.writeFileSync(file, str);
}

// hashes the contents of a file
util.hash = function(file, cb) {
  var h = crypto.createHash('sha1');
  var s = fs.ReadStream(file);
  s.on('data', function(d) {
    h.update(d);
  });

  s.on('end', function() {
    cb(null, h.digest('hex'));
  });

  s.on('error', function(err) {
    cb('Failed hashing file: ' + file);
  });
};

util.replace = function(str, replacements) {
  for (key in replacements)
    str = str.replace(key, replacements[key]);
  return str;
}

util.launch = function(args, cb) {
  args.opts = args.opts || {};
  var root = args.opts.cwd || __dirname;

  var invocation = {
    cmd: [args.cmd].concat(args.args).join(' '),
    cwd: root,
    stdout: '',
    stderr: '',
    exit_code: 0
  };

  proc.exec(invocation.cmd, args.opts, function(error, stdout, stderr) {
    invocation.exit_code = error;
    invocation.stdout = stdout;
    invocation.stderr = stderr;
    cb(error, invocation);
  });
};

util.message = function(msg) {
  return function(cb) {
    console.log(msg);
    cb();
  }
}

util.public = function(args, module) {
  args.forEach(function(arg) {
    if (util.isFunction(arg))
      module.exports[arg.name] = arg;
    else {
      for (key in arg)
        module.exports[key] = arg[key];
    }
  });
}

util.invalidate_module = function(module_path) {
  delete require.cache[module_path];
}

/*
// example of event execution when the libuv queue drained
function drained() {
  var handles = process._getActiveHandles();
  var requests = process._getActiveRequests();
  if (handles.length === 1 && handles[0] === this)
    process.exit();
  }
};

setInterval(drained, 100);
*/
<commit_msg>Fixed reference to dump()<commit_after>var mkdirp = require('mkdirp');
var clone = require('clone');

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var proc = require('child_process');
var util = require('util');
var assert = require('assert');

require('./object.js');

util.clone = clone;

// extends util with isFunction
util.isFunction = function(arg) {
  return typeof(arg) == 'function';
};

// extends util with exists
util.exists = function(obj) {
  return (obj !== undefined && obj !== null);
}

// extends util with zip
util.zip = function(arr) {
  var args = [].slice.call(arguments);
  return args[0].map(function(_, i) {
    return args.map(function(arr) {
      return arr[i];
    });
  });
}

util.__nextid = 0;
util.__pending = {};

// extends util with method to force single callback execution
util.force = function(cb, msg) {
  var id = ++util.__nextid;
  var wrapped = function() {
    delete util.__pending[id];
    return cb.apply(null, arguments);
  };
  util.__pending[id] = (msg ? msg + ' - ' : '') + 'initialized at ' + __marker;
  return wrapped;
}

process.on('exit', function() {
  assert(Object.keys(util.__pending).length === 0,
        'Unexecuted callbacks: ' + Object.values(util.__pending).reduce(function(prev, curr) { return prev + '\n' + curr.toString(); }, ''));
})

// pretty-printed json dump
util.dump = function(obj) {
  return JSON.stringify(obj, null, 2);
}

// serializes object to file
util.cache = function(file, obj, cb) {
  mkdirp.sync(path.dirname(file));
  if (util.exists(cb))
    fs.writeFile(file, util.dump(obj), cb);
  else
    fs.writeFileSync(file, util.dump(obj));
}

// retrieves object from file
util.retrieve = function(file, cb) {
  if (util.exists(cb)) {
    fs.readFile(file, function(err, data) {
      if (err)
        return cb(err);
      cb(null, JSON.parse(data));
    });
  }
  else
    return JSON.parse(fs.readFileSync(file));
}

// writes string to file
util.write = function(file, str, cb) {
  mkdirp.sync(path.dirname(file));
  if (util.exists(cb))
    fs.writeFile(file, str, cb);
  else
    fs.writeFileSync(file, str);
}

// hashes the contents of a file
util.hash = function(file, cb) {
  var h = crypto.createHash('sha1');
  var s = fs.ReadStream(file);
  s.on('data', function(d) {
    h.update(d);
  });

  s.on('end', function() {
    cb(null, h.digest('hex'));
  });

  s.on('error', function(err) {
    cb('Failed hashing file: ' + file);
  });
};

util.replace = function(str, replacements) {
  for (key in replacements)
    str = str.replace(key, replacements[key]);
  return str;
}

util.launch = function(args, cb) {
  args.opts = args.opts || {};
  var root = args.opts.cwd || __dirname;

  var invocation = {
    cmd: [args.cmd].concat(args.args).join(' '),
    cwd: root,
    stdout: '',
    stderr: '',
    exit_code: 0
  };

  proc.exec(invocation.cmd, args.opts, function(error, stdout, stderr) {
    invocation.exit_code = error;
    invocation.stdout = stdout;
    invocation.stderr = stderr;
    cb(error, invocation);
  });
};

util.message = function(msg) {
  return function(cb) {
    console.log(msg);
    cb();
  }
}

util.public = function(args, module) {
  args.forEach(function(arg) {
    if (util.isFunction(arg))
      module.exports[arg.name] = arg;
    else {
      for (key in arg)
        module.exports[key] = arg[key];
    }
  });
}

util.invalidate_module = function(module_path) {
  delete require.cache[module_path];
}

/*
// example of event execution when the libuv queue drained
function drained() {
  var handles = process._getActiveHandles();
  var requests = process._getActiveRequests();
  if (handles.length === 1 && handles[0] === this)
    process.exit();
  }
};

setInterval(drained, 100);
*/
<|endoftext|>


<commit_before>/**
 * Main library entry point. The module will return a function. If you are using it inside of another project then you
 * should require in grasshopper and execute the function. If you are using GH as a standalone app then you should
 * execute bin/grasshopper-js
 *
 * @param proxy - Express app that you want to use to act as a proxy to the grasshopper api
 */
module.exports = function(proxy){
    var _ = require('underscore'),
        express = require('express'),
        bridgetown = require('bridgetown-api'),
        grasshopper = require('grasshopper-core'),
        setHeaders = require('./api/middleware/setHeaders'),
        server = (_.isUndefined(proxy)) ? express() : proxy,
        PORT = (process.argv.length == 3 && process.argv[2] !== 'test') ? process.argv[2] : (process.env.PORT || 3000),
        routePath = '*';

    //Configure grasshopper core
    grasshopper.configure(function () {
        this.config = require('./config');
    });

    //Setup bridgetown configuration
    bridgetown.configure(function(){
        this.validate.token(function(token){
            return grasshopper.request(token).users.current();
        });
    });

    //Configure Express App
    server.configure( function () {
        server.use(express.static(__dirname + '/public'));

        if(server.get('grasshopper route prefix')){
            routePath = server.get('grasshopper route prefix') + '/*';
        }

        //Set the global route params for the given application route.
        server.all(routePath, [setHeaders, express.logger('default'), express.methodOverride(), express.json(), express.urlencoded()]);

        //Load in API Routes
        require('./api/routes/token')(server);
        require('./api/routes/users')(server);
        require('./api/routes/contentTypes')(server);
        require('./api/routes/content')(server);
        require('./api/routes/nodes')(server);
    });

    //Only start a server if a proxy is not available.
    if(_.isUndefined(proxy)){
        server.listen(PORT);
        console.log('Listening on port ' + PORT + '...');
    }
};<commit_msg>Fixed moved paths.<commit_after>/**
 * Main library entry point. The module will return a function. If you are using it inside of another project then you
 * should require in grasshopper and execute the function. If you are using GH as a standalone app then you should
 * execute bin/grasshopper-js
 *
 * @param proxy - Express app that you want to use to act as a proxy to the grasshopper api
 */
module.exports = function(proxy){
    var _ = require('underscore'),
        express = require('express'),
        bridgetown = require('bridgetown-api'),
        grasshopper = require('grasshopper-core'),
        setHeaders = require('./middleware/setHeaders'),
        server = (_.isUndefined(proxy)) ? express() : proxy,
        PORT = (process.argv.length == 3 && process.argv[2] !== 'test') ? process.argv[2] : (process.env.PORT || 3000),
        routePath = '*';

    //Configure grasshopper core
    grasshopper.configure(function () {
        this.config = require('./config');
    });

    //Setup bridgetown configuration
    bridgetown.configure(function(){
        this.validate.token(function(token){
            return grasshopper.request(token).users.current();
        });
    });

    //Configure Express App
    server.configure( function () {
        server.use(express.static(__dirname + '/public'));

        if(server.get('grasshopper route prefix')){
            routePath = server.get('grasshopper route prefix') + '/*';
        }

        //Set the global route params for the given application route.
        server.all(routePath, [setHeaders, express.logger('default'), express.methodOverride(), express.json(), express.urlencoded()]);

        //Load in API Routes
        require('./routes/token')(server);
        require('./routes/users')(server);
        require('./routes/contentTypes')(server);
        require('./routes/content')(server);
        require('./routes/nodes')(server);
    });

    //Only start a server if a proxy is not available.
    if(_.isUndefined(proxy)){
        server.listen(PORT);
        console.log('Listening on port ' + PORT + '...');
    }
};<|endoftext|>


<commit_before>var chalk = require('chalk'),
	constants = require('./constants'),
	fileServer = require('./fileServer'),
	format = require('util').format,
	fs = require('fs-extra'),
	logger = require('./logger'),
	path = require('path');

var $u = chalk.underline,
	$c = chalk.cyan,
	addCache = {};

exports.isAdded = function isCached(file) {
	return addCache[path.resolve(process.cwd(), file)];
};

exports.addToApp = function addToApp(file) {
	var src = path.resolve(process.cwd(), file),
		platform = exports.platform,
		relPath = path.join('__modules', src.replace(/^\//, '')),
		filename = path.basename(file),
		dst = path.resolve(constants.resourcesDir, filename),
		dstModule = path.resolve(constants.resourcesDir, relPath),
		isJsFile = /\.(?:js|json)$/.test(dstModule);

	// make sure source file exists
	if (!fs.existsSync(src)) {
		logger.error('file does not exist: "' + src + '"');
		return;
	}

	if (platform === 'ios') {
		try {
			fs.ensureDirSync(path.dirname(dst));
			fs.copySync(src, dst);

			if (isJsFile) {
				fs.ensureDirSync(path.dirname(dstModule));
				fs.copySync(src, dstModule);
			}
		} catch (e) {
			logger.error('Failed to copy file to app: "' + src + '"');
			return;
		}
	} else {
		fileServer.emit('file', createFileBuffer(src, dst));
	}

	addCache[src] = true;
	logger.system('%s %s', chalk.cyan.dim(filename), chalk.gray('file added to app'));
};

function createFileBuffer(src, dst) {
	var file = fs.readFileSync(src),
		fileLen = file.length,
		filepath = dst,
		filepathLen = dst.length;

	var buffer = new Buffer(4 + 4 + filepathLen + 4);
	buffer.writeInt32LE(4 + 4 + filepathLen + 4 + fileLen, 0);
	buffer.writeInt32LE(filepathLen, 4);
	buffer.write(filepath, 4 + 4, filepathLen);
	buffer.writeInt32LE(fileLen, 4 + 4 + filepathLen);

	return Buffer.concat([buffer, file]);
}

exports.printCommands = function printCommands(padding) {
	var pad = new Array(padding+1 || 5).join(' '),
		log = function() {
			var args = Array.prototype.slice.call(arguments);
			args[0] && (args[0] = pad + args[0]);
			console.log.apply(console, args);
		};

	log(format('%s %s %s', $c('.add'), $u('file'), $u('...')));
	log('  Add file(s) to the app');
	log('');
	log(format('%s', $c('.break')));
	log('  Abort the current multi-line statement');
	log('');
	log(format('%s', $c('.clear')));
	log('  Create a new execution context for the current REPL');
	log('');
	log(format('%s', $c('.exit')));
	log('  Exit triple');
	log('');
	log(format('%s', $c('.help')));
	log('  Shows command help while in the REPL');
	log('');
	log(format('%s <%s> [delay]', $c('.load'), $u('file')));
	log('  Load a local or remote JS file into the REPL, with optional delay in ms');
	log('');
	log(format('%s <%s>', $c('.save'), $u('file')));
	log('  Save the current REPL session JS to a file');
	log('');
};
<commit_msg>don't resolve, adds cwd when not needed<commit_after>var chalk = require('chalk'),
	constants = require('./constants'),
	fileServer = require('./fileServer'),
	format = require('util').format,
	fs = require('fs-extra'),
	logger = require('./logger'),
	path = require('path');

var $u = chalk.underline,
	$c = chalk.cyan,
	addCache = {};

exports.isAdded = function isCached(file) {
	return addCache[path.resolve(process.cwd(), file)];
};

exports.addToApp = function addToApp(file) {
	var src = path.resolve(process.cwd(), file),
		platform = exports.platform,
		relPath = path.join('__modules', src.replace(/^\//, '')),
		filename = path.basename(file),
		dst = path.join(constants.resourcesDir, filename),
		dstModule = path.join(constants.resourcesDir, relPath),
		isJsFile = /\.(?:js|json)$/.test(dstModule);

	// make sure source file exists
	if (!fs.existsSync(src)) {
		logger.error('file does not exist: "' + src + '"');
		return;
	}

	if (platform === 'ios') {
		try {
			fs.ensureDirSync(path.dirname(dst));
			fs.copySync(src, dst);

			if (isJsFile) {
				fs.ensureDirSync(path.dirname(dstModule));
				fs.copySync(src, dstModule);
			}
		} catch (e) {
			logger.error('Failed to copy file to app: "' + src + '"');
			return;
		}
	} else {
		fileServer.emit('file', createFileBuffer(src, dst));
	}

	addCache[src] = true;
	logger.system('%s %s', chalk.cyan.dim(filename), chalk.gray('file added to app'));
};

function createFileBuffer(src, dst) {
	var file = fs.readFileSync(src),
		fileLen = file.length,
		filepath = dst,
		filepathLen = dst.length;

	var buffer = new Buffer(4 + 4 + filepathLen + 4);
	buffer.writeInt32LE(4 + 4 + filepathLen + 4 + fileLen, 0);
	buffer.writeInt32LE(filepathLen, 4);
	buffer.write(filepath, 4 + 4, filepathLen);
	buffer.writeInt32LE(fileLen, 4 + 4 + filepathLen);

	return Buffer.concat([buffer, file]);
}

exports.printCommands = function printCommands(padding) {
	var pad = new Array(padding+1 || 5).join(' '),
		log = function() {
			var args = Array.prototype.slice.call(arguments);
			args[0] && (args[0] = pad + args[0]);
			console.log.apply(console, args);
		};

	log(format('%s %s %s', $c('.add'), $u('file'), $u('...')));
	log('  Add file(s) to the app');
	log('');
	log(format('%s', $c('.break')));
	log('  Abort the current multi-line statement');
	log('');
	log(format('%s', $c('.clear')));
	log('  Create a new execution context for the current REPL');
	log('');
	log(format('%s', $c('.exit')));
	log('  Exit triple');
	log('');
	log(format('%s', $c('.help')));
	log('  Shows command help while in the REPL');
	log('');
	log(format('%s <%s> [delay]', $c('.load'), $u('file')));
	log('  Load a local or remote JS file into the REPL, with optional delay in ms');
	log('');
	log(format('%s <%s>', $c('.save'), $u('file')));
	log('  Save the current REPL session JS to a file');
	log('');
};
<|endoftext|>


<commit_before>'use strict';
var fis = require('fis3');
var path = require('path');
var defaults = require('../config/defaults.js');

/**
 * gfis༯
 */
var _ = module.exports;

/**
 * ȡļ
 * @return {String} ļ
 */
_.getConfigFilename = function() {
    return 'gfe-config.json';
};

/**
 * ȡļ
 */
_.getConfig = function() {
    var config = defaults;
    var gfeConfigPath = path.join(process.cwd(), _.getConfigFilename());
    if (fis.util.exists(gfeConfigPath)) {
        var gfeConfig = fis.util.readJSON(gfeConfigPath);
        config = fis.util.merge(config, gfeConfig);
    } else {
        fis.util.write(gfeConfigPath, JSON.stringify(config, null, 4), 'utf-8');
    }

    return config;
};

/**
 * ĿsvnĿ¼
 */
_.getSvnUrl = function(){
    var svnPath = {
        "trunk":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/trunk/gome-gfe",
        "branch":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/branches/gome-gfe",
        "tag":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/tags/gome-gfe"
    }
    return svnPath;
}

/**
 * ȡwidgetsvnַ
 */
_.getWidgetSvnUrl = function(){
    return 'https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/gome-gfe/gfe-widget';
}
<commit_msg>提交工具类<commit_after>'use strict';
var fis = require('fis3');
var path = require('path');
var defaults = require('../config/defaults.js');

/**
 * gfis༯
 */
var _ = module.exports;

/**
 * ȡļ
 * @return {String} ļ
 */
_.getConfigFilename = function() {
    return 'gfe-config.json';
};

/**
 * ȡĿĸļ(build/project/xxx)
 * @return {String} Ŀĸļ
 */
_.getProjectRootFolder = function() {
    return 'project';
};

/**
 * ȡcdnĸļ(build/cdn/xxx)
 * @return {String} cdnĸļ
 */
_.getCdnRootFolder = function() {
    return 'cdn';
};

/**
 * ȡļ
 * @return {String} ļ
 */
_.getReleaseRootFolder = function() {
    return 'build';
};

/**
 * ȡļ
 */
_.getConfig = function() {
    var config = defaults;
    var gfeConfigPath = path.join(process.cwd(), _.getConfigFilename());
    if (fis.util.exists(gfeConfigPath)) {
        var gfeConfig = fis.util.readJSON(gfeConfigPath);
        config = fis.util.merge(config, gfeConfig);
    } else {
        fis.util.write(gfeConfigPath, JSON.stringify(config, null, 4), 'utf-8');
    }

    return config;
};

/**
 * ĿsvnĿ¼
 */
_.getSvnUrl = function(){
    var svnPath = {
        "trunk":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/trunk/gome-gfe",
        "branch":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/branches/gome-gfe",
        "tag":"https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/NewDevMode/tags/gome-gfe"
    };
    return svnPath;
};

/**
 * ȡwidgetsvnַ
 */
_.getWidgetSvnUrl = function(){
    return 'https://repo.ds.gome.com.cn:8443/svn/atg_poc/30_Coding/gome-gfe/gfe-widget';
};
<|endoftext|>


<commit_before>'use strict';

exports = module.exports = { };

// dependencies
//
exports.clone = require('lodash.clone');
exports.merge = require('lodash.merge');

/**
# boil(string path [, object options])
> path normalizer

arguments
- path, type `string`
- options, type `object` holding all extra information

returns
- null for non supported types
- an object with path and url props only

if the `o` object given had a not found prop
**/

var qsRE = new RegExp([
  '\\/?', // urls can end with slash but is optional
  '[?#]', // start of querystring/hash
  '[^!=:]', // exclude ?!, ?= and ?: regex strings
  '[^ ]+'
].join(''), 'g');

exports.boil = function boil(path, o){
  if(typeof path !== 'string'){ return null; }

  o = o || {};
  o.path = path.replace(/[ ]+/, ' ').trim();
  var urls = o.path.match(/(?:^|[ ])\/\S*/g) || [];

  urls.forEach(function(url){
    url = url.trim();
    o.path = o.path.replace(url, url.replace(qsRE, '') || '/');
  });

  if(o.notFound){
    o.url = urls.length > 1 ? urls : urls[0];
    o.notFound = o.path;
  }

  return o;
};
<commit_msg>fix: remove unnecessary trimming<commit_after>'use strict';

exports = module.exports = { };

// dependencies
//
exports.clone = require('lodash.clone');
exports.merge = require('lodash.merge');

/**
# boil(string path [, object options])
> path normalizer

arguments
- path, type `string`
- options, type `object` holding all extra information

returns
- null for non supported types
- an object with path and url props only

if the `o` object given had a not found prop
**/

var qsRE = new RegExp([
  '\\/?', // urls can end with slash but is optional
  '[?#]', // start of querystring/hash
  '[^!=:]', // exclude ?!, ?= and ?: regex strings
  '[^ ]+'
].join(''), 'g');

exports.boil = function boil(path, o){
  if(typeof path !== 'string'){ return null; }

  o = o || {};
  o.path = path.replace(/[ ]+/, ' ').trim();
  var urls = o.path.match(/[^\/ ]*\/\S*/) || [];

  urls.forEach(function(url){
    o.path = o.path.replace(url, url.replace(qsRE, '') || '/');
  });

  if(o.notFound){
    o.url = urls.length > 1 ? urls : urls[0];
    o.notFound = o.path;
  }

  return o;
};
<|endoftext|>


<commit_before>define(function (require, exports, module) {

	'use strict';

	//var _ = require('underscore');
	var Formula = require('fparser');
	var bs      = require('common/binarysearch/binarysearch');

	var Simulation = require('common/simulation/simulation');
	var MovingMan  = require('models/moving-man');

	/**
	 * Constants
	 */

	/**
	 * Wraps the update function in
	 */
	var MovingManSimulation = Simulation.extend({

		defaults: _.extend(Simulation.prototype.defaults, {
			containerWidth: 20,
			halfContainerWidth: 10,
			wallsEnabled: true,
			furthestRecordedTime: 0,
			maxTime: 20,
			recording: true,
			playbackSpeed: 1
		}),

		/**
		 * Object fields
		 */
		history: [],
		time: 0,
		positionFormula: null,

		/**
		 *
		 */
		initialize: function(attributes, options) {
			Simulation.prototype.initialize.apply(this, [attributes, options]);

			this.on('change:containerWidth', function() {
				this.set('halfContainerWidth', this.get('containerWidth') / 2);
			});

			/* We're keeping track of the playback speed separate from the sim's
			 *   timeScale because timeScale changes with modes, and we have to
			 *   persistently store the playback speed across modes.
			 */
			this.on('change:playbackSpeed', function(model, speed, options) {
				if (!this.get('recording'))
					this.set('timeScale', speed);
			});
		},

		/**
		 *
		 */
		applyOptions: function(options) {
			Simulation.prototype.applyOptions.apply(this, [options]);

			this.noRecording = options ? options.noRecording : false;
			if (this.noRecording)
				this.set('recording', false);
		},

		/**
		 *
		 */
		initComponents: function() {
			this.initMovingMan();
		},

		/**
		 *
		 */
		initMovingMan: function() {
			this.movingMan = new MovingMan(null, {
				simulation: this,
				noRecording: this.noRecording
			});
		},

		/**
		 *
		 */
		reset: function() {
			Simulation.prototype.reset.apply(this);

			// This is the fastest way to clear an array by benchmarks
			var history = this.history;
			while (history.length > 0) {
				history.pop();
			}
		},

		/**
		 * Only runs if simulation isn't currently paused.
		 * If we're recording, it saves state
		 */
		_update: function(time, delta) {
			if (this.get('recording')) {
				// Run update and then save state
				this.movingMan.update(time, delta);
				this.recordState();
				this.set('furthestRecordedTime', time);
			}
			else {
				// Either we're playing back or we just don't ever record
				if (!this.noRecording) {
					// We're playing back, so apply a saved state instead of updating
					this.applyPlaybackState();

					// And if we've reached the end of what we've recorded, stop
					if (time >= this.get('furthestRecordedTime'))
						this.pause();
				}
				else
					this.movingMan.update(time, delta);
			}
		},

		/**
		 *
		 */
		positionWithinBounds: function(x) {
			return (x >= -this.get('halfContainerWidth') && x <= this.get('halfContainerWidth'));
		},

		/**
		 * Evaluates the custom user-specified expression
		 */
		evaluatePositionFunction: function(time) {
			if (this.positionFormula)
				return this.positionFormula.evaluate({ t: time });
			else
				return 0;
		},

		/**
		 * Tries to set the custom expression and throws error if the
		 *   expression is bad.
		 */
		useCustomPositionFunction: function(expression) {
			// Showing the try-catch block even though we pass the error up
			try {
				// If this next line throws an error, we know it's bad.
				Formula.calc(expression, { t: 0 });

				// So if we made it this far, we've got a winner.
				this.positionFormula = new Formula(expression);
				this.movingMan.positionDriven(true);
			}
			catch (e) {
				this.positionFormula = null;
				throw e;
			}
		},

		/**
		 *
		 */
		dropCustomPositionFunction: function() {
			this.positionFormula = null;
		},

		/**
		 *
		 */
		usingCustomPositionFunction: function() {
			return this.positionFormula !== null;
		},

		/**
		 * We need to set up some stuff before we can play back.  The
		 *   PhET version sorted the history by the time closest to
		 *   the current step time at each step and had a "todo" note
		 *   to make it something more efficient like a binary search,
		 *   so I'm going ahead and implementing a binary search on a
		 *   presorted history instead of sorting states from all
		 *   frames on every frame.
		 */
		play: function() {
			if (!this.get('recording')) {
				// Sort the historical states by time ascending
				_.sortBy(this.history, function(state) {
					return state.time;
				});

				/* Store just the times in a parallel array so we
				 *   can do a binary search.
				 */
				this._historyTimes = _.pluck(this.history, 'time');
			}

			Simulation.prototype.play.apply(this);
		},

		/**
		 *
		 */
		rewind: function() {
			this.time = 0;
		},

		/**
		 *
		 */
		resetTimeAndHistory: function() {
			// This is the fastest way to clear an array by benchmarks
			var history = this.history;
			while (history.length > 0) {
				history.pop();
			}

			this.time = 0;

			this.movingMan.clear();
		},

		/**
		 * Sets playback mode to record
		 */
		record: function() {
			this.set('recording', true);
			this.set('timeScale', this.get('playbackSpeed'));
		},

		/**
		 * Sets playback mode to playback
		 */
		stopRecording: function() {
			this.set('recording', false);
			this.set('timeScale', 1);
		},

		/**
		 * Stores the current state of everything as a json object
		 *   in the history array for playback later.
		 */
		recordState: function() {
			this.history.push({
				time: this.time,
				wallsEnabled: this.get('wallsEnabled'),
				movingMan: this.movingMan.getState()
			});
		},

		/**
		 * Finds the appropriate state in history for this step and
		 *   applies it to the simulation.
		 */
		applyPlaybackState: function() {
			var state = this.findStateWithClosestTime(this.time);
			if (state) {
				this.set('wallsEnabled', state.wallsEnabled);
				this.movingMan.applyState(this.time, state.movingMan);
			}
		},

		/**
		 * Performs a binary search to find the state whose time
		 *   is closest to the specified time.
		 */
		findStateWithClosestTime: function(time) {
			var stateIndex = bs.closest(this._historyTimes, time);
			return this.history[stateIndex];
		},

	});

	return MovingManSimulation;
});
<commit_msg>Custom position function wasn't getting nulled out on reset<commit_after>define(function (require, exports, module) {

	'use strict';

	//var _ = require('underscore');
	var Formula = require('fparser');
	var bs      = require('common/binarysearch/binarysearch');

	var Simulation = require('common/simulation/simulation');
	var MovingMan  = require('models/moving-man');

	/**
	 * Constants
	 */

	/**
	 * Wraps the update function in
	 */
	var MovingManSimulation = Simulation.extend({

		defaults: _.extend(Simulation.prototype.defaults, {
			containerWidth: 20,
			halfContainerWidth: 10,
			wallsEnabled: true,
			furthestRecordedTime: 0,
			maxTime: 20,
			recording: true,
			playbackSpeed: 1
		}),

		/**
		 * Object fields
		 */
		history: [],
		time: 0,
		positionFormula: null,

		/**
		 *
		 */
		initialize: function(attributes, options) {
			Simulation.prototype.initialize.apply(this, [attributes, options]);

			this.on('change:containerWidth', function() {
				this.set('halfContainerWidth', this.get('containerWidth') / 2);
			});

			/* We're keeping track of the playback speed separate from the sim's
			 *   timeScale because timeScale changes with modes, and we have to
			 *   persistently store the playback speed across modes.
			 */
			this.on('change:playbackSpeed', function(model, speed, options) {
				if (!this.get('recording'))
					this.set('timeScale', speed);
			});
		},

		/**
		 *
		 */
		applyOptions: function(options) {
			Simulation.prototype.applyOptions.apply(this, [options]);

			this.noRecording = options ? options.noRecording : false;
			if (this.noRecording)
				this.set('recording', false);
		},

		/**
		 *
		 */
		initComponents: function() {
			this.initMovingMan();
		},

		/**
		 *
		 */
		initMovingMan: function() {
			this.movingMan = new MovingMan(null, {
				simulation: this,
				noRecording: this.noRecording
			});
		},

		/**
		 *
		 */
		reset: function() {
			Simulation.prototype.reset.apply(this);

			// This is the fastest way to clear an array by benchmarks
			var history = this.history;
			while (history.length > 0) {
				history.pop();
			}

			this.positionFormula = null;
		},

		/**
		 * Only runs if simulation isn't currently paused.
		 * If we're recording, it saves state
		 */
		_update: function(time, delta) {
			if (this.get('recording')) {
				// Run update and then save state
				this.movingMan.update(time, delta);
				this.recordState();
				this.set('furthestRecordedTime', time);
			}
			else {
				// Either we're playing back or we just don't ever record
				if (!this.noRecording) {
					// We're playing back, so apply a saved state instead of updating
					this.applyPlaybackState();

					// And if we've reached the end of what we've recorded, stop
					if (time >= this.get('furthestRecordedTime'))
						this.pause();
				}
				else
					this.movingMan.update(time, delta);
			}
		},

		/**
		 *
		 */
		positionWithinBounds: function(x) {
			return (x >= -this.get('halfContainerWidth') && x <= this.get('halfContainerWidth'));
		},

		/**
		 * Evaluates the custom user-specified expression
		 */
		evaluatePositionFunction: function(time) {
			if (this.positionFormula)
				return this.positionFormula.evaluate({ t: time });
			else
				return 0;
		},

		/**
		 * Tries to set the custom expression and throws error if the
		 *   expression is bad.
		 */
		useCustomPositionFunction: function(expression) {
			// Showing the try-catch block even though we pass the error up
			try {
				// If this next line throws an error, we know it's bad.
				Formula.calc(expression, { t: 0 });

				// So if we made it this far, we've got a winner.
				this.positionFormula = new Formula(expression);
				this.movingMan.positionDriven(true);
			}
			catch (e) {
				this.positionFormula = null;
				throw e;
			}
		},

		/**
		 *
		 */
		dropCustomPositionFunction: function() {
			this.positionFormula = null;
		},

		/**
		 *
		 */
		usingCustomPositionFunction: function() {
			return this.positionFormula !== null;
		},

		/**
		 * We need to set up some stuff before we can play back.  The
		 *   PhET version sorted the history by the time closest to
		 *   the current step time at each step and had a "todo" note
		 *   to make it something more efficient like a binary search,
		 *   so I'm going ahead and implementing a binary search on a
		 *   presorted history instead of sorting states from all
		 *   frames on every frame.
		 */
		play: function() {
			if (!this.get('recording')) {
				// Sort the historical states by time ascending
				_.sortBy(this.history, function(state) {
					return state.time;
				});

				/* Store just the times in a parallel array so we
				 *   can do a binary search.
				 */
				this._historyTimes = _.pluck(this.history, 'time');
			}

			Simulation.prototype.play.apply(this);
		},

		/**
		 *
		 */
		rewind: function() {
			this.time = 0;
		},

		/**
		 *
		 */
		resetTimeAndHistory: function() {
			// This is the fastest way to clear an array by benchmarks
			var history = this.history;
			while (history.length > 0) {
				history.pop();
			}

			this.time = 0;

			this.movingMan.clear();
		},

		/**
		 * Sets playback mode to record
		 */
		record: function() {
			this.set('recording', true);
			this.set('timeScale', this.get('playbackSpeed'));
		},

		/**
		 * Sets playback mode to playback
		 */
		stopRecording: function() {
			this.set('recording', false);
			this.set('timeScale', 1);
		},

		/**
		 * Stores the current state of everything as a json object
		 *   in the history array for playback later.
		 */
		recordState: function() {
			this.history.push({
				time: this.time,
				wallsEnabled: this.get('wallsEnabled'),
				movingMan: this.movingMan.getState()
			});
		},

		/**
		 * Finds the appropriate state in history for this step and
		 *   applies it to the simulation.
		 */
		applyPlaybackState: function() {
			var state = this.findStateWithClosestTime(this.time);
			if (state) {
				this.set('wallsEnabled', state.wallsEnabled);
				this.movingMan.applyState(this.time, state.movingMan);
			}
		},

		/**
		 * Performs a binary search to find the state whose time
		 *   is closest to the specified time.
		 */
		findStateWithClosestTime: function(time) {
			var stateIndex = bs.closest(this._historyTimes, time);
			return this.history[stateIndex];
		},

	});

	return MovingManSimulation;
});
<|endoftext|>


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

var _ = require('lodash'),
	async = require('async'),
	Err = require('../../../errors'),
	Waterline = require('waterline'),
	util = require('util'),
	fs = require('fs'),
	STRINGFILE = require('sails-stringfile');

module.exports = function(sails) {

	var loadAppModelsAndAdapters = require('./loadUserModules')(sails);

	/**
	 * Expose Hook definition
	 */

	return {

		defaults: {

			globals: {
				adapters: true,
				models: true
			},

			// Default model properties
			models: {

				// This default connection (i.e. datasource) for the app
				// will be used for each model unless otherwise specified.
				// connection: 'localDiskDb'
			},

			// Connections to data sources, web services, and external APIs.
			// Can be attached to models and/or accessed directly.
			connections: {

				// Built-in disk persistence
				// (defaults to .tmp/disk.db)
				// localDiskDb: { adapter: 'sails-disk' }
			}
		},

		configure: function () {

			var self = this;

			//////////////////////////////////////////////////////////////////////////////////////////
			// Backwards compat. for `config.adapters`
			//////////////////////////////////////////////////////////////////////////////////////////

			// `sails.config.adapters` is now `config.connections`
			if (sails.config.adapters) {

				// `config.adapters.default` is being replaced with `config.models.connection`
				if (sails.config.adapters['default']) {

					sails.after('lifted', function () {

						STRINGFILE.logDeprecationNotice(
							'config.adapters.default',
							STRINGFILE.get('links.docs.migrationGuide.connections'),
							sails.log.debug) &&
						STRINGFILE.logUpgradeNotice(
							STRINGFILE.get('upgrade.config.models.connection'), [], sails.log.debug);

					});

					sails.config.models.connection = sails.config.models.connection || sails.config.adapters['default'];
				}

				// Merge `config.adapters` into `config.connections`
				sails.after('lifted', function () {

					STRINGFILE.logDeprecationNotice(
						'config.adapters',
						STRINGFILE.get('links.docs.migrationGuide.connections'),
						sails.log.debug) &&
					STRINGFILE.logUpgradeNotice(
						STRINGFILE.get('upgrade.config.connections'), [], sails.log.debug);

				});
				_.each(sails.config.adapters, function (legacyAdapterConfig, connectionName) {

					// Ignore `default`
					// (it was a special case in Sails versions <= v0.10)
					if (connectionName === 'default') {
						return;
					}

					// Normalize `module` to `adapter`
					var connection = _.clone(legacyAdapterConfig);
					connection.adapter = connection.module;
					delete connection.module;

					sails.after('lifted', function () {

						STRINGFILE.logDeprecationNotice(
							'config.adapters.*.module',
							STRINGFILE.get('links.docs.migrationGuide.connections'),
							sails.log.debug) &&
						STRINGFILE.logUpgradeNotice(
							STRINGFILE.get('upgrade.config.connections.*.adapter'), [connectionName], sails.log.debug);

					});
					sails.config.connections[connectionName] = sails.config.connections[connectionName] = connection;
				});
				delete sails.config.adapters;

			} // </if (sails.config.adapters) >

			// Listen for reload events
			// (which will just run the hook's `initialize()` fn again)
			sails.on('hook:orm:reload', function() {
				self.initialize(function(err) {
					// If the re-initialization was a success, trigger an event
					// in case something needs to respond to the ORM reload (e.g. pubsub)
					if (!err) {
						sails.emit('hook:orm:reloaded');
					}
				});
			});

		},

		initialize: function(cb) {
			var self = this;

			////////////////////////////////////////////////////////////////////////////
			// NOTE: If a user hook needs to add or modify model definitions,
			// the hook should wait until `hook:orm:loaded`, then reload the original
			// model modules `orm/loadUserModules`. Finally, the ORM should be flushed using
			// `restart()` below.
			////////////////////////////////////////////////////////////////////////////

			// Load model and adapter definitions defined in the project
			async.auto({

				_loadModules: loadAppModelsAndAdapters,

				// Normalize model definitions and merge in defaults from `sails.config.models`
				modelDefs: ['_loadModules', function normalizeModelDefs (cb) {
					_.each(sails.models, self.normalizeModelDef);
					cb(null, sails.models);
				}],

				// Once all user model definitions are loaded into sails.models,
				// go ahead and start the ORM, instantiate the models
				instantiatedCollections: ['modelDefs', this.startORM],

				_exposeModels: ['instantiatedCollections', this.exposeModels]

			}, cb);
		},

		/**
		 * Merge defaults and normalize options in this model definition
		 */
		normalizeModelDef: function (modelDef, modelID) {

			// Implicit framework defaults
			var implicitDefaults = {
				identity: modelID,
				tableName: modelID
			};

			// App defaults from `sails.config.models`
			var appDefaults = sails.config.models;

			// Rebuild model definition using the defaults
			modelDef = _.merge(implicitDefaults, appDefaults, modelDef);

			// Backwards compatibilty for `Model.adapter`
			if (modelDef.adapter) {
				sails.log.verbose(
					'Deprecation warning :: ' +
					'Replacing `' + modelDef.globalId + '.adapter` ' +
					'with `' + modelDef.globalId + '.connection`....');
				modelDef.connection = modelDef.adapter;
				delete modelDef.adapter;
			}

			// If no connection can be determined (even by using app-level defaults [config.models])
			// throw a fatal error.
			if ( !modelDef.connection ) {
				return Err.fatal.__ModelIsMissingConnection__(modelDef.globalId);
			}

			// Coerce `Model.connection` to an array
			if ( ! _.isArray(modelDef.connection) ) {
				modelDef.connection = [modelDef.connection];
			}

			// ========================================================================
			// ========================================================================
			// ========================================================================

			// Iterate through each of this models' connections
			// -> Make sure the adapter specified has been required.
			// -> If invalid connection found, throw fatal error.
			modelDef.connection = _.map( modelDef.connection, function (connection) {
				_normalizeConnection(connection, modelID);
				return connection;
			});

			// If it isn't set directly, set the model's `schema` property
			// based on the first adapter in its connections (left -> right)
			if ( typeof modelDef.schema === 'undefined') {
				var connection, schema;
				for (var i in modelDef.connection) {
					connection = modelDef.connection[i];
					// console.log('checking connection: ', connection);
					if (typeof connection.schema !== 'undefined') {
						schema = connection.schema;
						break;
					}
				}
				// console.log('trying to determine preference for schema setting..', modelDef.schema, typeof modelDef.schema, typeof modelDef.schema !== 'undefined', schema);
				if (typeof schema !== 'undefined') {
					modelDef.schema = schema;
				}
			}

			// Save modified model definition back to sails.models
			sails.models[modelID] = modelDef;

			//
			// ========================================================================
			// ========================================================================
			// ========================================================================

		},

		/**
		 * Instantiate Waterline Collection for each Sails Model,
		 * then start the ORM.
		 *
		 * @param {Function}	cb
		 *						  -> err	// Error, if one occurred, or null
		 *
		 * @param {Object}		stack
		 *						stack.modelDefs {}
		 *
		 * @global {Object}		sails
		 *						sails.models {}
		 */
		startORM: function(cb, stack) {
			var modelDefs = stack.modelDefs;

			// -> Instantiate ORM in memory.
			// -> Iterate through each model definition:
			//		-> Create a proper Waterline Collection for each model
			//		-> then register it w/ the ORM.
			sails.log.verbose('Starting ORM...');
			var waterline = new Waterline();
			_.each(modelDefs, function loadModelsIntoWaterline (modelDef, modelID) {
				sails.log.silly('Registering model `' + modelID + '` in Waterline (ORM)');
				waterline.loadCollection( Waterline.Collection.extend(modelDef) );
			});

			// Find all the connections used
			var connections = _.reduce(sails.adapters, function getConnectionsInPlay (connections, adapter, adapterKey) {
				_.each(sails.config.connections, function(connection, connectionKey) {
					if (adapterKey === connection.adapter) {
						connections[connectionKey] = connection;
					}
				});
				return connections;
			}, {});

			// -> "Initialize" ORM
			// 		: This performs tasks like managing the schema across associations,
			//		: hooking up models to their connections, and auto-migrations.
			waterline.initialize({
				adapters: sails.adapters,
				connections: connections
			}, cb);
		},

		/**
		 * exposeModels
		 *
		 * @param {Function}	cb
		 *						  -> err	// Error, if one occurred, or null
		 *
		 * @param {Object}		stack
		 *						stack.instantiatedCollections {}
		 */
		exposeModels: function (cb, stack) {
			var collections = stack.instantiatedCollections.collections || [];

			Object.keys(collections).forEach(function eachInstantiatedCollection (modelID) {

				// Bind context for models
				// (this (breaks?)allows usage with tools like `async`)
				_.bindAll(collections[modelID]);

				// Derive information about this model's associations from its schema
				var associatedWith = [];
				_(collections[modelID].attributes).forEach(function buildSubsetOfAssociations(attrDef, attrName) {
					if (typeof attrDef === 'object' && (attrDef.model || attrDef.collection)) {
						associatedWith.push(_.merge({
							alias: attrName,
							type: attrDef.model ? 'model' : 'collection'
						}, attrDef));
					}
				});

				// Expose `Model.associations` (an array)
				collections[modelID].associations = associatedWith;

				// Set `sails.models.*` reference to instantiated Collection
				// Exposed as `sails.models[modelID]`
				sails.models[modelID] = collections[modelID];

				// Create global variable for this model
				// (if enabled in `sails.config.globals`)
				// Exposed as `[globalId]`
				if (sails.config.globals && sails.config.globals.models) {
					var globalName = sails.models[modelID].globalId || sails.models[modelID].identity;
					global[globalName] = collections[modelID];
				}
			});

			cb();
		}
	};

	/**
	 * Lookup a connection (e.g., `{ adapter: 'sails-disk' }`)
	 * by name (e.g., 'devDB')
	 *
	 * @param {String}	connectionName
	 *
	 * @param {String}	modelID
	 *					// Optional, improves quality of error messages
	 *
	 * @global	sails
	 *			sails.config
	 *			sails.config.connections {}
	 *
	 * @throws {Err.fatal}	__UnknownConnection__
	 * @api private
	 */
	function _lookupConnection (connectionName, modelID) {
		var connection = sails.config.connections[connectionName];

		// If this is not a known connection, throw a fatal error.
		if (!connection) {
			return Err.fatal.__UnknownConnection__ (connectionName, modelID);
		}
		return connection;
	}

	/**
	 * Normalize properties of a connection
	 * (handles deprecation warnings / validation errors and making types consistent)
	 *
	 * @param {Object}	connection
	 *					connection.adapter	// Name of adapter module used by this connection
	 *					connection.module	// Deprecated- equivalent to `connection.adapter`
	 *
	 * @param {String}	modelID
	 *					// Optional, improves quality of error messages
	 *					// Identity of the model this connection came from
	 *
	 * @throws {Err.fatal}		__UnknownConnection__
	 * @throws {Err.fatal}		__InvalidConnection__
	 * @throws {Err.fatal}		__InvalidAdapter__
	 * @api private
	 */
	function _normalizeConnection (connection, modelID) {

		// Connection specified has not been configured
		var connectionObject = sails.config.connections[connection];
		if(!connectionObject) return Err.fatal.__InvalidConnection__ (connection, modelID);

		// Backwards compatibilty for `connection.module`
		if ( connectionObject.module ) {
			sails.log.verbose(
				'Deprecation warning :: In model `' + modelID + '`\'s `connection` config, ' +
				'replacing `module` with `adapter`....');
			connectionObject.adapter = connectionObject.module;
			delete connectionObject.module;
		}

		// Adapter is required for a connection
		if ( !connectionObject.adapter ) {
			// Invalid connection found, throw fatal error.
			return Err.fatal.__InvalidConnection__ (connectionObject, modelID);
		}

		// Verify that referenced adapter has been loaded
		// If it doesn't, try and load it as a dependency from `node_modules`
		if (!sails.adapters[connectionObject.adapter]) {

			// (Format adapter name to make sure we make the best attempt we can)
			var moduleName = connectionObject.adapter;
			if ( ! moduleName.match(/^(sails-|waterline-)/) ) {
				moduleName = 'sails-' + moduleName;
			}

			// Since it is unknown so far, try and load the adapter from `node_modules`
			sails.log.verbose('Loading adapter (', moduleName, ') for ' + modelID, ' from `node_modules` directory...');
			var modulePath = sails.config.appPath + '/node_modules/' + moduleName;
			if ( !fs.existsSync (modulePath) ) {
				// If adapter doesn't exist, log an error and exit
				return Err.fatal.__UnknownAdapter__ (connectionObject.adapter, modelID, sails.majorVersion, sails.minorVersion);
			}

			// Since the module seems to exist, try to require it (execute the code)
			try {
				sails.adapters[moduleName] = require(modulePath);
			}
			catch (err) {
				return Err.fatal.__InvalidAdapter__ (moduleName, err);
			}
		}

		// Defaults connection object to its adapter's defaults
		var desAdapters = sails.adapters[connectionObject.adapter];
		connection = _.merge({}, desAdapters.defaults, connectionObject);

		// Success- connection normalized and validated
		// (any missing adapters were either acquired, or the loading process was stopped w/ a fatal error)
		return connection;
	}

};
<commit_msg>'exposeModels' is now 'prepareModels' (was doing a bunch more than exposing the globals now)<commit_after>/**
 * Module dependencies.
 */

var _ = require('lodash'),
	async = require('async'),
	Err = require('../../../errors'),
	Waterline = require('waterline'),
	util = require('util'),
	fs = require('fs'),
	STRINGFILE = require('sails-stringfile');

module.exports = function(sails) {

	var loadAppModelsAndAdapters = require('./loadUserModules')(sails);

	/**
	 * Expose Hook definition
	 */

	return {

		defaults: {

			globals: {
				adapters: true,
				models: true
			},

			// Default model properties
			models: {

				// This default connection (i.e. datasource) for the app
				// will be used for each model unless otherwise specified.
				// connection: 'localDiskDb'
			},

			// Connections to data sources, web services, and external APIs.
			// Can be attached to models and/or accessed directly.
			connections: {

				// Built-in disk persistence
				// (defaults to .tmp/disk.db)
				// localDiskDb: { adapter: 'sails-disk' }
			}
		},

		configure: function () {

			var self = this;

			//////////////////////////////////////////////////////////////////////////////////////////
			// Backwards compat. for `config.adapters`
			//////////////////////////////////////////////////////////////////////////////////////////

			// `sails.config.adapters` is now `config.connections`
			if (sails.config.adapters) {

				// `config.adapters.default` is being replaced with `config.models.connection`
				if (sails.config.adapters['default']) {

					sails.after('lifted', function () {

						STRINGFILE.logDeprecationNotice(
							'config.adapters.default',
							STRINGFILE.get('links.docs.migrationGuide.connections'),
							sails.log.debug) &&
						STRINGFILE.logUpgradeNotice(
							STRINGFILE.get('upgrade.config.models.connection'), [], sails.log.debug);

					});

					sails.config.models.connection = sails.config.models.connection || sails.config.adapters['default'];
				}

				// Merge `config.adapters` into `config.connections`
				sails.after('lifted', function () {

					STRINGFILE.logDeprecationNotice(
						'config.adapters',
						STRINGFILE.get('links.docs.migrationGuide.connections'),
						sails.log.debug) &&
					STRINGFILE.logUpgradeNotice(
						STRINGFILE.get('upgrade.config.connections'), [], sails.log.debug);

				});
				_.each(sails.config.adapters, function (legacyAdapterConfig, connectionName) {

					// Ignore `default`
					// (it was a special case in Sails versions <= v0.10)
					if (connectionName === 'default') {
						return;
					}

					// Normalize `module` to `adapter`
					var connection = _.clone(legacyAdapterConfig);
					connection.adapter = connection.module;
					delete connection.module;

					sails.after('lifted', function () {

						STRINGFILE.logDeprecationNotice(
							'config.adapters.*.module',
							STRINGFILE.get('links.docs.migrationGuide.connections'),
							sails.log.debug) &&
						STRINGFILE.logUpgradeNotice(
							STRINGFILE.get('upgrade.config.connections.*.adapter'), [connectionName], sails.log.debug);

					});
					sails.config.connections[connectionName] = sails.config.connections[connectionName] = connection;
				});
				delete sails.config.adapters;

			} // </if (sails.config.adapters) >

			// Listen for reload events
			// (which will just run the hook's `initialize()` fn again)
			sails.on('hook:orm:reload', function() {
				self.initialize(function(err) {
					// If the re-initialization was a success, trigger an event
					// in case something needs to respond to the ORM reload (e.g. pubsub)
					if (!err) {
						sails.emit('hook:orm:reloaded');
					}
				});
			});

		},

		initialize: function(cb) {
			var self = this;

			////////////////////////////////////////////////////////////////////////////
			// NOTE: If a user hook needs to add or modify model definitions,
			// the hook should wait until `hook:orm:loaded`, then reload the original
			// model modules `orm/loadUserModules`. Finally, the ORM should be flushed using
			// `restart()` below.
			////////////////////////////////////////////////////////////////////////////

			// Load model and adapter definitions defined in the project
			async.auto({

				_loadModules: loadAppModelsAndAdapters,

				// Normalize model definitions and merge in defaults from `sails.config.models`
				modelDefs: ['_loadModules', function normalizeModelDefs (cb) {
					_.each(sails.models, self.normalizeModelDef);
					cb(null, sails.models);
				}],

				// Once all user model definitions are loaded into sails.models,
				// go ahead and start the ORM, instantiate the models
				instantiatedCollections: ['modelDefs', this.startORM],

				_prepareModels: ['instantiatedCollections', this.prepareModels]

			}, cb);
		},

		/**
		 * Merge defaults and normalize options in this model definition
		 */
		normalizeModelDef: function (modelDef, modelID) {

			// Implicit framework defaults
			var implicitDefaults = {
				identity: modelID,
				tableName: modelID
			};

			// App defaults from `sails.config.models`
			var appDefaults = sails.config.models;

			// Rebuild model definition using the defaults
			modelDef = _.merge(implicitDefaults, appDefaults, modelDef);

			// Backwards compatibilty for `Model.adapter`
			if (modelDef.adapter) {
				sails.log.verbose(
					'Deprecation warning :: ' +
					'Replacing `' + modelDef.globalId + '.adapter` ' +
					'with `' + modelDef.globalId + '.connection`....');
				modelDef.connection = modelDef.adapter;
				delete modelDef.adapter;
			}

			// If no connection can be determined (even by using app-level defaults [config.models])
			// throw a fatal error.
			if ( !modelDef.connection ) {
				return Err.fatal.__ModelIsMissingConnection__(modelDef.globalId);
			}

			// Coerce `Model.connection` to an array
			if ( ! _.isArray(modelDef.connection) ) {
				modelDef.connection = [modelDef.connection];
			}

			// ========================================================================
			// ========================================================================
			// ========================================================================

			// Iterate through each of this models' connections
			// -> Make sure the adapter specified has been required.
			// -> If invalid connection found, throw fatal error.
			modelDef.connection = _.map( modelDef.connection, function (connection) {
				_normalizeConnection(connection, modelID);
				return connection;
			});

			// If it isn't set directly, set the model's `schema` property
			// based on the first adapter in its connections (left -> right)
			if ( typeof modelDef.schema === 'undefined') {
				var connection, schema;
				for (var i in modelDef.connection) {
					connection = modelDef.connection[i];
					// console.log('checking connection: ', connection);
					if (typeof connection.schema !== 'undefined') {
						schema = connection.schema;
						break;
					}
				}
				// console.log('trying to determine preference for schema setting..', modelDef.schema, typeof modelDef.schema, typeof modelDef.schema !== 'undefined', schema);
				if (typeof schema !== 'undefined') {
					modelDef.schema = schema;
				}
			}

			// Save modified model definition back to sails.models
			sails.models[modelID] = modelDef;

			//
			// ========================================================================
			// ========================================================================
			// ========================================================================

		},

		/**
		 * Instantiate Waterline Collection for each Sails Model,
		 * then start the ORM.
		 *
		 * @param {Function}	cb
		 *						  -> err	// Error, if one occurred, or null
		 *
		 * @param {Object}		stack
		 *						stack.modelDefs {}
		 *
		 * @global {Object}		sails
		 *						sails.models {}
		 */
		startORM: function(cb, stack) {
			var modelDefs = stack.modelDefs;

			// -> Instantiate ORM in memory.
			// -> Iterate through each model definition:
			//		-> Create a proper Waterline Collection for each model
			//		-> then register it w/ the ORM.
			sails.log.verbose('Starting ORM...');
			var waterline = new Waterline();
			_.each(modelDefs, function loadModelsIntoWaterline (modelDef, modelID) {
				sails.log.silly('Registering model `' + modelID + '` in Waterline (ORM)');
				waterline.loadCollection( Waterline.Collection.extend(modelDef) );
			});

			// Find all the connections used
			var connections = _.reduce(sails.adapters, function getConnectionsInPlay (connections, adapter, adapterKey) {
				_.each(sails.config.connections, function(connection, connectionKey) {
					if (adapterKey === connection.adapter) {
						connections[connectionKey] = connection;
					}
				});
				return connections;
			}, {});

			// -> "Initialize" ORM
			// 		: This performs tasks like managing the schema across associations,
			//		: hooking up models to their connections, and auto-migrations.
			waterline.initialize({
				adapters: sails.adapters,
				connections: connections
			}, cb);
		},

		/**
		 * prepareModels
		 *
		 * @param {Function}	cb
		 *						  -> err	// Error, if one occurred, or null
		 *
		 * @param {Object}		stack
		 *						stack.instantiatedCollections {}
		 */
		prepareModels: function (cb, stack) {
			var collections = stack.instantiatedCollections.collections || [];

			Object.keys(collections).forEach(function eachInstantiatedCollection (modelID) {

				// Bind context for models
				// (this (breaks?)allows usage with tools like `async`)
				_.bindAll(collections[modelID]);

				// Derive information about this model's associations from its schema
				var associatedWith = [];
				_(collections[modelID].attributes).forEach(function buildSubsetOfAssociations(attrDef, attrName) {
					if (typeof attrDef === 'object' && (attrDef.model || attrDef.collection)) {
						associatedWith.push(_.merge({
							alias: attrName,
							type: attrDef.model ? 'model' : 'collection'
						}, attrDef));
					}
				});

				// Expose `Model.associations` (an array)
				collections[modelID].associations = associatedWith;

				// Set `sails.models.*` reference to instantiated Collection
				// Exposed as `sails.models[modelID]`
				sails.models[modelID] = collections[modelID];

				// Create global variable for this model
				// (if enabled in `sails.config.globals`)
				// Exposed as `[globalId]`
				if (sails.config.globals && sails.config.globals.models) {
					var globalName = sails.models[modelID].globalId || sails.models[modelID].identity;
					global[globalName] = collections[modelID];
				}
			});

			cb();
		}
	};

	/**
	 * Lookup a connection (e.g., `{ adapter: 'sails-disk' }`)
	 * by name (e.g., 'devDB')
	 *
	 * @param {String}	connectionName
	 *
	 * @param {String}	modelID
	 *					// Optional, improves quality of error messages
	 *
	 * @global	sails
	 *			sails.config
	 *			sails.config.connections {}
	 *
	 * @throws {Err.fatal}	__UnknownConnection__
	 * @api private
	 */
	function _lookupConnection (connectionName, modelID) {
		var connection = sails.config.connections[connectionName];

		// If this is not a known connection, throw a fatal error.
		if (!connection) {
			return Err.fatal.__UnknownConnection__ (connectionName, modelID);
		}
		return connection;
	}

	/**
	 * Normalize properties of a connection
	 * (handles deprecation warnings / validation errors and making types consistent)
	 *
	 * @param {Object}	connection
	 *					connection.adapter	// Name of adapter module used by this connection
	 *					connection.module	// Deprecated- equivalent to `connection.adapter`
	 *
	 * @param {String}	modelID
	 *					// Optional, improves quality of error messages
	 *					// Identity of the model this connection came from
	 *
	 * @throws {Err.fatal}		__UnknownConnection__
	 * @throws {Err.fatal}		__InvalidConnection__
	 * @throws {Err.fatal}		__InvalidAdapter__
	 * @api private
	 */
	function _normalizeConnection (connection, modelID) {

		// Connection specified has not been configured
		var connectionObject = sails.config.connections[connection];
		if(!connectionObject) return Err.fatal.__InvalidConnection__ (connection, modelID);

		// Backwards compatibilty for `connection.module`
		if ( connectionObject.module ) {
			sails.log.verbose(
				'Deprecation warning :: In model `' + modelID + '`\'s `connection` config, ' +
				'replacing `module` with `adapter`....');
			connectionObject.adapter = connectionObject.module;
			delete connectionObject.module;
		}

		// Adapter is required for a connection
		if ( !connectionObject.adapter ) {
			// Invalid connection found, throw fatal error.
			return Err.fatal.__InvalidConnection__ (connectionObject, modelID);
		}

		// Verify that referenced adapter has been loaded
		// If it doesn't, try and load it as a dependency from `node_modules`
		if (!sails.adapters[connectionObject.adapter]) {

			// (Format adapter name to make sure we make the best attempt we can)
			var moduleName = connectionObject.adapter;
			if ( ! moduleName.match(/^(sails-|waterline-)/) ) {
				moduleName = 'sails-' + moduleName;
			}

			// Since it is unknown so far, try and load the adapter from `node_modules`
			sails.log.verbose('Loading adapter (', moduleName, ') for ' + modelID, ' from `node_modules` directory...');
			var modulePath = sails.config.appPath + '/node_modules/' + moduleName;
			if ( !fs.existsSync (modulePath) ) {
				// If adapter doesn't exist, log an error and exit
				return Err.fatal.__UnknownAdapter__ (connectionObject.adapter, modelID, sails.majorVersion, sails.minorVersion);
			}

			// Since the module seems to exist, try to require it (execute the code)
			try {
				sails.adapters[moduleName] = require(modulePath);
			}
			catch (err) {
				return Err.fatal.__InvalidAdapter__ (moduleName, err);
			}
		}

		// Defaults connection object to its adapter's defaults
		var desAdapters = sails.adapters[connectionObject.adapter];
		connection = _.merge({}, desAdapters.defaults, connectionObject);

		// Success- connection normalized and validated
		// (any missing adapters were either acquired, or the loading process was stopped w/ a fatal error)
		return connection;
	}

};
<|endoftext|>


<commit_before>
const PARTIES = ["M5S", "piùEuropa", "Lega Nord", "Forza Italia", "Potere Al Popolo",  "Fratelli d'Italia", "PD",  "Liberi e Uguali", "Casa Pound"];
const PARTYCOLORS  = ["#FCDA1B", "#2D9DB4", "#299733", "#13487B", "#DE0016", "#151653", "#EB733F", "#DE0000", "black"];

let container = d3.select("#container");
let width = container.node().getBoundingClientRect().width;
let height = container.node().getBoundingClientRect().height;

let svg = container.select("svg").attr("height", height);
let edgesCont = svg.append("g").attr("id", "edgesCont");
let nodesCont = svg.append("g").attr("id", "nodesCont");

// TOOLTIP
let tooltip =d3.select("#tooltip");

// SCALES
let radiusScale = d3.scaleSqrt().clamp(true).range([10,40]);
let strokeScale = d3.scaleLinear().clamp(true).range([1,5]);
let distanceScale = d3.scaleLinear().clamp(true).range([width*.1,10]); // lighter weight correspond to higher distances
let colorScale = d3.scaleOrdinal().range(PARTYCOLORS).domain(PARTIES);

// DATA
let graph;
let selectedSource;

// PHYSICS
let simulation;

function onLoaded(error, data) {

	if (error) throw error;

	let partiti = {};
	data.nodes.forEach(d=>{if(!partiti[d.partito]) partiti[d.partito]= d;});

	graph = data;

	// assign id based on indices
	graph.nodes.forEach((d,i)=> d.id=i);

	// update scales
	let sortedWeights = graph.edges.map((d)=>d.weight).sort();
	let quantileExtent = [d3.quantile(sortedWeights, 0.05), d3.quantile(sortedWeights, 0.95)];

	distanceScale.domain(quantileExtent);
	strokeScale.domain(quantileExtent);
	radiusScale.domain(d3.extent(graph.nodes, (d)=>d.tweets));

	updateGraph();

}

function updateGraph() {

	let edges = graph.edges.filter(d=>d.weight > 0.1);

	let link = edgesCont.selectAll(".link")
	.data(edges, (d)=>d.id);

	let linkGroups = link
	.enter()
	.append("g")
	.attr("class", "link")
	.style("opacity", .7)
	.on("mouseover", function(d){updateEdgeTooltip(d, d3.select(this));})
	.on("mouseout", function(){updateEdgeTooltip(null, null);});

	linkGroups
	.append("line")
	.attr("stroke-width", 10)
	.style("stroke-opacity", 0);

	linkGroups
	.append("line")
	.attr("class", "realLink")
	.attr("stroke-width", (d)=>strokeScale(d.weight));

	let node = nodesCont.selectAll(".node")
	.data(graph.nodes, (d)=>d.name);

	node
	.enter()
	.append("circle")
	.attr("class", "node")
	.attr("r", (d)=> (radiusScale(d.tweets)))
	.style("stroke-width", 0)
	.style("stroke", "black")
	.style("fill", d=>colorScale(d.partito))
	.style("fill-opacity", 1)
	.on("mousedown", updateSelectedNode)
	.call(d3.drag()
		.on("start", dragstarted)
		.on("drag", dragged)
		.on("end", dragended));

	node
	.exit()
	.remove();

	let text = svg
	.selectAll(".label")
	.data(graph.nodes);

	text
	.enter()
	.append("g")
	.attr("class", "label")
	.each(function(d){

		var el = d3.select(this);

		el
		.append("text")
		.attr("text-anchor", "middle")
		.attr("fill", "black")
		.text(d.name);

	});

	text
	.exit()
	.remove();

	if(!simulation) {
		simulation = d3.forceSimulation()
		.force("link", d3.forceLink())
		.force("charge", d3.forceCollide().radius((d)=>radiusScale(d.tweets)*2))
		.force("center", d3.forceCenter(width * .4, height * .4))
		.on("tick", ticked);
	}
	simulation.nodes(graph.nodes);

	simulation.force("link")
	.links(graph.edges)
	.distance((d)=> {
		return distanceScale(d.weight) + 200;
	});
}

function ticked() {
	svg.selectAll(".link").selectAll("line")
	.attr("x1", (d)=> d.source.x)
	.attr("y1", (d)=> d.source.y)
	.attr("x2", (d)=> d.target.x)
	.attr("y2", (d)=> d.target.y);

	svg.selectAll(".node")
	.attr("cx", (d)=> d.x)
	.attr("cy", (d)=> d.y);

	svg.selectAll(".label")
	.attr("transform", d=>`translate(${d.x}, ${d.y + radiusScale(d.tweets) + 10})`);

}

function dragstarted(d) {
	if (!d3.event.active) simulation.alphaTarget(0.3).restart();
	d.fx = d.x;
	d.fy = d.y;
}

function dragged(d) {
	d.fx = d3.event.x;
	d.fy = d3.event.y;
}

function dragended(d) {
	if (!d3.event.active) simulation.alphaTarget(0);
	d.fx = null;
	d.fy = null;
}

function updateEdgeTooltip(edge, el) {

	if(!selectedSource) return;

	if(edge && (edge.source.id == selectedSource.id || edge.target.id == selectedSource.id)) {

		el
		.select(".realLink")
		.style("stroke", "black");

		tooltip
		.append("h3")
		.text(`${edge.source.name} – ${edge.target.name} `);

		tooltip
		.append("b")
		.text("Parole in comune più usate");

		tooltip
		.append("p")
		.text(edge.words.most_similar.map(d=>d[0]).join(", "));

		tooltip
		.append("b")
		.text("Parole in comune meno usate");

		tooltip
		.append("p")
		.text(edge.words.most_different.map(d=>d[0]).join(", "));

		updateNodeStrokes(edge);

	} else {

		tooltip
		.html("");

		updateEdgeStrokes();
		updateNodeStrokes();

	}

}

function updateNodeStrokes(edge) {

	nodesCont
	.selectAll(".node")
	.style("stroke-width", d=> {

		let selected;

		if(edge) {
			selected = d.id == edge.source.id || d.id == edge.target.id;
		} else {
			selected = d.id == selectedSource.id;
		}

		return selected ? 3 : 0;
	});

}

function updateEdgeStrokes() {

	edgesCont
	.selectAll(".realLink")
	.style("stroke", d=>{
		let selected = d.source.id == selectedSource.id || d.target.id == selectedSource.id;
		return selected ? colorScale(selectedSource.partito) : "#ddd";
	});

}

function updateSelectedNode(d) {

	d.selected = true;
	selectedSource = d;

	edgesCont
	.selectAll(".link")
	.each(function(edge){

		let el = d3.select(this);

		let selected = edge.source.id == selectedSource.id || edge.target.id == selectedSource.id ;

		el.style("cursor", selected ? "pointer" : "default").style("opacity", selected ? 1 : .7);

		if( selected) {
			let node = el.node();
			node.parentNode.appendChild(node);
		}

	});

	updateEdgeStrokes(d);
	updateNodeStrokes();

}

// START
d3.json("politicians_graph.json", onLoaded);<commit_msg>partito -> party<commit_after>
const PARTIES = ["M5S", "piùEuropa", "Lega Nord", "Forza Italia", "Potere Al Popolo",  "Fratelli d'Italia", "PD",  "Liberi e Uguali", "Casa Pound"];
const PARTYCOLORS  = ["#FCDA1B", "#2D9DB4", "#299733", "#13487B", "#DE0016", "#151653", "#EB733F", "#DE0000", "black"];

let container = d3.select("#container");
let width = container.node().getBoundingClientRect().width;
let height = container.node().getBoundingClientRect().height;

let svg = container.select("svg").attr("height", height);
let edgesCont = svg.append("g").attr("id", "edgesCont");
let nodesCont = svg.append("g").attr("id", "nodesCont");

// TOOLTIP
let tooltip =d3.select("#tooltip");

// SCALES
let radiusScale = d3.scaleSqrt().clamp(true).range([10,40]);
let strokeScale = d3.scaleLinear().clamp(true).range([1,5]);
let distanceScale = d3.scaleLinear().clamp(true).range([width*.1,10]); // lighter weight correspond to higher distances
let colorScale = d3.scaleOrdinal().range(PARTYCOLORS).domain(PARTIES);

// DATA
let graph;
let selectedSource;

// PHYSICS
let simulation;

function onLoaded(error, data) {

	if (error) throw error;

	let parties = {};
	data.nodes.forEach(d=>{if(!parties[d.party]) parties[d.party]= d;});

	graph = data;

	// assign id based on indices
	graph.nodes.forEach((d,i)=> d.id=i);

	// update scales
	let sortedWeights = graph.edges.map((d)=>d.weight).sort();
	let quantileExtent = [d3.quantile(sortedWeights, 0.05), d3.quantile(sortedWeights, 0.95)];

	distanceScale.domain(quantileExtent);
	strokeScale.domain(quantileExtent);
	radiusScale.domain(d3.extent(graph.nodes, (d)=>d.tweets));

	updateGraph();

}

function updateGraph() {

	let edges = graph.edges.filter(d=>d.weight > 0.1);

	let link = edgesCont.selectAll(".link")
	.data(edges, (d)=>d.id);

	let linkGroups = link
	.enter()
	.append("g")
	.attr("class", "link")
	.style("opacity", .7)
	.on("mouseover", function(d){updateEdgeTooltip(d, d3.select(this));})
	.on("mouseout", function(){updateEdgeTooltip(null, null);});

	linkGroups
	.append("line")
	.attr("stroke-width", 10)
	.style("stroke-opacity", 0);

	linkGroups
	.append("line")
	.attr("class", "realLink")
	.attr("stroke-width", (d)=>strokeScale(d.weight));

	let node = nodesCont.selectAll(".node")
	.data(graph.nodes, (d)=>d.name);

	node
	.enter()
	.append("circle")
	.attr("class", "node")
	.attr("r", (d)=> (radiusScale(d.tweets)))
	.style("stroke-width", 0)
	.style("stroke", "black")
	.style("fill", d=>colorScale(d.party))
	.style("fill-opacity", 1)
	.on("mousedown", updateSelectedNode)
	.call(d3.drag()
		.on("start", dragstarted)
		.on("drag", dragged)
		.on("end", dragended));

	node
	.exit()
	.remove();

	let text = svg
	.selectAll(".label")
	.data(graph.nodes);

	text
	.enter()
	.append("g")
	.attr("class", "label")
	.each(function(d){

		var el = d3.select(this);

		el
		.append("text")
		.attr("text-anchor", "middle")
		.attr("fill", "black")
		.text(d.name);

	});

	text
	.exit()
	.remove();

	if(!simulation) {
		simulation = d3.forceSimulation()
		.force("link", d3.forceLink())
		.force("charge", d3.forceCollide().radius((d)=>radiusScale(d.tweets)*2))
		.force("center", d3.forceCenter(width * .4, height * .4))
		.on("tick", ticked);
	}
	simulation.nodes(graph.nodes);

	simulation.force("link")
	.links(graph.edges)
	.distance((d)=> {
		return distanceScale(d.weight) + 200;
	});
}

function ticked() {
	svg.selectAll(".link").selectAll("line")
	.attr("x1", (d)=> d.source.x)
	.attr("y1", (d)=> d.source.y)
	.attr("x2", (d)=> d.target.x)
	.attr("y2", (d)=> d.target.y);

	svg.selectAll(".node")
	.attr("cx", (d)=> d.x)
	.attr("cy", (d)=> d.y);

	svg.selectAll(".label")
	.attr("transform", d=>`translate(${d.x}, ${d.y + radiusScale(d.tweets) + 10})`);

}

function dragstarted(d) {
	if (!d3.event.active) simulation.alphaTarget(0.3).restart();
	d.fx = d.x;
	d.fy = d.y;
}

function dragged(d) {
	d.fx = d3.event.x;
	d.fy = d3.event.y;
}

function dragended(d) {
	if (!d3.event.active) simulation.alphaTarget(0);
	d.fx = null;
	d.fy = null;
}

function updateEdgeTooltip(edge, el) {

	if(!selectedSource) return;

	if(edge && (edge.source.id == selectedSource.id || edge.target.id == selectedSource.id)) {

		el
		.select(".realLink")
		.style("stroke", "black");

		tooltip
		.append("h3")
		.text(`${edge.source.name} – ${edge.target.name} `);

		tooltip
		.append("b")
		.text("Parole in comune più usate");

		tooltip
		.append("p")
		.text(edge.words.most_similar.map(d=>d[0]).join(", "));

		tooltip
		.append("b")
		.text("Parole in comune meno usate");

		tooltip
		.append("p")
		.text(edge.words.most_different.map(d=>d[0]).join(", "));

		updateNodeStrokes(edge);

	} else {

		tooltip
		.html("");

		updateEdgeStrokes();
		updateNodeStrokes();

	}

}

function updateNodeStrokes(edge) {

	nodesCont
	.selectAll(".node")
	.style("stroke-width", d=> {

		let selected;

		if(edge) {
			selected = d.id == edge.source.id || d.id == edge.target.id;
		} else {
			selected = d.id == selectedSource.id;
		}

		return selected ? 3 : 0;
	});

}

function updateEdgeStrokes() {

	edgesCont
	.selectAll(".realLink")
	.style("stroke", d=>{
		let selected = d.source.id == selectedSource.id || d.target.id == selectedSource.id;
		return selected ? colorScale(selectedSource.party) : "#ddd";
	});

}

function updateSelectedNode(d) {

	d.selected = true;
	selectedSource = d;

	edgesCont
	.selectAll(".link")
	.each(function(edge){

		let el = d3.select(this);

		let selected = edge.source.id == selectedSource.id || edge.target.id == selectedSource.id ;

		el.style("cursor", selected ? "pointer" : "default").style("opacity", selected ? 1 : .7);

		if( selected) {
			let node = el.node();
			node.parentNode.appendChild(node);
		}

	});

	updateEdgeStrokes(d);
	updateNodeStrokes();

}

// START
d3.json("politicians_graph.json", onLoaded);<|endoftext|>