<commit_before>'use strict';

var Promise = require('../ext/promise');
var path    = require('path');
var findup  = Promise.denodeify(require('findup'));
var resolve = Promise.denodeify(require('resolve'));
var fs      = require('fs');
var assign  = require('lodash-node/modern/objects/assign');
var DAG     = require('../utilities/DAG');
var Command = require('../models/command');
var Addon   = require('../models/addon');

var emberCLIVersion = require('../utilities/ember-cli-version');

function Project(root, pkg) {
  this.root          = root;
  this.pkg           = pkg;
  this.addonPackages = {};
}

Project.prototype.name = function() {
  return this.pkg.name;
};

Project.prototype.isEmberCLIProject = function() {
  return this.pkg.devDependencies && 'ember-cli' in this.pkg.devDependencies;
};

Project.prototype.isEmberCLIAddon = function() {
  return this.pkg.keywords && this.pkg.keywords.indexOf('ember-addon') > -1;
};

Project.prototype.config = function(env) {
  var configPath = 'config';

  if (this.pkg['ember-addon'] && this.pkg['ember-addon']['configPath']) {
    configPath = this.pkg['ember-addon']['configPath'];
  }
  if (fs.existsSync(path.join(this.root, configPath, 'environment.js'))) {
    return this.require('./' + path.join(configPath, 'environment'))(env);
  } else {
    return { };
  }
};

Project.prototype.has = function(file) {
  return fs.existsSync(path.join(this.root, file)) || fs.existsSync(path.join(this.root, file + '.js'));
};

Project.prototype.resolve = function(file) {
  return resolve(file, {
    basedir: this.root
  });
};

Project.prototype.require = function(file) {
  if (/^\.\//.test(file)) { // Starts with ./
    return require(path.join(this.root, file));
  } else {
    return require(path.join(this.root, 'node_modules', file));
  }
};

Project.prototype.emberCLIVersion = emberCLIVersion;

Project.prototype.dependencies = function(pkg) {
  pkg = pkg || this.pkg || {};
  return assign({}, pkg['devDependencies'], pkg['dependencies']);
};

Project.prototype.buildAddonPackages = function() {
  if (!this.root) { return; }

  var internalMiddlewarePath = path.join(this.root, path.relative(this.root, path.join(__dirname, '../tasks/server/middleware')));

  this.addIfAddon(path.join(internalMiddlewarePath, 'live-reload'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'history-support'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'serve-files'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'proxy-server'));

  this.discoverAddons(this.root, this.pkg);
};

Project.prototype.discoverAddons = function(root, pkg) {
  Object.keys(this.dependencies(pkg)).forEach(function(name) {
    if (name !== 'ember-cli') {
      var addonPath = path.join(root, 'node_modules', name);
      this.addIfAddon(addonPath);
    }
  }, this);

  if (pkg['ember-addon'] && pkg['ember-addon'].paths) {
    pkg['ember-addon'].paths.forEach(function(addonPath) {
      addonPath = path.join(root, addonPath);
      this.addIfAddon(addonPath);
    }, this);
  }
};

Project.prototype.addIfAddon = function(addonPath) {
  var pkgPath = path.join(addonPath, 'package.json');

  if(fs.existsSync(pkgPath)) {
    var addonPkg = require(pkgPath);
    var keywords = addonPkg.keywords || [];

    addonPkg['ember-addon'] = addonPkg['ember-addon'] || {};

    if (keywords.indexOf('ember-addon') > -1) {
      this.addonPackages[addonPkg.name] = {
        path: addonPath,
        pkg: addonPkg
      };
      this.discoverAddons(addonPath, addonPkg);
    }
  }
};

Project.prototype.initializeAddons = function() {
  var project         = this;
  var graph           = new DAG();
  var addon, emberAddonConfig;

  this.buildAddonPackages();

  for (var name in this.addonPackages) {
    addon            = this.addonPackages[name];
    emberAddonConfig = addon.pkg['ember-addon'];

    graph.addEdges(name, addon, emberAddonConfig.before, emberAddonConfig.after);
  }

  this.addons = [];
  graph.topsort(function (vertex) {
    var addon           = vertex.value;
    var AddonConstructor = Addon.lookup(addon);

    project.addons.push(new AddonConstructor(project));
  });
};

Project.prototype.addonCommands = function() {
  var commands = {};
  this.addons.forEach(function(addon){
    var includedCommands = (addon.includedCommands && addon.includedCommands()) || {};
    var addonCommands = {};
    for (var key in includedCommands) {
      addonCommands[key] = Command.extend(includedCommands[key]);
    }
    if(Object.keys(addonCommands).length) {
      commands[addon.name] = addonCommands;
    }
  });
  return commands;
};

Project.prototype.eachAddonCommand = function(callback) {
  if(this.initializeAddons && this.addonCommands) {
    this.initializeAddons();
    var addonCommands = this.addonCommands();

    Object.keys(addonCommands).forEach(function(addonName){
      callback(addonName, addonCommands[addonName]);
    }.bind(this));
  }
};

Project.prototype.localBlueprintLookupPath = function() {
  return path.join(this.root, 'blueprints');
};

Project.prototype.blueprintLookupPaths = function() {
  var lookupPaths = [this.localBlueprintLookupPath()];
  var addonLookupPaths = this.addonBlueprintLookupPaths();

  return lookupPaths.concat(addonLookupPaths);
};

Project.prototype.addonBlueprintLookupPaths = function() {
  var addonPaths = this.addons.map(function(addon) {
    if (addon.blueprintsPath) {
      return addon.blueprintsPath();
    }
  }, this);

  return addonPaths.filter(Boolean);
};

Project.closest = function(pathName) {
  return closestPackageJSON(pathName)
    .then(function(result) {
      return new Project(result.directory, result.pkg);
    })
    .catch(function(reason) {
      handleFindupError(pathName, reason);
    });
};

Project.closestSync = function(pathName) {
  try {
    var directory = findup.sync(pathName, 'package.json');

    return new Project(directory, require(path.join(directory, 'package.json')));
  } catch(reason) {
    handleFindupError(pathName, reason);
  }
};

var NULL_PROJECT = new Project(undefined, undefined);

NULL_PROJECT.isEmberCLIProject = function() {
  return false;
};

NULL_PROJECT.name = function() {
  return path.basename(process.cwd());
};

Project.NULL_PROJECT = NULL_PROJECT;

function NotFoundError(message) {
  this.name = 'NotFoundError';
  this.message = message;
  this.stack = (new Error()).stack;
}

NotFoundError.constructor = NotFoundError;
NotFoundError.prototype = Object.create(Error.prototype);

Project.NotFoundError = NotFoundError;

function closestPackageJSON(pathName) {
  return findup(pathName, 'package.json')
    .then(function(directory) {
      return Promise.hash({
        directory: directory,
        pkg: require(path.join(directory, 'package.json'))
      });
    });
}

function handleFindupError(pathName, reason) {
  // Would be nice if findup threw error subclasses
  if (reason && /not found/i.test(reason.message)) {
    throw new NotFoundError('No project found at or up from: `' + pathName + '`');
  } else {
    throw reason;
  }
}

// Export
module.exports = Project;
<commit_msg>Force addon deps to be included before addon<commit_after>'use strict';

var Promise = require('../ext/promise');
var path    = require('path');
var findup  = Promise.denodeify(require('findup'));
var resolve = Promise.denodeify(require('resolve'));
var fs      = require('fs');
var assign  = require('lodash-node/modern/objects/assign');
var DAG     = require('../utilities/DAG');
var Command = require('../models/command');
var Addon   = require('../models/addon');

var emberCLIVersion = require('../utilities/ember-cli-version');

function Project(root, pkg) {
  this.root          = root;
  this.pkg           = pkg;
  this.addonPackages = {};
}

Project.prototype.name = function() {
  return this.pkg.name;
};

Project.prototype.isEmberCLIProject = function() {
  return this.pkg.devDependencies && 'ember-cli' in this.pkg.devDependencies;
};

Project.prototype.isEmberCLIAddon = function() {
  return this.pkg.keywords && this.pkg.keywords.indexOf('ember-addon') > -1;
};

Project.prototype.config = function(env) {
  var configPath = 'config';

  if (this.pkg['ember-addon'] && this.pkg['ember-addon']['configPath']) {
    configPath = this.pkg['ember-addon']['configPath'];
  }
  if (fs.existsSync(path.join(this.root, configPath, 'environment.js'))) {
    return this.require('./' + path.join(configPath, 'environment'))(env);
  } else {
    return { };
  }
};

Project.prototype.has = function(file) {
  return fs.existsSync(path.join(this.root, file)) || fs.existsSync(path.join(this.root, file + '.js'));
};

Project.prototype.resolve = function(file) {
  return resolve(file, {
    basedir: this.root
  });
};

Project.prototype.require = function(file) {
  if (/^\.\//.test(file)) { // Starts with ./
    return require(path.join(this.root, file));
  } else {
    return require(path.join(this.root, 'node_modules', file));
  }
};

Project.prototype.emberCLIVersion = emberCLIVersion;

Project.prototype.dependencies = function(pkg) {
  pkg = pkg || this.pkg || {};
  return assign({}, pkg['devDependencies'], pkg['dependencies']);
};

Project.prototype.buildAddonPackages = function() {
  if (!this.root) { return; }

  var internalMiddlewarePath = path.join(this.root, path.relative(this.root, path.join(__dirname, '../tasks/server/middleware')));

  this.addIfAddon(path.join(internalMiddlewarePath, 'live-reload'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'history-support'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'serve-files'));
  this.addIfAddon(path.join(internalMiddlewarePath, 'proxy-server'));

  this.discoverAddons(this.root, this.pkg);
};

Project.prototype.discoverAddons = function(root, pkg) {
  Object.keys(this.dependencies(pkg)).forEach(function(name) {
    if (name !== 'ember-cli') {
      var addonPath = path.join(root, 'node_modules', name);
      this.addIfAddon(addonPath);
    }
  }, this);

  if (pkg['ember-addon'] && pkg['ember-addon'].paths) {
    pkg['ember-addon'].paths.forEach(function(addonPath) {
      addonPath = path.join(root, addonPath);
      this.addIfAddon(addonPath);
    }, this);
  }
};

Project.prototype.addIfAddon = function(addonPath) {
  var pkgPath = path.join(addonPath, 'package.json');

  if(fs.existsSync(pkgPath)) {
    var addonPkg = require(pkgPath);
    var keywords = addonPkg.keywords || [];

    addonPkg['ember-addon'] = addonPkg['ember-addon'] || {};

    if (keywords.indexOf('ember-addon') > -1) {
      this.discoverAddons(addonPath, addonPkg);
      this.addonPackages[addonPkg.name] = {
        path: addonPath,
        pkg: addonPkg
      };
    }
  }
};

Project.prototype.initializeAddons = function() {
  var project         = this;
  var graph           = new DAG();
  var addon, emberAddonConfig;

  this.buildAddonPackages();

  for (var name in this.addonPackages) {
    addon            = this.addonPackages[name];
    emberAddonConfig = addon.pkg['ember-addon'];

    graph.addEdges(name, addon, emberAddonConfig.before, emberAddonConfig.after);
  }

  this.addons = [];
  graph.topsort(function (vertex) {
    var addon           = vertex.value;
    var AddonConstructor = Addon.lookup(addon);

    project.addons.push(new AddonConstructor(project));
  });
};

Project.prototype.addonCommands = function() {
  var commands = {};
  this.addons.forEach(function(addon){
    var includedCommands = (addon.includedCommands && addon.includedCommands()) || {};
    var addonCommands = {};
    for (var key in includedCommands) {
      addonCommands[key] = Command.extend(includedCommands[key]);
    }
    if(Object.keys(addonCommands).length) {
      commands[addon.name] = addonCommands;
    }
  });
  return commands;
};

