<commit_before>
// activate a version of a package
// this presumes that it's been installed
// no need to worry about dependencies, because they were
// installed into the child package anyhow.

var mkdir = require("./utils/mkdir-p"),
  exec = require("./utils/exec");

module.exports = activate;

function activate (pkg, version, cb) {

}
<commit_msg>Activate command, working now.<commit_after>
// activate a version of a package
// this presumes that it's been installed
// no need to worry about dependencies, because they were
// installed into the child package anyhow.

var mkdir = require("./utils/mkdir-p"),
  exec = require("./utils/exec"),
  npm = require("../npm"),
  fs = require("fs"),
  log = require("./utils").log,
  path = require("path"),
  rm = require("./utils/rm-rf"),
  chain = require("./utils/chain"),
  exec = require("./utils/exec");

module.exports = activate;

function activate (pkg, version, cb) {
  // make sure package and version exists.
  // If there's already an active version, then deactivate it.
  // first, link .npm/{pkg}/{version} to .npm/{pkg}/{active}
  // then, link the things in the root without a version to the active one.

  var from = path.join(npm.dir, pkg, version),
    to = path.join(npm.dir, pkg, "active");
  link(from, to, function (er) {
    if (er) return cb(er);
    // now link the main and libs from the root to the active folder.
    var fromMain = path.join(npm.dir, pkg, "active/main.js"),
      toMain = path.join(npm.root, pkg+".js"),
      fromLib = path.join(npm.dir, pkg, "active/lib"),
      toLib = path.join(npm.root, pkg);
    chain(
      [function (cb) {
        fs.stat(fromMain, function (er, stat) {
          if (er) return cb();
          link(fromMain, toMain, cb);
        });
      }],
      [function (cb) {
        fs.stat(fromLib, function (er, stat) {
          if (er) return cb();
          link(fromLib, toLib, cb);
        });
      }],
      cb
    );
  });
}

function link (from, to, cb) {
  chain(
    [fs, "stat", from],
    [function (cb) { rm(to, function () { cb() }) }],
    [exec, "ln", ["-s", from, to]],
    [function (cb) {
      // TODO: save that this is active.
      cb();
    }],
    cb
  );
}
<|endoftext|>


<commit_before>"use strict";

// code will relocate an error or help message to near where the error actually is in CodeMirror.
define(function() {
  return function Relocator(codeMirror, codeMirrorScrollArea) {

    var relocator = {
      // called any time the codemirror source code area is scrolled
      scrollFunction: function() {},

      // called any time the browser window is resized
      resizeFunction: function() {},

      // clear old markings
      cleanup: function() {
        $(".CodeMirror-line-highlight").removeClass("CodeMirror-line-highlight");
        $(".help .up-arrow, help. .down-arrow, .error .up-arrow, .error .down-arrow").hide();
        this.scrollFunction = function() {};
      },

      // relocate an element to inside CodeMirror, pointing "at" the line for startMark
      relocate: function(element, startMark) {
        this.cleanup();

        // find the line position for the start mark
        var cmLocation = codeMirror.posFromIndex(startMark);
        var linePre = $($('.CodeMirror-gutter-text pre')[cmLocation.line]);
        linePre.addClass("CodeMirror-line-highlight");

        var contentPre = $($('.CodeMirror-lines pre')[cmLocation.line+2]);
        contentPre.addClass("CodeMirror-line-highlight");

        var hintMarker = $(".hintmarker");

        // move the message to this line
        var _tmp = hintMarker.clone();
        hintMarker.replaceWith(_tmp);
        codeMirrorScrollArea.append(hintMarker);
        _tmp.remove();

        // set the correct "top" value, making sure to place the element
        // below the error if it'd otherwise disappear from the top of
        // the content area due to close-to-zero placement.
        var baseValue = linePre.position().top - element.height() - 20,
            topValue = baseValue;

        if (topValue < 0) {
          topValue = linePre.position().top + 50;
          $(".up-arrow",$(element)).show();
        } else {
          $(".down-arrow",$(element)).show();
        }
        var gutterWidth = $(".CodeMirror-gutter").width();

        // Place hintmarker at the right height
        hintMarker.css({
          "top": topValue + "px",
          "left": gutterWidth + "px"
        });

        // Get its parent-indicated top position, and make
        // the hint box match this hintmarker position
        topValue = hintMarker.position().top;
        element.css({
          "top": topValue + "px",
          "left": gutterWidth + "px"
        });

        // Now, whenever the codemirror scroll area is scrolled, set
        // the hint height to match the hint marker's height so that
        // it looks like the hint box scrolls along with the code.
        this.scrollFunction = function() {
          var topval = hintMarker.position().top;
          element.css("top", topval + "px");
        };

        // Whenever the window is resized, we should get rid of the
        // currently active hint, hiding it and cleaning up.
        this.resizeFunction = function() {
          element.hide();
          this.cleanup();
        };
      }
    };

    // Set up the onscroll and onresize handling. Note that the
    // function(){...} wrappers are needed to prevent early binding.
    codeMirrorScrollArea.on("scroll", function() { relocator.scrollFunction(); });
    $(window).resize( function() { relocator.resizeFunction(); });

    return relocator;
  };
});
<commit_msg>style change from .resize(...) to .on('resize',...)<commit_after>"use strict";

// code will relocate an error or help message to near where the error actually is in CodeMirror.
define(function() {
  return function Relocator(codeMirror, codeMirrorScrollArea) {

    var relocator = {
      // called any time the codemirror source code area is scrolled
      scrollFunction: function() {},

      // called any time the browser window is resized
      resizeFunction: function() {},

      // clear old markings
      cleanup: function() {
        $(".CodeMirror-line-highlight").removeClass("CodeMirror-line-highlight");
        $(".help .up-arrow, help. .down-arrow, .error .up-arrow, .error .down-arrow").hide();
        this.scrollFunction = function() {};
      },

      // relocate an element to inside CodeMirror, pointing "at" the line for startMark
      relocate: function(element, startMark) {
        this.cleanup();

        // find the line position for the start mark
        var cmLocation = codeMirror.posFromIndex(startMark);
        var linePre = $($('.CodeMirror-gutter-text pre')[cmLocation.line]);
        linePre.addClass("CodeMirror-line-highlight");

        var contentPre = $($('.CodeMirror-lines pre')[cmLocation.line+2]);
        contentPre.addClass("CodeMirror-line-highlight");

        var hintMarker = $(".hintmarker");

        // move the message to this line
        var _tmp = hintMarker.clone();
        hintMarker.replaceWith(_tmp);
        codeMirrorScrollArea.append(hintMarker);
        _tmp.remove();

        // set the correct "top" value, making sure to place the element
        // below the error if it'd otherwise disappear from the top of
        // the content area due to close-to-zero placement.
        var baseValue = linePre.position().top - element.height() - 20,
            topValue = baseValue;

        if (topValue < 0) {
          topValue = linePre.position().top + 50;
          $(".up-arrow",$(element)).show();
        } else {
          $(".down-arrow",$(element)).show();
        }
        var gutterWidth = $(".CodeMirror-gutter").width();

        // Place hintmarker at the right height
        hintMarker.css({
          "top": topValue + "px",
          "left": gutterWidth + "px"
        });

        // Get its parent-indicated top position, and make
        // the hint box match this hintmarker position
        topValue = hintMarker.position().top;
        element.css({
          "top": topValue + "px",
          "left": gutterWidth + "px"
        });

        // Now, whenever the codemirror scroll area is scrolled, set
        // the hint height to match the hint marker's height so that
        // it looks like the hint box scrolls along with the code.
        this.scrollFunction = function() {
          var topval = hintMarker.position().top;
          element.css("top", topval + "px");
        };

        // Whenever the window is resized, we should get rid of the
        // currently active hint, hiding it and cleaning up.
        this.resizeFunction = function() {
          element.hide();
          this.cleanup();
        };
      }
    };

    // Set up the onscroll and onresize handling. Note that the
    // function(){...} wrappers are needed to prevent early binding.
    codeMirrorScrollArea.on("scroll", function() { relocator.scrollFunction(); });
    $(window).on("resize", function() { relocator.resizeFunction(); });

    return relocator;
  };
});
<|endoftext|>


<commit_before>var HTTP_STATUS_CODES = require('http').STATUS_CODES;

var fs = require('fs');
var os = require('os');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var request = require('request');
var xmlbuilder = require('xmlbuilder');
var stackTrace = require('stack-trace');
var traverse = require('traverse');

