<commit_before>var path          = require('path')
  , utils         = require('./utils')
  , join          = path.join
  , exists        = utils.exists
  , read          = utils.read
  , error         = utils.error
  , domainIgnoreR = /^data(?=::)|^external(?=::)|^M8(?=::)|^npm(?=::)/
  , domainIgnoreL = ['data', 'external', 'M8', 'npm']
  , domainPresent = /^([\w]*)::/;

// isAbsolute pass => reqStr and lies directly on the domain root
// isAbsolute fail => reqStr is relative to extraPath
function isAbsolute(reqStr) {
  return reqStr === '' || path.normalize(reqStr) === reqStr;
}

// Takes out domain prefix from a request string if exists
function stripDomain(reqStr) {
  var ary = reqStr.split('::');
  return ary[ary.length - 1];
}

/**
 * makeFinder
 *
 * finder factory for Resolver
 * @return finder function
 *
 * finder function scans join(base, req + ext) for closure held extensions
 */
function makeFinder(exts) {
  return function (base, req) {
    for (var i = 0; i < exts.length; i += 1) {
      var ext = exts[i]
        , attempt = join(base, req + ext);

      //console.log(attempt, '<- attempt, base->', base);
      if (exists(attempt)) {
        return (req + ext);
      }
    }
    return false;
  };
}

/**
 * npmResolve factory
 *
 * creates a function which finds the entry point of an npm module
 * create with the node_modules root
 *
 * @[in] absReq - path node module should exist on
 * @[in] silent - bool === !(errors should throw)
 * @[in] name   - name of the module for good error msgs
 */
function makeNpmResolver(root) {
  return function (absReq, name) {
    var folderPath = join(root, absReq)
      , jsonPath = join(folderPath, 'package.json')
      , json = {};

    //console.log('npmResolve', absReq, name, folderPath);

    // folder must exists if we commit to it
    if (!path.existsSync(folderPath)) {
      return false;
    }

    // package.json must exist
    if (!exists(jsonPath)) {
      error("resolver could not load npm module " + name + " - package.json not found");
      return false;
    }

    // package.json must be valid json
    try {
      json = JSON.parse(read(jsonPath));
    } catch (e) {
      error("could not load npm module " + name + " - package.json invalid");
    }

    // prefer browserMain entry point if specified, then main, then index
    var mainFile = json.browserMain || json.main || 'index';
    //console.log("npmResolve final?", mainFile);
    if (!exists(join(folderPath, mainFile))) {
      error("resolver could not load npm module " + name + "package.json lies about main: " + mainFile + " does not exist");
    }
    //console.log('npmResolve worked, returning', join(absReq, mainFile));
    return join(absReq, mainFile);
  };
}

/**
 * toAbsPath
 *
 * converts a generic detective request string to an absolute one
 * throws if it receives an obviously bad request
 *
 * @[in] reqStr - raw request string
 * @[in] extraPath - path of requiree's relative position to domain root
 * @[in] domain
 */
// absolutizes a path - special cases the npm domain
function toAbsPath(reqStr, extraPath, domain) {
  //console.log('toAbsPath', reqStr, extraPath);
  if (domainPresent.test(reqStr)) {
    domain = reqStr.match(domainPresent)[1]; // override current domain if explicitly specified
    if (!isAbsolute(reqStr)) {
      error("does not allow cross-domain relative requires (" + reqStr + ")");
    }
    return [stripDomain(reqStr), domain];
  }
  else if (isAbsolute(reqStr)) {
    //console.log("absolute reqStr", reqStr);
    // special case absolutes from npm domain
    // this sandboxes the npm domain (sensible)
    if (domain === 'npm') {
      //console.log('absolute npm string', reqStr, extraPath);
      return [reqStr, 'npm']; // explicit npms need to be handled elsewhere
    }
    else {
      return [reqStr, null];
    }
  }
  else {
    //console.log('relative request string', isAbsolute(reqStr));
    return [join(extraPath, reqStr), domain];
  }
}

/**
 * Resolver constructor
 * @[in] domains - {name : path} object
 * @[in] arbiters - list of requirable arbiters
 * @[in] exts - list of registered extensions
 */
function Resolver(domains, arbiters, exts, npmTree, builtIns, serverModules) {
  this.finder = makeFinder(exts);
  this.npmResolve = makeNpmResolver(domains.npm);
  this.domains = domains;
  this.arbiters = arbiters;
  this.exts = exts;
  this.npmTree = npmTree;
  this.builtIns = builtIns;
  this.serverModules = serverModules;
}

/**
 * scan [private]
 * scans a set of domain names for absReq
 *
 * @[in] absReq - require string relative to a domain root
 * @[in] scannable - ordered list of domain names to scan
 * @return === locate's return if found, else false
 **/
Resolver.prototype.scan = function (absReq, scannable) {
  //console.log("SCAN:", absReq, scannable, this.domains[scannable[0]]);
  var noTryFolder = false
    , lastChar = absReq.slice(-1);

  if (lastChar === '/' || lastChar === '\\') {
    absReq = join(absReq, 'index');
    noTryFolder = true;
  }
  for (var i = 0; i < scannable.length; i += 1) {
    var dom = scannable[i]
      , found = this.finder(this.domains[dom], absReq);

    if (found) {
      return [found, dom, true];
    }

    if (noTryFolder) {
      continue;
    }

    found = this.finder(this.domains[dom], join(absReq, 'index'));
    if (found) {
      return [found, dom, true];
    }
  }
  return false;
};

/**
 * locate
 *
 * locates a required file - throws on bad requests - main interface
 *
 * @[in] reqStr from detective
 * @[in] path of requiree's relative position to domain root
 * @[in] requiree's domain
 * @return [foundPath, domainName, isFake] where:
 *
 * [str] foundPath  - full path of the chosen file to use
 * [str] domainName - name of the domain it was found on
 * [bool] isReal    - true iff foundPath represents a real file
 **/
Resolver.prototype.locate = function (reqStr, currentPath, currentDomain) {
  //console.log("resolver locate:", reqStr, 'from', currentPath);
  var absResult = toAbsPath(reqStr, currentPath, currentDomain)
    , absReq = absResult[0]
    , foundDomain = absResult[1]
    , found = false
    , result = false
    , that = this
    , msg = '';

  //console.log("resolve this ", reqStr, currentDomain, "found: ", foundDomain, absReq);
  if (domainIgnoreL.indexOf(foundDomain) >= 0) {

    if (foundDomain === 'data' || foundDomain === 'external') {
      return [absReq, foundDomain, false];
    }
    if (foundDomain === 'M8') {
      if (this.arbiters.indexOf(absReq) >= 0) {
        return [absReq, 'M8', false];
      }
      error("resolver could not require non-existent arbiter: " + reqStr + " (from " + currentDomain + ")");
    }
    if (foundDomain === 'npm') {
      if (!this.domains.npm) {
        error("resolver cannot require from npm module without specifying the node_modules root");
      }
      var name = absReq; // at this point, this is safe

      // node module priority:
      // 1. if we are requiring a builtin (sanitized) server-side module - return that
      // 2a.  if required from root, do
      // 2b1. try to locate node module in node_module subfolder of current node module
      // 2b2. look up one level in the tree recursively until a hit is found || we hit the domain root
      // 4. throw

      // 1. builtins
      if (this.builtIns.indexOf(name) >= 0) {
        if (this.npmTree._builtIns.indexOf(name) < 0) {
          this.npmTree._builtIns.push(name);
        }
        return [name, 'npm', false]; // this should be fine, should really be on the npm namespace
      }
      // 1. unhandled node base modules
      else if (this.serverModules.indexOf(name) >= 0) {
        error("cannot require server side node module " + name);
      }

      var npmMain;

      // 2a. entry point branch to npm domain
      if (currentDomain !== 'npm') {
        //console.log('npm find', name);
        npmMain = this.npmResolve(name, name);
        if (npmMain) {
          this.npmTree[name] = {
            main : npmMain
          , deps : {}
          };
          return [npmMain, 'npm', true];
        }
        error('could not find module', reqStr);
      }

      // 2b. try current + node_modules + the string specified
      // but first make sure we start at the module's root before we join on node_modules
      var slash = '/'; //TODO
      var order = currentPath.split('node_modules').length;
      var moduleRoot = currentPath.split(slash).slice(0, Math.max(2 * (order - 2) + 1, 1)).join(slash);

      var expected = join(moduleRoot, 'node_modules', name);
      var branch = moduleRoot.split(slash + 'node_modules' + slash);
      //console.log('trying', expected, order, moduleRoot, currentPath, branch);
      npmMain = this.npmResolve(expected, name);
      if (npmMain) {
        var position = this.npmTree[branch[0]];
        for (var i = 1; i < branch.length; i += 1) {
          position = position.deps[branch[i]];
          if (!position) {
            error('internal resolver error 1'); // this should never happen
          }
        }
        position.deps[name] = {
          main : npmMain
        , deps : {}
        };
        //console.log('found', npmMain);
        return [npmMain, 'npm', true];
      }

      var oldBranch = branch;
      // 2b2.
      while (true) {
        expected = join(expected, '..', '..', '..', name);
        //console.log('trying', expected);
        if (expected === '.' || expected.slice(0,2) === '..') { // broken out of domain root
          break;
        }
        branch = branch.slice(0, -1); // we went one up

        npmMain = this.npmResolve(expected, name);
        if (npmMain) {
          // need to give a link to this module regardless of where in the hierarchy it is
          var oldPos = this.npmTree[oldBranch[0]];
          for (var i = 1; i < oldBranch.length; i += 1) {
            oldPos = oldPos.deps[oldBranch[i]];
            if (!oldPos) {
              error('internal resolver error 3');
            }
          }
          oldPos.deps[name] = {
            main : npmMain
          , deps : {}
          };

          // now make it requirable to everything above
          //console.log('found', npmMain, branch, !!branch.length, branch.length);
          if (!branch.length) {
            this.npmTree[name] = {
              main : npmMain
            , deps : {}
            }
            return [npmMain, 'npm', true];
          }
          var position = this.npmTree[branch[0]];
          for (var i = 1; i < branch.length; i += 1) {
            position = position.deps[branch[i]];
            if (!position) {
              error('internal resolver error 2'); // should never happen
            }
          }

          position.deps[name] = {
            main : npmMain
          , deps : {}
          };

          return [npmMain, 'npm', true];
        }
      }

      // 4. nothing worked
      error("failed to require npm module " + name);

    }
  }
  else { // anything that was absolutely required from outside npm
    if (foundDomain && !this.domains[foundDomain]) { // also prevents second call to npmResolve
      error("resolver could not require from an unconfigured domain: " + foundDomain);
    }
    if (foundDomain === 'app' && currentDomain !== 'app') {
      error("does not allow other domains to reference the app domain. required from " + currentDomain);
    }

    if (foundDomain) { // require to a specific/same domain - we must succeed in here
      result = this.scan(absReq, [foundDomain]);
      if (result) {
        return result;
      }
      msg = " for extensions " + this.exts.slice(1).join(', ');
      error("resolver failed to resolve require('" + reqStr + "') in " + foundDomain + msg);
    }

    // absolute requires from app domain cannot indirectly require npm modules for safety
    // but this behaviour needs to work inside the npm domain, so toAbsPath sandboxes it meaning we never get

    // arbiters check - safe to do globally as arbiters were specified explicitly
    if (this.arbiters.indexOf(absReq) >= 0) {
      return [absReq, 'M8', false];
    }

    // anything else - check currentDomain then all other standard ones for absReq
    var scannable = Object.keys(this.domains).filter(function (d) {
      return (d !== currentDomain && d !== 'npm');
    });
    scannable.unshift(currentDomain);

    result = this.scan(absReq, scannable);
    if (result) {
      return result;
    }
    msg = " - looked in " + scannable + " for extensions " + this.exts.slice(1).join(', ');
    error("resolver failed to resolve require('" + reqStr + "') from " + currentDomain + msg);
  }
};