Project.prototype.eachAddonCommand = function(callback) {
  if(this.initializeAddons && this.addonCommands) {
    this.initializeAddons();
    var addonCommands = this.addonCommands();

    Object.keys(addonCommands).forEach(function(addonName){
      callback(addonName, addonCommands[addonName]);
    }.bind(this));
  }
};

Project.prototype.localBlueprintLookupPath = function() {
  return path.join(this.root, 'blueprints');
};

Project.prototype.blueprintLookupPaths = function() {
  var lookupPaths = [this.localBlueprintLookupPath()];
  var addonLookupPaths = this.addonBlueprintLookupPaths();

  return lookupPaths.concat(addonLookupPaths);
};

Project.prototype.addonBlueprintLookupPaths = function() {
  var addonPaths = this.addons.map(function(addon) {
    if (addon.blueprintsPath) {
      return addon.blueprintsPath();
    }
  }, this);

  return addonPaths.filter(Boolean);
};

Project.closest = function(pathName) {
  return closestPackageJSON(pathName)
    .then(function(result) {
      return new Project(result.directory, result.pkg);
    })
    .catch(function(reason) {
      handleFindupError(pathName, reason);
    });
};

Project.closestSync = function(pathName) {
  try {
    var directory = findup.sync(pathName, 'package.json');

    return new Project(directory, require(path.join(directory, 'package.json')));
  } catch(reason) {
    handleFindupError(pathName, reason);
  }
};

var NULL_PROJECT = new Project(undefined, undefined);

NULL_PROJECT.isEmberCLIProject = function() {
  return false;
};

NULL_PROJECT.name = function() {
  return path.basename(process.cwd());
};

Project.NULL_PROJECT = NULL_PROJECT;

function NotFoundError(message) {
  this.name = 'NotFoundError';
  this.message = message;
  this.stack = (new Error()).stack;
}

NotFoundError.constructor = NotFoundError;
NotFoundError.prototype = Object.create(Error.prototype);

Project.NotFoundError = NotFoundError;

function closestPackageJSON(pathName) {
  return findup(pathName, 'package.json')
    .then(function(directory) {
      return Promise.hash({
        directory: directory,
        pkg: require(path.join(directory, 'package.json'))
      });
    });
}

function handleFindupError(pathName, reason) {
  // Would be nice if findup threw error subclasses
  if (reason && /not found/i.test(reason.message)) {
    throw new NotFoundError('No project found at or up from: `' + pathName + '`');
  } else {
    throw reason;
  }
}

// Export
module.exports = Project;
<|endoftext|>


<commit_before>// # Neuron Core

// ## CommonJS
// Neuron 3.x or newer is not the implementation of any CommonJs proposals
// but [module/1.0](http://wiki.commonjs.org/wiki/Modules/1.0), one of the stable CommonJs standards only.
// And by using neuron and [cortex](http://github.com/kaelzhang/cortex), user could write module/1.0 modules.

// ## Naming Conventions
// All naming of variables should accord to this.
// `'a@1.0.0/relative'`

// ### package
// The package which the current module belongs to.
// - name or package name: {string}  package `name`: 'a'
// - package or package id: {string}    contains package `name` and `version` and the splitter `'@'`. 'a@1.0.0' for instance.

// ### module
// A package is consist of several module objects.
// - mod: {object} the module object. use `mod` instead of `module` to avoid confliction
// - id or module id: the descripter that contains package name, version, and path information
//      {string} for example, `'a@1.0.0/relative'` is a module id(entifier)

// ### version
// Package version: '1.0.0'

// ### main entry
// The module of a package that designed to be accessed from the outside

// map -> identifier: module
// Expose the object for debugging
// @expose
var mods = neuron.mods = {};

// module define
// ---------------------------------------------------------------------------------------------------

// Method to define a module, `define` has no fault tolerance in neuron 2.0,
// because `define` method is no longer designed for human to use.
// `define` should be generated by some develop environment such as [cortex](http://ctx.io)
// @private

// @param {string} identifier (optional) module identifier
// @param {Array.<string>} dependencies ATTENSION! `dependencies` must be array of standard module identifier and
//    there will be NO fault tolerance for argument `dependencies`. Be carefull!
// @param {function(...[*])} factory
// @param {Object=} options

// @return {undefined}
function define(identifier, dependencies, factory, options) {
  options = options || {};

  var mod = getModuleById(identifier, null, options.main);
  mix(mod, options);

  // a single module might be defined more than once.
  // use this trick to prevent module redefining, avoiding the subsequent side effect.
  // mod.f        -> already defined
  // X mod.exports  -> the module initialization is done
  if (!mod.f) {
    mod.f = factory;

    // if has dependencies
    if (dependencies.length) {
      mod.deps = dependencies;

      // ['a@0.0.1']  -> {'a' -> 'a@0.0.1'}
      generateModuleVersionMap(dependencies, mod.v);
      if (options.asyncDeps) {
        generateModuleVersionMap(options.asyncDeps, mod.v);
      }

      // pending
      loadDependencies(dependencies, function() {
        ready(mod);
        // emit(mod, 'ready');
      }, mod);

    } else {
      // for standalone modules, run factory immediately.
      // emit(mod, 'ready');
      ready(mod);
    }

    // emit(mod, 'define');
  }
}

function ready (mod) {
  // execute pending callbacks and clean
  mod.c.forEach(function(c) {
    c(mod);
  });
  mod.c.length = 0;
  delete mod.c;

  // never delete `mod.v`, coz `require` method might be executed after module factory executed
  // ```js
  // module.exports = {
  //    abc: function() {
  //        return require('b');
  //    }
  // }
  // ```
}

// @private
// create version info of the dependencies of current module into current sandbox
// @param {Array.<string>} modules no type detecting
// @param {Object} host

// ['a@~0.1.0', 'b@~2.3.9']
// ->
// {
//     a: '~0.1.0',
//     b: '~2.3.9'
// }
function generateModuleVersionMap(modules, host) {
  modules.forEach(function(mod) {
    var name = mod.split('@')[0];
    host[name] = mod;
  });
}

// Generate the exports
// @param {Object} mod
function getExports(mod) {
  return mod.loaded

    // if !('exports' in mod)
    // A suspected circular invocation might occur.
    ? mod.exports
    // #82: since 4.5.0, a module only initialize factory functions when `require()`d.
    // A single module might
    : generateExports(mod);
}

function generateExports (mod) {
  var exports = {};
  // @expose
  var module = {
    exports: exports
  };

  // # 85
  // before module factory being invoked, mark the module as `loaded`
  // so we will not execute the factory function again
  mod.loaded = true;

  // to keep the object mod away from the executing context of factory,
  // use `factory` instead `mod.f`,
  // preventing user from fetching runtime data by 'this'
  var factory = mod.f;
  factory(createRequire(mod), exports, module);
  // delete mod.f;

  // during the execution of `factory`, `module.exports` might be changed
  // exports:
  // TWO ways to define the exports of a module
  // 1.
  // exports.method1 = method1;
  // exports.method2 = method2;

  // 2.
  // module.exports = {
  //        method1: method1,
  //        method2: method2
  // }

  // priority: 2 > 1
  return mod.exports = module.exports;
}

// function emit (mod, type) {
//   neuron.emit(type, {
//     mod: mod
//   });
// }

// module load
// ---------------------------------------------------------------------------------------------------

// @private
// @param {Array.<String>} dependencies
// @param {(function()} callback
// @param {Object} env Environment for cyclic detecting and generating the uri of child modules
// {
//     r: {string} the uri that its child dependent modules referring to
//     n: {string} namespace of the current module
// }
function loadDependencies(dependencies, callback, env) {
  var counter = dependencies.length;

  dependencies.forEach(function(id) {
    if (id) {
      var mod = getModuleById(id, env);
      registerModuleLoadCallback(mod, function() {
        if (--counter === 0) {
          callback();

          // prevent memleak
          callback = null;
        }
      }, env);

      // Prevent bad dependencies
    } else {
      --counter;
    }
  });
}

function useModule (mod, callback) {
  registerModuleLoadCallback(mod, function (mod) {
    callback(getExports(mod));
  });
}

// provide a module
// method to provide a module
// @param {Object} mod
// @param {function()} callback
function registerModuleLoadCallback(mod, callback) {
  mod.c
    ? mod.c.push(callback)
    : callback(mod);

  // everytime we encounter a module which is depended by the other module, `'use'` event fires
  neuron.emit('use', {
    mod: mod,

    // prevent duplicate loading
    // @type {boolean=} whether the module is already fetched, i.e. we don't need to fetch it from the remote server
    defined: !! mod.f
  });
}

// use the sandbox to specify the environment for every id that required in the current module
// @param {Object} env The object of the current module.
// @return {function}
function createRequire(env) {
  var require = function(id) {
    var mod = getModuleById(env.v[id] || id, env, null, true);
    return getExports(mod);
  };

  // @param {string} id Module identifier.
  // Since 4.2.0, we only allow to asynchronously load a single module
  require.async = function(id, callback) {
    var mod = getModuleById(id, env);

    if (!mod.main) {
      if (isPathRelative(id)) {
        // If user try to load a non-entry module, it will get a 404 response
        mod.async = true;
      } else {
        // We only allow to `require.async` main module or entries of the current package
        return;
      }
    }

    useModule(mod, callback);
  };

  return require;
}

// cases:

// 1. calculate relative paths
// 2. load modules

// ```
// 'a@0.0.1/b.js'
// -> define('a@0.0.1/b', ['./c'], factory, {main: true});
// if main entry is not
// -> {
//     'a@0.0.1/b': mod_b,
//     'a@0.0.1': mod_b
// }
// -> 'a/0.0.1/a.js'

// 'a@0.0.1/c'
// -> define('a@0.0.1/c', [], factory, {});
// -> {
//     'a@0.0.1/c': mod_c
// }
// ```

// get a module by id. if not exists, a ghost module(which will be filled after its first `define`) will be created
// @param {string} id
// @param {Object} env the environment module,
// @param {boolean=} is_main_definition When it is defining a main entry.
// @param {boolean=} strict If true, if a module is not found, it will throw errors instead of creating a new module
function getModuleById(id, env, is_main_definition, strict) {
  var parsed;

  // `env` exists, which means the module is accessed by requiring within another module.
  if (env) {
    // pathResolve('align', 'jquery')   -> 'jquery'
    // pathResolve('align', './')
    id = pathResolve(env.id, id);
  }

  // 'a@1.0.0'    -> 'a@1.0.0'
  // 'a'          -> 'a@latest'
  // 'a/inner'    -> 'a@latest/inner'
  parsed = parseModuleId(id);

  // Suppose:
  // {
  //     'a': {
  //         '~1.2.3': '1.2.12'
  //     }
  // }

  // We route a package of certain range to a specific version,
  // so several modules may point to a same exports

  // `NEURON_CONF` is generated by `neuron.config`
  parsed.v = NEURON_CONF.transform(parsed.v, parsed.n);
  id = formatModuleId(parsed);

  var mod = mods[id];
  if (!mod) {
    if (strict) {
      throw new Error("Cannot find module '" + id + "'");
    }

    var pkg = formatPackageId(parsed);

    // In this case, `getModuleById` is invoked by `define`.
    if (is_main_definition) {
      mod =
        mods[id] =
        mods[pkg] =

      // The module id of main entry is the package id.
      mods[pkg] || createModule(parsed, id, pkg);

      // There is only posibility to run `getModuleById` with `isMain` set by `true`:
      // ```
      // define(id, dependencies, factory, {main: true}).
      // ```
      // And, before this,
      // `mods[pkg]` might have already been assigned with a falsy `id` property.

      // For example
      // {
      //     name: 'a',
      //     version: '0.0.1',
      //     main: 'lib/index.js'
      // }

      // 1. `getModuleById('a@0.0.1')`, and load 'a/0.0.1/a.js'
      // {
      //     id: 'a@0.0.1',
      //     pkg: 'a@0.0.1'
      // }

      // 2. (in a.js), define('a@0.0.1/lib/index', [], factory, {main: true})
      // Then, `getModuleById('a@0.0.1/lib/index')` will get the result of the 1st step.
      // Obviously,
      // 'a@0.0.1' is not the real module id of the main entry,
      // while 'a@0.0.1/lib/index' is, so:
      mod.id = id;

    } else {
      mod = mods[id] = createModule(parsed, id, pkg);

      if (id === pkg) {
        mod.main = true;
      }
    }
  }

  return mod;
}