module.exports = Airbrake;
util.inherits(Airbrake, EventEmitter);
function Airbrake() {
  this.key = null;

  this.env = process.env.NODE_ENV;
  this.projectRoot = null;
  this.appVersion = null;

  // Disabled, see comments in appendServerEnvironmentXml()
  // this.hostname = os.hostname();

  this.protocol = 'http';
  this.host = 'airbrakeapp.com';
}

Airbrake.PACKAGE = (function() {
  var json = fs.readFileSync(__dirname + '/../package.json', 'utf8');
  return JSON.parse(json);
})();

Airbrake.createClient = function(key, env) {
  var instance = new this();
  instance.key = key;
  instance.env = env || instance.env;
  return instance;
};

Airbrake.prototype.handleExceptions = function() {
  var self = this;
  process.on('uncaughtException', function(err) {
    self.notify(err, function(notifyErr, url) {
      if (notifyErr) {
        self.log('Uncaught Exception: Could not notify Airbreak!');
        self.log(notifyErr.stack);
      } else {
        self.log('Uncaught Exception: Airbreak was notified: ' + url);
      }

      self.log(err.stack);
      process.exit(1);
    });
  });
};

Airbrake.prototype.log = function(str) {
  console.error(str);
};

Airbrake.prototype.notify = function(err, cb) {
  var body = this.notifyXml(err);

  var options = {
    method: 'POST',
    url: this.url('/notifier_api/v2/notices'),
    body: body,
    timeout: 30 * 1000,
    headers: {
      'Content-Length': body.length,
    },
  };

  var self = this;
  var callback = function(err) {
    if (cb) {
      cb.apply(self, arguments);
      return;
    }

    if (err) {
      self.emit('error', err);
    }
  };

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];
      return callback(new Error(
        'Notification failed: ' + res.statusCode + ' ' + status
      ));
    }

    var m = body.match(/<url>([^<]+)/i);
    var url = (m)
      ? m[1]
      : null;

    callback(null, url);
  });
};

Airbrake.prototype.url = function(path) {
  return this.protocol + '://' + this.host + path;
};

Airbrake.prototype.notifyXml = function(err, pretty) {
  var notice = xmlbuilder().begin('notice', {
    version: '1.0',
    encoding: 'UTF-8'
  });

  this.appendHeaderXml(notice);
  this.appendErrorXml(notice, err);
  this.appendRequestXml(notice, err);
  this.appendServerEnvironmentXml(notice);

  return notice.up().toString({pretty: pretty});
};

Airbrake.prototype.appendHeaderXml = function(notice) {
  notice
    .att('version', '2.0')
    .ele('api-key')
      .txt(this.key)
    .up()
    .ele('notifier')
      .ele('name')
        .txt(Airbrake.PACKAGE.name)
      .up()
      .ele('version')
        .txt(Airbrake.PACKAGE.version)
      .up()
      .ele('url')
        .txt(Airbrake.PACKAGE.homepage)
      .up()
    .up();
};

Airbrake.prototype.appendErrorXml = function(notice, err) {
  var trace = stackTrace.parse(err);
  var error = notice
    .ele('error')
      .ele('class')
        .txt(err.type || 'Error')
      .up()
      .ele('message')
        .txt(err.message)
      .up()
      .ele('backtrace')

  trace.forEach(function(callSite) {
    error
      .ele('line')
        .att('method', callSite.getFunctionName())
        .att('file', callSite.getFileName())
        .att('number', callSite.getLineNumber())
  });
};

Airbrake.prototype.appendRequestXml = function(notice, err) {
  var request = notice.ele('request');

  ['url', 'component', 'action'].forEach(function(nodeName) {
    var node = request.ele(nodeName);
    if (err[nodeName]) {
      node.txt(err[nodeName]);
    }
  });

  this.addRequestVars(request, 'cgi-data', this.cgiDataVars(err));
  this.addRequestVars(request, 'session', this.sessionVars(err));
  this.addRequestVars(request, 'params', this.paramsVars(err));
};

Airbrake.prototype.addRequestVars = function(request, type, vars) {
  this.emit('vars', type, vars);

  var node;
  Object.keys(vars).forEach(function(key) {
    // JSON.stringify throws on circular structures, lets remove those
    var val = traverse(vars[key]).map(function(node) {
      if (this.circular) {
        this.update('[Circular]');
      }
    });

    val = JSON.stringify(val);

    node = node || request.ele(type);

    node
      .ele('var')
      .att('key', key)
      .txt(val);
  });
};

Airbrake.prototype.cgiDataVars = function(err) {
  var cgiData = {};
  Object.keys(process.env).forEach(function(key) {
    cgiData[key] = process.env[key];
  });

  var errorEnv = (err.env instanceof Object)
    ? err.env
    : {};

  Object.keys(errorEnv).forEach(function(key) {
    cgiData[key] = err.env[key];
  });

  return cgiData;
};

Airbrake.prototype.sessionVars = function(err) {
  return (err.session instanceof Object)
    ? err.session
    : {};
};

Airbrake.prototype.paramsVars = function(err) {
  return (err.params instanceof Object)
    ? err.params
    : {};
};

Airbrake.prototype.appendServerEnvironmentXml = function(notice) {
  var serverEnvironment = notice.ele('server-environment');

  if (this.projectRoot) {
    serverEnvironment
      .ele('project-root')
      .txt(this.projectRoot);
  }

  serverEnvironment
      .ele('environment-name')
      .txt(this.env)

  if (this.appVersion) {
    serverEnvironment
      .ele('app-version')
      .txt(this.appVersion);
  }

  // This is not documented, but the Airbrake API told me about it when sending
  // some invalid data. Going to find out if they want people to use it first
  // before enabling.

  //if (this.hostname) {
    //serverEnvironment
      //.ele('hostname')
      //.txt(this.hostname);
  //}
};
<commit_msg>Add comment about xml parsing<commit_after>var HTTP_STATUS_CODES = require('http').STATUS_CODES;

var fs = require('fs');
var os = require('os');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var request = require('request');
var xmlbuilder = require('xmlbuilder');
var stackTrace = require('stack-trace');
var traverse = require('traverse');

module.exports = Airbrake;
util.inherits(Airbrake, EventEmitter);
function Airbrake() {
  this.key = null;

  this.env = process.env.NODE_ENV;
  this.projectRoot = null;
  this.appVersion = null;

  // Disabled, see comments in appendServerEnvironmentXml()
  // this.hostname = os.hostname();

  this.protocol = 'http';
  this.host = 'airbrakeapp.com';
}

Airbrake.PACKAGE = (function() {
  var json = fs.readFileSync(__dirname + '/../package.json', 'utf8');
  return JSON.parse(json);
})();

Airbrake.createClient = function(key, env) {
  var instance = new this();
  instance.key = key;
  instance.env = env || instance.env;
  return instance;
};

Airbrake.prototype.handleExceptions = function() {
  var self = this;
  process.on('uncaughtException', function(err) {
    self.notify(err, function(notifyErr, url) {
      if (notifyErr) {
        self.log('Uncaught Exception: Could not notify Airbreak!');
        self.log(notifyErr.stack);
      } else {
        self.log('Uncaught Exception: Airbreak was notified: ' + url);
      }

      self.log(err.stack);
      process.exit(1);
    });
  });
};

Airbrake.prototype.log = function(str) {
  console.error(str);
};

Airbrake.prototype.notify = function(err, cb) {
  var body = this.notifyXml(err);

  var options = {
    method: 'POST',
    url: this.url('/notifier_api/v2/notices'),
    body: body,
    timeout: 30 * 1000,
    headers: {
      'Content-Length': body.length,
    },
  };

  var self = this;
  var callback = function(err) {
    if (cb) {
      cb.apply(self, arguments);
      return;
    }

    if (err) {
      self.emit('error', err);
    }
  };

  request(options, function(err, res, body) {
    if (err) {
      return callback(err);
    }

    if (res.statusCode >= 300) {
      var status = HTTP_STATUS_CODES[res.statusCode];
      return callback(new Error(
        'Notification failed: ' + res.statusCode + ' ' + status
      ));
    }

    // Give me a break, this is legit : )
    var m = body.match(/<url>([^<]+)/i);
    var url = (m)
      ? m[1]
      : null;

    callback(null, url);
  });
};

Airbrake.prototype.url = function(path) {
  return this.protocol + '://' + this.host + path;
};

Airbrake.prototype.notifyXml = function(err, pretty) {
  var notice = xmlbuilder().begin('notice', {
    version: '1.0',
    encoding: 'UTF-8'
  });

  this.appendHeaderXml(notice);
  this.appendErrorXml(notice, err);
  this.appendRequestXml(notice, err);
  this.appendServerEnvironmentXml(notice);

  return notice.up().toString({pretty: pretty});
};