module.exports = function (domains, arbiters, exts, npmTree, builtIns, serverModules) {
  var r = new Resolver(domains, arbiters, exts, npmTree, builtIns, serverModules);
  return function () {
    return r.locate.apply(r, arguments);
  };
};
<commit_msg>be more lenient about npm package.main's file extensions (for issue 14)<commit_after>var path          = require('path')
  , utils         = require('./utils')
  , join          = path.join
  , exists        = utils.exists
  , read          = utils.read
  , error         = utils.error
  , domainIgnoreR = /^data(?=::)|^external(?=::)|^M8(?=::)|^npm(?=::)/
  , domainIgnoreL = ['data', 'external', 'M8', 'npm']
  , domainPresent = /^([\w]*)::/;

// isAbsolute pass => reqStr and lies directly on the domain root
// isAbsolute fail => reqStr is relative to extraPath
function isAbsolute(reqStr) {
  return reqStr === '' || path.normalize(reqStr) === reqStr;
}

// Takes out domain prefix from a request string if exists
function stripDomain(reqStr) {
  var ary = reqStr.split('::');
  return ary[ary.length - 1];
}

/**
 * makeFinder
 *
 * finder factory for Resolver
 * @return finder function
 *
 * finder function scans join(base, req + ext) for closure held extensions
 */
function makeFinder(exts) {
  return function (base, req) {
    for (var i = 0; i < exts.length; i += 1) {
      var ext = exts[i]
        , attempt = join(base, req + ext);

      //console.log(attempt, '<- attempt, base->', base);
      if (exists(attempt)) {
        return (req + ext);
      }
    }
    return false;
  };
}

/**
 * npmResolve factory
 *
 * creates a function which finds the entry point of an npm module
 * create with the node_modules root
 *
 * @[in] absReq - path node module should exist on
 * @[in] silent - bool === !(errors should throw)
 * @[in] name   - name of the module for good error msgs
 */
function makeNpmResolver(root) {
  return function (absReq, name) {
    var folderPath = join(root, absReq)
      , jsonPath = join(folderPath, 'package.json')
      , json = {};

    //console.log('npmResolve', absReq, name, folderPath);

    // folder must exists if we commit to it
    if (!path.existsSync(folderPath)) {
      return false;
    }

    // package.json must exist
    if (!exists(jsonPath)) {
      error("resolver could not load npm module " + name + " - package.json not found");
      return false;
    }

    // package.json must be valid json
    try {
      json = JSON.parse(read(jsonPath));
    } catch (e) {
      error("could not load npm module " + name + " - package.json invalid");
    }

    // prefer browserMain entry point if specified, then main, then index
    var mainFile = json.browserMain || json.main || 'index';
    //console.log("npmResolve final?", mainFile);
    if (!exists(join(folderPath, mainFile))) {
      if (!exists(join(folderPath, mainFile + '.js'))) {
        error("resolver could not load npm module " + name + "'s package.json lies about main: " + mainFile + " does not exist");
      }
      mainFile += '.js';
    }
    //console.log('npmResolve worked, returning', join(absReq, mainFile));
    return join(absReq, mainFile);
  };
}

/**
 * toAbsPath
 *
 * converts a generic detective request string to an absolute one
 * throws if it receives an obviously bad request
 *
 * @[in] reqStr - raw request string
 * @[in] extraPath - path of requiree's relative position to domain root
 * @[in] domain
 */
// absolutizes a path - special cases the npm domain
function toAbsPath(reqStr, extraPath, domain) {
  //console.log('toAbsPath', reqStr, extraPath);
  if (domainPresent.test(reqStr)) {
    domain = reqStr.match(domainPresent)[1]; // override current domain if explicitly specified
    if (!isAbsolute(reqStr)) {
      error("does not allow cross-domain relative requires (" + reqStr + ")");
    }
    return [stripDomain(reqStr), domain];
  }
  else if (isAbsolute(reqStr)) {
    //console.log("absolute reqStr", reqStr);
    // special case absolutes from npm domain
    // this sandboxes the npm domain (sensible)
    if (domain === 'npm') {
      //console.log('absolute npm string', reqStr, extraPath);
      return [reqStr, 'npm']; // explicit npms need to be handled elsewhere
    }
    else {
      return [reqStr, null];
    }
  }
  else {
    //console.log('relative request string', isAbsolute(reqStr));
    return [join(extraPath, reqStr), domain];
  }
}

/**
 * Resolver constructor
 * @[in] domains - {name : path} object
 * @[in] arbiters - list of requirable arbiters
 * @[in] exts - list of registered extensions
 */
function Resolver(domains, arbiters, exts, npmTree, builtIns, serverModules) {
  this.finder = makeFinder(exts);
  this.npmResolve = makeNpmResolver(domains.npm);
  this.domains = domains;
  this.arbiters = arbiters;
  this.exts = exts;
  this.npmTree = npmTree;
  this.builtIns = builtIns;
  this.serverModules = serverModules;
}

/**
 * scan [private]
 * scans a set of domain names for absReq
 *
 * @[in] absReq - require string relative to a domain root
 * @[in] scannable - ordered list of domain names to scan
 * @return === locate's return if found, else false
 **/
Resolver.prototype.scan = function (absReq, scannable) {
  //console.log("SCAN:", absReq, scannable, this.domains[scannable[0]]);
  var noTryFolder = false
    , lastChar = absReq.slice(-1);

  if (lastChar === '/' || lastChar === '\\') {
    absReq = join(absReq, 'index');
    noTryFolder = true;
  }
  for (var i = 0; i < scannable.length; i += 1) {
    var dom = scannable[i]
      , found = this.finder(this.domains[dom], absReq);

    if (found) {
      return [found, dom, true];
    }

    if (noTryFolder) {
      continue;
    }

    found = this.finder(this.domains[dom], join(absReq, 'index'));
    if (found) {
      return [found, dom, true];
    }
  }
  return false;
};

/**
 * locate
 *
 * locates a required file - throws on bad requests - main interface
 *
 * @[in] reqStr from detective
 * @[in] path of requiree's relative position to domain root
 * @[in] requiree's domain
 * @return [foundPath, domainName, isFake] where:
 *
 * [str] foundPath  - full path of the chosen file to use
 * [str] domainName - name of the domain it was found on
 * [bool] isReal    - true iff foundPath represents a real file
 **/
Resolver.prototype.locate = function (reqStr, currentPath, currentDomain) {
  //console.log("resolver locate:", reqStr, 'from', currentPath);
  var absResult = toAbsPath(reqStr, currentPath, currentDomain)
    , absReq = absResult[0]
    , foundDomain = absResult[1]
    , found = false
    , result = false
    , that = this
    , msg = '';

  //console.log("resolve this ", reqStr, currentDomain, "found: ", foundDomain, absReq);
  if (domainIgnoreL.indexOf(foundDomain) >= 0) {

    if (foundDomain === 'data' || foundDomain === 'external') {
      return [absReq, foundDomain, false];
    }
    if (foundDomain === 'M8') {
      if (this.arbiters.indexOf(absReq) >= 0) {
        return [absReq, 'M8', false];
      }
      error("resolver could not require non-existent arbiter: " + reqStr + " (from " + currentDomain + ")");
    }
    if (foundDomain === 'npm') {
      var name = absReq; // at this point, this is safe

      // node module priority:
      // 1. if we are requiring a builtin (sanitized) server-side module - return that
      // 2a.  if required from root, do
      // 2b1. try to locate node module in node_module subfolder of current node module
      // 2b2. look up one level in the tree recursively until a hit is found || we hit the domain root
      // 4. throw

      // 1. builtins
      if (this.builtIns.indexOf(name) >= 0) {
        if (this.npmTree._builtIns.indexOf(name) < 0) {
          this.npmTree._builtIns.push(name);
        }
        return [name, 'npm', false]; // this should be fine, should really be on the npm namespace
      }
      // 1. unhandled node base modules
      else if (this.serverModules.indexOf(name) >= 0) {
        error("cannot require server side node module " + name);
      }

      // catch illegal use if not builtIn (they do not require a node_modules root)
      if (!this.domains.npm) {
        error("resolver cannot require non-builtin node modules without specifying the node_modules root. tried " + name);
      }

      var npmMain;

      // 2a. entry point branch to npm domain
      if (currentDomain !== 'npm') {
        //console.log('npm find', name);
        npmMain = this.npmResolve(name, name);
        if (npmMain) {
          this.npmTree[name] = {
            main : npmMain
          , deps : {}
          };
          return [npmMain, 'npm', true];
        }
        error('could not find module', reqStr);
      }

      // 2b. try current + node_modules + the string specified
      // but first make sure we start at the module's root before we join on node_modules
      var slash = '/'; //TODO
      var order = currentPath.split('node_modules').length;
      var moduleRoot = currentPath.split(slash).slice(0, Math.max(2 * (order - 2) + 1, 1)).join(slash);

      var expected = join(moduleRoot, 'node_modules', name);
      var branch = moduleRoot.split(slash + 'node_modules' + slash);
      //console.log('trying', expected, order, moduleRoot, currentPath, branch);
      npmMain = this.npmResolve(expected, name);
      if (npmMain) {
        var position = this.npmTree[branch[0]];
        for (var i = 1; i < branch.length; i += 1) {
          position = position.deps[branch[i]];
          if (!position) {
            error('internal resolver error 1');
            // if this happens then we are not able to walk up to requiree's point
            // recursive solving => this should be impossible
          }
        }
        position.deps[name] = {
          main : npmMain
        , deps : {}
        };
        //console.log('found', npmMain);
        return [npmMain, 'npm', true];
      }

      // 2b2.
      var oldBranch = branch;
      while (true) {
        expected = join(expected, '..', '..', '..', name);
        //console.log('trying', expected);
        if (expected === '.' || expected.slice(0,2) === '..') { // broken out of domain root
          break;
        }
        branch = branch.slice(0, -1); // we went one up

        npmMain = this.npmResolve(expected, name);
        if (npmMain) {
          // need to give a link to this module regardless of where in the hierarchy it is
          var oldPos = this.npmTree[oldBranch[0]];
          for (var i = 1; i < oldBranch.length; i += 1) {
            oldPos = oldPos.deps[oldBranch[i]];
            if (!oldPos) {
              error('internal resolver error 3');
              // if this happens then we are not able to walk up to the point we have
              // already filled in. recursive solving => this should be impossible
            }
          }
          oldPos.deps[name] = {
            main : npmMain
          , deps : {}
          };

          // now make it requirable to everything above
          //console.log('found', npmMain, branch, !!branch.length, branch.length);
          if (!branch.length) {
            // structure of the tree is different at base for historical reasons
            this.npmTree[name] = {
              main : npmMain
            , deps : {}
            }
            return [npmMain, 'npm', true];
          }
          var position = this.npmTree[branch[0]];
          for (var i = 1; i < branch.length; i += 1) {
            position = position.deps[branch[i]];
            if (!position) {
              error('internal resolver error 2');
              // if this happens then we are not able to walk _partially_ up towards
              // a point we have defined. recursive solving => this should be impossible
            }
          }
          position.deps[name] = {
            main : npmMain
          , deps : {}
          };
          return [npmMain, 'npm', true];
        }
      }

      // 4. nothing worked
      error("failed to require npm module " + name);

    }
  }
  else { // anything that was absolutely required from outside npm
    if (foundDomain && !this.domains[foundDomain]) { // also prevents second call to npmResolve
      error("resolver could not require from an unconfigured domain: " + foundDomain);
    }
    if (foundDomain === 'app' && currentDomain !== 'app') {
      error("does not allow other domains to reference the app domain. required from " + currentDomain);
    }

    if (foundDomain) { // require to a specific/same domain - we must succeed in here
      result = this.scan(absReq, [foundDomain]);
      if (result) {
        return result;
      }
      msg = " for extensions " + this.exts.slice(1).join(', ');
      error("resolver failed to resolve require('" + reqStr + "') in " + foundDomain + msg);
    }

    // absolute requires from app domain cannot indirectly require npm modules for safety
    // but this behaviour needs to work inside the npm domain, so toAbsPath sandboxes it meaning we never get

    // arbiters check - safe to do globally as arbiters were specified explicitly
    if (this.arbiters.indexOf(absReq) >= 0) {
      return [absReq, 'M8', false];
    }

    // anything else - check currentDomain then all other standard ones for absReq
    var scannable = Object.keys(this.domains).filter(function (d) {
      return (d !== currentDomain && d !== 'npm');
    });
    scannable.unshift(currentDomain);

    result = this.scan(absReq, scannable);
    if (result) {
      return result;
    }
    msg = " - looked in " + scannable + " for extensions " + this.exts.slice(1).join(', ');
    error("resolver failed to resolve require('" + reqStr + "') from " + currentDomain + msg);
  }
};