function createModule(parsed, id, pkg) {
  return {
    // package name: 'a'
    name: parsed.n,
    // package version: '1.1.0'
    version: parsed.v,
    // module path: '/b'
    path: parsed.p,
    // module id: 'a@1.1.0/b'
    id: id,
    // package id: 'a@1.1.0'
    pkg: pkg,
    // @type {Array.<function()>} callbacks
    c: [],
    // @type {Object} version map of the current module
    v: {}
  };
}

// @const
// 'a@1.2.3/abc' ->
// ['a@1.2.3/abc', 'a', '1.2.3', '/abc']

//                    01            2         3
var REGEX_PARSE_ID = /^([^\/]+?)(?:@([^\/]+))?(\/.*)?$/;

// @param {string} resolved path-resolved module identifier
function parseModuleId(resolved) {
  var match = resolved.match(REGEX_PARSE_ID);
  var name = match[1];

  // 'a/inner' -> 'a@latest/inner'
  var version = match[2] || 'latest';
  var path = match[3] || '';

  // There always be matches
  return {
    n: name,
    v: version,
    p: path
  };
}

// Format package id
function formatPackageId(parsed) {
  return parsed.n + '@' + parsed.v;
}

// Format module id
function formatModuleId(parsed) {
  return formatPackageId(parsed) + parsed.p;
}

// @public
// ----------------------------------------------------------------------------------

// event support
// mix(loader, Event);

/**
 change log:

 import ./ChangeLog.md;

 */<commit_msg>#88: adds event: circular and more comments<commit_after>// # Neuron Core

// ## CommonJS
// Neuron 3.x or newer is not the implementation of any CommonJs proposals
// but [module/1.0](http://wiki.commonjs.org/wiki/Modules/1.0), one of the stable CommonJs standards only.
// And by using neuron and [cortex](http://github.com/kaelzhang/cortex), user could write module/1.0 modules.

// ## Naming Conventions
// All naming of variables should accord to this.
// `'a@1.0.0/relative'`

// ### package
// The package which the current module belongs to.
// - name or package name: {string}  package `name`: 'a'
// - package or package id: {string}    contains package `name` and `version` and the splitter `'@'`. 'a@1.0.0' for instance.

// ### module
// A package is consist of several module objects.
// - mod: {object} the module object. use `mod` instead of `module` to avoid confliction
// - id or module id: the descripter that contains package name, version, and path information
//      {string} for example, `'a@1.0.0/relative'` is a module id(entifier)

// ### version
// Package version: '1.0.0'

// ### main entry
// The module of a package that designed to be accessed from the outside

// map -> identifier: module
// Expose the object for debugging
// @expose
var mods = neuron.mods = {};

// module define
// ---------------------------------------------------------------------------------------------------

// Method to define a module, `define` has no fault tolerance in neuron 2.0,
// because `define` method is no longer designed for human to use.
// `define` should be generated by some develop environment such as [cortex](http://ctx.io)
// @private

// **NOTICE** that `define` method is not used by developers directly,
// so there's no type checking, and no fault tolerance.

// @param {string} identifier (optional) module identifier
// @param {Array.<string>} dependencies ATTENSION! `dependencies` must be array of standard module identifier and
//    there will be NO fault tolerance for argument `dependencies`. Be carefull!
// @param {function(...[*])} factory
// @param {Object=} options

// @return {undefined}
function define(identifier, dependencies, factory, options) {
  options = options || {};

  var mod = getModuleById(identifier, null, options.main);
  mix(mod, options);

  // a single module might be defined more than once.
  // use this trick to prevent module redefining, avoiding the subsequent side effect.
  // mod.f        -> already defined
  // X mod.exports  -> the module initialization is done
  if (!mod.f) {
    mod.f = factory;

    // if has dependencies
    if (dependencies.length) {
      mod.deps = dependencies;

      // ['a@0.0.1']  -> {'a' -> 'a@0.0.1'}
      generateModuleVersionMap(dependencies, mod.v);
      if (options.asyncDeps) {
        generateModuleVersionMap(options.asyncDeps, mod.v);
      }

      // pending
      loadDependencies(dependencies, function() {
        ready(mod);
        // emit(mod, 'ready');
      }, mod);

    } else {
      // for standalone modules, run factory immediately.
      // emit(mod, 'ready');
      ready(mod);
    }

    // emit(mod, 'define');
  }
}

function ready (mod) {
  // execute pending callbacks and clean
  mod.c.forEach(function(c) {
    c(mod);
  });
  mod.c.length = 0;
  delete mod.c;

  // never delete `mod.v`, coz `require` method might be executed after module factory executed
  // ```js
  // module.exports = {
  //    abc: function() {
  //        return require('b');
  //    }
  // }
  // ```
}

// @private
// create version info of the dependencies of current module into current sandbox
// @param {Array.<string>} modules no type detecting
// @param {Object} host

// ['a@~0.1.0', 'b@~2.3.9']
// ->
// {
//     a: '~0.1.0',
//     b: '~2.3.9'
// }
function generateModuleVersionMap(modules, host) {
  modules.forEach(function(mod) {
    var name = mod.split('@')[0];
    host[name] = mod;
  });
}

// Generate the exports
// @param {Object} mod
function getExports(mod) {
  if (mod.loaded) {

    // In node.js, if there are circular dependencies, `module.exports` will be `{}` by default,
    // while `mod.exports` will be undefined in neuron,
    // which is different from here.

    // Actually, neuron(~5.0.0) could not handle static circular dependencies,
    // in which situation, method `ready(mod)` will never be called.
    // But, static circular dependencies is a piece of cake for builders, such like [cortex](http://github.com/cortexjs/cortex)

    // If `'exports'` is not in mod, we treated it as a circular dependency suspectedly.
    if (!('exports' in mod)) {
      neuron.emit('circular', {
        mod: mod
      });
    }

    return mod.exports;
  }

  // #82: since 4.5.0, a module only initialize factory functions when `require()`d.
  // A single module might
  return generateExports(mod);
}

function generateExports (mod) {
  var exports = {};
  // @expose
  var module = {
    exports: exports
  };

  // # 85
  // before module factory being invoked, mark the module as `loaded`
  // so we will not execute the factory function again
  mod.loaded = true;

  // to keep the object mod away from the executing context of factory,
  // use `factory` instead `mod.f`,
  // preventing user from fetching runtime data by 'this'
  var factory = mod.f;
  factory(createRequire(mod), exports, module);
  // delete mod.f;

  // during the execution of `factory`, `module.exports` might be changed
  // exports:
  // TWO ways to define the exports of a module
  // 1.
  // exports.method1 = method1;
  // exports.method2 = method2;

  // 2.
  // module.exports = {
  //        method1: method1,
  //        method2: method2
  // }

  // priority: 2 > 1
  return mod.exports = module.exports;
}

// function emit (mod, type) {
//   neuron.emit(type, {
//     mod: mod
//   });
// }

// module load
// ---------------------------------------------------------------------------------------------------

// @private
// @param {Array.<String>} dependencies
// @param {(function()} callback
// @param {Object} env Environment for cyclic detecting and generating the uri of child modules
// {
//     r: {string} the uri that its child dependent modules referring to
//     n: {string} namespace of the current module
// }
function loadDependencies(dependencies, callback, env) {
  var counter = dependencies.length;

  dependencies.forEach(function(id) {
    if (id) {
      var mod = getModuleById(id, env);
      registerModuleLoadCallback(mod, function() {
        if (--counter === 0) {
          callback();

          // prevent memleak
          callback = null;
        }
      }, env);

      // Prevent bad dependencies
    } else {
      --counter;
    }
  });
}

function useModule (mod, callback) {
  registerModuleLoadCallback(mod, function (mod) {
    callback(getExports(mod));
  });
}

// provide a module
// method to provide a module
// @param {Object} mod
// @param {function()} callback
function registerModuleLoadCallback(mod, callback) {
  mod.c
    ? mod.c.push(callback)
    : callback(mod);

  // everytime we encounter a module which is depended by the other module, `'use'` event fires
  neuron.emit('use', {
    mod: mod,

    // prevent duplicate loading
    // @type {boolean=} whether the module is already fetched, i.e. we don't need to fetch it from the remote server
    defined: !! mod.f
  });
}

// use the sandbox to specify the environment for every id that required in the current module
// @param {Object} env The object of the current module.
// @return {function}
function createRequire(env) {
  var require = function(id) {
    var mod = getModuleById(env.v[id] || id, env, null, true);
    return getExports(mod);
  };

  // @param {string} id Module identifier.
  // Since 4.2.0, we only allow to asynchronously load a single module
  require.async = function(id, callback) {
    var mod = getModuleById(id, env);

    if (!mod.main) {
      if (isPathRelative(id)) {
        // If user try to load a non-entry module, it will get a 404 response
        mod.async = true;
      } else {
        // We only allow to `require.async` main module or entries of the current package
        return;
      }
    }

    useModule(mod, callback);
  };

  return require;
}

// cases:

// 1. calculate relative paths
// 2. load modules

// ```
// 'a@0.0.1/b.js'
// -> define('a@0.0.1/b', ['./c'], factory, {main: true});
// if main entry is not
// -> {
//     'a@0.0.1/b': mod_b,
//     'a@0.0.1': mod_b
// }
// -> 'a/0.0.1/a.js'

// 'a@0.0.1/c'
// -> define('a@0.0.1/c', [], factory, {});
// -> {
//     'a@0.0.1/c': mod_c
// }
// ```

// get a module by id. if not exists, a ghost module(which will be filled after its first `define`) will be created
// @param {string} id
// @param {Object} env the environment module,
// @param {boolean=} is_main_definition When it is defining a main entry.
// @param {boolean=} strict If true, if a module is not found, it will throw errors instead of creating a new module
function getModuleById(id, env, is_main_definition, strict) {
  var parsed;

  // `env` exists, which means the module is accessed by requiring within another module.
  if (env) {
    // pathResolve('align', 'jquery')   -> 'jquery'
    // pathResolve('align', './')
    id = pathResolve(env.id, id);
  }

  // 'a@1.0.0'    -> 'a@1.0.0'
  // 'a'          -> 'a@latest'
  // 'a/inner'    -> 'a@latest/inner'
  parsed = parseModuleId(id);

  // Suppose:
  // {
  //     'a': {
  //         '~1.2.3': '1.2.12'
  //     }
  // }

  // We route a package of certain range to a specific version,
  // so several modules may point to a same exports

  // `NEURON_CONF` is generated by `neuron.config`
  parsed.v = NEURON_CONF.transform(parsed.v, parsed.n);
  id = formatModuleId(parsed);

  var mod = mods[id];
  if (!mod) {
    if (strict) {
      throw new Error("Cannot find module '" + id + "'");
    }

    var pkg = formatPackageId(parsed);

    // In this case, `getModuleById` is invoked by `define`.
    if (is_main_definition) {
      mod =
        mods[id] =
        mods[pkg] =

      // The module id of main entry is the package id.
      mods[pkg] || createModule(parsed, id, pkg);

      // There is only posibility to run `getModuleById` with `isMain` set by `true`:
      // ```
      // define(id, dependencies, factory, {main: true}).
      // ```
      // And, before this,
      // `mods[pkg]` might have already been assigned with a falsy `id` property.

      // For example
      // {
      //     name: 'a',
      //     version: '0.0.1',
      //     main: 'lib/index.js'
      // }

      // 1. `getModuleById('a@0.0.1')`, and load 'a/0.0.1/a.js'
      // {
      //     id: 'a@0.0.1',
      //     pkg: 'a@0.0.1'
      // }

      // 2. (in a.js), define('a@0.0.1/lib/index', [], factory, {main: true})
      // Then, `getModuleById('a@0.0.1/lib/index')` will get the result of the 1st step.
      // Obviously,
      // 'a@0.0.1' is not the real module id of the main entry,
      // while 'a@0.0.1/lib/index' is, so:
      mod.id = id;

    } else {
      mod = mods[id] = createModule(parsed, id, pkg);

      if (id === pkg) {
        mod.main = true;
      }
    }
  }

  return mod;
}