Airbrake.prototype.appendHeaderXml = function(notice) {
  notice
    .att('version', '2.0')
    .ele('api-key')
      .txt(this.key)
    .up()
    .ele('notifier')
      .ele('name')
        .txt(Airbrake.PACKAGE.name)
      .up()
      .ele('version')
        .txt(Airbrake.PACKAGE.version)
      .up()
      .ele('url')
        .txt(Airbrake.PACKAGE.homepage)
      .up()
    .up();
};

Airbrake.prototype.appendErrorXml = function(notice, err) {
  var trace = stackTrace.parse(err);
  var error = notice
    .ele('error')
      .ele('class')
        .txt(err.type || 'Error')
      .up()
      .ele('message')
        .txt(err.message)
      .up()
      .ele('backtrace')

  trace.forEach(function(callSite) {
    error
      .ele('line')
        .att('method', callSite.getFunctionName())
        .att('file', callSite.getFileName())
        .att('number', callSite.getLineNumber())
  });
};

Airbrake.prototype.appendRequestXml = function(notice, err) {
  var request = notice.ele('request');

  ['url', 'component', 'action'].forEach(function(nodeName) {
    var node = request.ele(nodeName);
    if (err[nodeName]) {
      node.txt(err[nodeName]);
    }
  });

  this.addRequestVars(request, 'cgi-data', this.cgiDataVars(err));
  this.addRequestVars(request, 'session', this.sessionVars(err));
  this.addRequestVars(request, 'params', this.paramsVars(err));
};

Airbrake.prototype.addRequestVars = function(request, type, vars) {
  this.emit('vars', type, vars);

  var node;
  Object.keys(vars).forEach(function(key) {
    // JSON.stringify throws on circular structures, lets remove those
    var val = traverse(vars[key]).map(function(node) {
      if (this.circular) {
        this.update('[Circular]');
      }
    });

    val = JSON.stringify(val);

    node = node || request.ele(type);

    node
      .ele('var')
      .att('key', key)
      .txt(val);
  });
};

Airbrake.prototype.cgiDataVars = function(err) {
  var cgiData = {};
  Object.keys(process.env).forEach(function(key) {
    cgiData[key] = process.env[key];
  });

  var errorEnv = (err.env instanceof Object)
    ? err.env
    : {};

  Object.keys(errorEnv).forEach(function(key) {
    cgiData[key] = err.env[key];
  });

  return cgiData;
};

Airbrake.prototype.sessionVars = function(err) {
  return (err.session instanceof Object)
    ? err.session
    : {};
};

Airbrake.prototype.paramsVars = function(err) {
  return (err.params instanceof Object)
    ? err.params
    : {};
};

Airbrake.prototype.appendServerEnvironmentXml = function(notice) {
  var serverEnvironment = notice.ele('server-environment');

  if (this.projectRoot) {
    serverEnvironment
      .ele('project-root')
      .txt(this.projectRoot);
  }

  serverEnvironment
      .ele('environment-name')
      .txt(this.env)

  if (this.appVersion) {
    serverEnvironment
      .ele('app-version')
      .txt(this.appVersion);
  }

  // This is not documented, but the Airbrake API told me about it when sending
  // some invalid data. Going to find out if they want people to use it first
  // before enabling.

  //if (this.hostname) {
    //serverEnvironment
      //.ele('hostname')
      //.txt(this.hostname);
  //}
};
<|endoftext|>


<commit_before>!function($) {

"use strict";

var FOUNDATION_VERSION = '6.2.4';

// Global Foundation object
// This is attached to the window, or used as a module for AMD/Browserify
var Foundation = {
  version: FOUNDATION_VERSION,

  /**
   * Stores initialized plugins.
   */
  _plugins: {},

  /**
   * Stores generated unique ids for plugin instances
   */
  _uuids: [],

  /**
   * Returns a boolean for RTL support
   */
  rtl: function(){
    return $('html').attr('dir') === 'rtl';
  },
  /**
   * Defines a Foundation plugin, adding it to the `Foundation` namespace and the list of plugins to initialize when reflowing.
   * @param {Object} plugin - The constructor of the plugin.
   */
  plugin: function(plugin, name) {
    // Object key to use when adding to global Foundation object
    // Examples: Foundation.Reveal, Foundation.OffCanvas
    var className = (name || functionName(plugin));
    // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin
    // Examples: data-reveal, data-off-canvas
    var attrName  = hyphenate(className);

    // Add to the Foundation object and the plugins list (for reflowing)
    this._plugins[attrName] = this[className] = plugin;
  },
  /**
   * @function
   * Populates the _uuids array with pointers to each individual plugin instance.
   * Adds the `zfPlugin` data-attribute to programmatically created plugins to allow use of $(selector).foundation(method) calls.
   * Also fires the initialization event for each plugin, consolidating repetitive code.
   * @param {Object} plugin - an instance of a plugin, usually `this` in context.
   * @param {String} name - the name of the plugin, passed as a camelCased string.
   * @fires Plugin#init
   */
  registerPlugin: function(plugin, name){
    var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase();
    plugin.uuid = this.GetYoDigits(6, pluginName);

    if(!plugin.$element.attr(`data-${pluginName}`)){ plugin.$element.attr(`data-${pluginName}`, plugin.uuid); }
    if(!plugin.$element.data('zfPlugin')){ plugin.$element.data('zfPlugin', plugin); }
          /**
           * Fires when the plugin has initialized.
           * @event Plugin#init
           */
    plugin.$element.trigger(`init.zf.${pluginName}`);

    this._uuids.push(plugin.uuid);

    return;
  },
  /**
   * @function
   * Removes the plugins uuid from the _uuids array.
   * Removes the zfPlugin data attribute, as well as the data-plugin-name attribute.
   * Also fires the destroyed event for the plugin, consolidating repetitive code.
   * @param {Object} plugin - an instance of a plugin, usually `this` in context.
   * @fires Plugin#destroyed
   */
  unregisterPlugin: function(plugin){
    var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor));

    this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1);
    plugin.$element.removeAttr(`data-${pluginName}`).removeData('zfPlugin')
          /**
           * Fires when the plugin has been destroyed.
           * @event Plugin#destroyed
           */
          .trigger(`destroyed.zf.${pluginName}`);
    for(var prop in plugin){
      plugin[prop] = null;//clean up script to prep for garbage collection.
    }
    return;
  },

  /**
   * @function
   * Causes one or more active plugins to re-initialize, resetting event listeners, recalculating positions, etc.
   * @param {String} plugins - optional string of an individual plugin key, attained by calling `$(element).data('pluginName')`, or string of a plugin class i.e. `'dropdown'`
   * @default If no argument is passed, reflow all currently active plugins.
   */
   reInit: function(plugins){
     var isJQ = plugins instanceof $;
     try{
       if(isJQ){
         plugins.each(function(){
           $(this).data('zfPlugin')._init();
         });
       }else{
         var type = typeof plugins,
         _this = this,
         fns = {
           'object': function(plgs){
             plgs.forEach(function(p){
               p = hyphenate(p);
               $('[data-'+ p +']').foundation('_init');
             });
           },
           'string': function(){
             plugins = hyphenate(plugins);
             $('[data-'+ plugins +']').foundation('_init');
           },
           'undefined': function(){
             this['object'](Object.keys(_this._plugins));
           }
         };
         fns[type](plugins);
       }
     }catch(err){
       console.error(err);
     }finally{
       return plugins;
     }
   },

  /**
   * returns a random base-36 uid with namespacing
   * @function
   * @param {Number} length - number of random base-36 digits desired. Increase for more random strings.
   * @param {String} namespace - name of plugin to be incorporated in uid, optional.
   * @default {String} '' - if no plugin name is provided, nothing is appended to the uid.
   * @returns {String} - unique id
   */
  GetYoDigits: function(length, namespace){
    length = length || 6;
    return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1) + (namespace ? `-${namespace}` : '');
  },
  /**
   * Initialize plugins on any elements within `elem` (and `elem` itself) that aren't already initialized.
   * @param {Object} elem - jQuery object containing the element to check inside. Also checks the element itself, unless it's the `document` object.
   * @param {String|Array} plugins - A list of plugins to initialize. Leave this out to initialize everything.
   */
  reflow: function(elem, plugins) {

    // If plugins is undefined, just grab everything
    if (typeof plugins === 'undefined') {
      plugins = Object.keys(this._plugins);
    }
    // If plugins is a string, convert it to an array with one item
    else if (typeof plugins === 'string') {
      plugins = [plugins];
    }

    var _this = this;

    // Iterate through each plugin
    $.each(plugins, function(i, name) {
      // Get the current plugin
      var plugin = _this._plugins[name];

      // Localize the search to all elements inside elem, as well as elem itself, unless elem === document
      var $elem = $(elem).find('[data-'+name+']').addBack('[data-'+name+']');

      // For each plugin found, initialize it
      $elem.each(function() {
        var $el = $(this),
            opts = {};
        // Don't double-dip on plugins
        if ($el.data('zfPlugin')) {
          console.warn("Tried to initialize "+name+" on an element that already has a Foundation plugin.");
          return;
        }

        if($el.attr('data-options')){
          var thing = $el.attr('data-options').split(';').forEach(function(e, i){
            var opt = e.split(':').map(function(el){ return el.trim(); });
            if(opt[0]) opts[opt[0]] = parseValue(opt[1]);
          });
        }
        try{
          $el.data('zfPlugin', new plugin($(this), opts));
        }catch(er){
          console.error(er);
        }finally{
          return;
        }
      });
    });
  },
  getFnName: functionName,
  transitionend: function($elem){
    var transitions = {
      'transition': 'transitionend',
      'WebkitTransition': 'webkitTransitionEnd',
      'MozTransition': 'transitionend',
      'OTransition': 'otransitionend'
    };
    var elem = document.createElement('div'),
        end;

    for (var t in transitions){
      if (typeof elem.style[t] !== 'undefined'){
        end = transitions[t];
      }
    }
    if(end){
      return end;
    }else{
      end = setTimeout(function(){
        $elem.triggerHandler('transitionend', [$elem]);
      }, 1);
      return 'transitionend';
    }
  }
};