module.exports = function (domains, arbiters, exts, npmTree, builtIns, serverModules) {
  var r = new Resolver(domains, arbiters, exts, npmTree, builtIns, serverModules);
  return function () {
    return r.locate.apply(r, arguments);
  };
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
MIT License

Copyright (c) 2017 Jon Gallant, Justine Cocchi, James Trott, and Bryan Hughes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

const spawn = require('child_process').spawn;
const path = require('path');

const isDone = {};

let errored = false;
function finalize(dir, code) {
  isDone[dir] = true;
  if (code) {
    errored = true;
  }
  for (const dir in isDone) {
    if (!isDone[dir]) {
      return;
    }
  }
  if (errored) {
    console.error('\nFinished installing dependencies, but there was an error. See the output log above.\n');
  } else {
    console.log('\nFinished installing dependencies!\n');
  }
}

function install(cwd) {
  isDone[cwd] = false;
  spawn('npm', [ 'install', '--no-progress' ], {
    cwd,
    stdio: 'inherit'
  }).on('exit', (code) => finalize(cwd, code));
}

console.log('Installing all dependencies');

install(path.join(__dirname, 'client'));
install(path.join(__dirname, 'common'));
install(path.join(__dirname, 'server', 'iot-hub-message-router'));
install(path.join(__dirname, 'server', 'decompress'));
install(path.join(__dirname, 'server', 'message'));
install(path.join(__dirname, 'server', 'schema'));
<commit_msg>Got install script to work on Windows<commit_after>#!/usr/bin/env node
/*
MIT License

Copyright (c) 2017 Jon Gallant, Justine Cocchi, James Trott, and Bryan Hughes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

const spawn = require('child_process').spawn;
const path = require('path');

const npmCommand = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';

const isDone = {};

let errored = false;
function finalize(dir, code) {
  isDone[dir] = true;
  if (code) {
    errored = true;
  }
  for (const dir in isDone) {
    if (!isDone[dir]) {
      return;
    }
  }
  if (errored) {
    console.error('\nFinished installing dependencies, but there was an error. See the output log above.\n');
  } else {
    console.log('\nFinished installing dependencies!\n');
  }
}

function install(cwd) {
  isDone[cwd] = false;
  spawn(npmCommand, [ 'install', '--no-progress' ], {
    cwd,
    stdio: 'inherit'
  }).on('exit', (code) => finalize(cwd, code));
}

console.log('Installing all dependencies');

install(path.join(__dirname, 'client'));
install(path.join(__dirname, 'common'));
install(path.join(__dirname, 'server', 'iot-hub-message-router'));
install(path.join(__dirname, 'server', 'decompress'));
install(path.join(__dirname, 'server', 'message'));
install(path.join(__dirname, 'server', 'schema'));
<|endoftext|>


<commit_before>var logging = require("./logging");
var config = require("./config");
var crc = require("crc").crc32;

var human_status = {
  "-2": "user error",   // e.g. invalid size
  "-1": "server error", // e.g. network issues
  0: "none",            // cached as null (user has no skin)
  1: "cached",          // found on disk
  2: "downloaded",      // profile downloaded, skin downloaded from mojang servers
  3: "checked",         // profile re-downloaded (was too old), has no skin or skin cached
};

// handles HTTP responses
// +request+ a http.IncomingMessage
// +response+ a http.ServerResponse
// +result+ an object with:
//  * status:   see human_status, required for images without err
//  * redirect: redirect URL
//  * body:     file or message, required unless redirect is present or status is < 0
//  * type:     a valid Content-Type for the body, defaults to "text/plain"
//  * hash:     image hash, required when body is an image
//  * err:      a possible Error
module.exports = function(request, response, result) {

  response.on("close", function() {
    logging.warn(request.id, "Connection closed");
  });

  response.on("finish", function() {
    logging.log(request.id, response.statusCode, "(" + (human_status[result.status] || "-") + ")");
  });

  response.on("error", function(err) {
    logging.error(request.id, err);
  });

  // These headers are the same for every response
  var headers = {
    "Content-Type": (result.body && result.type) || "text/plain",
    "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
    "Response-Time": Date.now() - request.start,
    "X-Request-ID": request.id,
    "Access-Control-Allow-Origin": "*"
  };

  if (result.err) {
    logging.error(result.err);
    logging.error(result.err.stack);
    result.status = -1;
  }

  if (result.status !== undefined && result.status !== null) {
    headers["X-Storage-Type"] = human_status[result.status];
  }

  if (result.body) {
    // use Mojang's image hash if available
    // use crc32 as a hash function otherwise
    var etag = result.body && result.hash && result.hash.substr(0, 10) || crc(result.body);
    headers.Etag = "\"" + etag + "\"";

    // handle etag caching
    var incoming_etag = request.headers["if-none-match"];
    if (incoming_etag && incoming_etag === headers.Etag) {
      response.writeHead(304, headers);
      response.end();
      return;
    }
  }

  if (result.redirect) {
    headers.Location = result.redirect;
    response.writeHead(307, headers);
    response.end();
    return;
  }

  if (result.status === -2) {
    response.writeHead(422, headers);
    response.end(result.body);
  } else if (result.status === -1) {
    response.writeHead(500, headers);
    response.end(result.body);
  } else {
    response.writeHead(result.body ? 200 : 404, headers);
    response.end(result.body);
  }
};<commit_msg>remove unnecessary double check<commit_after>var logging = require("./logging");
var config = require("./config");
var crc = require("crc").crc32;

var human_status = {
  "-2": "user error",   // e.g. invalid size
  "-1": "server error", // e.g. network issues
  0: "none",            // cached as null (user has no skin)
  1: "cached",          // found on disk
  2: "downloaded",      // profile downloaded, skin downloaded from mojang servers
  3: "checked",         // profile re-downloaded (was too old), has no skin or skin cached
};

// handles HTTP responses
// +request+ a http.IncomingMessage
// +response+ a http.ServerResponse
// +result+ an object with:
//  * status:   see human_status, required for images without err
//  * redirect: redirect URL
//  * body:     file or message, required unless redirect is present or status is < 0
//  * type:     a valid Content-Type for the body, defaults to "text/plain"
//  * hash:     image hash, required when body is an image
//  * err:      a possible Error
module.exports = function(request, response, result) {

  response.on("close", function() {
    logging.warn(request.id, "Connection closed");
  });

  response.on("finish", function() {
    logging.log(request.id, response.statusCode, "(" + (human_status[result.status] || "-") + ")");
  });

  response.on("error", function(err) {
    logging.error(request.id, err);
  });

  // These headers are the same for every response
  var headers = {
    "Content-Type": (result.body && result.type) || "text/plain",
    "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
    "Response-Time": Date.now() - request.start,
    "X-Request-ID": request.id,
    "Access-Control-Allow-Origin": "*"
  };

  if (result.err) {
    logging.error(result.err);
    logging.error(result.err.stack);
    result.status = -1;
  }

  if (result.status !== undefined && result.status !== null) {
    headers["X-Storage-Type"] = human_status[result.status];
  }

  if (result.body) {
    // use Mojang's image hash if available
    // use crc32 as a hash function otherwise
    var etag = result.hash && result.hash.substr(0, 10) || crc(result.body);
    headers.Etag = "\"" + etag + "\"";

    // handle etag caching
    var incoming_etag = request.headers["if-none-match"];
    if (incoming_etag && incoming_etag === headers.Etag) {
      response.writeHead(304, headers);
      response.end();
      return;
    }
  }

  if (result.redirect) {
    headers.Location = result.redirect;
    response.writeHead(307, headers);
    response.end();
    return;
  }

  if (result.status === -2) {
    response.writeHead(422, headers);
    response.end(result.body);
  } else if (result.status === -1) {
    response.writeHead(500, headers);
    response.end(result.body);
  } else {
    response.writeHead(result.body ? 200 : 404, headers);
    response.end(result.body);
  }
};<|endoftext|>


<commit_before>const fs = require("fs"),
	exec = require('child_process').exec,
	modules = [
		"stc",
		"stc-eslint",
		"stc-babel",
		"stc-typescript",
		"stc-uglify",
		"stc-dep-parser",
		"stc-plugin",
		"stc-file",
		"stc-cluster",
		"stc-cache",
		"stc-demo",
		"stc-plugin-invoke",
		"stc-helper",
		"stc-replace",
		"stc-cli",
		"stc-log"
	],
	STR_DASH = "========================================",
	REG_LOCAL = /^stc[\w-]*$/,
	REG_DEMO_DIR = /stc-demo$/;

var currentJob = "",
	totalPassed = 0;

Promise.resolve()
	.then(curryTask("Making stcjs dir", () => {
		if (isInStcDemo()) {
			console.log("In dir stc-demo, doesn't require so.");
			return;
		}
		return folderExistsPromise('stcjs')
			.catch(() => execPromise("mkdir stcjs"));
	}))
	.then(curryTask("Switching folder to stcjs", () => {
		if (isInStcDemo()) {
			process.chdir('../');
		} else {
			process.chdir('stcjs');
		}
		console.log('Current directory: ' + process.cwd());
	}))
	.then(curryTask("Git Cloning or pulling", () => {
		return Promise.all(modules.map((name) => {
			return folderExistsPromise(name, true)
				.then(() => execPromise('git branch | grep "* master" && git pull origin master', { cwd: name }).catch(() =>{
					console.log(`${name} is not on master branch, ignore.`)
				}))
				.catch(() => execPromise(`git clone https://github.com/stcjs/${name}/`));
		}))
	}))
	.then(curryTask("Making folder node_modules", () => {
		return folderExistsPromise('node_modules')
			.catch(() => execPromise("mkdir node_modules")); // todo using `fs.mkdir`
	}))
	.then(curryTask("Making soft links for each project", () => {
		return folderExistsPromise('node_modules/stc')
			.catch(() => execAll(`ln -s ../:name :name`, {
				cwd: `node_modules`
			})) // todo using `fs.symlink`
	}))
	.then(curryTask("Resolving all `package.json` & generating one", () => {
		return resolvePackageJSON()
	}))
	.then(curryTask("Installing npm package", () => {
		return execPromise("npm install --registry=https://registry.npm.taobao.org", {
			pipe: true
		})
	}))
	.then(() => {
		console.log(`${STR_DASH}\nAll done.`);
	})
	.catch((err) => {
		console.error(`${STR_DASH}\nError during task: ${currentJob}`);
		console.error(err);
	});

function isInStcDemo() {
	return REG_DEMO_DIR.test(process.cwd());
}

function curryTask(taskName, fn) {
	return function () {
		var startTime = +new Date();
		currentJob = taskName;
		console.log(`${STR_DASH}\nTask start: ${currentJob}`);
		return (fn() || Promise.resolve())
			.then(() => {
				var passed = new Date() - startTime;
				totalPassed += passed;
				console.log(`Task done after: ${passed}ms, total passed time: ${totalPassed}ms.`)
			});
	}
}

function resolvePackageJSON() {
	var package = {
		dependencies: {},
		devDependencies: {}
	};
	return Promise.all(
		modules.map((name) => {
			var dir = `${name}/package.json`;
			return readJSONPromise(dir)
				.then((data) => {
					setKey(data, "dependencies");
					setKey(data, "devDependencies");
				})
				.then(() => {
					console.log(`Parsed\t${dir}`);
				})
				.catch((err) => {
					console.log(`Error\t${dir}`);
					// console.error(err);
				});
		})
	).then(() => writeJSONPromise(`package.json`, package));

	function setKey(data, base) {
		for (var key in data[base]) {
			if (REG_LOCAL.test(key)) {
				continue;
			}
			if (!package[base][key] || package[base][key] > data[base][key]) {
				package[base][key] = data[base][key];
			}
		}
	}

	function readJSONPromise(file) {
		return new Promise((resolve, reject) => {
			fs.readFile(file, "utf-8", (err, data) => {
				if (err) {
					reject(err);
					return;
				}
				resolve(
					JSON.parse(data.toString())
				);
			});
		});
	}

	function writeJSONPromise(file, json) {
		return new Promise((resolve, reject) => {
			fs.writeFile(file, JSON.stringify(json, null, '\t'), "utf-8", (err, data) => {
				if (err) {
					reject(err);
					return;
				}
				resolve();
			});
		});
	}
}

function execAll(str, options) {
	return Promise.all(
		modules.map((name) => execPromise(
			str.replace(/:name/g, name),
			options
		))
	);
}

function folderExistsPromise(folder, mute) {
	return new Promise((resolve, reject) => {
		fs.access(folder, fs.R_OK, (err) => {
			if (err) {
				reject(err);
				return;
			}
			resolve();
		});
	}).then(() => {
		!mute && console.log(`Folder "${folder}" exists.`);
	});
}

function execPromise(cmd, options) {
	console.log(`${cmd}${options && options.cwd && ("\t@" + options.cwd) || ""}`);
	var promise = new Promise((resolve, reject) => {
		var event = exec(cmd, options, (err, stdout, stderr) => {
			if (err) {
				reject(err);
				return;
			}
			resolve();
		});
		if (options && options.pipe) {
			event.stdout.pipe(process.stdout);
			event.stderr.pipe(process.stderr);
		}
	});

	return promise;
}
<commit_msg>Feat: update install.js. dynamically symbol link adding<commit_after>const fs = require("fs"),
	exec = require('child_process').exec,
	modules = [
		"stc",
		"stc-eslint",
		"stc-babel",
		"stc-typescript",
		"stc-uglify",
		"stc-dep-parser",
		"stc-plugin",
		"stc-file",
		"stc-cluster",
		"stc-cache",
		"stc-demo",
		"stc-plugin-invoke",
		"stc-helper",
		"stc-replace",
		"stc-cli",
		"stc-log"
	],
	STR_DASH = "========================================",
	REG_LOCAL = /^stc[\w-]*$/,
	REG_DEMO_DIR = /stc-demo$/;

var currentJob = "",
	totalPassed = 0;

Promise.resolve()
	.then(curryTask("Making stcjs dir", () => {
		if (isInStcDemo()) {
			console.log("In dir stc-demo, doesn't require so.");
			return;
		}
		return folderExistsPromise('stcjs')
			.catch(() => execPromise("mkdir stcjs"));
	}))
	.then(curryTask("Switching folder to stcjs", () => {
		if (isInStcDemo()) {
			process.chdir('../');
		} else {
			process.chdir('stcjs');
		}
		console.log('Current directory: ' + process.cwd());
	}))
	.then(curryTask("Git Cloning or pulling", () => {
		return Promise.all(modules.map((name) => {
			return folderExistsPromise(name, true)
				.then(() => execPromise('git branch | grep "* master" && git pull origin master', { cwd: name }).catch(() => {
					console.log(`${name} is not on master branch, ignore.`)
				}))
				.catch(() => execPromise(`git clone https://github.com/stcjs/${name}/`));
		}))
	}))
	.then(curryTask("Making folder node_modules", () => {
		return folderExistsPromise('node_modules')
			.catch(() => execPromise("mkdir node_modules")); // todo using `fs.mkdir`
	}))
	.then(curryTask("Making symbol link for stc projects in node_modules", () => {
		return Promise.all(modules.map((name) => {
			return folderExistsPromise(`node_modules/${name}`)
				.catch(() => execPromise(`ln -s ../${name} ${name}`, {
					cwd: `node_modules`
				}));
		}));
	}))
	.then(curryTask("Resolving all `package.json` & generating one", () => {
		return resolvePackageJSON()
	}))
	.then(curryTask("Installing npm package", () => {
		return execPromise("npm install --registry=https://registry.npm.taobao.org", {
			pipe: true
		})
	}))
	.then(() => {
		console.log(`${STR_DASH}\nAll done.`);
	})
	.catch((err) => {
		console.error(`${STR_DASH}\nError during task: ${currentJob}`);
		console.error(err);
	});

function isInStcDemo() {
	return REG_DEMO_DIR.test(process.cwd());
}

function curryTask(taskName, fn) {
	return function () {
		var startTime = +new Date();
		currentJob = taskName;
		console.log(`${STR_DASH}\nTask start: ${currentJob}`);
		return (fn() || Promise.resolve())
			.then(() => {
				var passed = new Date() - startTime;
				totalPassed += passed;
				console.log(`Task done after: ${passed}ms, total passed time: ${totalPassed}ms.`)
			});
	}
}

function resolvePackageJSON() {
	var package = {
		dependencies: {},
		devDependencies: {}
	};
	return Promise.all(
		modules.map((name) => {
			var dir = `${name}/package.json`;
			return readJSONPromise(dir)
				.then((data) => {
					setKey(data, "dependencies");
					setKey(data, "devDependencies");
				})
				.then(() => {
					console.log(`Parsed\t${dir}`);
				})
				.catch((err) => {
					console.log(`Error\t${dir}`);
					// console.error(err);
				});
		})
	).then(() => writeJSONPromise(`package.json`, package));

	function setKey(data, base) {
		for (var key in data[base]) {
			if (REG_LOCAL.test(key)) {
				continue;
			}
			if (!package[base][key] || package[base][key] > data[base][key]) {
				package[base][key] = data[base][key];
			}
		}
	}

	function readJSONPromise(file) {
		return new Promise((resolve, reject) => {
			fs.readFile(file, "utf-8", (err, data) => {
				if (err) {
					reject(err);
					return;
				}
				resolve(
					JSON.parse(data.toString())
				);
			});
		});
	}

	function writeJSONPromise(file, json) {
		return new Promise((resolve, reject) => {
			fs.writeFile(file, JSON.stringify(json, null, '\t'), "utf-8", (err, data) => {
				if (err) {
					reject(err);
					return;
				}
				resolve();
			});
		});
	}
}

function folderExistsPromise(folder, mute) {
	return new Promise((resolve, reject) => {
		fs.access(folder, fs.R_OK, (err) => {
			if (err) {
				reject(err);
				return;
			}
			resolve();
		});
	}).then(() => {
		!mute && console.log(`Folder "${folder}" exists.`);
	});
}

function execPromise(cmd, options) {
	console.log(`${cmd}${options && options.cwd && ("\t@" + options.cwd) || ""}`);
	var promise = new Promise((resolve, reject) => {
		var event = exec(cmd, options, (err, stdout, stderr) => {
			if (err) {
				reject(err);
				return;
			}
			resolve();
		});
		if (options && options.pipe) {
			event.stdout.pipe(process.stdout);
			event.stderr.pipe(process.stderr);
		}
	});

	return promise;
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Flora response object.
 *
 * @constructor
 * @param {Request} request
 * @param {Function} callback
 */
var Response = module.exports = function (request, callback) {
    this.request = request;

    /**
     * Response meta information
     *
     * @type {Object}
     * @name Response#meta
     */
    this.meta = {
        statusCode: 200
    };

    /**
     * Error info (null on success)
     *
     * @type {Object}
     * @name Response#error
     */
    this.error = null;

    /**
     * Response data
     *
     * @type {(Object|Array.<Object>)}
     * @name Response#data
     */
    this.data = null;

    /**
     * Pagination information
     *
     * @type {(null|Object)}
     * @name Response#cursor
     */

    /**
     * @type {Function}
     * @private
     */
    this._callback = callback || function () {};
    this._sent = false;
};

/**
 * Add profiling and meta data to the response and call our callback.
 *
 * @param {(Object|Array.<Object>|Error)} payload  - Response data
 */
Response.prototype.send = function (payload) {
    var self = this;

    if (this._sent) {
        return this._callback(new Error('Response#send was already called'));
    }
    this._sent = true;

    if (payload instanceof Error) {
        return this._callback(payload);
    } else {
        this.data = payload;
    }

    process.nextTick(function () {
        self.request._profiler.end();
        self.meta.duration = self.request._profiler.getDuration();

        if (self.request._profile === 'raw' || self.request._profile === '1') {
            var profile = self.request._profiler.report();

            if (self.request._profile === 'raw') {
                self.meta.profile = profile;
            } else {
                self.meta.profile = asciiArtProfile(profile, self.meta.duration, 100);
            }
        }

        self._callback(null, self);
    });

    return this;
};

function asciiArtProfile(profile, totalDuration, width) {
    return profile.map(function(measure) {
        var startTime = Math.round(measure.startTime * width / totalDuration);

        if (measure.duration !== null) {
            var duration = Math.round(measure.duration * width / totalDuration);

            return strRepeat('.', startTime) +
                strRepeat('#', duration) +
                strRepeat('.', width - startTime - duration) +
                ' (' + measure.name + ' - ' + measure.duration + 'ms)';
        } else {
            return strRepeat('.', startTime) +
                strRepeat('?', width - startTime) +
                ' (' + measure.name + ' - still running!)';
        }
    });
}

function strRepeat(str, count) {
    return new Array(count + 1).join(str);
}
<commit_msg>profiler: handle all possible overflows in asciiArtProfile()<commit_after>'use strict';

/**
 * Flora response object.
 *
 * @constructor
 * @param {Request} request
 * @param {Function} callback
 */
var Response = module.exports = function (request, callback) {
    this.request = request;

    /**
     * Response meta information
     *
     * @type {Object}
     * @name Response#meta
     */
    this.meta = {
        statusCode: 200
    };

    /**
     * Error info (null on success)
     *
     * @type {Object}
     * @name Response#error
     */
    this.error = null;

    /**
     * Response data
     *
     * @type {(Object|Array.<Object>)}
     * @name Response#data
     */
    this.data = null;

    /**
     * Pagination information
     *
     * @type {(null|Object)}
     * @name Response#cursor
     */

    /**
     * @type {Function}
     * @private
     */
    this._callback = callback || function () {};
    this._sent = false;
};

/**
 * Add profiling and meta data to the response and call our callback.
 *
 * @param {(Object|Array.<Object>|Error)} payload  - Response data
 */
Response.prototype.send = function (payload) {
    var self = this;

    if (this._sent) {
        return this._callback(new Error('Response#send was already called'));
    }
    this._sent = true;

    if (payload instanceof Error) {
        return this._callback(payload);
    } else {
        this.data = payload;
    }

    process.nextTick(function () {
        self.request._profiler.end();
        self.meta.duration = self.request._profiler.getDuration();

        if (self.request._profile === 'raw' || self.request._profile === '1') {
            var profile = self.request._profiler.report();

            if (self.request._profile === 'raw') {
                self.meta.profile = profile;
            } else {
                self.meta.profile = asciiArtProfile(profile, self.meta.duration, 100);
            }
        }

        self._callback(null, self);
    });

    return this;
};

function asciiArtProfile(profile, totalDuration, width) {
    if (totalDuration <= 0) return ['total duration = ' + totalDuration + 'ms!? Wow ... that was fast :-)'];
    if (width < 10) width = 10;

    return profile.map(function(measure) {
        var beforeChar = '.', beforeWidth;
        var beginChar = '';
        var durationChar = '#', durationWidth;
        var endChar = '';
        var afterChar = '.', afterWidth;
        var description;

        beforeWidth = Math.round(measure.startTime * width / totalDuration);
        if (beforeWidth > width) { beforeWidth = width; beginChar = '>'; }
        if (beforeWidth < 0) { beforeWidth = 0; beginChar = '<'; }

        if (measure.duration !== null) {
            durationWidth = Math.round(measure.duration * width / totalDuration);
            if (durationWidth > width - beforeWidth) { durationWidth = width - beforeWidth; }
            if (measure.duration > totalDuration - measure.startTime) { endChar = '>'; }
            if (durationWidth < 0) { durationWidth = 1; durationChar = '!'; endChar = '<'; }
            if (durationWidth < 1) { durationWidth = 1; durationChar = '|'; }
            description = ' (' + measure.name + ' - ' + measure.duration + 'ms)';
        } else {
            durationWidth = width - beforeWidth;
            durationChar = '?';
            afterWidth = 0;
            description = ' (' + measure.name + ' - still running!)';
        }

        afterWidth = width - beforeWidth - beginChar.length - durationWidth - endChar.length;
        if (afterWidth < 0) {
            if (durationWidth + afterWidth > 0) durationWidth += afterWidth;
            else if (beforeWidth + afterWidth > 0) beforeWidth += afterWidth;

            afterWidth = 0;
        }

        return strRepeat(beforeChar, beforeWidth) +
            beginChar +
            strRepeat(durationChar, durationWidth) +
            endChar +
            strRepeat(afterChar, afterWidth) +
            description;
    });

    function strRepeat(str, count) {
        return new Array(count + 1).join(str);
    }
}
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');

if (!fs.existsSync('bin'))
	fs.mkdirSync('bin');

moveAll('build/Release/', 'bin/', '.node');

function moveAll(from, to, ext) {
	fs.readdirSync(from)
		.filter(function(name) { return path.extname(name) === ext; })
		.forEach(function(name) {
			fs.rename(path.join(from, name), path.join(to, name));
		});
}<commit_msg>Fix install script for Node 0.6<commit_after>var fs = require('fs');
var path = require('path');

if (!(fs.existsSync || path.existsSync)('bin'))
	fs.mkdirSync('bin');

moveAll('build/Release/', 'bin/', '.node');

function moveAll(from, to, ext) {
	fs.readdirSync(from)
		.filter(function(name) { return path.extname(name) === ext; })
		.forEach(function(name) {
			fs.rename(path.join(from, name), path.join(to, name));
		});
}<|endoftext|>


<commit_before>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var assert = require('assert');
var crypto = require('crypto');
var http = require('http');
var Stream = require('stream').Stream;
var util = require('util');

var mime = require('mime');

var errors = require('./errors');
var Request = require('./request');

///--- Globals

var HttpError = errors.HttpError;
var RestError = errors.RestError;

var ALLOW_HEADERS = [
  'Accept',
  'Accept-Version',
  'Content-Length',
  'Content-MD5',
  'Content-Type',
  'Date',
  'X-Api-Version'
].join(', ');

var EXPOSE_HEADERS = [
  'X-Api-Version',
  'X-Request-Id'
].join(', ');

var DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

var MONTHS = [
  'Jan',
  'Feb',
  'Mar',
  'Apr',
  'May',
  'Jun',
  'Jul',
  'Aug',
  'Sep',
  'Oct',
  'Nov',
  'Dec'
];

///--- Helpers

function httpDate(now) {
  if (!now)
    now = new Date();

  function pad(val) {
    if (parseInt(val, 10) < 10)
      val = '0' + val;
    return val;
  }

  return DAYS[now.getUTCDay()] + ', ' +
    pad(now.getUTCDate()) + ' ' +
    MONTHS[now.getUTCMonth()] + ' ' +
    now.getUTCFullYear() + ' ' +
    pad(now.getUTCHours()) + ':' +
    pad(now.getUTCMinutes()) + ':' +
    pad(now.getUTCSeconds()) + ' GMT';
}

function formatBinary(req, res, body) {
  if (!body)
    return null;

  if (!Buffer.isBuffer(body))
    body = new Buffer(body.toString());

  return body;
}

function formatText(req, res, body) {
  if (!body)
    return null;

  if (body instanceof Error) {
    body = body.message;
  } else if (typeof (body) === 'object') {
    body = JSON.stringify(body);
  } else {
    body = body.toString();
  }

  return body;
}

function formatJSON(req, res, body) {
  if (!body)
    return null;

  if (body instanceof Error) {
    if (body instanceof RestError) {
      body = body.body;
    } else {
      body = {
        message: body.message
      };
    }
  }

  if (Buffer.isBuffer(body))
    body = body.toString('base64');

  return JSON.stringify(body);
}

function ensureDefaultFormatters(res) {
  if (!res.formatters)
    res.formatters = {};

  //
  // We do this so that JSON formatters et al happen before custom ones,
  // like HTML (i.e., if your client is curl, accept defaults to * / *, and
  // v8 object keys are predictable, so we order them on the object such that
  // JSON goes first
  //

  var save = res.formatters || {};
  res.formatters = {};
  if (!save['application/json'])
    res.formatters['application/json'] = formatJSON;

  if (!save['text/plain'])
    res.formatters['text/plain'] = formatText;

  if (!save['application/octet-stream'])
    res.formatters['application/octet-stream'] = formatBinary;

  Object.keys(save).forEach(function (k) {
    if (!res.formatters[k])
      res.formatters[k] = save[k];
  });

  return this;
}

///--- API

/**
 * Response is a wrapper over node's http.OutgoingMessage object.
 *
 * Previous versions of restify just extended the prototype, but that was
 * problemtic if used in conjunction with other modules that do this as well
 * (namely express).
 *
 * This object exposes all of the properties/events/methods of the standard
 * Response object, plus some extra goodies.
 *
 * Note that at construct time, you pass in a map of mime type to formatter
 * functions. i.e:
 *
 * var res = new Response({
 *   formatters: {
 *     json: function (req, res, data, callback) {
 *       return callback(null, JSON.stringify(data));
 *     }
 *   }
 * });
 *
 * Note there is a special formatter called `error` which is invoked when
 * data is an error.
 *
 * @param {Object} options pass in bunyan handle, http.OutgoingMessage and a
 *                 Request.
 * @throws {TypeError} on input error.
 */
function Response(options) {
  if (typeof (options) !== 'object')
    throw new TypeError('options (Object) required');
  if (typeof (options.log) !== 'object')
    throw new TypeError('options.log (Object) required');
  if (typeof (options.response) !== 'object')
    throw new TypeError('options.response (http.OutgoingMessage) required');
  if (!(options.request instanceof Request))
    throw new TypeError('options.request (Request) required');
  if (options.version && typeof (options.version) !== 'string')
    throw new TypeError('options.version (String) required');

  var self = this;

  Stream.call(this);

  this.charSet = false;
  this._contentType = false;
  this._continueSent = false;
  this.formatters = {};
  this.log = options.request.log;
  this.methods = options.methods || [];
  this.req = options.request;
  this.res = options.response;
  this.serverName = options.serverName || 'restify';
  this.version = options.version || false;
  this.responseTimeHeader = options.responseTimeHeader || 'X-Response-Time';
  this.responseTimeFormatter = function(durationInMilliseconds) { return durationInMilliseconds; };

  // make sure the options is a function (if not we don't allow you to override)
  if (typeof(options.responseTimeFormatter) === 'function') {
    this.responseTimeFormatter = options.responseTimeFormatter;
  }

  // Generate the formatters
  if (options.formatters) {
    Object.keys(options.formatters).forEach(function (k) {
      if (k.indexOf('/') === -1)
        k = mime.lookup(k);

      self.formatters[k] = options.formatters[k];
    });
  }
  ensureDefaultFormatters(this);

  this.__defineSetter__('code', function (c) {
    if (typeof (c) !== 'number')
      throw new TypeError('code (Number) required');
    if (c < 100 || c > 599)
      throw new TypeError('code is not a valid HTTP status code');

    self.res.statusCode = c;
  });

  this.__defineGetter__('code', function () {
    return self.res.statusCode || 200;
  });

  this.__defineSetter__('contentLength', function (len) {
    if (typeof (len) !== 'number')
      throw new TypeError('contentLength must be Number');

    self.header('Content-Length', len);
  });

  this.__defineGetter__('contentLength', function () {
    return self.res.getHeader('Content-Length');
  });

  this.__defineSetter__('contentType', function (type) {
    if (typeof (type) !== 'string')
      throw new TypeError('contentType must be String');

    if (type.indexOf('/') === -1)
      type = mime.lookup(type);

    if (!self.charSet)
      self.charSet = mime.charsets.lookup(type, self.charSet);

    self._contentType = type;
  });

  this.__defineGetter__('contentType', function () {
    return self._contentType;
  });

  this.__defineGetter__('etag', function () {
    return self.get('etag');
  });

  this.__defineSetter__('etag', function (val) {
    return self.set('etag', val);
  });

  this.__defineGetter__('headers', function () {
    return self.res._headers || {};
  });

  this.__defineGetter__('id', function () {
    return self.req.requestId;
  });

  this.__defineGetter__('requestId', function () {
    return self.req.requestId;
  });

  this.__defineGetter__('statusCode', function () {
    return self.code;
  });

  this.__defineSetter__('statusCode', function (code) {
    self.code = code;
  });

  var types = Object.keys(this.formatters);
  this.__defineGetter__('types', function () {
    return types;
  });

  this.__defineGetter__('writable', function () {
    return self.res.writable;
  });

  this.__defineGetter__('writeable', function () {
    return self.res.writable;
  });

  ///--- Events
  this.res.on('drain', function () {
    return self.emit('drain');
  });

  this.res.on('error', function (err) {
    return self.emit('error', err);
  });

  this.res.on('close', function () {
    return self.emit('close');
  });

  this.res.on('pipe', function (src) {
    return self.emit('pipe', src);
  });

  // Finally write the default headers in
  this.defaultHeaders();
}
util.inherits(Response, Stream);
module.exports = Response;

Response.ACCEPTABLE = [
  'application/json',
  'text/plain',
  'application/octet-stream'
];

///--- Set up pass-throughs for all the APIs

Object.keys(http.OutgoingMessage.prototype).forEach(function (m) {
  Response.prototype[m] = function () {
    return this.res[m].apply(this.res, arguments);
  };
});

///--- http.OutgoingMessage APIs

Response.prototype.writeHead = function writeHead() {
  if (this.statusCode === 204 || this.statusCode === 304) {
    this.removeHeader('Content-Length');
    this.removeHeader('Content-MD5');
    this.removeHeader('Content-Type');
  }

  this.res.writeHead.apply(this.res, arguments);
  this.emit('header');
};

Response.prototype.writeContinue = function writeContinue() {
  return this.res.writeContinue.apply(this.res, arguments);
};

///-- Express APIs (that we want)

Response.prototype.header = function header(name, value) {
  if (typeof (name) !== 'string')
    throw new TypeError('name (String) required');

  if (value === undefined)
    return this.getHeader(name);

  if (value instanceof Date)
    value = httpDate(value);

  this.setHeader(name, value);
  return value;
};

Response.prototype.get = function get(name) {
  return this.getHeader(name);
};

Response.prototype.set = function set(name, val) {
  if (arguments.length === 2) {
    if (typeof (name) !== 'string')
      throw new TypeError('name (String) required');
    this.header(name, val);
  } else {
    if (typeof (name) !== 'object')
      throw new TypeError('Object required for argument 1');

    var self = this;
    Object.keys(name).forEach(function (k) {
      self.header(k, name[k]);
    });
  }

  return this;
};

Response.prototype.cache = function cache(type, options) {
  if (typeof (type) !== 'string') {
    options = type;
    type = 'public';
  }

  if (options && options.maxAge) {
    if (typeof (options.maxAge) !== 'number')
      throw new TypeError('options.maxAge (Number) required');
    type += ', max-age=' + (options.maxAge / 1000);
  }

  return this.header('Cache-Control', type);
};

Response.prototype.status = function status(code) {
  this.code = code;
  return this;
};

Response.prototype.defaultHeaders = function defaultHeaders() {
  this.header('Access-Control-Allow-Origin', '*');
  this.header('Access-Control-Allow-Headers', ALLOW_HEADERS);

  if (this.methods.length)
    this.header('Access-Control-Allow-Methods', this.methods.join());

  this.header('Access-Control-Expose-Headers', EXPOSE_HEADERS + ', ' + this.responseTimeHeader);
  this.header('Server', this.serverName);

  if (this.version)
    this.header('X-Api-Version', this.version);

  this.header('X-Request-Id', this.id);
};

Response.prototype.finishHeaders = function finishHeaders(data) {
  var now = new Date();

  if (!this.header('Connection') && !this.keepAlive)
    this.header('Connection', 'close');

  if (!this.header('Content-Length') && data) {
    if (Buffer.isBuffer(data)) {
      this.header('Content-Length', data.length);
    } else {
      this.header('Content-Length', Buffer.byteLength(data));
    }
  } else {
    this.header('Content-Length', 0);
  }

  if (!this.header('Content-MD5') && data) {
    var hash = crypto.createHash('md5');
    hash.update(data);
    this.header('Content-MD5', hash.digest('base64'));
  }

  if (!this.header('Content-Type') && data && this.contentType) {
    var type = this.contentType;
    if (this.charSet)
      type += '; charset=' + this.charSet;
    this.header('Content-Type', type);
  }

  if (!this.header('Date'))
    this.header('Date', httpDate(now));

  if (!this.header(this.responseTimeHeader))
    this.header(this.responseTimeHeader, this.responseTimeFormatter(now.getTime() - this.req.time.getTime()));
};

Response.prototype.send = function send(body) {
  assert.ok(this.methods);

  var head = (this.req.method === 'HEAD');

  switch (arguments.length) {
  case 0:
    body = null;
    break;

  case 1:
    if (typeof (body) === 'number') {
      this.statusCode = body;
      body = null;
    } else if (body && body instanceof HttpError) {
      this.statusCode = body.statusCode;
    }
    break;

  default:
    this.statusCode = body;
    body = arguments[1];
    break;
  }

  // the formatter might tack in Content- headers, so fill in headers after
  // serialization
  var data = body ? this.format(body) : null;
  this.finishHeaders(data);

  this.writeHead(this.statusCode);
  if (data && !head && this.statusCode !== 204 && this.statusCode !== 304)
    this.write(data);
  this.end();

  var self = this;
  this.log.trace({res: self}, 'response sent');
  return this;
};

Response.prototype.json = function json(obj) {
  if (arguments.length === 2) {
    this.code = obj;
    obj = arguments[1];
  }

  if (typeof (obj) !== 'object')
    throw new TypeError('object (Object) required');

  this.contentType = 'application/json';
  return this.send(obj);
};

Response.prototype.format = function format(body) {
  var log = this.log;

  log.trace('format entered(type=%s)', this.contentType);

  if (!this.contentType) {
    for (var i = 0; i < this.types.length; i++) {
      if (this.req.accepts(this.types[i])) {
        this.contentType = this.types[i];
        break;
      }
    }
  }

  if (this.types.indexOf(this.contentType) === -1) {
    this.contentType = 'application/octet-stream';
    log.trace('format content-type overriden: %s', this.contentType);
  }

  assert.ok(this.formatters[this.contentType]);

  if (body instanceof Error)
    this.code = (body instanceof errors.HttpError) ? body.statusCode : 500;

  var data = this.formatters[this.contentType](this.req, this, body);

  log.trace('format returing: %s', data);

  return data;
};

Response.prototype.toString = function toString() {
  var headers = '';
  var self = this;
  Object.keys(this.headers).forEach(function (k) {
    headers += k + ': ' + self.headers[k] + '\n';
  });
  return 'HTTP/1.1 ' + this.code + ' ' + http.STATUS_CODES[this.code] + '\n' +
    headers;
};
<commit_msg>Fixed response.js to now emit the finish event when the response is ended, making Restify compatiable with node-logging.<commit_after>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var assert = require('assert');
var crypto = require('crypto');
var http = require('http');
var Stream = require('stream').Stream;
var util = require('util');

var mime = require('mime');

var errors = require('./errors');
var Request = require('./request');

///--- Globals

var HttpError = errors.HttpError;
var RestError = errors.RestError;

var ALLOW_HEADERS = [
  'Accept',
  'Accept-Version',
  'Content-Length',
  'Content-MD5',
  'Content-Type',
  'Date',
  'X-Api-Version'
].join(', ');

var EXPOSE_HEADERS = [
  'X-Api-Version',
  'X-Request-Id'
].join(', ');

var DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

var MONTHS = [
  'Jan',
  'Feb',
  'Mar',
  'Apr',
  'May',
  'Jun',
  'Jul',
  'Aug',
  'Sep',
  'Oct',
  'Nov',
  'Dec'
];

///--- Helpers

function httpDate(now) {
  if (!now)
    now = new Date();

  function pad(val) {
    if (parseInt(val, 10) < 10)
      val = '0' + val;
    return val;
  }

  return DAYS[now.getUTCDay()] + ', ' +
    pad(now.getUTCDate()) + ' ' +
    MONTHS[now.getUTCMonth()] + ' ' +
    now.getUTCFullYear() + ' ' +
    pad(now.getUTCHours()) + ':' +
    pad(now.getUTCMinutes()) + ':' +
    pad(now.getUTCSeconds()) + ' GMT';
}

function formatBinary(req, res, body) {
  if (!body)
    return null;

  if (!Buffer.isBuffer(body))
    body = new Buffer(body.toString());

  return body;
}

function formatText(req, res, body) {
  if (!body)
    return null;

  if (body instanceof Error) {
    body = body.message;
  } else if (typeof (body) === 'object') {
    body = JSON.stringify(body);
  } else {
    body = body.toString();
  }

  return body;
}

function formatJSON(req, res, body) {
  if (!body)
    return null;

  if (body instanceof Error) {
    if (body instanceof RestError) {
      body = body.body;
    } else {
      body = {
        message: body.message
      };
    }
  }

  if (Buffer.isBuffer(body))
    body = body.toString('base64');

  return JSON.stringify(body);
}

function ensureDefaultFormatters(res) {
  if (!res.formatters)
    res.formatters = {};

  //
  // We do this so that JSON formatters et al happen before custom ones,
  // like HTML (i.e., if your client is curl, accept defaults to * / *, and
  // v8 object keys are predictable, so we order them on the object such that
  // JSON goes first
  //

  var save = res.formatters || {};
  res.formatters = {};
  if (!save['application/json'])
    res.formatters['application/json'] = formatJSON;

  if (!save['text/plain'])
    res.formatters['text/plain'] = formatText;

  if (!save['application/octet-stream'])
    res.formatters['application/octet-stream'] = formatBinary;

  Object.keys(save).forEach(function (k) {
    if (!res.formatters[k])
      res.formatters[k] = save[k];
  });

  return this;
}

///--- API

/**
 * Response is a wrapper over node's http.OutgoingMessage object.
 *
 * Previous versions of restify just extended the prototype, but that was
 * problemtic if used in conjunction with other modules that do this as well
 * (namely express).
 *
 * This object exposes all of the properties/events/methods of the standard
 * Response object, plus some extra goodies.
 *
 * Note that at construct time, you pass in a map of mime type to formatter
 * functions. i.e:
 *
 * var res = new Response({
 *   formatters: {
 *     json: function (req, res, data, callback) {
 *       return callback(null, JSON.stringify(data));
 *     }
 *   }
 * });
 *
 * Note there is a special formatter called `error` which is invoked when
 * data is an error.
 *
 * @param {Object} options pass in bunyan handle, http.OutgoingMessage and a
 *                 Request.
 * @throws {TypeError} on input error.
 */
function Response(options) {
  if (typeof (options) !== 'object')
    throw new TypeError('options (Object) required');
  if (typeof (options.log) !== 'object')
    throw new TypeError('options.log (Object) required');
  if (typeof (options.response) !== 'object')
    throw new TypeError('options.response (http.OutgoingMessage) required');
  if (!(options.request instanceof Request))
    throw new TypeError('options.request (Request) required');
  if (options.version && typeof (options.version) !== 'string')
    throw new TypeError('options.version (String) required');

  var self = this;

  Stream.call(this);

  this.charSet = false;
  this._contentType = false;
  this._continueSent = false;
  this.formatters = {};
  this.log = options.request.log;
  this.methods = options.methods || [];
  this.req = options.request;
  this.res = options.response;
  this.serverName = options.serverName || 'restify';
  this.version = options.version || false;
  this.responseTimeHeader = options.responseTimeHeader || 'X-Response-Time';
  this.responseTimeFormatter = function(durationInMilliseconds) { return durationInMilliseconds; };

  // make sure the options is a function (if not we don't allow you to override)
  if (typeof(options.responseTimeFormatter) === 'function') {
    this.responseTimeFormatter = options.responseTimeFormatter;
  }

  // Generate the formatters
  if (options.formatters) {
    Object.keys(options.formatters).forEach(function (k) {
      if (k.indexOf('/') === -1)
        k = mime.lookup(k);

      self.formatters[k] = options.formatters[k];
    });
  }
  ensureDefaultFormatters(this);

  this.__defineSetter__('code', function (c) {
    if (typeof (c) !== 'number')
      throw new TypeError('code (Number) required');
    if (c < 100 || c > 599)
      throw new TypeError('code is not a valid HTTP status code');

    self.res.statusCode = c;
  });

  this.__defineGetter__('code', function () {
    return self.res.statusCode || 200;
  });

  this.__defineSetter__('contentLength', function (len) {
    if (typeof (len) !== 'number')
      throw new TypeError('contentLength must be Number');

    self.header('Content-Length', len);
  });

  this.__defineGetter__('contentLength', function () {
    return self.res.getHeader('Content-Length');
  });

  this.__defineSetter__('contentType', function (type) {
    if (typeof (type) !== 'string')
      throw new TypeError('contentType must be String');

    if (type.indexOf('/') === -1)
      type = mime.lookup(type);

    if (!self.charSet)
      self.charSet = mime.charsets.lookup(type, self.charSet);

    self._contentType = type;
  });

  this.__defineGetter__('contentType', function () {
    return self._contentType;
  });

  this.__defineGetter__('etag', function () {
    return self.get('etag');
  });

  this.__defineSetter__('etag', function (val) {
    return self.set('etag', val);
  });

  this.__defineGetter__('headers', function () {
    return self.res._headers || {};
  });

  this.__defineGetter__('id', function () {
    return self.req.requestId;
  });

  this.__defineGetter__('requestId', function () {
    return self.req.requestId;
  });

  this.__defineGetter__('statusCode', function () {
    return self.code;
  });

  this.__defineSetter__('statusCode', function (code) {
    self.code = code;
  });

  var types = Object.keys(this.formatters);
  this.__defineGetter__('types', function () {
    return types;
  });

  this.__defineGetter__('writable', function () {
    return self.res.writable;
  });

  this.__defineGetter__('writeable', function () {
    return self.res.writable;
  });

  ///--- Events
  this.res.on('drain', function () {
    return self.emit('drain');
  });

  this.res.on('error', function (err) {
    return self.emit('error', err);
  });

  this.res.on('close', function () {
    return self.emit('close');
  });

  this.res.on('pipe', function (src) {
    return self.emit('pipe', src);
  });

  this.res.on('finish', function (src) {
    return self.emit('finish', src);
  }
  // Finally write the default headers in
  this.defaultHeaders();
}
util.inherits(Response, Stream);
module.exports = Response;

Response.ACCEPTABLE = [
  'application/json',
  'text/plain',
  'application/octet-stream'
];

///--- Set up pass-throughs for all the APIs

Object.keys(http.OutgoingMessage.prototype).forEach(function (m) {
  Response.prototype[m] = function () {
    return this.res[m].apply(this.res, arguments);
  };
});

///--- http.OutgoingMessage APIs

Response.prototype.writeHead = function writeHead() {
  if (this.statusCode === 204 || this.statusCode === 304) {
    this.removeHeader('Content-Length');
    this.removeHeader('Content-MD5');
    this.removeHeader('Content-Type');
  }

  this.res.writeHead.apply(this.res, arguments);
  this.emit('header');
};

Response.prototype.writeContinue = function writeContinue() {
  return this.res.writeContinue.apply(this.res, arguments);
};

///-- Express APIs (that we want)

Response.prototype.header = function header(name, value) {
  if (typeof (name) !== 'string')
    throw new TypeError('name (String) required');

  if (value === undefined)
    return this.getHeader(name);

  if (value instanceof Date)
    value = httpDate(value);

  this.setHeader(name, value);
  return value;
};

Response.prototype.get = function get(name) {
  return this.getHeader(name);
};

Response.prototype.set = function set(name, val) {
  if (arguments.length === 2) {
    if (typeof (name) !== 'string')
      throw new TypeError('name (String) required');
    this.header(name, val);
  } else {
    if (typeof (name) !== 'object')
      throw new TypeError('Object required for argument 1');

    var self = this;
    Object.keys(name).forEach(function (k) {
      self.header(k, name[k]);
    });
  }

  return this;
};

Response.prototype.cache = function cache(type, options) {
  if (typeof (type) !== 'string') {
    options = type;
    type = 'public';
  }

  if (options && options.maxAge) {
    if (typeof (options.maxAge) !== 'number')
      throw new TypeError('options.maxAge (Number) required');
    type += ', max-age=' + (options.maxAge / 1000);
  }

  return this.header('Cache-Control', type);
};

Response.prototype.status = function status(code) {
  this.code = code;
  return this;
};

Response.prototype.defaultHeaders = function defaultHeaders() {
  this.header('Access-Control-Allow-Origin', '*');
  this.header('Access-Control-Allow-Headers', ALLOW_HEADERS);

  if (this.methods.length)
    this.header('Access-Control-Allow-Methods', this.methods.join());

  this.header('Access-Control-Expose-Headers', EXPOSE_HEADERS + ', ' + this.responseTimeHeader);
  this.header('Server', this.serverName);

  if (this.version)
    this.header('X-Api-Version', this.version);

  this.header('X-Request-Id', this.id);
};

Response.prototype.finishHeaders = function finishHeaders(data) {
  var now = new Date();

  if (!this.header('Connection') && !this.keepAlive)
    this.header('Connection', 'close');

  if (!this.header('Content-Length') && data) {
    if (Buffer.isBuffer(data)) {
      this.header('Content-Length', data.length);
    } else {
      this.header('Content-Length', Buffer.byteLength(data));
    }
  } else {
    this.header('Content-Length', 0);
  }

  if (!this.header('Content-MD5') && data) {
    var hash = crypto.createHash('md5');
    hash.update(data);
    this.header('Content-MD5', hash.digest('base64'));
  }

  if (!this.header('Content-Type') && data && this.contentType) {
    var type = this.contentType;
    if (this.charSet)
      type += '; charset=' + this.charSet;
    this.header('Content-Type', type);
  }

  if (!this.header('Date'))
    this.header('Date', httpDate(now));

  if (!this.header(this.responseTimeHeader))
    this.header(this.responseTimeHeader, this.responseTimeFormatter(now.getTime() - this.req.time.getTime()));
};

Response.prototype.send = function send(body) {
  assert.ok(this.methods);

  var head = (this.req.method === 'HEAD');

  switch (arguments.length) {
  case 0:
    body = null;
    break;

  case 1:
    if (typeof (body) === 'number') {
      this.statusCode = body;
      body = null;
    } else if (body && body instanceof HttpError) {
      this.statusCode = body.statusCode;
    }
    break;

  default:
    this.statusCode = body;
    body = arguments[1];
    break;
  }

  // the formatter might tack in Content- headers, so fill in headers after
  // serialization
  var data = body ? this.format(body) : null;
  this.finishHeaders(data);

  this.writeHead(this.statusCode);
  if (data && !head && this.statusCode !== 204 && this.statusCode !== 304)
    this.write(data);
  this.end();

  var self = this;
  this.log.trace({res: self}, 'response sent');
  return this;
};

Response.prototype.json = function json(obj) {
  if (arguments.length === 2) {
    this.code = obj;
    obj = arguments[1];
  }

  if (typeof (obj) !== 'object')
    throw new TypeError('object (Object) required');

  this.contentType = 'application/json';
  return this.send(obj);
};

Response.prototype.format = function format(body) {
  var log = this.log;

  log.trace('format entered(type=%s)', this.contentType);

  if (!this.contentType) {
    for (var i = 0; i < this.types.length; i++) {
      if (this.req.accepts(this.types[i])) {
        this.contentType = this.types[i];
        break;
      }
    }
  }

  if (this.types.indexOf(this.contentType) === -1) {
    this.contentType = 'application/octet-stream';
    log.trace('format content-type overriden: %s', this.contentType);
  }

  assert.ok(this.formatters[this.contentType]);

  if (body instanceof Error)
    this.code = (body instanceof errors.HttpError) ? body.statusCode : 500;

  var data = this.formatters[this.contentType](this.req, this, body);

  log.trace('format returing: %s', data);

  return data;
};

Response.prototype.toString = function toString() {
  var headers = '';
  var self = this;
  Object.keys(this.headers).forEach(function (k) {
    headers += k + ': ' + self.headers[k] + '\n';
  });
  return 'HTTP/1.1 ' + this.code + ' ' + http.STATUS_CODES[this.code] + '\n' +
    headers;
};
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn,
  exec = require('child_process').exec;

process.stdout.write("================================================================================\n");
process.stdout.write("=                                                                              =\n");
process.stdout.write("=  To install with C++ bson parser do <npm install mongodb --mongodb:native>   =\n");
process.stdout.write("=                                                                              =\n");
process.stdout.write("================================================================================\n");

// Check if we want to build the native code
var build_native = process.env['npm_package_config_mongodb_native'] != null ? process.env['npm_package_config_mongodb_native'] : 'false';
build_native = process.env['npm_config_mongodb_native'] != null ? process.env['npm_config_mongodb_native'] : build_native;
build_native = build_native == 'true' ? true : false;

// If we are building the native bson extension ensure we use gmake if available
if(build_native) {
  // Check if we need to use gmake
  exec('which gmake', function(err, stdout, stderr) {
    // Set up spawn command
    var make = null;
    // No gmake build using make
    if(err != null) {
      make = spawn('make', ['node_gyp'], {cwd:process.env['PWD']});
    } else {
      make = spawn('gmake', ['node_gyp'], {cwd:process.env['PWD']});
    }

    // Execute spawn
    make.stdout.on('data', function(data) {
      process.stdout.write(data);
    })

    make.stderr.on('data', function(data) {
      process.stdout.write(data);
    })

    make.on('exit', function(code) {
      process.stdout.write('child process exited with code ' + code + "\n");
    })
  });
}

<commit_msg>Added debug to install script<commit_after>var spawn = require('child_process').spawn,
  exec = require('child_process').exec;

process.stdout.write("================================================================================\n");
process.stdout.write("=                                                                              =\n");
process.stdout.write("=  To install with C++ bson parser do <npm install mongodb --mongodb:native>   =\n");
process.stdout.write("=                                                                              =\n");
process.stdout.write("================================================================================\n");

// Check if we want to build the native code
var build_native = process.env['npm_package_config_mongodb_native'] != null ? process.env['npm_package_config_mongodb_native'] : 'false';
if(process.env['npm_config_mongodb_debug']) {
  console.log("== process.env['npm_package_config_mongodb_native'] :: " + process.env['npm_package_config_mongodb_native']);
  console.log("== build_native :: " + build_native);
}

build_native = process.env['npm_config_mongodb_native'] != null ? process.env['npm_config_mongodb_native'] : build_native;
if(process.env['npm_config_mongodb_debug']) {
  console.log("== process.env['npm_config_mongodb_native'] :: " + process.env['npm_config_mongodb_native']);
  console.log("== build_native :: " + build_native);
}

build_native = build_native == 'true' ? true : false;
if(process.env['npm_config_mongodb_debug']) {
  console.log("== build_native :: " + build_native);
}

// If we are building the native bson extension ensure we use gmake if available
if(build_native) {
  // Check if we need to use gmake
  exec('which gmake', function(err, stdout, stderr) {
    // Set up spawn command
    var make = null;
    // No gmake build using make
    if(err != null) {
      make = spawn('make', ['node_gyp'], {cwd:process.env['PWD']});
    } else {
      make = spawn('gmake', ['node_gyp'], {cwd:process.env['PWD']});
    }

    // Execute spawn
    make.stdout.on('data', function(data) {
      process.stdout.write(data);
    })

    make.stderr.on('data', function(data) {
      process.stdout.write(data);
    })

    make.on('exit', function(code) {
      process.stdout.write('child process exited with code ' + code + "\n");
    })
  });
}

<|endoftext|>


<commit_before>var Response = function(socket, msg_id) {
    this._socket = socket;
    this._msg_id = msg_id;
};

Response.prototype.json = function json(data) {
    if (typeof data !== 'object') {
        console.error('since data is not JSON object, Use Response.send() instead')
    }
    this._socket.success([this._msg_id], data);
};

Response.prototype.send = function send(data) {
    this._socket.success([this._msg_id], data);
};

Response.prototype.error = function error(err) {
    this._socket.error([this._msg_id], err);
};

module.exports = Response;
<commit_msg>send error when data contains err field<commit_after>var Response = function(socket, msg_id) {
    this._socket = socket;
    this._msg_id = msg_id;
};

Response.prototype.json = function json(data) {
    if (typeof data !== 'object') {
        console.error('since data is not JSON object, Use Response.send() instead')
    }
    if ('err' in data)
        this.error(data['err']);
    else
        this.send(data);
};

Response.prototype.send = function send(data) {
    this._socket.success([this._msg_id], data);
};

Response.prototype.error = function error(err) {
    this._socket.error([this._msg_id], err);
};

module.exports = Response;
<|endoftext|>


<commit_before>'use strict';

//
// Compatibility with older node.js as path.exists got moved to `fs`.
//
var fs = require('fs')
  , path = require('path')
  , os = require('os')
  , hook = path.join(__dirname, 'hook')
  , root = path.resolve(__dirname, '..', '..')
  , exists = fs.existsSync || path.existsSync;

//
// Gather the location of the possible hidden .git directory, the hooks
// directory which contains all git hooks and the absolute location of the
// `pre-commit` file. The path needs to be absolute in order for the symlinking
// to work correctly.
//
var git = path.resolve(root, '.git')
  , hooks = path.resolve(git, 'hooks')
  , precommit = path.resolve(hooks, 'pre-commit');

//
// Bail out if we don't have an `.git` directory as the hooks will not get
// triggered. If we do have directory create a hooks folder if it doesn't exist.
//
if (!exists(git) || !fs.lstatSync(git).isDirectory()) return;
if (!exists(hooks)) fs.mkdirSync(hooks);

//
// If there's an existing `pre-commit` hook we want to back it up instead of
// overriding it and losing it completely as it might contain something
// important.
//
if (exists(precommit) && !fs.lstatSync(precommit).isSymbolicLink()) {
  console.log('pre-commit:');
  console.log('pre-commit: Detected an existing git pre-commit hook');
  fs.writeFileSync(precommit +'.old', fs.readFileSync(precommit));
  console.log('pre-commit: Old pre-commit hook backuped to pre-commit.old');
  console.log('pre-commit:');
}

//
// We cannot create a symlink over an existing file so make sure it's gone and
// finish the installation process.
//
try { fs.unlinkSync(precommit); }
catch (e) {}

// Create generic precommit hook that launches this modules hook (as well
// as stashing - unstashing the unstaged changes)
// TODO: we could keep launching the old pre-commit scripts
var hookRelativeUnixPath = hook.replace(root, '.');
if(os.platform() === 'win32') {
  hookRelativeUnixPath = hookRelativeUnixPath.replace(/[\\\/]+/g, '/');
}
var precommitContent = '#!/bin/bash' + os.EOL
  +  hookRelativeUnixPath + os.EOL
  + 'RESULT=$?' + os.EOL
  + '[ $RESULT -ne 0 ] && exit 1' + os.EOL
  + 'exit 0' + os.EOL;

//
// It could be that we do not have rights to this folder which could cause the
// installation of this module to completely fail. We should just output the
// error instead destroying the whole npm install process.
//
try { fs.writeFileSync(precommit, precommitContent); }
catch (e) {
  console.error('pre-commit:');
  console.error('pre-commit: Failed to create the hook file in your .git/hooks folder because:');
  console.error('pre-commit: '+ e.message);
  console.error('pre-commit: The hook was not installed.');
  console.error('pre-commit:');
}
<commit_msg>[fix] chmod 0777 the newly created file; Fixes #88<commit_after>'use strict';

//
// Compatibility with older node.js as path.exists got moved to `fs`.
//
var fs = require('fs')
  , path = require('path')
  , os = require('os')
  , hook = path.join(__dirname, 'hook')
  , root = path.resolve(__dirname, '..', '..')
  , exists = fs.existsSync || path.existsSync;

//
// Gather the location of the possible hidden .git directory, the hooks
// directory which contains all git hooks and the absolute location of the
// `pre-commit` file. The path needs to be absolute in order for the symlinking
// to work correctly.
//
var git = path.resolve(root, '.git')
  , hooks = path.resolve(git, 'hooks')
  , precommit = path.resolve(hooks, 'pre-commit');

//
// Bail out if we don't have an `.git` directory as the hooks will not get
// triggered. If we do have directory create a hooks folder if it doesn't exist.
//
if (!exists(git) || !fs.lstatSync(git).isDirectory()) return;
if (!exists(hooks)) fs.mkdirSync(hooks);

//
// If there's an existing `pre-commit` hook we want to back it up instead of
// overriding it and losing it completely as it might contain something
// important.
//
if (exists(precommit) && !fs.lstatSync(precommit).isSymbolicLink()) {
  console.log('pre-commit:');
  console.log('pre-commit: Detected an existing git pre-commit hook');
  fs.writeFileSync(precommit +'.old', fs.readFileSync(precommit));
  console.log('pre-commit: Old pre-commit hook backuped to pre-commit.old');
  console.log('pre-commit:');
}

//
// We cannot create a symlink over an existing file so make sure it's gone and
// finish the installation process.
//
try { fs.unlinkSync(precommit); }
catch (e) {}

// Create generic precommit hook that launches this modules hook (as well
// as stashing - unstashing the unstaged changes)
// TODO: we could keep launching the old pre-commit scripts
var hookRelativeUnixPath = hook.replace(root, '.');

if(os.platform() === 'win32') {
  hookRelativeUnixPath = hookRelativeUnixPath.replace(/[\\\/]+/g, '/');
}

var precommitContent = '#!/bin/bash' + os.EOL
  +  hookRelativeUnixPath + os.EOL
  + 'RESULT=$?' + os.EOL
  + '[ $RESULT -ne 0 ] && exit 1' + os.EOL
  + 'exit 0' + os.EOL;

//
// It could be that we do not have rights to this folder which could cause the
// installation of this module to completely fail. We should just output the
// error instead destroying the whole npm install process.
//
try { fs.writeFileSync(precommit, precommitContent); }
catch (e) {
  console.error('pre-commit:');
  console.error('pre-commit: Failed to create the hook file in your .git/hooks folder because:');
  console.error('pre-commit: '+ e.message);
  console.error('pre-commit: The hook was not installed.');
  console.error('pre-commit:');
}

try { fs.chmodSync(precommit, 777); }
catch (e) {
  console.error('pre-commit:');
  console.error('pre-commit: chmod 0777 the pre-commit file in your .git/hooks folder because:');
  console.error('pre-commit: '+ e.message);
  console.error('pre-commit:');
}
<|endoftext|>