function createModule(parsed, id, pkg) {
  return {
    // package name: 'a'
    name: parsed.n,
    // package version: '1.1.0'
    version: parsed.v,
    // module path: '/b'
    path: parsed.p,
    // module id: 'a@1.1.0/b'
    id: id,
    // package id: 'a@1.1.0'
    pkg: pkg,
    // @type {Array.<function()>} callbacks
    c: [],
    // @type {Object} version map of the current module
    v: {}
  };
}

// @const
// 'a@1.2.3/abc' ->
// ['a@1.2.3/abc', 'a', '1.2.3', '/abc']

//                    01            2         3
var REGEX_PARSE_ID = /^([^\/]+?)(?:@([^\/]+))?(\/.*)?$/;

// @param {string} resolved path-resolved module identifier
function parseModuleId(resolved) {
  var match = resolved.match(REGEX_PARSE_ID);
  var name = match[1];

  // 'a/inner' -> 'a@latest/inner'
  var version = match[2] || 'latest';
  var path = match[3] || '';

  // There always be matches
  return {
    n: name,
    v: version,
    p: path
  };
}

// Format package id
function formatPackageId(parsed) {
  return parsed.n + '@' + parsed.v;
}

// Format module id
function formatModuleId(parsed) {
  return formatPackageId(parsed) + parsed.p;
}

// @public
// ----------------------------------------------------------------------------------

// event support
// mix(loader, Event);

/**
 change log:

 import ./ChangeLog.md;

 */<|endoftext|>


<commit_before>"use strict";

const parseCommand = require("string-argv");  // possible alternative: parse-spawn-args
const detectType = require("type-detect");

module.exports = normalizeArgs;

/**
 * This function normalizes the arguments of the {@link sync} and {@link async}
 * so they can be passed to Node's {@link child_process.spawn} or
 * {@link child_process.spawn} functions.
 *
 * @param {string|string[]} command
 * The command to run (e.g. "git"), or the command and its arguments as a string
 * (e.g. "git commit -a -m fixed_stuff"), or the command and its arguments as an
 * array (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {string|string[]} [args]
 * The command arguments as a string (e.g. "git commit -a -m fixed_stuff") or as an array
 * (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {object} [options]
 * The same options as {@link child_process.spawn} or {@link child_process.spawnSync}.
 *
 * @param {function} [callback]
 * The callback that will receive the results, if applicable.
 *
 * @returns {object}
 */
function normalizeArgs (params) {
  let command, args, options, callback, error;

  try {
    // Shift the arguments, if necessary
    let shifted = shiftArgs(params);

    command = shifted.command;
    args = shifted.args;
    options = shifted.options;
    callback = shifted.callback;
    let commandArgs = [];

    if (typeof command === "string" && args === undefined) {
      // The command parameter is actually the command AND arguments,
      // so split the string into an array
      command = splitArgString(command);
    }

    if (Array.isArray(command)) {
      // Split the command from the arguments
      commandArgs = command.slice(1);
      command = command[0];
    }

    if (typeof args === "string") {
      // Convert the `args` argument from a string an array
      args = splitArgString(args);
    }

    if (Array.isArray(args)) {
      // Add these arguments to any arguments from above
      args = commandArgs.concat(args);
    }

    if (args === undefined || args === null) {
      args = commandArgs;
    }

    if (options === undefined || options === null) {
      options = {};
    }

    // Set default options
    options.encoding = options.encoding || "utf8";

    // Validate all arguments
    validateArgs(command, args, options, callback);
  }
  catch (err) {
    error = err;
  }

  return { command, args, options, callback, error };
}

/**
 * Detects whether any optional arguments have been omitted,
 * and shifts the other arguments as needed.
 *
 * @param {string|string[]} command
 * @param {string|string[]} [args]
 * @param {object} [options]
 * @param {function} [callback]
 * @returns {object}
 */
function shiftArgs (params) {
  params = Array.prototype.slice.call(params);
  let command, args, options, callback;

  // Check for a callback as the final parameter
  let lastParam = params[params.length - 1];
  if (typeof lastParam === "function") {
    callback = lastParam;
    params.pop();
  }

  // Check for an options object as the second-to-last parameter
  lastParam = params[params.length - 1];
  if (typeof lastParam === "object" && !Array.isArray(lastParam)) {
    options = lastParam;
    params.pop();
  }

  // The first parameter is the command
  command = params.shift();

  // All remaining parameters are the args
  if (params.length === 0) {
    args = undefined;
  }
  else if (params.length === 1 && Array.isArray(params[0])) {
    args = params[0];
  }
  else if (params.length === 1 && params[0] === "") {
    args = [];
  }
  else {
    args = params;
  }

  return { command, args, options, callback };
}

/**
 * Validates all arguments, and throws an error if any are invalid.
 *
 * @param {string} command
 * @param {string[]} args
 * @param {object} options
 * @param {function} [callback]
 */
function validateArgs (command, args, options, callback) {
  if (command === undefined || command === null) {
    throw new Error("The command to execute is missing.");
  }

  if (typeof command !== "string") {
    throw new Error("The command to execute should be a string, not " + friendlyType(command));
  }

  if (!Array.isArray(args)) {
    throw new Error(
      "The command arguments should be a string or an array, not " +
      friendlyType(args)
    );
  }

  for (let i = 0; i < args.length; i++) {
    let arg = args[i];

    if (typeof arg !== "string") {
      throw new Error(
        `The command arguments should be strings, but argument #${i + 1} is ` +
        friendlyType(arg)
      );
    }
  }

  if (typeof options !== "object") {
    throw new Error(
      "The options should be an object, not " +
      friendlyType(options)
    );
  }

  if (callback !== undefined && callback !== null) {
    if (typeof callback !== "function") {
      throw new Error("The callback should be a function, not " + friendlyType(callback));
    }
  }
}

/**
 * Splits an argument string (e.g. git commit -a -m "fixed stuff")
 * into an array (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {string} argString
 * @returns {string[]}
 */
function splitArgString (argString) {
  try {
    return parseCommand(argString);
  }
  catch (error) {
    throw new Error(`Could not parse the string: ${argString}\n${error.message}`);
  }
}

/**
 * Returns the friendly type name of the given value, for use in error messages.
 *
 * @param {*} val
 * @returns {string}
 */
function friendlyType (val) {
  let type = detectType(val);
  let firstChar = String(type)[0].toLowerCase();

  if (["a", "e", "i", "o", "u"].indexOf(firstChar) === -1) {
    return `a ${type}.`;
  }
  else {
    return `an ${type}.`;
  }
}
<commit_msg>Simplified code by using object spread syntax<commit_after>"use strict";

const parseCommand = require("string-argv");  // possible alternative: parse-spawn-args
const detectType = require("type-detect");

module.exports = normalizeArgs;

/**
 * This function normalizes the arguments of the {@link sync} and {@link async}
 * so they can be passed to Node's {@link child_process.spawn} or
 * {@link child_process.spawn} functions.
 *
 * @param {string|string[]} command
 * The command to run (e.g. "git"), or the command and its arguments as a string
 * (e.g. "git commit -a -m fixed_stuff"), or the command and its arguments as an
 * array (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {string|string[]} [args]
 * The command arguments as a string (e.g. "git commit -a -m fixed_stuff") or as an array
 * (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {object} [options]
 * The same options as {@link child_process.spawn} or {@link child_process.spawnSync}.
 *
 * @param {function} [callback]
 * The callback that will receive the results, if applicable.
 *
 * @returns {object}
 */
function normalizeArgs (params) {
  let command, args, options, callback, error;

  try {
    // Shift the arguments, if necessary
    ({ command, args, options, callback } = shiftArgs(params));

    let commandArgs = [];

    if (typeof command === "string" && args === undefined) {
      // The command parameter is actually the command AND arguments,
      // so split the string into an array
      command = splitArgString(command);
    }

    if (Array.isArray(command)) {
      // Split the command from the arguments
      commandArgs = command.slice(1);
      command = command[0];
    }

    if (typeof args === "string") {
      // Convert the `args` argument from a string an array
      args = splitArgString(args);
    }

    if (Array.isArray(args)) {
      // Add these arguments to any arguments from above
      args = commandArgs.concat(args);
    }

    if (args === undefined || args === null) {
      args = commandArgs;
    }

    if (options === undefined || options === null) {
      options = {};
    }

    // Set default options
    options.encoding = options.encoding || "utf8";

    // Validate all arguments
    validateArgs(command, args, options, callback);
  }
  catch (err) {
    error = err;
  }

  return { command, args, options, callback, error };
}

/**
 * Detects whether any optional arguments have been omitted,
 * and shifts the other arguments as needed.
 *
 * @param {string|string[]} command
 * @param {string|string[]} [args]
 * @param {object} [options]
 * @param {function} [callback]
 * @returns {object}
 */
function shiftArgs (params) {
  params = Array.prototype.slice.call(params);
  let command, args, options, callback;

  // Check for a callback as the final parameter
  let lastParam = params[params.length - 1];
  if (typeof lastParam === "function") {
    callback = lastParam;
    params.pop();
  }

  // Check for an options object as the second-to-last parameter
  lastParam = params[params.length - 1];
  if (typeof lastParam === "object" && !Array.isArray(lastParam)) {
    options = lastParam;
    params.pop();
  }

  // The first parameter is the command
  command = params.shift();

  // All remaining parameters are the args
  if (params.length === 0) {
    args = undefined;
  }
  else if (params.length === 1 && Array.isArray(params[0])) {
    args = params[0];
  }
  else if (params.length === 1 && params[0] === "") {
    args = [];
  }
  else {
    args = params;
  }

  return { command, args, options, callback };
}

/**
 * Validates all arguments, and throws an error if any are invalid.
 *
 * @param {string} command
 * @param {string[]} args
 * @param {object} options
 * @param {function} [callback]
 */
function validateArgs (command, args, options, callback) {
  if (command === undefined || command === null) {
    throw new Error("The command to execute is missing.");
  }

  if (typeof command !== "string") {
    throw new Error("The command to execute should be a string, not " + friendlyType(command));
  }

  if (!Array.isArray(args)) {
    throw new Error(
      "The command arguments should be a string or an array, not " +
      friendlyType(args)
    );
  }

  for (let i = 0; i < args.length; i++) {
    let arg = args[i];

    if (typeof arg !== "string") {
      throw new Error(
        `The command arguments should be strings, but argument #${i + 1} is ` +
        friendlyType(arg)
      );
    }
  }

  if (typeof options !== "object") {
    throw new Error(
      "The options should be an object, not " +
      friendlyType(options)
    );
  }

  if (callback !== undefined && callback !== null) {
    if (typeof callback !== "function") {
      throw new Error("The callback should be a function, not " + friendlyType(callback));
    }
  }
}