Foundation.util = {
  /**
   * Function for applying a debounce effect to a function call.
   * @function
   * @param {Function} func - Function to be called at end of timeout.
   * @param {Number} delay - Time in ms to delay the call of `func`.
   * @returns function
   */
  throttle: function (func, delay) {
    var timer = null;

    return function () {
      var context = this, args = arguments;

      if (timer === null) {
        timer = setTimeout(function () {
          func.apply(context, args);
          timer = null;
        }, delay);
      }
    };
  }
};

// TODO: consider not making this a jQuery function
// TODO: need way to reflow vs. re-initialize
/**
 * The Foundation jQuery method.
 * @param {String|Array} method - An action to perform on the current jQuery object.
 */
var foundation = function(method) {
  var type = typeof method,
      $meta = $('meta.foundation-mq'),
      $noJS = $('.no-js');

  if(!$meta.length){
    $('<meta class="foundation-mq">').appendTo(document.head);
  }
  if($noJS.length){
    $noJS.removeClass('no-js');
  }

  if(type === 'undefined'){//needs to initialize the Foundation object, or an individual plugin.
    Foundation.MediaQuery._init();
    Foundation.reflow(this);
  }else if(type === 'string'){//an individual method to invoke on a plugin or group of plugins
    var args = Array.prototype.slice.call(arguments, 1);//collect all the arguments, if necessary
    var plugClass = this.data('zfPlugin');//determine the class of plugin

    if(plugClass !== undefined && plugClass[method] !== undefined){//make sure both the class and method exist
      if(this.length === 1){//if there's only one, call it directly.
          plugClass[method].apply(plugClass, args);
      }else{
        this.each(function(i, el){//otherwise loop through the jQuery collection and invoke the method on each
          plugClass[method].apply($(el).data('zfPlugin'), args);
        });
      }
    }else{//error for no class or no method
      throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.');
    }
  }else{//error for invalid argument type
    throw new TypeError(`We're sorry, ${type} is not a valid parameter. You must use a string representing the method you wish to invoke.`);
  }
  return this;
};

window.Foundation = Foundation;
$.fn.foundation = foundation;

// Polyfill for requestAnimationFrame
(function() {
  if (!Date.now || !window.Date.now)
    window.Date.now = Date.now = function() { return new Date().getTime(); };

  var vendors = ['webkit', 'moz'];
  for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
      var vp = vendors[i];
      window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
      window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                 || window[vp+'CancelRequestAnimationFrame']);
  }
  if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent)
    || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
    var lastTime = 0;
    window.requestAnimationFrame = function(callback) {
        var now = Date.now();
        var nextTime = Math.max(lastTime + 16, now);
        return setTimeout(function() { callback(lastTime = nextTime); },
                          nextTime - now);
    };
    window.cancelAnimationFrame = clearTimeout;
  }
  /**
   * Polyfill for performance.now, required by rAF
   */
  if(!window.performance || !window.performance.now){
    window.performance = {
      start: Date.now(),
      now: function(){ return Date.now() - this.start; }
    };
  }
})();
if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // native functions don't have a prototype
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}
// Polyfill to get the name of a function in IE9
function functionName(fn) {
  if (Function.prototype.name === undefined) {
    var funcNameRegex = /function\s([^(]{1,})\(/;
    var results = (funcNameRegex).exec((fn).toString());
    return (results && results.length > 1) ? results[1].trim() : "";
  }
  else if (fn.prototype === undefined) {
    return fn.constructor.name;
  }
  else {
    return fn.prototype.constructor.name;
  }
}
function parseValue(str){
  if(/true/.test(str)) return true;
  else if(/false/.test(str)) return false;
  else if(!isNaN(str * 1)) return parseFloat(str);
  return str;
}
// Convert PascalCase to kebab-case
// Thank you: http://stackoverflow.com/a/8955580
function hyphenate(str) {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

}(jQuery);
<commit_msg>parseValue() full match with string literals<commit_after>!function($) {

"use strict";

var FOUNDATION_VERSION = '6.2.4';

// Global Foundation object
// This is attached to the window, or used as a module for AMD/Browserify
var Foundation = {
  version: FOUNDATION_VERSION,

  /**
   * Stores initialized plugins.
   */
  _plugins: {},

  /**
   * Stores generated unique ids for plugin instances
   */
  _uuids: [],

  /**
   * Returns a boolean for RTL support
   */
  rtl: function(){
    return $('html').attr('dir') === 'rtl';
  },
  /**
   * Defines a Foundation plugin, adding it to the `Foundation` namespace and the list of plugins to initialize when reflowing.
   * @param {Object} plugin - The constructor of the plugin.
   */
  plugin: function(plugin, name) {
    // Object key to use when adding to global Foundation object
    // Examples: Foundation.Reveal, Foundation.OffCanvas
    var className = (name || functionName(plugin));
    // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin
    // Examples: data-reveal, data-off-canvas
    var attrName  = hyphenate(className);

    // Add to the Foundation object and the plugins list (for reflowing)
    this._plugins[attrName] = this[className] = plugin;
  },
  /**
   * @function
   * Populates the _uuids array with pointers to each individual plugin instance.
   * Adds the `zfPlugin` data-attribute to programmatically created plugins to allow use of $(selector).foundation(method) calls.
   * Also fires the initialization event for each plugin, consolidating repetitive code.
   * @param {Object} plugin - an instance of a plugin, usually `this` in context.
   * @param {String} name - the name of the plugin, passed as a camelCased string.
   * @fires Plugin#init
   */
  registerPlugin: function(plugin, name){
    var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase();
    plugin.uuid = this.GetYoDigits(6, pluginName);

    if(!plugin.$element.attr(`data-${pluginName}`)){ plugin.$element.attr(`data-${pluginName}`, plugin.uuid); }
    if(!plugin.$element.data('zfPlugin')){ plugin.$element.data('zfPlugin', plugin); }
          /**
           * Fires when the plugin has initialized.
           * @event Plugin#init
           */
    plugin.$element.trigger(`init.zf.${pluginName}`);

    this._uuids.push(plugin.uuid);

    return;
  },
  /**
   * @function
   * Removes the plugins uuid from the _uuids array.
   * Removes the zfPlugin data attribute, as well as the data-plugin-name attribute.
   * Also fires the destroyed event for the plugin, consolidating repetitive code.
   * @param {Object} plugin - an instance of a plugin, usually `this` in context.
   * @fires Plugin#destroyed
   */
  unregisterPlugin: function(plugin){
    var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor));

    this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1);
    plugin.$element.removeAttr(`data-${pluginName}`).removeData('zfPlugin')
          /**
           * Fires when the plugin has been destroyed.
           * @event Plugin#destroyed
           */
          .trigger(`destroyed.zf.${pluginName}`);
    for(var prop in plugin){
      plugin[prop] = null;//clean up script to prep for garbage collection.
    }
    return;
  },

  /**
   * @function
   * Causes one or more active plugins to re-initialize, resetting event listeners, recalculating positions, etc.
   * @param {String} plugins - optional string of an individual plugin key, attained by calling `$(element).data('pluginName')`, or string of a plugin class i.e. `'dropdown'`
   * @default If no argument is passed, reflow all currently active plugins.
   */
   reInit: function(plugins){
     var isJQ = plugins instanceof $;
     try{
       if(isJQ){
         plugins.each(function(){
           $(this).data('zfPlugin')._init();
         });
       }else{
         var type = typeof plugins,
         _this = this,
         fns = {
           'object': function(plgs){
             plgs.forEach(function(p){
               p = hyphenate(p);
               $('[data-'+ p +']').foundation('_init');
             });
           },
           'string': function(){
             plugins = hyphenate(plugins);
             $('[data-'+ plugins +']').foundation('_init');
           },
           'undefined': function(){
             this['object'](Object.keys(_this._plugins));
           }
         };
         fns[type](plugins);
       }
     }catch(err){
       console.error(err);
     }finally{
       return plugins;
     }
   },

  /**
   * returns a random base-36 uid with namespacing
   * @function
   * @param {Number} length - number of random base-36 digits desired. Increase for more random strings.
   * @param {String} namespace - name of plugin to be incorporated in uid, optional.
   * @default {String} '' - if no plugin name is provided, nothing is appended to the uid.
   * @returns {String} - unique id
   */
  GetYoDigits: function(length, namespace){
    length = length || 6;
    return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1) + (namespace ? `-${namespace}` : '');
  },
  /**
   * Initialize plugins on any elements within `elem` (and `elem` itself) that aren't already initialized.
   * @param {Object} elem - jQuery object containing the element to check inside. Also checks the element itself, unless it's the `document` object.
   * @param {String|Array} plugins - A list of plugins to initialize. Leave this out to initialize everything.
   */
  reflow: function(elem, plugins) {

    // If plugins is undefined, just grab everything
    if (typeof plugins === 'undefined') {
      plugins = Object.keys(this._plugins);
    }
    // If plugins is a string, convert it to an array with one item
    else if (typeof plugins === 'string') {
      plugins = [plugins];
    }

    var _this = this;

    // Iterate through each plugin
    $.each(plugins, function(i, name) {
      // Get the current plugin
      var plugin = _this._plugins[name];

      // Localize the search to all elements inside elem, as well as elem itself, unless elem === document
      var $elem = $(elem).find('[data-'+name+']').addBack('[data-'+name+']');

      // For each plugin found, initialize it
      $elem.each(function() {
        var $el = $(this),
            opts = {};
        // Don't double-dip on plugins
        if ($el.data('zfPlugin')) {
          console.warn("Tried to initialize "+name+" on an element that already has a Foundation plugin.");
          return;
        }

        if($el.attr('data-options')){
          var thing = $el.attr('data-options').split(';').forEach(function(e, i){
            var opt = e.split(':').map(function(el){ return el.trim(); });
            if(opt[0]) opts[opt[0]] = parseValue(opt[1]);
          });
        }
        try{
          $el.data('zfPlugin', new plugin($(this), opts));
        }catch(er){
          console.error(er);
        }finally{
          return;
        }
      });
    });
  },
  getFnName: functionName,
  transitionend: function($elem){
    var transitions = {
      'transition': 'transitionend',
      'WebkitTransition': 'webkitTransitionEnd',
      'MozTransition': 'transitionend',
      'OTransition': 'otransitionend'
    };
    var elem = document.createElement('div'),
        end;

    for (var t in transitions){
      if (typeof elem.style[t] !== 'undefined'){
        end = transitions[t];
      }
    }
    if(end){
      return end;
    }else{
      end = setTimeout(function(){
        $elem.triggerHandler('transitionend', [$elem]);
      }, 1);
      return 'transitionend';
    }
  }
};