/**
 * Splits an argument string (e.g. git commit -a -m "fixed stuff")
 * into an array (e.g. ["git", "commit", "-a", "-m", "fixed stuff"]).
 *
 * @param {string} argString
 * @returns {string[]}
 */
function splitArgString (argString) {
  try {
    return parseCommand(argString);
  }
  catch (error) {
    throw new Error(`Could not parse the string: ${argString}\n${error.message}`);
  }
}

/**
 * Returns the friendly type name of the given value, for use in error messages.
 *
 * @param {*} val
 * @returns {string}
 */
function friendlyType (val) {
  let type = detectType(val);
  let firstChar = String(type)[0].toLowerCase();

  if (["a", "e", "i", "o", "u"].indexOf(firstChar) === -1) {
    return `a ${type}.`;
  }
  else {
    return `an ${type}.`;
  }
}
<|endoftext|>


<commit_before>module.exports = function(exports) {
    // ************************
    // Offsite Gateway Methods
    // ************************
    var https = require('https');
    var restler = require('restler');
    var vars = exports.vars;
    var serverMode = 'LIVE';
    var gatewaySession = [];
    var redirect_uri = false;

    exports.setMode = function(mode) {
        if(mode != 'LIVE' && mode != 'TEST') {
            return false;
        }

        serverMode = mode;

        return true;
    };

    /**
     * Clears out any products previously
     * placed in the offsite gateway session
     * effectively starting a new session
     *
     * @return {boolean} Whether or not the session was cleared
     */
    exports.startGatewaySession = function(redirectUri) {
        gatewaySession = [];
        redirect_uri = redirectUri;

        return true;
    };

    /**
     * Add a product to the current offsite
     * gateway session
     *
     * @param {string} Product name; (required)
     * @param {float} Product price; (required)
     * @param {string} Product description; (optional)
     * @param {int} Quantity of product; (optional, defaults to 1)
     *
     * @return {boolean} Whether or not the product was added succesfully
     */
    exports.addGatewayProduct = function(name, amount, description, quantity) {
        // Verify required paramteres
        if (!name) { throw new Error('Missing arg name'); }
        if (!amount) { throw new Error('Missing arg amount'); }

        // Assume defaults
        if (!description) { description = ''; }
        if (!quantity) { quantity = 1; }

        product = {
            'Name': name,
            'Description': description,
            'Price': amount,
            'Quantity': quantity
        };

        gatewaySession.push(product);

        return true;
    };

    /**
     * Create an offsite gateway checkout
     * session
     *
     * @param {string} The destination account ID; Can only be a Dwolla ID; (required)
     * @param {string} Any order ID; (optional)
     * @param {float} Discount amount; (optional)
     * @param {float} Shipping amount; (optional)
     * @param {float} Tax amount; (optional)
     * @param {string} Notes/memos to be associated with transaction; (optional)
     * @param {string} A URL to POST the transaction result to; (optional)
     *
     * @return {string} The URL for the checkout session
     */
    exports.getGatewayURL = function(destination_id, params, fn) {
      // Verify required paramteres
      if (!destination_id) { throw new Error('Missing arg destination_id'); }

      // Params are optional
      if (!fn || typeof params === 'function') {
          fn = params;
          params = {};
      }

      // Assume defaults
      if (!params.order_id) { params.order_id = false; }
      if (!params.callback) { params.callback = false; }
      if (!params.allow_funding_sources) { params.allow_funding_sources = false; }
      if (!params.discount) { params.discount = 0; } else { params.discount = parseFloat(params.discount); }
      if (!params.tax) { params.tax = 0; } else { params.tax = parseFloat(params.tax); }
      if (!params.shipping) { params.shipping = 0; } else { params.shipping = parseFloat(params.shipping); }
      if (!params.notes) { params.notes = ''; }

     	// Calcualte subtotal
     	var subtotal = 0;
     	gatewaySession.forEach(function(product) {
         	subtotal += parseFloat(product['Price']) * parseFloat(product['Quantity']);
     	});

     	// Calculate grand total
     	total = Math.round((subtotal - params.discount + params.shipping + params.tax) * 100) / 100;

     	// Create request body
     	request = {
    		'Key'     : vars._client_id,
    		'Secret'  : vars._client_secret,
    		'Test'    : (serverMode == 'TEST') ? 'true' : 'false',
    		'AllowFundingSources' : (params.allow_funding_sources == 'TEST') ? 'true' : 'false',
    		'PurchaseOrder': {
    			'DestinationId' : destination_id,
    			'OrderItems'    : gatewaySession,
    			'Discount'      : -params.discount,
    			'Shipping'      : params.shipping,
    			'Tax'           : params.tax,
    			'Total'			: total,
    			'Notes'         : params.notes
    		}
     	};

    	// Append optional parameters
    	if(redirect_uri) { request['Redirect'] = redirect_uri; }
    	if(params.callback) { request['Callback'] = params.callback; }
    	if(params.order_id) { request['OrderId'] = params.order_id; }

        var host = exports.sandbox ? 'uat.dwolla.com' : 'www.dwolla.com';

    	// Send off the request
    	restler
    	   .post('https://' +  host + '/payment/request', {
    	       headers: { 'Content-Type': 'application/json' },
        	   data: JSON.stringify(request)
        	})
        	.on('complete', function(data) {
        	   if(data['Result'] != 'Success') {
            	   return fn(data['Message']);
        	   } else {
            	   return fn(false, 'https://' + host + '/payment/checkout/' + data['CheckoutId']);
        	   }
        	});
    };

    /**
     * Verify a signature that came back
     * with an offsite gateway redirect
     *
     * @param {string} Proposed signature; (required)
     * @param {string} Dwolla's checkout ID; (required)
     * @param {string} Dwolla's reported total amount; (required)
     *
     * @return {boolean} Whether or not the signature is valid
     */
    exports.verifyGatewaySignature = function(signature, checkout_id, amount) {
        // Verify required paramteres
        if (!signature) { throw new Error('Missing arg signature'); }
        if (!amount) { throw new Error('Missing arg checkout_id'); }
        if (!checkout_id) { throw new Error('Missing arg amount'); }

        // Require crypto lib
        var crypto = require('crypto');

    	// Normalize parameters
    	amount = parseFloat(amount).toFixed(2);

    	// Calculate an HMAC-SHA1 hexadecimal hash
    	// of the checkoutId and amount ampersand separated
    	// using the consumer secret of the application
    	// as the hash key.
    	//
    	// @doc: http://developers.dwolla.com/dev/docs/gateway
        hash = crypto.createHmac('sha1', vars._client_secret).update(checkout_id + "&" + amount).digest('hex');

        return hash == signature;
    };
};<commit_msg>remove unused import<commit_after>module.exports = function(exports) {
    // ************************
    // Offsite Gateway Methods
    // ************************
    var restler = require('restler');
    var vars = exports.vars;
    var serverMode = 'LIVE';
    var gatewaySession = [];
    var redirect_uri = false;

    exports.setMode = function(mode) {
        if(mode != 'LIVE' && mode != 'TEST') {
            return false;
        }

        serverMode = mode;

        return true;
    };

    /**
     * Clears out any products previously
     * placed in the offsite gateway session
     * effectively starting a new session
     *
     * @return {boolean} Whether or not the session was cleared
     */
    exports.startGatewaySession = function(redirectUri) {
        gatewaySession = [];
        redirect_uri = redirectUri;

        return true;
    };

    /**
     * Add a product to the current offsite
     * gateway session
     *
     * @param {string} Product name; (required)
     * @param {float} Product price; (required)
     * @param {string} Product description; (optional)
     * @param {int} Quantity of product; (optional, defaults to 1)
     *
     * @return {boolean} Whether or not the product was added succesfully
     */
    exports.addGatewayProduct = function(name, amount, description, quantity) {
        // Verify required paramteres
        if (!name) { throw new Error('Missing arg name'); }
        if (!amount) { throw new Error('Missing arg amount'); }

        // Assume defaults
        if (!description) { description = ''; }
        if (!quantity) { quantity = 1; }

        product = {
            'Name': name,
            'Description': description,
            'Price': amount,
            'Quantity': quantity
        };

        gatewaySession.push(product);

        return true;
    };

    /**
     * Create an offsite gateway checkout
     * session
     *
     * @param {string} The destination account ID; Can only be a Dwolla ID; (required)
     * @param {string} Any order ID; (optional)
     * @param {float} Discount amount; (optional)
     * @param {float} Shipping amount; (optional)
     * @param {float} Tax amount; (optional)
     * @param {string} Notes/memos to be associated with transaction; (optional)
     * @param {string} A URL to POST the transaction result to; (optional)
     *
     * @return {string} The URL for the checkout session
     */
    exports.getGatewayURL = function(destination_id, params, fn) {
      // Verify required paramteres
      if (!destination_id) { throw new Error('Missing arg destination_id'); }

      // Params are optional
      if (!fn || typeof params === 'function') {
          fn = params;
          params = {};
      }

      // Assume defaults
      if (!params.order_id) { params.order_id = false; }
      if (!params.callback) { params.callback = false; }
      if (!params.allow_funding_sources) { params.allow_funding_sources = false; }
      if (!params.discount) { params.discount = 0; } else { params.discount = parseFloat(params.discount); }
      if (!params.tax) { params.tax = 0; } else { params.tax = parseFloat(params.tax); }
      if (!params.shipping) { params.shipping = 0; } else { params.shipping = parseFloat(params.shipping); }
      if (!params.notes) { params.notes = ''; }

     	// Calcualte subtotal
     	var subtotal = 0;
     	gatewaySession.forEach(function(product) {
         	subtotal += parseFloat(product['Price']) * parseFloat(product['Quantity']);
     	});

     	// Calculate grand total
     	total = Math.round((subtotal - params.discount + params.shipping + params.tax) * 100) / 100;

     	// Create request body
     	request = {
    		'Key'     : vars._client_id,
    		'Secret'  : vars._client_secret,
    		'Test'    : (serverMode == 'TEST') ? 'true' : 'false',
    		'AllowFundingSources' : (params.allow_funding_sources == 'TEST') ? 'true' : 'false',
    		'PurchaseOrder': {
    			'DestinationId' : destination_id,
    			'OrderItems'    : gatewaySession,
    			'Discount'      : -params.discount,
    			'Shipping'      : params.shipping,
    			'Tax'           : params.tax,
    			'Total'			: total,
    			'Notes'         : params.notes
    		}
     	};

    	// Append optional parameters
    	if(redirect_uri) { request['Redirect'] = redirect_uri; }
    	if(params.callback) { request['Callback'] = params.callback; }
    	if(params.order_id) { request['OrderId'] = params.order_id; }

        var host = exports.sandbox ? 'uat.dwolla.com' : 'www.dwolla.com';

    	// Send off the request
    	restler
    	   .post('https://' +  host + '/payment/request', {
    	       headers: { 'Content-Type': 'application/json' },
        	   data: JSON.stringify(request)
        	})
        	.on('complete', function(data) {
        	   if(data['Result'] != 'Success') {
            	   return fn(data['Message']);
        	   } else {
            	   return fn(false, 'https://' + host + '/payment/checkout/' + data['CheckoutId']);
        	   }
        	});
    };

    /**
     * Verify a signature that came back
     * with an offsite gateway redirect
     *
     * @param {string} Proposed signature; (required)
     * @param {string} Dwolla's checkout ID; (required)
     * @param {string} Dwolla's reported total amount; (required)
     *
     * @return {boolean} Whether or not the signature is valid
     */
    exports.verifyGatewaySignature = function(signature, checkout_id, amount) {
        // Verify required paramteres
        if (!signature) { throw new Error('Missing arg signature'); }
        if (!amount) { throw new Error('Missing arg checkout_id'); }
        if (!checkout_id) { throw new Error('Missing arg amount'); }

        // Require crypto lib
        var crypto = require('crypto');

    	// Normalize parameters
    	amount = parseFloat(amount).toFixed(2);

    	// Calculate an HMAC-SHA1 hexadecimal hash
    	// of the checkoutId and amount ampersand separated
    	// using the consumer secret of the application
    	// as the hash key.
    	//
    	// @doc: http://developers.dwolla.com/dev/docs/gateway
        hash = crypto.createHmac('sha1', vars._client_secret).update(checkout_id + "&" + amount).digest('hex');

        return hash == signature;
    };
};<|endoftext|>


<commit_before>var phantom = phantom || {},
	system = require('system'),
	urlparse = require('url').parse,
	page = require('webpage').create(),
	fs = require("fs"),
	utils = require("./utils.js"),
	logModule = require("./logger.js"),
	pipelineExecutorModule = require("./pipeline.executor.js"),
	loadInProgress = false,
	testindex = 0,
	customCallback,
	waitForExternalExecution = false,
	i,
	jasmineCoreRoot = "./../node_modules/jasmine-core/lib/jasmine-core",
	jasmineReportersRoot = "./../node_modules/jasmine-reporters/src",
	jasmineSources = [jasmineCoreRoot + "/jasmine.js",
						jasmineCoreRoot + "/jasmine-html.js",
						"boot.js",
						jasmineReportersRoot + "/tap_reporter.js",
						jasmineReportersRoot + "/nunit_reporter.js"],
	suitesResults;

var options = JSON.parse(system.args[1]);
var logger = new logModule.Logger(options.verbose);
var pipelineExecutor = new pipelineExecutorModule.PipelineExecutor(page, logger, function(){
	return waitForExternalExecution;
})

page.onConsoleMessage = function(msg, lineNum, sourceId) {
	console.log('WEB console: ' + msg);
};

page.viewportSize = {
  width: 1600,
  height: 900
};

pipelineExecutor.push("Opening url " + options.siteUrl, function(){
	page.open(options.siteUrl);
});

if(options.phantomInitCallbacks){
	for(i = 0; i < options.phantomInitCallbacks.length; i++){
		(function(i){
			var customCallback = require(options.phantomInitCallbacks[i]);
			pipelineExecutor.push("Executing custom callback " + i, function(){
				waitForExternalExecution = true;
				customCallback(page, options, function(){
					waitForExternalExecution = false;
				});
			});
		})(i);
	}
}

if(options.additionalJS){
	pipelineExecutor.push("Injecting additional JavaScript files", function(){
		for (i = 0; i < options.additionalJS.length; i++) {
			if(!page.injectJs(options.additionalJS[i])){
				logger.log("Unable to inject script " + options.additionalJS[i]);
				logger.log("Stopping...");
				phantom.exit();
			}
		}
	});
}

pipelineExecutor.push("Injecting jasmine sources", function(){
	page.evaluate(function(){
		window.__phantom_writeFile = function(fileName, xmlText){
			window.jasmineDone = true;
			window.jasmineResults = xmlText;
		}
	});
	for (i = 0; i < jasmineSources.length; i++) {
		if(!page.injectJs(jasmineSources[i])){
			logger.log("Unable to inject jasmine script " + jasmineSources[i]);
			logger.log("Stopping...");
			phantom.exit();
		}
	}
	page.evaluate(function(){
		window.jasmine.getEnv().addReporter(new window.jasmineReporters.TapReporter());
		window.jasmine.getEnv().addReporter(new window.jasmineReporters.NUnitXmlReporter());
	});
});

pipelineExecutor.push("Injecting spec script", function(){
	if(!page.injectJs(options.specPath)){
		logger.log("Unable to inject spec script " + options.specPath);
		logger.log("Stopping...");
		phantom.exit();
	}
});

pipelineExecutor.push("Running jasmine", function(){
	page.evaluate(function(){
		window.jasmine.getEnv().execute();
	});
});

pipelineExecutor.push("Waiting for jasmine to finish", function(){
	waitForExternalExecution = true;
	utils.waitfor(function() {
		return page.evaluate(function() {
				return !!(window.jasmineDone);
			});
		}, function(){
			suitesResults = page.evaluate(function(){
				return window.jasmineResults;
			});
			waitForExternalExecution = false;
		}, function(){
			logger.log("Jasmine timed out. Stopping...");
			waitForExternalExecution = false;
		}, -1);
});

pipelineExecutor.push("Finishing", function(){
	fs.write(options.resultsFileName, suitesResults, 'w');
	logger.log("Test complete");
});

pipelineExecutor.execute(function(){
	phantom.exit();
});<commit_msg>Fixed for the new npm.<commit_after>var phantom = phantom || {},
	system = require('system'),
	urlparse = require('url').parse,
	page = require('webpage').create(),
	fs = require("fs"),
	utils = require("./utils.js"),
	logModule = require("./logger.js"),
	pipelineExecutorModule = require("./pipeline.executor.js"),
	loadInProgress = false,
	testindex = 0,
	customCallback,
	waitForExternalExecution = false,
	i,
	jasmineCoreRoot = "./../../jasmine-core/lib/jasmine-core",
	jasmineReportersRoot = "./../../jasmine-reporters/src",
	jasmineSources = [jasmineCoreRoot + "/jasmine.js",
						jasmineCoreRoot + "/jasmine-html.js",
						"boot.js",
						jasmineReportersRoot + "/tap_reporter.js",
						jasmineReportersRoot + "/nunit_reporter.js"],
	suitesResults;

var options = JSON.parse(system.args[1]);
var logger = new logModule.Logger(options.verbose);
var pipelineExecutor = new pipelineExecutorModule.PipelineExecutor(page, logger, function(){
	return waitForExternalExecution;
})

page.onConsoleMessage = function(msg, lineNum, sourceId) {
	console.log('WEB console: ' + msg);
};

page.viewportSize = {
  width: 1600,
  height: 900
};

pipelineExecutor.push("Opening url " + options.siteUrl, function(){
	page.open(options.siteUrl);
});

if(options.phantomInitCallbacks){
	for(i = 0; i < options.phantomInitCallbacks.length; i++){
		(function(i){
			var customCallback = require(options.phantomInitCallbacks[i]);
			pipelineExecutor.push("Executing custom callback " + i, function(){
				waitForExternalExecution = true;
				customCallback(page, options, function(){
					waitForExternalExecution = false;
				});
			});
		})(i);
	}
}

if(options.additionalJS){
	pipelineExecutor.push("Injecting additional JavaScript files", function(){
		for (i = 0; i < options.additionalJS.length; i++) {
			if(!page.injectJs(options.additionalJS[i])){
				logger.log("Unable to inject script " + options.additionalJS[i]);
				logger.log("Stopping...");
				phantom.exit();
			}
		}
	});
}

pipelineExecutor.push("Injecting jasmine sources", function(){
	page.evaluate(function(){
		window.__phantom_writeFile = function(fileName, xmlText){
			window.jasmineDone = true;
			window.jasmineResults = xmlText;
		}
	});
	for (i = 0; i < jasmineSources.length; i++) {
		if(!page.injectJs(jasmineSources[i])){
			logger.log("Unable to inject jasmine script " + jasmineSources[i]);
			logger.log("Stopping...");
			phantom.exit();
		}
	}
	page.evaluate(function(){
		window.jasmine.getEnv().addReporter(new window.jasmineReporters.TapReporter());
		window.jasmine.getEnv().addReporter(new window.jasmineReporters.NUnitXmlReporter());
	});
});

pipelineExecutor.push("Injecting spec script", function(){
	if(!page.injectJs(options.specPath)){
		logger.log("Unable to inject spec script " + options.specPath);
		logger.log("Stopping...");
		phantom.exit();
	}
});

pipelineExecutor.push("Running jasmine", function(){
	page.evaluate(function(){
		window.jasmine.getEnv().execute();
	});
});

pipelineExecutor.push("Waiting for jasmine to finish", function(){
	waitForExternalExecution = true;
	utils.waitfor(function() {
		return page.evaluate(function() {
				return !!(window.jasmineDone);
			});
		}, function(){
			suitesResults = page.evaluate(function(){
				return window.jasmineResults;
			});
			waitForExternalExecution = false;
		}, function(){
			logger.log("Jasmine timed out. Stopping...");
			waitForExternalExecution = false;
		}, -1);
});

pipelineExecutor.push("Finishing", function(){
	fs.write(options.resultsFileName, suitesResults, 'w');
	logger.log("Test complete");
});

pipelineExecutor.execute(function(){
	phantom.exit();
});<|endoftext|>


<commit_before>var vec3 = require('vec3');
var Vec3 = vec3.Vec3;
var assert = require('assert');
var Block = require('../block');
var Painting = require('../painting');
var Location = require('../location');
var ChatMessage = require('../chat_message');

module.exports = inject;

var paintingFaceToVec = [
  new Vec3(0, 0, -1),
  new Vec3(-1, 0, 0),
  new Vec3(0, 0, 1),
  new Vec3(1, 0, 0),
];