Foundation.util = {
  /**
   * Function for applying a debounce effect to a function call.
   * @function
   * @param {Function} func - Function to be called at end of timeout.
   * @param {Number} delay - Time in ms to delay the call of `func`.
   * @returns function
   */
  throttle: function (func, delay) {
    var timer = null;

    return function () {
      var context = this, args = arguments;

      if (timer === null) {
        timer = setTimeout(function () {
          func.apply(context, args);
          timer = null;
        }, delay);
      }
    };
  }
};

// TODO: consider not making this a jQuery function
// TODO: need way to reflow vs. re-initialize
/**
 * The Foundation jQuery method.
 * @param {String|Array} method - An action to perform on the current jQuery object.
 */
var foundation = function(method) {
  var type = typeof method,
      $meta = $('meta.foundation-mq'),
      $noJS = $('.no-js');

  if(!$meta.length){
    $('<meta class="foundation-mq">').appendTo(document.head);
  }
  if($noJS.length){
    $noJS.removeClass('no-js');
  }

  if(type === 'undefined'){//needs to initialize the Foundation object, or an individual plugin.
    Foundation.MediaQuery._init();
    Foundation.reflow(this);
  }else if(type === 'string'){//an individual method to invoke on a plugin or group of plugins
    var args = Array.prototype.slice.call(arguments, 1);//collect all the arguments, if necessary
    var plugClass = this.data('zfPlugin');//determine the class of plugin

    if(plugClass !== undefined && plugClass[method] !== undefined){//make sure both the class and method exist
      if(this.length === 1){//if there's only one, call it directly.
          plugClass[method].apply(plugClass, args);
      }else{
        this.each(function(i, el){//otherwise loop through the jQuery collection and invoke the method on each
          plugClass[method].apply($(el).data('zfPlugin'), args);
        });
      }
    }else{//error for no class or no method
      throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.');
    }
  }else{//error for invalid argument type
    throw new TypeError(`We're sorry, ${type} is not a valid parameter. You must use a string representing the method you wish to invoke.`);
  }
  return this;
};

window.Foundation = Foundation;
$.fn.foundation = foundation;