function inject(bot) {
  var columns = {};
  var signs = {};
  var paintingsByPos = {};
  var paintingsById = {};

  function addPainting(painting) {
    paintingsById[painting.id] = painting;
    paintingsByPos[painting.position] = painting;
  }

  function deletePainting(painting) {
    delete paintingsById[painting.id];
    delete paintingsByPos[painting.position];
  }

  function addColumn(args) {
    var columnCorner = new Vec3(args.x * 16, 0, args.z * 16);
    var key = columnKeyXZ(columnCorner.x, columnCorner.z);
    if(!args.bitMap) {
      // stop storing the chunk column
      delete columns[key];
      bot.emit("chunkColumnUnload", columnCorner);
      return;
    }
    var column = columns[key];
    if(!column) columns[key] = column = new Column();
    var chunkIncluded = new Array(16);
    var y;
    for(y = 0; y < 16; ++y) {
      chunkIncluded[y] = args.bitMap & (1 << y);
    }

    var offset = 0;

    // block types
    var size = 16 * 16 * 16 * 2;
    for(y = 0; y < 16; ++y) {
      var blockId = args.data.slice(offset, offset + size);

      // Column.metadata doesn't exist anymore.
      column.blockType[y] = chunkIncluded[y] ? blockId : null;
      offset = chunkIncluded[y] ? offset + size : offset;
    }
    size = 16 * 16 * 16 / 2;
    // light
    for(y = 0; y < 16; ++y) {
      column.light[y] = chunkIncluded[y] ?
        args.data.slice(offset, offset + size) : null;
      offset = chunkIncluded[y] ? offset + size : offset;
    }
    // sky light
    if(args.skyLightSent) {
      for(y = 0; y < 16; ++y) {
        column.skyLight[y] = chunkIncluded[y] ?
          args.data.slice(offset, offset + size) : null;
        offset = chunkIncluded[y] ? offset + size : offset;
      }
    }
    // biome
    if(args.groundUp) {
      size = 256;
      column.biome = args.data.slice(offset, offset + size);
      offset += size;
    }

    assert.strictEqual(offset, args.data.length);
    bot.emit("chunkColumnLoad", columnCorner);
  }

  function findBlock(options) {
    var check;
    if(typeof(options.matching) !== 'function') {
      if(!Array.isArray(options.matching)) {
        options.matching = [options.matching];
      }
      check=isMatchingType;
    }
    else check=options.matching;
    options.point = options.point || bot.entity.position;
    options.maxDistance = options.maxDistance || 16;
    var cursor = vec3();
    var point = options.point;
    var max = options.maxDistance;
    var found;
    for(cursor.x = point.x - max; cursor.x < point.x + max; cursor.x++) {
      for(cursor.y = point.y - max; cursor.y < point.y + max; cursor.y++) {
        for(cursor.z = point.z - max; cursor.z < point.z + max; cursor.z++) {
          found = bot.blockAt(cursor);
          if (check(found)) return found;
        }
      }
    }

    function isMatchingType(block) {
      return options.matching.indexOf(block.type) >= 0;
    }
  }

  function blockAt(absolutePoint) {
    var loc = new Location(absolutePoint);
    var key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z);
    var column = columns[key];
    // null column means chunk not loaded
    if(!column) return null;
    var blockType = double_bite(column.blockType);
    var nibbleIndex = loc.blockIndex >> 1;
    var lowNibble = loc.blockIndex % 2 === 1;

    var biomeId = column.biome.readUInt8(loc.biomeBlockIndex);

    var block = new Block(blockType >> 4, biomeId, blockType & 0x0f);
    block.light = nib(column.light);
    block.skyLight = nib(column.skyLight);
    block.position = loc.floored;
    block.signText = signs[loc.floored];
    block.painting = paintingsByPos[loc.floored];

    return block;

    function double_bite(array) {
      var buf = array[loc.chunkYIndex];
      return buf ? buf.readUInt16LE(loc.blockIndex * 2) : 0;
    }

    function nib(array) {
      var buf = array[loc.chunkYIndex];
      return buf ? nibble(buf.readUInt8(nibbleIndex), lowNibble) : 0;
    }
  }

  function chunkColumn(x, z) {
    var key = columnKeyXZ(x, z);
    return columns[key];
  }

  function emitBlockUpdate(oldBlock, newBlock) {
    bot.emit("blockUpdate", oldBlock, newBlock);
    var position = oldBlock ? oldBlock.position :
      (newBlock ? newBlock.position : null);
    if(position) bot.emit("blockUpdate:" + newBlock.position, oldBlock, newBlock);
  }

  function updateBlock(point, type, metadata) {
    var oldBlock = blockAt(point);
    var loc = new Location(point);
    var key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z);
    var column = columns[key];
    // sometimes minecraft server sends us block updates before it sends
    // us the column that the block is in. ignore this.
    if(!column) return;
    var blockTypeBuffer = column.blockType[loc.chunkYIndex];
    // if it's null, it was all air, but now we're inserting a block.
    if(!blockTypeBuffer) {
      blockTypeBuffer = new Buffer(16 * 16 * 16 * 2);
      blockTypeBuffer.fill(0);
      column.blockType[loc.chunkYIndex] = blockTypeBuffer;
    }
    blockTypeBuffer.writeUInt16LE((type << 4) | metadata, loc.blockIndex * 2);

    delete signs[loc.floored];

    var painting = paintingsByPos[loc.floored];
    if(painting) deletePainting(painting);

    emitBlockUpdate(oldBlock, blockAt(point));
  }

  bot._client.on('map_chunk', function(packet) {
    addColumn({
      x: packet.x,
      z: packet.z,
      bitMap: packet.bitMap,
      skyLightSent: true,
      groundUp: packet.groundUp,
      data: packet.chunkData,
    });
  });

  bot._client.on('map_chunk_bulk', function(packet) {
    var offset = 0;
    var meta, i, size;
    for(i = 0; i < packet.meta.length; ++i) {
      meta = packet.meta[i];
      size = (8192 + (packet.skyLightSent ? 2048 : 0)) *
        onesInShort(meta.bitMap) + // block ids
        2048 * onesInShort(meta.bitMap) + // (two bytes per block id)
        256; // biomes
      addColumn({
        x: meta.x,
        z: meta.z,
        bitMap: meta.bitMap,
        skyLightSent: packet.skyLightSent,
        groundUp: true,
        data: packet.data.slice(offset, offset + size),
      });
      offset += size;
    }

    assert.strictEqual(offset, packet.data.length);
  });

  bot._client.on('multi_block_change', function(packet) {
    // multi block change
    var i, record, metadata, type, blockX, blockZ, y, pt;
    for(i = 0; i < packet.recordCount; ++i) {
      record = packet.records[i];

      metadata = (record.blockId & 0x0f);
      type = (record.blockId) >> 4;
      y = record.y;
      blockZ = (record.horizontalPos & 0x0f);
      blockX = (record.horizontalPos >> 4) & 0x0f;

      pt = new Vec3(packet.chunkX * 16 + blockX, y, packet.chunkZ * 16 + blockZ);
      updateBlock(pt, type, metadata);
    }
  });

  bot._client.on('block_change', function(packet) {
    // block change
    var pt = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    updateBlock(pt, packet.type >> 4, packet.type & 0x0f);
  });

  bot._client.on('explosion', function(packet) {
    // explosion
    packet.affectedBlockOffsets.forEach(function(offset) {
      var pt = vec3(offset).offset(packet.x, packet.y, packet.z);
      updateBlock(pt.floor(), 0, 0);
    });
  });

  bot._client.on('spawn_entity_painting', function(packet) {
    var pos = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    var painting = new Painting(packet.entityId,
      pos, packet.title, paintingFaceToVec[packet.direction]);
    addPainting(painting);
  });

  bot._client.on('entity_destroy', function(packet) {
    // destroy entity
    packet.entityIds.forEach(function(id) {
      var painting = paintingsById[id];
      if(painting) deletePainting(painting);
    });
  });

  bot._client.on('update_sign', function(packet) {
    // update sign
    var pos = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    var oldBlock = blockAt(pos);

    // Some servers send blank lines in signs wrong, causing the chat handler to crash.
    if(packet.text1 == 'null') {
      packet.text1 = '""'
    }
    if(packet.text2 == 'null') {
      packet.text2 = '""'
    }
    if(packet.text3 == 'null') {
      packet.text3 = '""'
    }
    if(packet.text4 == 'null') {
      packet.text4 = '""'
    }

    signs[pos] = new ChatMessage(JSON.parse(packet.text1)) + "\n" + new ChatMessage(JSON.parse(packet.text2)) +
      "\n" + new ChatMessage(JSON.parse(packet.text3)) + "\n" + new ChatMessage(JSON.parse(packet.text4));
    emitBlockUpdate(oldBlock, blockAt(pos));
  });
  bot.updateSign = function(block, text) {
    var lines = text.split("\n");
    if(lines.length > 4) {
      bot.emit("error", new Error("too many lines for sign text"));
      return;
    }
    for(var i = 0; i < lines.length; ++i) {
      if(lines[i].length > 15) {
        bot.emit("error", new Error("signs have max line length 15"));
        return;
      }
    }
    bot._client.write('update_sign', {
      location: block.position,
      text1: JSON.stringify(lines[0]),
      text2: JSON.stringify(lines[1]),
      text3: JSON.stringify(lines[2]),
      text4: JSON.stringify(lines[3])
    });
  };

  // if we get a respawn packet and the dimension is changed,
  // unload all chunks from memory.
  var dimension;
  bot._client.on('login', function(packet) {
    dimension = packet.dimension
  });
  bot._client.on('respawn', function(packet) {
    if(dimension === packet.dimension) return;
    dimension = packet.dimension;
    columns = {};
  });

  bot.findBlock = findBlock;
  bot.blockAt = blockAt;
  bot._chunkColumn = chunkColumn;
  bot._updateBlock = updateBlock;
}

function columnKeyXZ(x, z) {
  return x + ',' + z;
}

function onesInShort(n) {
  n = n & 0xffff;
  var count = 0;
  for(var i = 0; i < 16; ++i) {
    count = ((1 << i) & n) ? count + 1 : count;
  }
  return count;
}

function nibble(wholeByte, low) {
  return low ?
  wholeByte & 0x0f :
  wholeByte >> 4;
}

function Column() {
  this.blockType = new Array(16);
  this.light = new Array(16);
  this.skyLight = new Array(16);
  this.biome = null;
}

<commit_msg>Fix #306 : chunks have a different size in the nether http://wiki.vg/Protocol#Chunk_Data "The server does not send skylight information for nether-chunks, it's up to the client to know if the player is currently in the nether."<commit_after>var vec3 = require('vec3');
var Vec3 = vec3.Vec3;
var assert = require('assert');
var Block = require('../block');
var Painting = require('../painting');
var Location = require('../location');
var ChatMessage = require('../chat_message');

module.exports = inject;

var paintingFaceToVec = [
  new Vec3(0, 0, -1),
  new Vec3(-1, 0, 0),
  new Vec3(0, 0, 1),
  new Vec3(1, 0, 0),
];