// Polyfill for requestAnimationFrame
(function() {
  if (!Date.now || !window.Date.now)
    window.Date.now = Date.now = function() { return new Date().getTime(); };

  var vendors = ['webkit', 'moz'];
  for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
      var vp = vendors[i];
      window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
      window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                 || window[vp+'CancelRequestAnimationFrame']);
  }
  if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent)
    || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
    var lastTime = 0;
    window.requestAnimationFrame = function(callback) {
        var now = Date.now();
        var nextTime = Math.max(lastTime + 16, now);
        return setTimeout(function() { callback(lastTime = nextTime); },
                          nextTime - now);
    };
    window.cancelAnimationFrame = clearTimeout;
  }
  /**
   * Polyfill for performance.now, required by rAF
   */
  if(!window.performance || !window.performance.now){
    window.performance = {
      start: Date.now(),
      now: function(){ return Date.now() - this.start; }
    };
  }
})();
if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // native functions don't have a prototype
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}
// Polyfill to get the name of a function in IE9
function functionName(fn) {
  if (Function.prototype.name === undefined) {
    var funcNameRegex = /function\s([^(]{1,})\(/;
    var results = (funcNameRegex).exec((fn).toString());
    return (results && results.length > 1) ? results[1].trim() : "";
  }
  else if (fn.prototype === undefined) {
    return fn.constructor.name;
  }
  else {
    return fn.prototype.constructor.name;
  }
}
function parseValue(str){
  if('true' === str) return true;
  else if('false' === str) return false;
  else if(!isNaN(str * 1)) return parseFloat(str);
  return str;
}
// Convert PascalCase to kebab-case
// Thank you: http://stackoverflow.com/a/8955580
function hyphenate(str) {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

}(jQuery);
<|endoftext|>


<commit_before>var http = require('http'),
    fs = require('fs'),
    pathlib = require('path'),
    uri = require('url'),
    mime = require('./content-type'),
    log = require('./log'),
    package = JSON.parse(fs.readFileSync(__dirname+'/../package.json', 'utf8')),
    sys = require('sys'),
    Script = process.binding('evals').Script;

exports.default_settings = {
    "timeout_milliseconds": 1000 * 30,
    "hosts" : {},
    "port" : 8080, /* a port that you don't need root to bind to */
    "default_host" : {
        "root" : process.cwd()
    },
    "log_level" : log.levels.DEBUG
};
exports.log_levels = log.levels;

var settings;

var server;

/* require() all the scripts at the start, so there's no
 * waiting for in the middle of a request */
function load_hostspecific_handlers() {
    for (var host in settings.hosts) {
        var script = settings.hosts[host]['handler'];
        if (script !== undefined && typeof script === 'string') {
            /* remove filename extension */
            var require_name = script.match(/(.*)\..*/)[1];
            settings.hosts[host].handler = require(require_name);
        }
    }
}

/* call the module_init method if exists on each registered module.
   allows modules to hook in to the server startup event. */
function handlers_init() {
    for(var host in settings.hosts) {
        if(settings.hosts[host].handler && settings.hosts[host].handler.handler_init) {
            settings.hosts[host].handler.handler_init();
        }
    }
}

/* default preprocessor - just send the file out */
var preprocess_request = map_request_to_local_file;

exports.start = function(custom_settings, callback) {
    settings = custom_settings || {};
    settings.__proto__ = exports.default_settings;

    load_hostspecific_handlers();
    if (settings.request_preprocessor) {
        preprocess_request = settings.request_preprocessor;
    }

    log.level = settings.log_level;
    log.info( "Starting server on port", settings.port);

    server = http.createServer(function(req,resp) {
        log.debug("Request from", req.connection.remoteAddress, "for", req.url);
        log.debug(JSON.stringify(req.headers));
        preprocess_request(req, resp, map_request_to_local_file);
    });
    server.listen(settings.port);
    handlers_init();
    server.addListener('listening', function() {
        if (callback) callback();
    });
    server.addListener('connection', function(connection) {
        connection.setTimeout(settings.timeout_milliseconds);
        connection.addListener('timeout', function() {
            log.debug("Connection from",connection.remoteAddress,"timed out. Closing it...");
            connection.destroy();
        });
    });
};

/* decides which file on our file system the request is asking for
 * then dispatch to stream_file to send it out */
function map_request_to_local_file(req, resp) {
    var url = uri.parse(req.url);
    //if the parsed url doesn't have a pathname, default to '/'
    var pathname = (url.pathname || '/');
    var clean_pathname = pathname.
        replace(/\.\.\//g,''). //disallow parent directory access
            replace(/\%20/g,' ');  //convert spaces

    function select_vhost() {
        if (req.headers.host) {
            var hostname = req.headers.host.split(':')[0]; //remove port
            return settings.hosts[hostname] || settings.default_host;
        } else {
            return settings.default_host;
        }
    }
    var vhost = select_vhost(req.headers.host);
    if (vhost.handler && vhost.handler.handle) {
        var action = vhost.handler.handle(req,resp);
        if(action && typeof action === 'function') {
            if(vhost.handler.handler_environment){
                action.apply(vhost.handler.handler_environment(req, resp))
            }
            else {
                action(req, resp);
            }
            return;
        }
    }
    var path = pathlib.join(vhost.root, clean_pathname);
    if (path.match(/\.sjs$/)) {
        execute_sjs(path, req, resp);
    } else {
        serve_static_file(path, req, resp);
    }
}

exports.stop = function(callback) {
    if (server) {
        if (callback) server.addListener('close', callback);
        server.close();
    }
};

function serve_static_file(path, req, resp) {
    function send_headers(httpstatus, headers) {
        headers = headers || {};
        headers["Server"] = "Antinode/"+package.version+" Node.js/"+process.version;
        headers["Date"] = (new Date()).toUTCString();

        resp.writeHead(httpstatus, headers);
    }

    fs.stat(path, function (err, stats) {
        if (err) {
            // ENOENT is normal on 'file not found'
            if (err.errno != process.ENOENT) {
                // any other error is abnormal - log it
                log.error("fs.stat(",path,") failed: ", err);
            }
            return file_not_found();
        }
        if (stats.isDirectory()) {
            if (req.url.match(/\/$/)) {
                return serve_static_file(pathlib.join(path, "index.html"), req, resp);
            }
            else {
                var redirect_host = req.headers.host ? ('http://' + req.headers['host']) : '';
                return redirect_302_found(redirect_host + req.url + '/');
            }
        }
        if (!stats.isFile()) {
            return file_not_found();
        } else {
            var if_modified_since = req.headers['if-modified-since'];
            if (if_modified_since) {
                var req_date = new Date(if_modified_since);
                if (stats.mtime <= req_date && req_date <= Date.now()) {
                    return not_modified();
                }
                else stream_file(path, stats);
            } else if (req.method == 'HEAD') {
                send_headers(200, {
                    'Content-Length':stats.size,
                    'Content-Type':mime.mime_type(path),
                    'Last-Modified': stats.mtime
                });
                resp.end('');
            } else {
                return stream_file(path, stats);
            }
        }
    });

    function stream_file(file, stats) {
        try {
            var readStream = fs.createReadStream(file);
        }
        catch (err) {
            log.debug("fs.createReadStream(",file,") error: ",sys.inspect(err,true));
            return file_not_found();
        }

        send_headers(200, {
            'Content-Length':stats.size,
            'Content-Type':mime.mime_type(file),
            'Last-Modified':stats.mtime
        });
        sys.pump(readStream, resp, function() {
            log.debug('pumped',file);
        });

        req.connection.addListener('timeout', function() {
            /* dont destroy it when the fd's already closed */
            if (readStream.readable) {
                log.debug('timed out. destroying file read stream');
                readStream.destroy();
            }
        });

        readStream.addListener('fd', function(fd) {
            log.debug("opened",path,"on fd",fd);
        });

        readStream.addListener('error', function (err) {
            log.error('error reading',file,sys.inspect(err));
            resp.end('');
        });
        resp.addListener('error', function (err) {
            log.error('error writing',file,sys.inspect(err));
            readStream.destroy();
        });
    }

    function not_modified() {
        // no need to send content length or type
        log.debug("304 for resource ", path);
        send_headers(304);
        resp.end('');
    }

    function file_not_found() {
        log.debug("404 opening path: '"+path+"'");
        var body = "404: " + req.url + " not found.\n";
        send_headers(404,{
            'Content-Length':body.length,
            'Content-Type':"text/plain"
        });
        if (req.method != 'HEAD') {
            resp.end(body, 'utf-8');
        } else {
            resp.end('');
        }
    }

    function server_error(message) {
        log.error(message);
        send_headers(500, {
            'Content-Length':message.length,
            'Content-Type':"text/plain"
        });
        if (req.method !== 'HEAD') {
            resp.end(message,'utf-8');
        }
    }

    function redirect_302_found(location) {
        log.debug('redirecting with "302 Found" to ' + location);
        send_headers(302, {
            'Location' : location
        });
        resp.end('');
    }
}

function execute_sjs(path, req, resp) {
    fs.readFile(path, 'utf8', function(err, script) {
        try {
            if (err) throw err;
            var sandbox = {
                log: log,
                require: require,
                __filename: path,
                __dirname: pathlib.dirname(path)
            };
            Script.runInNewContext(script, sandbox, path);
            sandbox.handle(req, resp);
        }
        catch (e) {
            resp.writeHead(500,{'Content-Type':'text/plain'});
            resp.end("Error executing server script "+path+": "+e);
        }
    });
}

function close(fd) {
    fs.close(fd);
    log.debug("closed fd",fd);
}
<commit_msg>Fixed invalid redirect when accessing a directory with a query string.<commit_after>var http = require('http'),
    fs = require('fs'),
    pathlib = require('path'),
    uri = require('url'),
    mime = require('./content-type'),
    log = require('./log'),
    package = JSON.parse(fs.readFileSync(__dirname+'/../package.json', 'utf8')),
    sys = require('sys'),
    Script = process.binding('evals').Script;

exports.default_settings = {
    "timeout_milliseconds": 1000 * 30,
    "hosts" : {},
    "port" : 8080, /* a port that you don't need root to bind to */
    "default_host" : {
        "root" : process.cwd()
    },
    "log_level" : log.levels.DEBUG
};
exports.log_levels = log.levels;

var settings;

var server;

/* require() all the scripts at the start, so there's no
 * waiting for in the middle of a request */
function load_hostspecific_handlers() {
    for (var host in settings.hosts) {
        var script = settings.hosts[host]['handler'];
        if (script !== undefined && typeof script === 'string') {
            /* remove filename extension */
            var require_name = script.match(/(.*)\..*/)[1];
            settings.hosts[host].handler = require(require_name);
        }
    }
}

/* call the module_init method if exists on each registered module.
   allows modules to hook in to the server startup event. */
function handlers_init() {
    for(var host in settings.hosts) {
        if(settings.hosts[host].handler && settings.hosts[host].handler.handler_init) {
            settings.hosts[host].handler.handler_init();
        }
    }
}

/* default preprocessor - just send the file out */
var preprocess_request = map_request_to_local_file;

exports.start = function(custom_settings, callback) {
    settings = custom_settings || {};
    settings.__proto__ = exports.default_settings;

    load_hostspecific_handlers();
    if (settings.request_preprocessor) {
        preprocess_request = settings.request_preprocessor;
    }

    log.level = settings.log_level;
    log.info( "Starting server on port", settings.port);

    server = http.createServer(function(req,resp) {
        log.debug("Request from", req.connection.remoteAddress, "for", req.url);
        log.debug(JSON.stringify(req.headers));
        preprocess_request(req, resp, map_request_to_local_file);
    });
    server.listen(settings.port);
    handlers_init();
    server.addListener('listening', function() {
        if (callback) callback();
    });
    server.addListener('connection', function(connection) {
        connection.setTimeout(settings.timeout_milliseconds);
        connection.addListener('timeout', function() {
            log.debug("Connection from",connection.remoteAddress,"timed out. Closing it...");
            connection.destroy();
        });
    });
};

/* decides which file on our file system the request is asking for
 * then dispatch to stream_file to send it out */
function map_request_to_local_file(req, resp) {
    var url = uri.parse(req.url);
    //if the parsed url doesn't have a pathname, default to '/'
    var pathname = (url.pathname || '/');
    var clean_pathname = pathname.
        replace(/\.\.\//g,''). //disallow parent directory access
            replace(/\%20/g,' ');  //convert spaces

    function select_vhost() {
        if (req.headers.host) {
            var hostname = req.headers.host.split(':')[0]; //remove port
            return settings.hosts[hostname] || settings.default_host;
        } else {
            return settings.default_host;
        }
    }
    var vhost = select_vhost(req.headers.host);
    if (vhost.handler && vhost.handler.handle) {
        var action = vhost.handler.handle(req,resp);
        if(action && typeof action === 'function') {
            if(vhost.handler.handler_environment){
                action.apply(vhost.handler.handler_environment(req, resp))
            }
            else {
                action(req, resp);
            }
            return;
        }
    }
    var path = pathlib.join(vhost.root, clean_pathname);
    if (path.match(/\.sjs$/)) {
        execute_sjs(path, req, resp);
    } else {
        serve_static_file(path, req, resp);
    }
}

exports.stop = function(callback) {
    if (server) {
        if (callback) server.addListener('close', callback);
        server.close();
    }
};

function serve_static_file(path, req, resp) {
    function send_headers(httpstatus, headers) {
        headers = headers || {};
        headers["Server"] = "Antinode/"+package.version+" Node.js/"+process.version;
        headers["Date"] = (new Date()).toUTCString();

        resp.writeHead(httpstatus, headers);
    }

    fs.stat(path, function (err, stats) {
        if (err) {
            // ENOENT is normal on 'file not found'
            if (err.errno != process.ENOENT) {
                // any other error is abnormal - log it
                log.error("fs.stat(",path,") failed: ", err);
            }
            return file_not_found();
        }
        if (stats.isDirectory()) {
            var parsed_url = uri.parse(req.url);
            if (parsed_url.pathname.match(/\/$/)) {
                return serve_static_file(pathlib.join(path, "index.html"), req, resp);
            }
            else {
                var redirect_host = req.headers.host ? ('http://' + req.headers['host']) : '';
                var redirect_path = parsed_url.pathname + "/" + (parsed_url.search || "");
                return redirect_302_found(redirect_host + redirect_path);
            }
        }
        if (!stats.isFile()) {
            return file_not_found();
        } else {
            var if_modified_since = req.headers['if-modified-since'];
            if (if_modified_since) {
                var req_date = new Date(if_modified_since);
                if (stats.mtime <= req_date && req_date <= Date.now()) {
                    return not_modified();
                }
                else stream_file(path, stats);
            } else if (req.method == 'HEAD') {
                send_headers(200, {
                    'Content-Length':stats.size,
                    'Content-Type':mime.mime_type(path),
                    'Last-Modified': stats.mtime
                });
                resp.end('');
            } else {
                return stream_file(path, stats);
            }
        }
    });

    function stream_file(file, stats) {
        try {
            var readStream = fs.createReadStream(file);
        }
        catch (err) {
            log.debug("fs.createReadStream(",file,") error: ",sys.inspect(err,true));
            return file_not_found();
        }

        send_headers(200, {
            'Content-Length':stats.size,
            'Content-Type':mime.mime_type(file),
            'Last-Modified':stats.mtime
        });
        sys.pump(readStream, resp, function() {
            log.debug('pumped',file);
        });

        req.connection.addListener('timeout', function() {
            /* dont destroy it when the fd's already closed */
            if (readStream.readable) {
                log.debug('timed out. destroying file read stream');
                readStream.destroy();
            }
        });

        readStream.addListener('fd', function(fd) {
            log.debug("opened",path,"on fd",fd);
        });

        readStream.addListener('error', function (err) {
            log.error('error reading',file,sys.inspect(err));
            resp.end('');
        });
        resp.addListener('error', function (err) {
            log.error('error writing',file,sys.inspect(err));
            readStream.destroy();
        });
    }

    function not_modified() {
        // no need to send content length or type
        log.debug("304 for resource ", path);
        send_headers(304);
        resp.end('');
    }

    function file_not_found() {
        log.debug("404 opening path: '"+path+"'");
        var body = "404: " + req.url + " not found.\n";
        send_headers(404,{
            'Content-Length':body.length,
            'Content-Type':"text/plain"
        });
        if (req.method != 'HEAD') {
            resp.end(body, 'utf-8');
        } else {
            resp.end('');
        }
    }

    function server_error(message) {
        log.error(message);
        send_headers(500, {
            'Content-Length':message.length,
            'Content-Type':"text/plain"
        });
        if (req.method !== 'HEAD') {
            resp.end(message,'utf-8');
        }
    }

    function redirect_302_found(location) {
        log.debug('redirecting with "302 Found" to ' + location);
        send_headers(302, {
            'Location' : location
        });
        resp.end('');
    }
}

function execute_sjs(path, req, resp) {
    fs.readFile(path, 'utf8', function(err, script) {
        try {
            if (err) throw err;
            var sandbox = {
                log: log,
                require: require,
                __filename: path,
                __dirname: pathlib.dirname(path)
            };
            Script.runInNewContext(script, sandbox, path);
            sandbox.handle(req, resp);
        }
        catch (e) {
            resp.writeHead(500,{'Content-Type':'text/plain'});
            resp.end("Error executing server script "+path+": "+e);
        }
    });
}

function close(fd) {
    fs.close(fd);
    log.debug("closed fd",fd);
}
<|endoftext|>


<commit_before>/**
 * Blueprint API Configuration
 * (sails.config.blueprints)
 *
 * These settings are for the global configuration of blueprint routes and
 * request options (which impact the behavior of blueprint actions).
 *
 * You may also override any of these settings on a per-controller basis
 * by defining a '_config' key in your controller defintion, and assigning it
 * a configuration object with overrides for the settings in this file.
 * A lot of the configuration options below affect so-called "CRUD methods",
 * or your controllers' `find`, `create`, `update`, and `destroy` actions.
 *
 * It's important to realize that, even if you haven't defined these yourself, as long as
 * a model exists with the same name as the controller, Sails will respond with built-in CRUD
 * logic in the form of a JSON API, including support for sort, pagination, and filtering.
 *
 * For more information on the blueprint API, check out:
 * http://sailsjs.org/#/documentation/reference/blueprint-api
 *
 * For more information on the settings in this file, see:
 * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.blueprints.html
 *
 */

module.exports.blueprints = {

  /***************************************************************************
  *                                                                          *
  * Action routes speed up the backend development workflow by               *
  * eliminating the need to manually bind routes. When enabled, GET, POST,   *
  * PUT, and DELETE routes will be generated for every one of a controller's *
  * actions.                                                                 *
  *                                                                          *
  * If an `index` action exists, additional naked routes will be created for *
  * it. Finally, all `actions` blueprints support an optional path           *
  * parameter, `id`, for convenience.                                        *
  *                                                                          *
  * `actions` are enabled by default, and can be OK for production--         *
  * however, if you'd like to continue to use controller/action autorouting  *
  * in a production deployment, you must take great care not to              *
  * inadvertently expose unsafe/unintentional controller logic to GET        *
  * requests.                                                                *
  *                                                                          *
  ***************************************************************************/

  // actions: true,

  /***************************************************************************
  *                                                                          *
  * RESTful routes (`sails.config.blueprints.rest`)                          *
  *                                                                          *
  * REST blueprints are the automatically generated routes Sails uses to     *
  * expose a conventional REST API on top of a controller's `find`,          *
  * `create`, `update`, and `destroy` actions.                               *
  *                                                                          *
  * For example, a BoatController with `rest` enabled generates the          *
  * following routes:                                                        *
  * :::::::::::::::::::::::::::::::::::::::::::::::::::::::                  *
  *  GET /boat/:id? -> BoatController.find                                   *
  *  POST /boat -> BoatController.create                                     *
  *  PUT /boat/:id -> BoatController.update                                  *
  *  DELETE /boat/:id -> BoatController.destroy                              *
  *                                                                          *
  * `rest` blueprint routes are enabled by default, and are suitable for use *
  * in a production scenario, as long you take standard security precautions *
  * (combine w/ policies, etc.)                                              *
  *                                                                          *
  ***************************************************************************/

  // rest: true,

  /***************************************************************************
  *                                                                          *
  * Shortcut routes are simple helpers to provide access to a                *
  * controller's CRUD methods from your browser's URL bar. When enabled,     *
  * GET, POST, PUT, and DELETE routes will be generated for the              *
  * controller's`find`, `create`, `update`, and `destroy` actions.           *
  *                                                                          *
  * `shortcuts` are enabled by default, but should be disabled in            *
  * production.                                                              *
  *                                                                          *
  ***************************************************************************/

  // shortcuts: true,

  /***************************************************************************
  *                                                                          *
  * An optional mount path for all blueprint routes on a controller,         *
  * including `rest`, `actions`, and `shortcuts`. This allows you to take    *
  * advantage of blueprint routing, even if you need to namespace your API   *
  * methods.                                                                 *
  *                                                                          *
  * (NOTE: This only applies to blueprint autoroutes, not manual routes from *
  * `sails.config.routes`)                                                   *
  *                                                                          *
  ***************************************************************************/

  // prefix: '',

  /***************************************************************************
  *                                                                          *
  * Whether to pluralize controller names in blueprint routes.               *
  *                                                                          *
  * (NOTE: This only applies to blueprint autoroutes, not manual routes from *
  * `sails.config.routes`)                                                   *
  *                                                                          *
  * For example, REST blueprints for `FooController` with `pluralize`        *
  * enabled:                                                                 *
  * GET /foos/:id?                                                           *
  * POST /foos                                                               *
  * PUT /foos/:id?                                                           *
  * DELETE /foos/:id?                                                        *
  *                                                                          *
  ***************************************************************************/

  // pluralize: false,

  /***************************************************************************
  *                                                                          *
  * Whether the blueprint controllers should populate model fetches with     *
  * data from other models which are linked by associations                  *
  *                                                                          *
  * If you have a lot of data in one-to-many associations, leaving this on   *
  * may result in very heavy api calls                                       *
  *                                                                          *
  ***************************************************************************/

  // populate: true,

  /****************************************************************************
  *                                                                           *
  * Whether to run Model.watch() in the find and findOne blueprint actions.   *
  * Can be overridden on a per-model basis.                                   *
  *                                                                           *
  ****************************************************************************/

  // autoWatch: true,

  /****************************************************************************
  *                                                                           *
  * The default number of records to show in the response from a "find"       *
  * action. Doubles as the default size of populated arrays if populate is    *
  * true.                                                                     *
  *                                                                           *
  ****************************************************************************/

  // defaultLimit: 30

};
<commit_msg>Configure server-side api routes to read /api/[resources]/:id<commit_after>/**
 * Blueprint API Configuration
 * (sails.config.blueprints)
 *
 * These settings are for the global configuration of blueprint routes and
 * request options (which impact the behavior of blueprint actions).
 *
 * You may also override any of these settings on a per-controller basis
 * by defining a '_config' key in your controller defintion, and assigning it
 * a configuration object with overrides for the settings in this file.
 * A lot of the configuration options below affect so-called "CRUD methods",
 * or your controllers' `find`, `create`, `update`, and `destroy` actions.
 *
 * It's important to realize that, even if you haven't defined these yourself, as long as
 * a model exists with the same name as the controller, Sails will respond with built-in CRUD
 * logic in the form of a JSON API, including support for sort, pagination, and filtering.
 *
 * For more information on the blueprint API, check out:
 * http://sailsjs.org/#/documentation/reference/blueprint-api
 *
 * For more information on the settings in this file, see:
 * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.blueprints.html
 *
 */

module.exports.blueprints = {

  /***************************************************************************
  *                                                                          *
  * Action routes speed up the backend development workflow by               *
  * eliminating the need to manually bind routes. When enabled, GET, POST,   *
  * PUT, and DELETE routes will be generated for every one of a controller's *
  * actions.                                                                 *
  *                                                                          *
  * If an `index` action exists, additional naked routes will be created for *
  * it. Finally, all `actions` blueprints support an optional path           *
  * parameter, `id`, for convenience.                                        *
  *                                                                          *
  * `actions` are enabled by default, and can be OK for production--         *
  * however, if you'd like to continue to use controller/action autorouting  *
  * in a production deployment, you must take great care not to              *
  * inadvertently expose unsafe/unintentional controller logic to GET        *
  * requests.                                                                *
  *                                                                          *
  ***************************************************************************/

  // actions: true,

  /***************************************************************************
  *                                                                          *
  * RESTful routes (`sails.config.blueprints.rest`)                          *
  *                                                                          *
  * REST blueprints are the automatically generated routes Sails uses to     *
  * expose a conventional REST API on top of a controller's `find`,          *
  * `create`, `update`, and `destroy` actions.                               *
  *                                                                          *
  * For example, a BoatController with `rest` enabled generates the          *
  * following routes:                                                        *
  * :::::::::::::::::::::::::::::::::::::::::::::::::::::::                  *
  *  GET /boat/:id? -> BoatController.find                                   *
  *  POST /boat -> BoatController.create                                     *
  *  PUT /boat/:id -> BoatController.update                                  *
  *  DELETE /boat/:id -> BoatController.destroy                              *
  *                                                                          *
  * `rest` blueprint routes are enabled by default, and are suitable for use *
  * in a production scenario, as long you take standard security precautions *
  * (combine w/ policies, etc.)                                              *
  *                                                                          *
  ***************************************************************************/

  // rest: true,

  /***************************************************************************
  *                                                                          *
  * Shortcut routes are simple helpers to provide access to a                *
  * controller's CRUD methods from your browser's URL bar. When enabled,     *
  * GET, POST, PUT, and DELETE routes will be generated for the              *
  * controller's`find`, `create`, `update`, and `destroy` actions.           *
  *                                                                          *
  * `shortcuts` are enabled by default, but should be disabled in            *
  * production.                                                              *
  *                                                                          *
  ***************************************************************************/

  // shortcuts: true,

  /***************************************************************************
  *                                                                          *
  * An optional mount path for all blueprint routes on a controller,         *
  * including `rest`, `actions`, and `shortcuts`. This allows you to take    *
  * advantage of blueprint routing, even if you need to namespace your API   *
  * methods.                                                                 *
  *                                                                          *
  * (NOTE: This only applies to blueprint autoroutes, not manual routes from *
  * `sails.config.routes`)                                                   *
  *                                                                          *
  ***************************************************************************/

  prefix: '/api',

  /***************************************************************************
  *                                                                          *
  * Whether to pluralize controller names in blueprint routes.               *
  *                                                                          *
  * (NOTE: This only applies to blueprint autoroutes, not manual routes from *
  * `sails.config.routes`)                                                   *
  *                                                                          *
  * For example, REST blueprints for `FooController` with `pluralize`        *
  * enabled:                                                                 *
  * GET /foos/:id?                                                           *
  * POST /foos                                                               *
  * PUT /foos/:id?                                                           *
  * DELETE /foos/:id?                                                        *
  *                                                                          *
  ***************************************************************************/

  pluralize: true,

  /***************************************************************************
  *                                                                          *
  * Whether the blueprint controllers should populate model fetches with     *
  * data from other models which are linked by associations                  *
  *                                                                          *
  * If you have a lot of data in one-to-many associations, leaving this on   *
  * may result in very heavy api calls                                       *
  *                                                                          *
  ***************************************************************************/

  // populate: true,

  /****************************************************************************
  *                                                                           *
  * Whether to run Model.watch() in the find and findOne blueprint actions.   *
  * Can be overridden on a per-model basis.                                   *
  *                                                                           *
  ****************************************************************************/

  // autoWatch: true,

  /****************************************************************************
  *                                                                           *
  * The default number of records to show in the response from a "find"       *
  * action. Doubles as the default size of populated arrays if populate is    *
  * true.                                                                     *
  *                                                                           *
  ****************************************************************************/

  // defaultLimit: 30

};
<|endoftext|>