function inject(bot) {
  var columns = {};
  var signs = {};
  var paintingsByPos = {};
  var paintingsById = {};

  function addPainting(painting) {
    paintingsById[painting.id] = painting;
    paintingsByPos[painting.position] = painting;
  }

  function deletePainting(painting) {
    delete paintingsById[painting.id];
    delete paintingsByPos[painting.position];
  }

  function addColumn(args) {
    var columnCorner = new Vec3(args.x * 16, 0, args.z * 16);
    var key = columnKeyXZ(columnCorner.x, columnCorner.z);
    if(!args.bitMap) {
      // stop storing the chunk column
      delete columns[key];
      bot.emit("chunkColumnUnload", columnCorner);
      return;
    }
    var column = columns[key];
    if(!column) columns[key] = column = new Column();
    var chunkIncluded = new Array(16);
    var y;
    for(y = 0; y < 16; ++y) {
      chunkIncluded[y] = args.bitMap & (1 << y);
    }

    var offset = 0;

    // block types
    var size = 16 * 16 * 16 * 2;
    for(y = 0; y < 16; ++y) {
      var blockId = args.data.slice(offset, offset + size);

      // Column.metadata doesn't exist anymore.
      column.blockType[y] = chunkIncluded[y] ? blockId : null;
      offset = chunkIncluded[y] ? offset + size : offset;
    }
    size = 16 * 16 * 16 / 2;
    // light
    for(y = 0; y < 16; ++y) {
      column.light[y] = chunkIncluded[y] ?
        args.data.slice(offset, offset + size) : null;
      offset = chunkIncluded[y] ? offset + size : offset;
    }
    // sky light
    if(args.skyLightSent) {
      for(y = 0; y < 16; ++y) {
        column.skyLight[y] = chunkIncluded[y] ?
          args.data.slice(offset, offset + size) : null;
        offset = chunkIncluded[y] ? offset + size : offset;
      }
    }
    // biome
    if(args.groundUp) {
      size = 256;
      column.biome = args.data.slice(offset, offset + size);
      offset += size;
    }

    assert.strictEqual(offset, args.data.length);
    bot.emit("chunkColumnLoad", columnCorner);
  }

  function findBlock(options) {
    var check;
    if(typeof(options.matching) !== 'function') {
      if(!Array.isArray(options.matching)) {
        options.matching = [options.matching];
      }
      check=isMatchingType;
    }
    else check=options.matching;
    options.point = options.point || bot.entity.position;
    options.maxDistance = options.maxDistance || 16;
    var cursor = vec3();
    var point = options.point;
    var max = options.maxDistance;
    var found;
    for(cursor.x = point.x - max; cursor.x < point.x + max; cursor.x++) {
      for(cursor.y = point.y - max; cursor.y < point.y + max; cursor.y++) {
        for(cursor.z = point.z - max; cursor.z < point.z + max; cursor.z++) {
          found = bot.blockAt(cursor);
          if (check(found)) return found;
        }
      }
    }

    function isMatchingType(block) {
      return options.matching.indexOf(block.type) >= 0;
    }
  }

  function blockAt(absolutePoint) {
    var loc = new Location(absolutePoint);
    var key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z);
    var column = columns[key];
    // null column means chunk not loaded
    if(!column) return null;
    var blockType = double_bite(column.blockType);
    var nibbleIndex = loc.blockIndex >> 1;
    var lowNibble = loc.blockIndex % 2 === 1;

    var biomeId = column.biome.readUInt8(loc.biomeBlockIndex);

    var block = new Block(blockType >> 4, biomeId, blockType & 0x0f);
    block.light = nib(column.light);
    block.skyLight = nib(column.skyLight);
    block.position = loc.floored;
    block.signText = signs[loc.floored];
    block.painting = paintingsByPos[loc.floored];

    return block;

    function double_bite(array) {
      var buf = array[loc.chunkYIndex];
      return buf ? buf.readUInt16LE(loc.blockIndex * 2) : 0;
    }

    function nib(array) {
      var buf = array[loc.chunkYIndex];
      return buf ? nibble(buf.readUInt8(nibbleIndex), lowNibble) : 0;
    }
  }

  function chunkColumn(x, z) {
    var key = columnKeyXZ(x, z);
    return columns[key];
  }

  function emitBlockUpdate(oldBlock, newBlock) {
    bot.emit("blockUpdate", oldBlock, newBlock);
    var position = oldBlock ? oldBlock.position :
      (newBlock ? newBlock.position : null);
    if(position) bot.emit("blockUpdate:" + newBlock.position, oldBlock, newBlock);
  }

  function updateBlock(point, type, metadata) {
    var oldBlock = blockAt(point);
    var loc = new Location(point);
    var key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z);
    var column = columns[key];
    // sometimes minecraft server sends us block updates before it sends
    // us the column that the block is in. ignore this.
    if(!column) return;
    var blockTypeBuffer = column.blockType[loc.chunkYIndex];
    // if it's null, it was all air, but now we're inserting a block.
    if(!blockTypeBuffer) {
      blockTypeBuffer = new Buffer(16 * 16 * 16 * 2);
      blockTypeBuffer.fill(0);
      column.blockType[loc.chunkYIndex] = blockTypeBuffer;
    }
    blockTypeBuffer.writeUInt16LE((type << 4) | metadata, loc.blockIndex * 2);

    delete signs[loc.floored];

    var painting = paintingsByPos[loc.floored];
    if(painting) deletePainting(painting);

    emitBlockUpdate(oldBlock, blockAt(point));
  }

  bot._client.on('map_chunk', function(packet) {
    addColumn({
      x: packet.x,
      z: packet.z,
      bitMap: packet.bitMap,
      skyLightSent: bot.game.dimension!=="nether",
      groundUp: packet.groundUp,
      data: packet.chunkData,
    });
  });

  bot._client.on('map_chunk_bulk', function(packet) {
    var offset = 0;
    var meta, i, size;
    for(i = 0; i < packet.meta.length; ++i) {
      meta = packet.meta[i];
      size = (8192 + (packet.skyLightSent ? 2048 : 0)) *
        onesInShort(meta.bitMap) + // block ids
        2048 * onesInShort(meta.bitMap) + // (two bytes per block id)
        256; // biomes
      addColumn({
        x: meta.x,
        z: meta.z,
        bitMap: meta.bitMap,
        skyLightSent: packet.skyLightSent,
        groundUp: true,
        data: packet.data.slice(offset, offset + size),
      });
      offset += size;
    }

    assert.strictEqual(offset, packet.data.length);
  });

  bot._client.on('multi_block_change', function(packet) {
    // multi block change
    var i, record, metadata, type, blockX, blockZ, y, pt;
    for(i = 0; i < packet.recordCount; ++i) {
      record = packet.records[i];

      metadata = (record.blockId & 0x0f);
      type = (record.blockId) >> 4;
      y = record.y;
      blockZ = (record.horizontalPos & 0x0f);
      blockX = (record.horizontalPos >> 4) & 0x0f;

      pt = new Vec3(packet.chunkX * 16 + blockX, y, packet.chunkZ * 16 + blockZ);
      updateBlock(pt, type, metadata);
    }
  });

  bot._client.on('block_change', function(packet) {
    // block change
    var pt = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    updateBlock(pt, packet.type >> 4, packet.type & 0x0f);
  });

  bot._client.on('explosion', function(packet) {
    // explosion
    packet.affectedBlockOffsets.forEach(function(offset) {
      var pt = vec3(offset).offset(packet.x, packet.y, packet.z);
      updateBlock(pt.floor(), 0, 0);
    });
  });

  bot._client.on('spawn_entity_painting', function(packet) {
    var pos = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    var painting = new Painting(packet.entityId,
      pos, packet.title, paintingFaceToVec[packet.direction]);
    addPainting(painting);
  });

  bot._client.on('entity_destroy', function(packet) {
    // destroy entity
    packet.entityIds.forEach(function(id) {
      var painting = paintingsById[id];
      if(painting) deletePainting(painting);
    });
  });

  bot._client.on('update_sign', function(packet) {
    // update sign
    var pos = new Vec3(packet.location.x, packet.location.y, packet.location.z);
    var oldBlock = blockAt(pos);

    // Some servers send blank lines in signs wrong, causing the chat handler to crash.
    if(packet.text1 == 'null') {
      packet.text1 = '""'
    }
    if(packet.text2 == 'null') {
      packet.text2 = '""'
    }
    if(packet.text3 == 'null') {
      packet.text3 = '""'
    }
    if(packet.text4 == 'null') {
      packet.text4 = '""'
    }

    signs[pos] = new ChatMessage(JSON.parse(packet.text1)) + "\n" + new ChatMessage(JSON.parse(packet.text2)) +
      "\n" + new ChatMessage(JSON.parse(packet.text3)) + "\n" + new ChatMessage(JSON.parse(packet.text4));
    emitBlockUpdate(oldBlock, blockAt(pos));
  });
  bot.updateSign = function(block, text) {
    var lines = text.split("\n");
    if(lines.length > 4) {
      bot.emit("error", new Error("too many lines for sign text"));
      return;
    }
    for(var i = 0; i < lines.length; ++i) {
      if(lines[i].length > 15) {
        bot.emit("error", new Error("signs have max line length 15"));
        return;
      }
    }
    bot._client.write('update_sign', {
      location: block.position,
      text1: JSON.stringify(lines[0]),
      text2: JSON.stringify(lines[1]),
      text3: JSON.stringify(lines[2]),
      text4: JSON.stringify(lines[3])
    });
  };

  // if we get a respawn packet and the dimension is changed,
  // unload all chunks from memory.
  var dimension;
  bot._client.on('login', function(packet) {
    dimension = packet.dimension
  });
  bot._client.on('respawn', function(packet) {
    if(dimension === packet.dimension) return;
    dimension = packet.dimension;
    columns = {};
  });

  bot.findBlock = findBlock;
  bot.blockAt = blockAt;
  bot._chunkColumn = chunkColumn;
  bot._updateBlock = updateBlock;
}

function columnKeyXZ(x, z) {
  return x + ',' + z;
}

function onesInShort(n) {
  n = n & 0xffff;
  var count = 0;
  for(var i = 0; i < 16; ++i) {
    count = ((1 << i) & n) ? count + 1 : count;
  }
  return count;
}

function nibble(wholeByte, low) {
  return low ?
  wholeByte & 0x0f :
  wholeByte >> 4;
}

function Column() {
  this.blockType = new Array(16);
  this.light = new Array(16);
  this.skyLight = new Array(16);
  this.biome = null;
}

<|endoftext|>


<commit_before>'use strict';

var through = require('through2');
var Remarkable = require('remarkable');
var PluginError = require('plugin-error');
var prettify = require('pretty-remarkable');
var _ = require('lodash');

module.exports = plugin('verb', 'format');

/**
 * Apply basic formatting to markdown
 */

function plugin(appname, name, config) {
  var pluginname = appname + '-' + name + ':';

  return function formatPlugins(locals) {
    locals = _.extend({}, config, locals);
    var app = this;
    var argv = app.get('argv');

    // add a trailing newline to docs?
    var newline = argv.newline || app.config.get('newline');

    return through.obj(function (file, enc, cb) {
      if (file.isNull()) {
        this.push(file);
        return cb();
      }
      if (file.isStream()) {
        this.emit('error', new PluginError(pluginname, 'Streaming is not supported.'));
        return cb();
      }
      if (file.path.indexOf('README.md') === -1 || noformat(app, file, locals, argv)) {
        this.push(file);
        return cb();
      }

      // pass some extra formatting info to `pretty-remarkable`
      var opts = _.extend({}, locals, file.options);
      opts.username = app.get('data.username');
      opts.name = app.get('data.author.name');

      // prettify
      var str = pretty(file.contents.toString(), opts);
      str = str.trim() + (newline ? '\n' : '');
      str = fixList(str);

      // rebuffer contents
      file.contents = new Buffer(str);
      this.push(file);
      return cb();
    });
  };
}

/**
 * Fix list formatting
 */

function fixList(str) {
  str = str.replace(/(  - \[?[^)]+\)?)\n\n\*\s/gm, '$1\n* ');
  return str;
}

/**
 * Instantiate `Remarkable` and use the `prettify` plugin
 * on the given `str`.
 *
 * @param  {String} `str`
 * @param  {Object} `options`
 * @return {String}
 */

function pretty(str, options) {
  return new Remarkable(options)
    .use(prettify)
    .render(str);
}

/**
 * Push the `file` through if the user has specfied
 * not to format it.
 */

function noformat(app, file, locals, argv) {
  return app.isTrue('noformat') || app.isFalse('format')
    || file.noformat === true || file.format === false
    || locals.noformat === true || locals.format === false
    || argv.noformat === true || argv.format === false;
}
<commit_msg>fixes bad `strong` formatting:<commit_after>'use strict';

var through = require('through2');
var Remarkable = require('remarkable');
var PluginError = require('plugin-error');
var prettify = require('pretty-remarkable');
var _ = require('lodash');

module.exports = plugin('verb', 'format');

/**
 * Apply basic formatting to markdown
 */

function plugin(appname, name, config) {
  var pluginname = appname + '-' + name + ':';

  return function formatPlugins(locals) {
    locals = _.extend({}, config, locals);
    var app = this;
    var argv = app.get('argv');

    // add a trailing newline to docs?
    var newline = argv.newline || app.config.get('newline');

    return through.obj(function (file, enc, cb) {
      if (file.isNull()) {
        this.push(file);
        return cb();
      }
      if (file.isStream()) {
        this.emit('error', new PluginError(pluginname, 'Streaming is not supported.'));
        return cb();
      }
      if (file.path.indexOf('README.md') === -1 || noformat(app, file, locals, argv)) {
        this.push(file);
        return cb();
      }

      // pass some extra formatting info to `pretty-remarkable`
      var opts = _.extend({}, locals, file.options);
      opts.username = app.get('data.username');
      opts.name = app.get('data.author.name');

      // prettify
      var str = pretty(file.contents.toString(), opts);
      str = str.trim() + (newline ? '\n' : '');
      str = fixList(str);

      // rebuffer contents
      file.contents = new Buffer(str);
      this.push(file);
      return cb();
    });
  };
}

/**
 * Fix list formatting
 */

function fixList(str) {
  str = str.replace(/(  - \[?[^)]+\)?)\n\n\*\s/gm, '$1\n* ');
  str = str.split('__{_}_*').join('**{*}**');
  return str;
}

/**
 * Instantiate `Remarkable` and use the `prettify` plugin
 * on the given `str`.
 *
 * @param  {String} `str`
 * @param  {Object} `options`
 * @return {String}
 */

function pretty(str, options) {
  return new Remarkable(options)
    .use(prettify)
    .render(str);
}

/**
 * Push the `file` through if the user has specfied
 * not to format it.
 */

function noformat(app, file, locals, argv) {
  return app.isTrue('noformat') || app.isFalse('format')
    || file.noformat === true || file.format === false
    || locals.noformat === true || locals.format === false
    || argv.noformat === true || argv.format === false;
}
<|endoftext|>