<commit_before>// load PSNRequest object (we will extend it with our helper functions)
var PSNRequest = require("./psn_request");

// which fields to request when getting a profile
var profileFields = "@default,relation,requestMessageFlag,presence,@personalDetail,trophySummary";
var messageFields = "@default,messageGroupId,messageGroupDetail,totalUnseenMessages,totalMessages,latestMessage";

/** Get a PSN user's profile
 * @param username		PSN username to request
 * @param callback		Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getProfile = function(username, callback)
{
	this.Get(
		this.ReplacePSNUsername("https://{{region}}-prof.np.community.playstation.net/userProfile/v1/users/{{id}}/profile", username),
		{
			fields: profileFields
		},
		callback
	);
}

/** Get current user's message groups
 * @param callback		Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getMessageGroups = function(callback)
{
	this.Get(
		"https://{{region}}-gmsg.np.community.playstation.net/groupMessaging/v1/users/{{psn}}/messageGroups",
		{
			fields: messageFields
		},
		callback
	);
}

/** Get data from a specific message. All this data can be found in getMessageGroups
 * @param messageGroupId 	Group ID requested message belongs to
 * @param messageUid 		Message ID to fetch
 * @param messageKind		Kind of message (as int)
 * @param callback			Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getMessageContent = function(messageGroupId, messageUid, messageKind, callback)
{
	var contentKey = false;

	// convert kind ID to contentKey string
	messageKind = parseInt(messageKind);
	if (messageKind == 1) contentKey = "message"; // text (no attachment)
	else if (messageKind == 3) contentKey = "image-data-0"; // photo/image
	else if (messageKind == 1011) contentKey = "voice-data-0"; // voice data
	else if (messageKind == 8) contentKey = "store-url-0"; // PSN store link

	if (!contentKey)
	{
		// check js/people/groupmessage.js in PSN app to find contentKey types (and their kind IDs)
		if (callback) callback("Error: Unknown PSN message kind: " + messageKind);
		return;
	}

	this.Get(
		"https://{{region}}-gmsg.np.community.playstation.net/groupMessaging/v1/messageGroups/{{messageGroupId}}/messages/{{messageUid}}".
			replace("{{messageGroupId}}", this.CleanPSNList(messageGroupId)).
			replace("{{messageUid}}", parseInt(messageUid)),
		{
			contentKey: contentKey
		},
		callback
	);
}

// list valid filters for activity feeds
PSNRequest.prototype.activityTypes = [
	"PURCHASED",
	"RATED",
	"VIDEO_UPLOAD",
	"SCREENSHOT_UPLOAD",
	"PLAYED_GAME",
	"STORE_PROMO",
	"WATCHED_VIDEO",
	"TROPHY",
	"BROADCASTING",
	"LIKED",
	"PROFILE_PIC",
	"FRIENDED",
	"CONTENT_SHARE"
];

/** Get the signed-in user's activity feed
 * @param feed		type of feed, either "feed" or "news" (optional, defaults to "news")
 * @param filters	array of strings to filter by (optional, defaults to no filters)
 *					Allowed: PURCHASED, RATED, VIDEO_UPLOAD, SCREENSHOT_UPLOAD, PLAYED_GAME, STORE_PROMO, WATCHED_VIDEO, TROPHY, BROADCASTING, LIKED, PROFILE_PIC, FRIENDED and CONTENT_SHARE
 *					Use an empty array (or leave out argument) for all types
 * @param page 		Page of feed to load (default: 0)
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getLatestActivity = function(feed, filters, page, callback)
{
	// handle defaults for missing feed or filters arguments
	if (typeof feed == "function")
	{
		callback = feed;
		feed = "news";
		filters = [];
		page = 0;
	}
	else if (typeof filters == "function")
	{
		callback = filters;
		filters = [];
		page = 0;
	}
	else if (typeof page == "function")
	{
		callback = page;
		page = 0;
	}

	// check filters are valid
	for(var i=0; i<filters.length; i++)
	{
		// remove filter if not in our valid list
		if (this.activityTypes.indexOf(filters[i]) == -1)
		{
			filters.splice(i, 1);
			i--;
		}
	}

	this.Get(
		"https://activity.api.np.km.playstation.net/activity/api/v1/users/{{psn}}/" + (feed == "feed" ? "feed" : "news") + "/" + parseInt(page),
		{
			filters: filters
		},
		callback
	);
}

/** Like an activity from the activity feed
 * @param storyId	The ID of the activity we want to like
 * @param dislike	(optional) set to true to dislike instead of like
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.likeActivity = function(storyId, dislike, callback)
{
	// support passing dislike manually into the function
	if (typeof dislike == "function")
	{
		callback = dislike;
		dislike = false;
	}

	this.Get(
		"https://activity.api.np.km.playstation.net/activity/api/v1/users/{{psn}}/set/" + (dislike ? "dis" : "") + "like/story/{{storyId}}".
		// tidy up passed in story ID - contains 42 lower-case hexadecimal chars in format: {8}-{4}-{4}-{4}-{12}
		replace("{{storyId}}", storyId.replace(/[^a-z0-9\-]/g, "")),
		{},
		callback
	);
}

/** Dislike an activity from the activity feed
 * @param storyId	The ID of the activity we want to dislike
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.dislikeActivity = function(storyId, callback)
{
	// just call like with dislike set to true
	this.likeActivity(storyId, true, callback);
}

// return our new psn request object with our new helper functions
module.exports = PSNRequest;<commit_msg>Add getNotification method<commit_after>// load PSNRequest object (we will extend it with our helper functions)
var PSNRequest = require("./psn_request");

// which fields to request when getting a profile
var profileFields = "@default,relation,requestMessageFlag,presence,@personalDetail,trophySummary";
var messageFields = "@default,messageGroupId,messageGroupDetail,totalUnseenMessages,totalMessages,latestMessage";
var notificationFields = "@default,message,actionUrl";

/** Get a PSN user's profile
 * @param username		PSN username to request
 * @param callback		Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getProfile = function(username, callback)
{
	this.Get(
		this.ReplacePSNUsername("https://{{region}}-prof.np.community.playstation.net/userProfile/v1/users/{{id}}/profile", username),
		{
			fields: profileFields
		},
		callback
	);
}

/** Get current user's message groups
 * @param callback		Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getMessageGroups = function(callback)
{
	this.Get(
		"https://{{region}}-gmsg.np.community.playstation.net/groupMessaging/v1/users/{{psn}}/messageGroups",
		{
			fields: messageFields
		},
		callback
	);
}

/** Get data from a specific message. All this data can be found in getMessageGroups
 * @param messageGroupId 	Group ID requested message belongs to
 * @param messageUid 		Message ID to fetch
 * @param messageKind		Kind of message (as int)
 * @param callback			Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getMessageContent = function(messageGroupId, messageUid, messageKind, callback)
{
	var contentKey = false;

	// convert kind ID to contentKey string
	messageKind = parseInt(messageKind);
	if (messageKind == 1) contentKey = "message"; // text (no attachment)
	else if (messageKind == 3) contentKey = "image-data-0"; // photo/image
	else if (messageKind == 1011) contentKey = "voice-data-0"; // voice data
	else if (messageKind == 8) contentKey = "store-url-0"; // PSN store link

	if (!contentKey)
	{
		// check js/people/groupmessage.js in PSN app to find contentKey types (and their kind IDs)
		if (callback) callback("Error: Unknown PSN message kind: " + messageKind);
		return;
	}

	this.Get(
		"https://{{region}}-gmsg.np.community.playstation.net/groupMessaging/v1/messageGroups/{{messageGroupId}}/messages/{{messageUid}}".
			replace("{{messageGroupId}}", this.CleanPSNList(messageGroupId)).
			replace("{{messageUid}}", parseInt(messageUid)),
		{
			contentKey: contentKey
		},
		callback
	);
}

// list valid filters for activity feeds
PSNRequest.prototype.activityTypes = [
	"PURCHASED",
	"RATED",
	"VIDEO_UPLOAD",
	"SCREENSHOT_UPLOAD",
	"PLAYED_GAME",
	"STORE_PROMO",
	"WATCHED_VIDEO",
	"TROPHY",
	"BROADCASTING",
	"LIKED",
	"PROFILE_PIC",
	"FRIENDED",
	"CONTENT_SHARE"
];

/** Get the signed-in user's activity feed
 * @param feed		type of feed, either "feed" or "news" (optional, defaults to "news")
 * @param filters	array of strings to filter by (optional, defaults to no filters)
 *					Allowed: PURCHASED, RATED, VIDEO_UPLOAD, SCREENSHOT_UPLOAD, PLAYED_GAME, STORE_PROMO, WATCHED_VIDEO, TROPHY, BROADCASTING, LIKED, PROFILE_PIC, FRIENDED and CONTENT_SHARE
 *					Use an empty array (or leave out argument) for all types
 * @param page 		Page of feed to load (default: 0)
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getLatestActivity = function(feed, filters, page, callback)
{
	// handle defaults for missing feed or filters arguments
	if (typeof feed == "function")
	{
		callback = feed;
		feed = "news";
		filters = [];
		page = 0;
	}
	else if (typeof filters == "function")
	{
		callback = filters;
		filters = [];
		page = 0;
	}
	else if (typeof page == "function")
	{
		callback = page;
		page = 0;
	}

	// check filters are valid
	for(var i=0; i<filters.length; i++)
	{
		// remove filter if not in our valid list
		if (this.activityTypes.indexOf(filters[i]) == -1)
		{
			filters.splice(i, 1);
			i--;
		}
	}

	this.Get(
		"https://activity.api.np.km.playstation.net/activity/api/v1/users/{{psn}}/" + (feed == "feed" ? "feed" : "news") + "/" + parseInt(page),
		{
			filters: filters
		},
		callback
	);
}

/** Like an activity from the activity feed
 * @param storyId	The ID of the activity we want to like
 * @param dislike	(optional) set to true to dislike instead of like
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.likeActivity = function(storyId, dislike, callback)
{
	// support passing dislike manually into the function
	if (typeof dislike == "function")
	{
		callback = dislike;
		dislike = false;
	}

	this.Get(
		"https://activity.api.np.km.playstation.net/activity/api/v1/users/{{psn}}/set/" + (dislike ? "dis" : "") + "like/story/{{storyId}}".
		// tidy up passed in story ID - contains 42 lower-case hexadecimal chars in format: {8}-{4}-{4}-{4}-{12}
		replace("{{storyId}}", storyId.replace(/[^a-z0-9\-]/g, "")),
		{},
		callback
	);
}

/** Dislike an activity from the activity feed
 * @param storyId	The ID of the activity we want to dislike
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.dislikeActivity = function(storyId, callback)
{
	// just call like with dislike set to true
	this.likeActivity(storyId, true, callback);
}

/** Get notifications of currently authenticated user
 * @param callback	Callback function with error (false if no error) and returned data object
 */
PSNRequest.prototype.getNotifications = function(callback)
{
	this.Get(
		"https://{{region}}-ntl.np.community.playstation.net/notificationList/v1/users/{{psn}}/notifications",
		{
			fields: notificationFields,
			npLanguage: "{{lang}}"
		},
		callback
	);
}

// return our new psn request object with our new helper functions
module.exports = PSNRequest;<|endoftext|>


<commit_before>var cons = require('consolidate');
var utils = require('loader-utils');
var path = require('path');
var fs = require('fs');

module.exports = function(content) {
  this.cacheable && this.cacheable();

  var callback = this.async();
  var opt = utils.getOptions(this);

  function exportContent(content) {
    if (opt.raw) {
      callback(null, content);
    } else {
      callback(null, "module.exports = " + JSON.stringify(content));
    }
  }

  // with no engine given, use the file extension as engine
  if(!opt.engine) {
    opt.engine = path.extname(this.request).substr(1).toLowerCase();
  }

  if(!cons[opt.engine]) {
    throw new Error("Engine '"+ opt.engine +"' isn't available in Consolidate.js");
  }

  // for relative includes
  opt.filename = this.resourcePath;
  opt.dirname = path.dirname(this.resourcePath);

  if(opt.files instanceof Array) {
    opt.files.reverse().forEach(function(file) {
      file = path.join(opt.dirname, file + '.json');
      if(!fs.existsSync(file)) {
        throw new Error("Data file '"+ file +"' does not exist");
      }
      opt = Object.assign(require(file), opt);    // ensure that opt takes precedence
    })
    delete opt.file;
  }

  cons[opt.engine].render(content, opt, function(err, html) {
    if(err) {
      throw err;
    }
    exportContent(html);
  });
};
<commit_msg>make each loaded file a dependency - for watching don't use require(file), because that is cached by node fix delete typo<commit_after>var cons = require('consolidate');
var utils = require('loader-utils');
var path = require('path');
var fs = require('fs');

module.exports = function(content) {
  this.cacheable && this.cacheable();

  var callback = this.async();
  var opt = utils.getOptions(this);

  function exportContent(content) {
    if (opt.raw) {
      callback(null, content);
    } else {
      callback(null, "module.exports = " + JSON.stringify(content));
    }
  }

  // with no engine given, use the file extension as engine
  if(!opt.engine) {
    opt.engine = path.extname(this.request).substr(1).toLowerCase();
  }

  if(!cons[opt.engine]) {
    throw new Error("Engine '"+ opt.engine +"' isn't available in Consolidate.js");
  }

  // for relative includes
  opt.filename = this.resourcePath;
  opt.dirname = path.dirname(this.resourcePath);

  const self = this;
  if(opt.files instanceof Array) {
    opt.files.reverse().forEach(function(file) {
      var file = path.join(opt.dirname, file + '.json');
      if(!fs.existsSync(file)) {
        throw new Error("Data file '"+ file +"' does not exist");
      }
      opt = Object.assign(JSON.parse(fs.readFileSync(file)), opt);    // ensure that opt takes precedence
      self.addDependency(file);
    })
    delete opt.files;
  }

  cons[opt.engine].render(content, opt, function(err, html) {
    if(err) {
      throw err;
    }
    exportContent(html);
  });
};
<|endoftext|>


<commit_before>'use strict';

var FreeList = require('freelist').FreeList
  , Route = require('routable')
  , Primus = require('primus')
  , colors = require('colors')
  , path = require('path')
  , url = require('url')
  , fs = require('fs');

//
// Library internals.
//
var Librarian = require('./librarian')
  , Resource = require('./resource')
  , Pagelet = require('./pagelet')
  , Pool = require('./pool')
  , Page = require('./page')
  , ACL = require('./acl');

//
// Try to detect if we've got domains support. So we can easily serve 500 error
// pages when we have an error.
//
var domain;

try { domain = require('domain'); }
catch (e) {}

/**
 * Our pagelet managment.
 *
 * The following options are available:
 *
 * - transport: The transport engine we should use for real-time.
 * - cache: A object were we store our url->page mapping.
 * - stream: Where we should write our logs to.
 * - parser: Which parser should be used to send data in real-time.
 *
 * @constructor
 * @param {Server} server HTTP/S based server instance.
 * @param {Mixed} pages String or array of pages we serve.
 * @param {Object} options Configuration.
 * @api public
 */
function Pipe(server, pages, options) {
  options = this.options(options || {});

  this.resources = new Pool({ type: 'resources' }); // Resource pool.
  this.stream = options('stream', process.stdout);  // Our log stream.
  this.domains = !!options('domain') && domain;     // Call all requests in a domain.
  this.statusCodes = Object.create(null);           // Stores error pages.
  this.cache = options('cache', null);              // Enable URL lookup caching.

  //
  // Process the pages.
  //
  this.pages = this.resolve(pages, this.transform); // Our Page constructors.
  this.discover(this.pages);                        // Find error pages.

  //
  // Now that everything is procesed, we can setup our internals.
  //
  this.server = server;
  this.primus = new Primus(this.server, {
    transformer: options('transport', 'websockets'),
    pathname: options('pathname', '/pagelets'),
    parser: options('parser', 'json')
  });

  //
  // Setup our CSS/JS library.
  //
  this.library = new Librarian(this);

  //
  // Setup ACL.
  //
  this.acl = new ACL(this);

  //
  // Start listening for incoming requests.
  //
  this.server.on('request', this.dispatch.bind(this));
  this.primus.on('connection', this.connection.bind(this));
}

Pipe.prototype.__proto__ = require('events').EventEmitter.prototype;

/**
 * Checks if options exists.
 *
 * @param {Object} obj
 * @returns {Function}
 * @api private
 */
Pipe.prototype.options = function options(obj) {
  return function get(key, backup) {
    return key in obj ? obj[key] : backup;
  };
};

/**
 * Simple log method.
 *
 * @param {String} type The log type.
 * @api private
 */
Pipe.prototype.log = function log(type) {
  var data = Array.prototype.slice.call(arguments, 1)
    , level = Pipe.prototype.log.levels[type];

  if (this.stream) {
    //
    // Add some padding, write the log type, and join as pretty string.
    //
    this.stream.write(['  '+ level +' '].concat(data).join(' ') + '\n');
  } else {
    this.emit.apply(this, ['log', type].concat(data));
  }

  return this;
};

/**
 * Pretty logger prefixes.
 *
 * @type {Object}
 * @private
 */
Pipe.prototype.log.levels = {
  'warn': '𝓦'.yellow,
  'error': '𝓔'.red,
  'info': '𝓘'.blue
};

/**
 * Transform strings, array of strings, objects, things in to the actual
 * constructors.
 *
 * @param {String|Array|Object} files The files.
 * @param {Function} transform Transformation function
 * @returns {Array}
 * @api private
 */
Pipe.prototype.resolve = function resolve(files, transform) {
  if ('string' === typeof files) {
    files = fs.readdirSync(files).map(function locate(file) {
      return path.resolve(files, file);
    });
  } else if (!Array.isArray(files)) {
    files = Object.keys(files).map(function merge(name) {
      var constructor = files[name];

      //
      // Add a name to the prototype, if we have this property in the prototype.
      // This mostly applies for the Pagelets.
      //
      if ('name' in constructor.prototype) {
        constructor.prototype.name = constructor.prototype.name || name;
      }

      return constructor;
    });
  }

  files = files.filter(function jsonly(file) {
    //
    // Make sure we only use valid JavaScript files as sources. We want to
    // ignore stuff like potential .log files.
    //
    return path.extname(file) === '.js';
  }).map(function map(constructor) {
    //
    // It's not required to supply us with instances, we can just
    // automatically require them if they are using the:
    //
    //   module.exports = base.extend();
    //
    // pattern for defining the pages/pagelets.
    //
    if ('string' === typeof constructor) {
      constructor = require(constructor);
    }

    //
    // We didn't receive a proper page instance.
    //
    if ('function' !== typeof constructor) {
      var invalid = (JSON.stringify(constructor) || constructor.toString());
      this.log('warn', 'Ignorning invalid constructor: '+ invalid);
      return undefined;
    }

    return constructor;
  }, this).filter(Boolean);

  return transform
    ? files.map(transform.bind(this))
    : files;
};

/**
 * Discover if the user supplied us with custom error pages so we use that
 * in case we need to handle a 404 or and 500 error page.
 *
 * @param {Array} pages All enabled pages.
 * @api private
 */
Pipe.prototype.discover = function discover(pages) {
  var fivehundered
    , fourofour;

  pages.forEach(function each(page) {
    if (page.router.test('/500')) fivehundered = page;
    if (page.router.test('/404')) fourofour = page;
  });

  //
  // We don't have any 500 or 404 handlers, so use some default pages that are
  // provided by us. But as these page are not processed yet, we need to kick
  // them through our transform process.
  //
  if (!fivehundered) fivehundered = this.transform(require('./pages/500'));
  if (!fourofour) fourofour = this.transform(require('./pages/404'));

  this.statusCodes[500] = fivehundered;
  this.statusCodes[404] = fourofour;

  return this;
};

/**
 * We need to extract items from the Page prototype and transform it in to
 * something useful.
 *
 * @param {Page} page Page constructor.
 * @return {Page} The upgrade page.
 * @api private
 */
Pipe.prototype.transform = function transform(Page) {
  var method = Page.prototype.method
    , router = Page.prototype.path
    , pipe = this;

  //
  // This page has already been processed, bailout.
  //
  if (Page.properties) return Page;

  //
  // Parse the methods to an array of accepted HTTP methods. We'll only accept
  // there requests and should deny every other possible method.
  //
  if (!Array.isArray(method)) method = method.split(/[\s,]+?/);
  method = method.filter(Boolean).map(function transformation(method) {
    return method.toUpperCase();
  });

  //
  // Update the pagelets, if any.
  //
  if (Page.prototype.pagelets) {
    var pagelets = this.resolve(Page.prototype.pagelets, function map(Pagelet) {
      //
      // This pagelet has already been processed before as pages can share
      // pagelets.
      //
      if (Pagelet.properties) return Pagelet;

      var prototype = Pagelet.prototype
        , dir = prototype.directory;

      if (prototype.view) Pagelet.prototype.view = path.resolve(dir, prototype.view);
      if (prototype.css) Pagelet.prototype.css = path.resolve(dir, prototype.css);
      if (prototype.js) Pagelet.prototype.js = path.resolve(dir, prototype.js);

      if (!prototype.render || 'function' !== typeof prototype.render) {
        throw new Error('Pagelet('+ prototype.name + ') is missing a `render` method');
      }

      //
      // Make sure that all our dependencies are also directly mapped to an
      // absolute url.
      //
      if (prototype.dependencies) {
        Pagelet.prototype.dependencies = prototype.dependencies.map(function (dep) {
          return path.resolve(dir, dep);
        });
      }

      Pagelet.properties = Object.keys(Pagelet.prototype);

      //
      // Setup a FreeList for the pagelets so we can re-use the pagelet
      // instances and reduce garbage collection.
      //
      Pagelet.collection = new FreeList('pagelet', Pagelet.prototype.freelist || 1000, function () {
        return new Pagelet();
      });

      return Pagelet;
    });

    //
    // Save the transformed pagelets.
    //
    Page.prototype.pagelets = pagelets;
  }

  //
  // Add the properties to the page.
  //
  Page.properties = Object.keys(Page.prototype);      // All properties before init.
  Page.router = new Route(router);                    // Actual HTTP route.
  Page.method = method;                               // Available HTTP methods.
  Page.id = router.toString() +'&&'+ method.join();   // Unique id.

  //
  // Setup a FreeList for the page so we can re-use the page instances and
  // reduce garbage collection to a bare minimum.
  //
  Page.collection = new FreeList('page', Page.prototype.freelist || 1000, function () {
    return new Page(pipe);
  });

  return Page;
};

/**
 * Find the correct Page constructor based on the given url.
 *
 * @param {String} url The url we need to find.
 * @returns {Mixed} either a Page constructor or undefined;
 * @api public
 */
Pipe.prototype.find = function find(url, method) {
  if (this.cache && this.cache.has(url)) return this.cache.get(url);

  for (var i = 0, page, length = this.pages.length; i < length; i++) {
    page = this.pages[i];

    if (!page.router.test(url)) continue;
    if (method && page.method.length && !~page.method.indexOf(method)) continue;

    if (this.cache) this.cache.set(url, page);
    return page;
  }

  return undefined;
};

/**
 * Dispatch incoming requests.
 *
 * @TODO handle POST requests.
 * @param {Request} req HTTP request.
 * @param {Resposne} res HTTP response.
 * @api private
 */
Pipe.prototype.dispatch = function dispatch(req, res) {
  this.decorate(req);

  //
  // Find the page that matches our route, if we don't find anything assume
  // we've got to send a 404 instead.
  //
  var Page = this.find(req.uri.pathname) || this.statusCodes[404]
    , page = Page.alloc();

  if (this.domains) {
    page.domain = domain.create();
    page.domain.run(function run() {
      run.configure(req, res);
    });
  } else {
    page.configure(req, res);
  }

  return this;
};

/**
 * Decorate the request object with some extensions.
 *
 * @param {Request} req HTTP request.
 * @api private
 */
Pipe.prototype.decorate = function decorate(req) {
  req.uri = req.uri || url.parse(req.url, true);
  req.query = req.query || req.uri.query;

  //
  // Add some silly HTTP properties for connect.js compatiblity.
  //
  req.originalUrl = req.url;
};

/**
 * Handle incoming real-time requests.
 *
 * @param {Spark} spark A real-time "socket".
 * @api private
 */
Pipe.prototype.connection = function connection(spark) {

};

/**
 * Create a new Pagelet/Pipe server.
 *
 * @param {Number} port Port number we should listen on.
 * @param {Array} pages List with pages.
 * @param {Object} options Configuration.
 * @returns {Pipe}
 * @api public
 */
Pipe.createServer = function createServer(port, pages, options) {
  options = options || {};

  var certs = 'key' in options && 'cert' in options
    , secure = certs || 443 === port
    , spdy = 'spdy' in options
    , server;

  //
  // We need to have SSL certs for SPDY and secure servers.
  //
  if (secure || spdy && !certs) {
    throw new Error('Missing the SSL key or certificate files in the options.');
  }

  if (spdy) {
    server = require('spdy').createServer(options);
  } else if (secure) {
    server = require('https').createServer(options);
  } else {
    server = require('http').createServer();
  }

  //
  // Now that we've got a server, we can setup the pipe and start listening.
  //
  var pipe = new Pipe(server, pages || options.pages, options);
  server.listen(port);

  return pipe;
};

//
// Expose our constructors.
//
Pipe.Resource = Resource;
Pipe.Pagelet = Pagelet;
Pipe.Page = Page;

//
// Expose the constructor.
//
module.exports = Pipe;
<commit_msg>[minor] Pass in the method.<commit_after>'use strict';

var FreeList = require('freelist').FreeList
  , Route = require('routable')
  , Primus = require('primus')
  , colors = require('colors')
  , path = require('path')
  , url = require('url')
  , fs = require('fs');

//
// Library internals.
//
var Librarian = require('./librarian')
  , Resource = require('./resource')
  , Pagelet = require('./pagelet')
  , Pool = require('./pool')
  , Page = require('./page')
  , ACL = require('./acl');

//
// Try to detect if we've got domains support. So we can easily serve 500 error
// pages when we have an error.
//
var domain;

try { domain = require('domain'); }
catch (e) {}

/**
 * Our pagelet managment.
 *
 * The following options are available:
 *
 * - transport: The transport engine we should use for real-time.
 * - cache: A object were we store our url->page mapping.
 * - stream: Where we should write our logs to.
 * - parser: Which parser should be used to send data in real-time.
 *
 * @constructor
 * @param {Server} server HTTP/S based server instance.
 * @param {Mixed} pages String or array of pages we serve.
 * @param {Object} options Configuration.
 * @api public
 */
function Pipe(server, pages, options) {
  options = this.options(options || {});

  this.resources = new Pool({ type: 'resources' }); // Resource pool.
  this.stream = options('stream', process.stdout);  // Our log stream.
  this.domains = !!options('domain') && domain;     // Call all requests in a domain.
  this.statusCodes = Object.create(null);           // Stores error pages.
  this.cache = options('cache', null);              // Enable URL lookup caching.

  //
  // Process the pages.
  //
  this.pages = this.resolve(pages, this.transform); // Our Page constructors.
  this.discover(this.pages);                        // Find error pages.

  //
  // Now that everything is procesed, we can setup our internals.
  //
  this.server = server;
  this.primus = new Primus(this.server, {
    transformer: options('transport', 'websockets'),
    pathname: options('pathname', '/pagelets'),
    parser: options('parser', 'json')
  });

  //
  // Setup our CSS/JS library.
  //
  this.library = new Librarian(this);

  //
  // Setup ACL.
  //
  this.acl = new ACL(this);

  //
  // Start listening for incoming requests.
  //
  this.server.on('request', this.dispatch.bind(this));
  this.primus.on('connection', this.connection.bind(this));
}

Pipe.prototype.__proto__ = require('events').EventEmitter.prototype;

/**
 * Checks if options exists.
 *
 * @param {Object} obj
 * @returns {Function}
 * @api private
 */
Pipe.prototype.options = function options(obj) {
  return function get(key, backup) {
    return key in obj ? obj[key] : backup;
  };
};

/**
 * Simple log method.
 *
 * @param {String} type The log type.
 * @api private
 */
Pipe.prototype.log = function log(type) {
  var data = Array.prototype.slice.call(arguments, 1)
    , level = Pipe.prototype.log.levels[type];

  if (this.stream) {
    //
    // Add some padding, write the log type, and join as pretty string.
    //
    this.stream.write(['  '+ level +' '].concat(data).join(' ') + '\n');
  } else {
    this.emit.apply(this, ['log', type].concat(data));
  }

  return this;
};

/**
 * Pretty logger prefixes.
 *
 * @type {Object}
 * @private
 */
Pipe.prototype.log.levels = {
  'warn': '𝓦'.yellow,
  'error': '𝓔'.red,
  'info': '𝓘'.blue
};

/**
 * Transform strings, array of strings, objects, things in to the actual
 * constructors.
 *
 * @param {String|Array|Object} files The files.
 * @param {Function} transform Transformation function
 * @returns {Array}
 * @api private
 */
Pipe.prototype.resolve = function resolve(files, transform) {
  if ('string' === typeof files) {
    files = fs.readdirSync(files).map(function locate(file) {
      return path.resolve(files, file);
    });
  } else if (!Array.isArray(files)) {
    files = Object.keys(files).map(function merge(name) {
      var constructor = files[name];

      //
      // Add a name to the prototype, if we have this property in the prototype.
      // This mostly applies for the Pagelets.
      //
      if ('name' in constructor.prototype) {
        constructor.prototype.name = constructor.prototype.name || name;
      }

      return constructor;
    });
  }

  files = files.filter(function jsonly(file) {
    //
    // Make sure we only use valid JavaScript files as sources. We want to
    // ignore stuff like potential .log files.
    //
    return path.extname(file) === '.js';
  }).map(function map(constructor) {
    //
    // It's not required to supply us with instances, we can just
    // automatically require them if they are using the:
    //
    //   module.exports = base.extend();
    //
    // pattern for defining the pages/pagelets.
    //
    if ('string' === typeof constructor) {
      constructor = require(constructor);
    }

    //
    // We didn't receive a proper page instance.
    //
    if ('function' !== typeof constructor) {
      var invalid = (JSON.stringify(constructor) || constructor.toString());
      this.log('warn', 'Ignorning invalid constructor: '+ invalid);
      return undefined;
    }

    return constructor;
  }, this).filter(Boolean);

  return transform
    ? files.map(transform.bind(this))
    : files;
};

/**
 * Discover if the user supplied us with custom error pages so we use that
 * in case we need to handle a 404 or and 500 error page.
 *
 * @param {Array} pages All enabled pages.
 * @api private
 */
Pipe.prototype.discover = function discover(pages) {
  var fivehundered
    , fourofour;

  pages.forEach(function each(page) {
    if (page.router.test('/500')) fivehundered = page;
    if (page.router.test('/404')) fourofour = page;
  });

  //
  // We don't have any 500 or 404 handlers, so use some default pages that are
  // provided by us. But as these page are not processed yet, we need to kick
  // them through our transform process.
  //
  if (!fivehundered) fivehundered = this.transform(require('./pages/500'));
  if (!fourofour) fourofour = this.transform(require('./pages/404'));

  this.statusCodes[500] = fivehundered;
  this.statusCodes[404] = fourofour;

  return this;
};

/**
 * We need to extract items from the Page prototype and transform it in to
 * something useful.
 *
 * @param {Page} page Page constructor.
 * @return {Page} The upgrade page.
 * @api private
 */
Pipe.prototype.transform = function transform(Page) {
  var method = Page.prototype.method
    , router = Page.prototype.path
    , pipe = this;

  //
  // This page has already been processed, bailout.
  //
  if (Page.properties) return Page;

  //
  // Parse the methods to an array of accepted HTTP methods. We'll only accept
  // there requests and should deny every other possible method.
  //
  if (!Array.isArray(method)) method = method.split(/[\s,]+?/);
  method = method.filter(Boolean).map(function transformation(method) {
    return method.toUpperCase();
  });

  //
  // Update the pagelets, if any.
  //
  if (Page.prototype.pagelets) {
    var pagelets = this.resolve(Page.prototype.pagelets, function map(Pagelet) {
      //
      // This pagelet has already been processed before as pages can share
      // pagelets.
      //
      if (Pagelet.properties) return Pagelet;

      var prototype = Pagelet.prototype
        , dir = prototype.directory;

      if (prototype.view) Pagelet.prototype.view = path.resolve(dir, prototype.view);
      if (prototype.css) Pagelet.prototype.css = path.resolve(dir, prototype.css);
      if (prototype.js) Pagelet.prototype.js = path.resolve(dir, prototype.js);

      if (!prototype.render || 'function' !== typeof prototype.render) {
        throw new Error('Pagelet('+ prototype.name + ') is missing a `render` method');
      }

      //
      // Make sure that all our dependencies are also directly mapped to an
      // absolute url.
      //
      if (prototype.dependencies) {
        Pagelet.prototype.dependencies = prototype.dependencies.map(function (dep) {
          return path.resolve(dir, dep);
        });
      }

      Pagelet.properties = Object.keys(Pagelet.prototype);

      //
      // Setup a FreeList for the pagelets so we can re-use the pagelet
      // instances and reduce garbage collection.
      //
      Pagelet.collection = new FreeList('pagelet', Pagelet.prototype.freelist || 1000, function () {
        return new Pagelet();
      });

      return Pagelet;
    });

    //
    // Save the transformed pagelets.
    //
    Page.prototype.pagelets = pagelets;
  }

  //
  // Add the properties to the page.
  //
  Page.properties = Object.keys(Page.prototype);      // All properties before init.
  Page.router = new Route(router);                    // Actual HTTP route.
  Page.method = method;                               // Available HTTP methods.
  Page.id = router.toString() +'&&'+ method.join();   // Unique id.

  //
  // Setup a FreeList for the page so we can re-use the page instances and
  // reduce garbage collection to a bare minimum.
  //
  Page.collection = new FreeList('page', Page.prototype.freelist || 1000, function () {
    return new Page(pipe);
  });

  return Page;
};

/**
 * Find the correct Page constructor based on the given url.
 *
 * @param {String} url The url we need to find.
 * @returns {Mixed} either a Page constructor or undefined;
 * @api public
 */
Pipe.prototype.find = function find(url, method) {
  if (this.cache && this.cache.has(url)) return this.cache.get(url);

  for (var i = 0, page, length = this.pages.length; i < length; i++) {
    page = this.pages[i];

    if (!page.router.test(url)) continue;
    if (method && page.method.length && !~page.method.indexOf(method)) continue;

    if (this.cache) this.cache.set(url, page);
    return page;
  }

  return undefined;
};

/**
 * Dispatch incoming requests.
 *
 * @TODO handle POST requests.
 * @param {Request} req HTTP request.
 * @param {Resposne} res HTTP response.
 * @api private
 */
Pipe.prototype.dispatch = function dispatch(req, res) {
  this.decorate(req);

  //
  // Find the page that matches our route, if we don't find anything assume
  // we've got to send a 404 instead.
  //
  var Page = this.find(req.uri.pathname, req.method) || this.statusCodes[404]
    , page = Page.alloc();

  if (this.domains) {
    page.domain = domain.create();
    page.domain.run(function run() {
      run.configure(req, res);
    });
  } else {
    page.configure(req, res);
  }

  return this;
};

/**
 * Decorate the request object with some extensions.
 *
 * @param {Request} req HTTP request.
 * @api private
 */
Pipe.prototype.decorate = function decorate(req) {
  req.uri = req.uri || url.parse(req.url, true);
  req.query = req.query || req.uri.query;

  //
  // Add some silly HTTP properties for connect.js compatiblity.
  //
  req.originalUrl = req.url;
};

/**
 * Handle incoming real-time requests.
 *
 * @param {Spark} spark A real-time "socket".
 * @api private
 */
Pipe.prototype.connection = function connection(spark) {

};

/**
 * Create a new Pagelet/Pipe server.
 *
 * @param {Number} port Port number we should listen on.
 * @param {Array} pages List with pages.
 * @param {Object} options Configuration.
 * @returns {Pipe}
 * @api public
 */
Pipe.createServer = function createServer(port, pages, options) {
  options = options || {};

  var certs = 'key' in options && 'cert' in options
    , secure = certs || 443 === port
    , spdy = 'spdy' in options
    , server;

  //
  // We need to have SSL certs for SPDY and secure servers.
  //
  if (secure || spdy && !certs) {
    throw new Error('Missing the SSL key or certificate files in the options.');
  }

  if (spdy) {
    server = require('spdy').createServer(options);
  } else if (secure) {
    server = require('https').createServer(options);
  } else {
    server = require('http').createServer();
  }

  //
  // Now that we've got a server, we can setup the pipe and start listening.
  //
  var pipe = new Pipe(server, pages || options.pages, options);
  server.listen(port);

  return pipe;
};

//
// Expose our constructors.
//
Pipe.Resource = Resource;
Pipe.Pagelet = Pagelet;
Pipe.Page = Page;

//
// Expose the constructor.
//
module.exports = Pipe;
<|endoftext|>


<commit_before>"use strict";

var fs                          = require('fs'),
    EventEmitter                = require('events').EventEmitter,
    path                        = require('path'),
    rng                         = require('crypto').rng,
    q                           = require('kew'),
    through                     = require('through'),
    nodeResolve                 = require('resolve'),
    browserResolve              = require('browser-resolve'),
    transformResolve            = resolveWith.bind(null, nodeResolve),
    aggregate                   = require('stream-aggregate-promise'),
    combine                     = require('stream-combiner'),
    asStream                    = require('as-stream'),
    utils                       = require('lodash'),
    depsTransform               = require('./transforms/deps'),
    jsonTransform               = require('./transforms/json');

module.exports = function(entries, opts) {
  return new Graph(entries, opts).toStream()
}

module.exports.Graph = Graph
module.exports.GraphResolution = GraphResolution

function Graph(entries, opts) {
  opts = opts || {}
  opts.basedir = opts.basedir || process.cwd()

  this.opts = opts
  this.entries = []
  this.cache = this.opts.cache = {}

  if (entries)
    [].concat(entries).filter(Boolean).forEach(this.addEntry.bind(this))
}

Graph.prototype = utils.assign(Graph.prototype, EventEmitter.prototype, {

  addEntry: function(m) {
    var mod = {entry: true, package: undefined}
    if (typeof m.pipe === 'function') {
      mod.id = path.join(this.opts.basedir, rng(8).toString('hex') + '.js')
      mod.sourcePromise = aggregate(m)
    } else if (utils.isString(m)) {
      mod.id = path.resolve(m)
    } else {
      mod = m
      mod.id = path.resolve(mod.id)
    }
    this.entries.push(mod)
    this.cache[mod.id] = mod
    return this
  },

  toStream: function() {
    var resolution = new GraphResolution(this.entries, this.opts);
    var modules = resolution.toStream();
    var interceptor = through(function(mod) {
      this.emit('module', mod);
      interceptor.queue(mod);
    }.bind(this));
    return combine(modules, interceptor);
  },

  toPromise: function() {
    return aggregate(this.toStream()).then(function(mods) {
      var graph = {};
      for (var i = 0, length = mods.length; i < length; i++)
        graph[mods[i].id] = mods[i];
      return graph;
    });

  },

  invalidateModule: function(id) {
    if (this.cache[id])
      this.cache[id] = {
        id: id,
        package: this.cache[id].package
      };
  }
});

function GraphResolution(entries, opts) {
  this.opts = opts || {}
  this.output = through()
  this.output.pause()
  process.nextTick(this.output.resume.bind(this.output))
  this.basedir = this.opts.basedir || process.cwd()
  this.extensions = ['.js'].concat(this.opts.extensions).filter(Boolean)
  this.resolveImpl = resolveWith.bind(null, this.opts.resolve || browserResolve)
  this.cache = opts.cache || {}
  this.seen = {}
  this.entries = entries
}

GraphResolution.prototype = {

  resolve: function(id, parent) {
    if (this.opts.filter && !this.opts.filter(id))
      return q.resolve({id: false})

    var relativeTo = {
      packageFilter: parent.packageFilter || this.opts.packageFilter,
      extensions: parent.extensions ? parent.extensions : this.extensions,
      modules: this.opts.modules,
      paths: [],
      filename: parent.id,
      package: parent.package
    }

    return this.resolveImpl(id, relativeTo)
      .then(function(mod) {
        this.cache[mod.id] = utils.assign(this.cache[mod.id] || {}, mod)
        return this.cache[mod.id]
      }.bind(this))
      .fail(function(err) {
        err.message += ' (while resolving module ' + id + ', required from ' + parent.id;
        throw err
      }.bind(this))
  },

  resolveMany: function(ids, parent) {
    var result = {},
        resolutions = q.all(ids.map(function(id) {
          return this.resolve(id, parent).then(function(r) {result[id] = r.id})
        }.bind(this)))
    return resolutions.then(function() { return result })
  },

  toStream: function() {
    q.all(this.entries
      .map(function(mod) {return this.walk(mod, {id: '/'})}.bind(this)))
      .fail(this.output.emit.bind(this.output, 'error'))
      .fin(this.output.queue.bind(this.output, null))
    return this.output
  },

  walk: function(mod, parent) {
    var modID = mod.id || mod
    if (this.seen[modID]) return
    this.seen[modID] = true

    if (this.cache[modID])
      mod = this.cache[modID]

    if (mod.source) {
      var cached = this.cache[modID]
      this.report(cached)
      return this.walkDeps(cached, parent)
    }

    return this.applyTransforms(mod)
      .then(this.report.bind(this))
      .then(this.walkDeps.bind(this))
  },

  walkDeps: function(mod) {
    if (mod.deps && Object.keys(mod.deps).length > 0)
      return q.all(Object.keys(mod.deps)
        .filter(function(id) { return mod.deps[id] })
        .map(function(id) { return this.walk(mod.deps[id], mod) }.bind(this)))
  },

  report: function(mod) {
    delete mod.sourcePromise
    this.cache[mod.id] = mod

    if (!mod.deps)
      mod.deps = {}

    if (Buffer.isBuffer(mod.source))
      mod.source = mod.source.toString()

    this.output.queue(utils.clone(mod, true));
    return mod
  },

  readSource: function(mod) {
    if (mod.source) return q.resolve(mod)
    var promise = mod.sourcePromise || aggregate(fs.createReadStream(mod.id))
    return promise.then(function(source) {
      mod.source = source
      return mod
    })
  },

  applyTransforms: function(mod) {
    var transforms = [].concat(this.opts.globalTransform)

    var isTopLevel = this.entries.some(function (entry) {
      return path.relative(path.dirname(entry.id), mod.id)
        .split('/').indexOf('node_modules') < 0
    })

    if (mod.package && this.opts.transformKey)
      transforms = transforms.concat(this.getPackageTransform(mod.package))

    if (isTopLevel)
      transforms = transforms.concat(this.opts.transform)

    transforms = transforms
      .filter(Boolean)
      .map(this.loadTransform.bind(this, mod))
      .concat(depsTransform)

    if (/\.json$/.exec(mod.id))
      transforms.push(jsonTransform)

    if (transforms.length > 0)
      return q.all(transforms)
        .then(this.runTransformPipeline.bind(this, this.readSource(mod)))
    else
      return mod;
  },

  runTransformPipeline: function(mod, transforms) {
    return transforms.reduce(function(mod, t) {
      var run = (t.length === 1) ? this.runStreamingTransform : this.runTransform
      return mod.then(run.bind(this, t))
    }.bind(this), mod)
  },

  runStreamingTransform: function(transform, mod) {
    return aggregate(asStream(mod.source).pipe(transform(mod.id)))
      .then(function(source) {
        mod.source = source
        return mod
      })
  },

  runTransform: function(transform, mod) {
    return q.resolve(transform(mod, this)).then(mergeInto.bind(null, mod))
  },

  loadTransform: function(mod, transform) {
    if (!utils.isString(transform)) return q.resolve(transform)

    return transformResolve(transform, {basedir: path.dirname(mod.id)})
      .fail(transformResolve.bind(null, transform, {basedir: this.basedir}))
      .then(function(res) {
        if (!res)
          throw new Error([
            'cannot find transform module ', transform,
            ' while transforming ', mod.id
          ].join(''))
        return require(res.id)
      }.bind(this))
  },

  getPackageTransform: function(pkg) {
    this.opts.transformKey.forEach(function (k) {
      if (pkg && typeof pkg === 'object') pkg = pkg[k]
    })
    return [].concat(pkg).filter(Boolean)
  },

  noParse: function(id) {
    if (!this.opts.noParse)
      return false
    else if (Array.isArray(this.opts.noParse))
      return this.opts.noParse.indexOf(id) > -1
    else
      return this.opts.noParse(id)
  }
}

function mergeInto(target, source) {
  if (!source) return target
  var result = utils.assign({}, target)
  for (var k in source) {
    var t = result[k], s = source[k]
    if (utils.isArray(t) && utils.isArray(s))
      result[k] = t.concat(s)
    else if (utils.isObject(t) && utils.isObject(s))
      result[k] = mergeInto(t, s)
    else
      result[k] = s
  }
  return result
}

function resolveWith(resolve, id, parent) {
  var p = q.defer()
  resolve(id, parent, function(err, filename, pkg) {
    if (err)
      p.reject(err)
    else
      p.resolve({id: filename, package: pkg})
  })
  return p
}
<commit_msg>Pick object from cache only if id and deps are present<commit_after>"use strict";

var fs                          = require('fs'),
    EventEmitter                = require('events').EventEmitter,
    path                        = require('path'),
    rng                         = require('crypto').rng,
    q                           = require('kew'),
    through                     = require('through'),
    nodeResolve                 = require('resolve'),
    browserResolve              = require('browser-resolve'),
    transformResolve            = resolveWith.bind(null, nodeResolve),
    aggregate                   = require('stream-aggregate-promise'),
    combine                     = require('stream-combiner'),
    asStream                    = require('as-stream'),
    utils                       = require('lodash'),
    depsTransform               = require('./transforms/deps'),
    jsonTransform               = require('./transforms/json');

module.exports = function(entries, opts) {
  return new Graph(entries, opts).toStream()
}

module.exports.Graph = Graph
module.exports.GraphResolution = GraphResolution

function Graph(entries, opts) {
  opts = opts || {}
  opts.basedir = opts.basedir || process.cwd()

  this.opts = opts
  this.entries = []
  this.cache = this.opts.cache = {}

  if (entries)
    [].concat(entries).filter(Boolean).forEach(this.addEntry.bind(this))
}

Graph.prototype = utils.assign(Graph.prototype, EventEmitter.prototype, {

  addEntry: function(m) {
    var mod = {entry: true, package: undefined}
    if (typeof m.pipe === 'function') {
      mod.id = path.join(this.opts.basedir, rng(8).toString('hex') + '.js')
      mod.sourcePromise = aggregate(m)
    } else if (utils.isString(m)) {
      mod.id = path.resolve(m)
    } else {
      mod = m
      mod.id = path.resolve(mod.id)
    }
    this.entries.push(mod)
    this.cache[mod.id] = mod
    return this
  },

  toStream: function() {
    var resolution = new GraphResolution(this.entries, this.opts);
    var modules = resolution.toStream();
    var interceptor = through(function(mod) {
      this.emit('module', mod);
      interceptor.queue(mod);
    }.bind(this));
    return combine(modules, interceptor);
  },

  toPromise: function() {
    return aggregate(this.toStream()).then(function(mods) {
      var graph = {};
      for (var i = 0, length = mods.length; i < length; i++)
        graph[mods[i].id] = mods[i];
      return graph;
    });

  },

  invalidateModule: function(id) {
    if (this.cache[id])
      this.cache[id] = {
        id: id,
        package: this.cache[id].package
      };
  }
});

function GraphResolution(entries, opts) {
  this.opts = opts || {}
  this.output = through()
  this.output.pause()
  process.nextTick(this.output.resume.bind(this.output))
  this.basedir = this.opts.basedir || process.cwd()
  this.extensions = ['.js'].concat(this.opts.extensions).filter(Boolean)
  this.resolveImpl = resolveWith.bind(null, this.opts.resolve || browserResolve)
  this.cache = opts.cache || {}
  this.seen = {}
  this.entries = entries
}

GraphResolution.prototype = {

  resolve: function(id, parent) {
    if (this.opts.filter && !this.opts.filter(id))
      return q.resolve({id: false})

    var relativeTo = {
      packageFilter: parent.packageFilter || this.opts.packageFilter,
      extensions: parent.extensions ? parent.extensions : this.extensions,
      modules: this.opts.modules,
      paths: [],
      filename: parent.id,
      package: parent.package
    }

    return this.resolveImpl(id, relativeTo)
      .then(function(mod) {
        this.cache[mod.id] = utils.assign(this.cache[mod.id] || {}, mod)
        return this.cache[mod.id]
      }.bind(this))
      .fail(function(err) {
        err.message += ' (while resolving module ' + id + ', required from ' + parent.id;
        throw err
      }.bind(this))
  },

  resolveMany: function(ids, parent) {
    var result = {},
        resolutions = q.all(ids.map(function(id) {
          return this.resolve(id, parent).then(function(r) {result[id] = r.id})
        }.bind(this)))
    return resolutions.then(function() { return result })
  },

  toStream: function() {
    q.all(this.entries
      .map(function(mod) {return this.walk(mod, {id: '/'})}.bind(this)))
      .fail(this.output.emit.bind(this.output, 'error'))
      .fin(this.output.queue.bind(this.output, null))
    return this.output
  },

  walk: function(mod, parent) {
    var modID = mod.id || mod
    if (this.seen[modID]) return
    this.seen[modID] = true

    if (this.cache[modID])
      mod = this.cache[modID]

    if (mod.id && mod.source && mod.deps) {
      var cached = this.cache[modID]
      this.report(cached)
      return this.walkDeps(cached, parent)
    }

    return this.applyTransforms(mod)
      .then(this.report.bind(this))
      .then(this.walkDeps.bind(this))
  },

  walkDeps: function(mod) {
    if (mod.deps && Object.keys(mod.deps).length > 0)
      return q.all(Object.keys(mod.deps)
        .filter(function(id) { return mod.deps[id] })
        .map(function(id) { return this.walk(mod.deps[id], mod) }.bind(this)))
  },

  report: function(mod) {
    delete mod.sourcePromise
    this.cache[mod.id] = mod

    if (!mod.deps)
      mod.deps = {}

    if (Buffer.isBuffer(mod.source))
      mod.source = mod.source.toString()

    this.output.queue(utils.clone(mod, true));
    return mod
  },

  readSource: function(mod) {
    if (mod.source) return q.resolve(mod)
    var promise = mod.sourcePromise || aggregate(fs.createReadStream(mod.id))
    return promise.then(function(source) {
      mod.source = source
      return mod
    })
  },

  applyTransforms: function(mod) {
    var transforms = [].concat(this.opts.globalTransform)

    var isTopLevel = this.entries.some(function (entry) {
      return path.relative(path.dirname(entry.id), mod.id)
        .split('/').indexOf('node_modules') < 0
    })

    if (mod.package && this.opts.transformKey)
      transforms = transforms.concat(this.getPackageTransform(mod.package))

    if (isTopLevel)
      transforms = transforms.concat(this.opts.transform)

    transforms = transforms
      .filter(Boolean)
      .map(this.loadTransform.bind(this, mod))
      .concat(depsTransform)

    if (/\.json$/.exec(mod.id))
      transforms.push(jsonTransform)

    if (transforms.length > 0)
      return q.all(transforms)
        .then(this.runTransformPipeline.bind(this, this.readSource(mod)))
    else
      return mod;
  },

  runTransformPipeline: function(mod, transforms) {
    return transforms.reduce(function(mod, t) {
      var run = (t.length === 1) ? this.runStreamingTransform : this.runTransform
      return mod.then(run.bind(this, t))
    }.bind(this), mod)
  },

  runStreamingTransform: function(transform, mod) {
    return aggregate(asStream(mod.source).pipe(transform(mod.id)))
      .then(function(source) {
        mod.source = source
        return mod
      })
  },

  runTransform: function(transform, mod) {
    return q.resolve(transform(mod, this)).then(mergeInto.bind(null, mod))
  },

  loadTransform: function(mod, transform) {
    if (!utils.isString(transform)) return q.resolve(transform)

    return transformResolve(transform, {basedir: path.dirname(mod.id)})
      .fail(transformResolve.bind(null, transform, {basedir: this.basedir}))
      .then(function(res) {
        if (!res)
          throw new Error([
            'cannot find transform module ', transform,
            ' while transforming ', mod.id
          ].join(''))
        return require(res.id)
      }.bind(this))
  },

  getPackageTransform: function(pkg) {
    this.opts.transformKey.forEach(function (k) {
      if (pkg && typeof pkg === 'object') pkg = pkg[k]
    })
    return [].concat(pkg).filter(Boolean)
  },

  noParse: function(id) {
    if (!this.opts.noParse)
      return false
    else if (Array.isArray(this.opts.noParse))
      return this.opts.noParse.indexOf(id) > -1
    else
      return this.opts.noParse(id)
  }
}

function mergeInto(target, source) {
  if (!source) return target
  var result = utils.assign({}, target)
  for (var k in source) {
    var t = result[k], s = source[k]
    if (utils.isArray(t) && utils.isArray(s))
      result[k] = t.concat(s)
    else if (utils.isObject(t) && utils.isObject(s))
      result[k] = mergeInto(t, s)
    else
      result[k] = s
  }
  return result
}

function resolveWith(resolve, id, parent) {
  var p = q.defer()
  resolve(id, parent, function(err, filename, pkg) {
    if (err)
      p.reject(err)
    else
      p.resolve({id: filename, package: pkg})
  })
  return p
}
<|endoftext|>


<commit_before>'use strict';

var ieee754 = require('ieee754');

module.exports = Protobuf;
function Protobuf(buf) {
    this.buf = buf;
    this.pos = 0;
}

Protobuf.prototype = {
    get length() { return this.buf.length; }
};

Protobuf.Varint = 0;
Protobuf.Int64 = 1;
Protobuf.Message = 2;
Protobuf.String = 2;
Protobuf.Packed = 2;
Protobuf.Int32 = 5;

Protobuf.prototype.destroy = function() {
    this.buf = null;
};

// === READING =================================================================

Protobuf.prototype.readUInt32 = function() {
    var val = this.buf.readUInt32LE(this.pos);
    this.pos += 4;
    return val;
};

Protobuf.prototype.readUInt64 = function() {
    var val = this.buf.readUInt64LE(this.pos);
    this.pos += 8;
    return val;
};

Protobuf.prototype.readFloat = function() {
    var val = ieee754.read(this.buf, this.pos, true, 23, 4);
    this.pos += 4;
    return val;
};

Protobuf.prototype.readDouble = function() {
    var val = ieee754.read(this.buf, this.pos, true, 52, 8);
    this.pos += 8;
    return val;
};

Protobuf.prototype.readVarint = function() {
    // TODO: bounds checking
    var pos = this.pos,
        buf = this.buf;

    if (buf[pos] <= 0x7f) {
        this.pos++;
        return buf[pos];
    } else if (buf[pos + 1] <= 0x7f) {
        this.pos += 2;
        return (buf[pos] & 0x7f) | (buf[pos + 1] << 7);
    } else if (buf[pos + 2] <= 0x7f) {
        this.pos += 3;
        return (buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2]) << 14;
    } else if (buf[pos + 3] <= 0x7f) {
        this.pos += 4;
        return (buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2] & 0x7f) << 14 | (buf[pos + 3]) << 21;
    } else if (buf[pos + 4] <= 0x7f) {
        this.pos += 5;
        return ((buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2] & 0x7f) << 14 | (buf[pos + 3]) << 21) + (buf[pos + 4] * 268435456);
    } else {
        this.skip(Protobuf.Varint);
        return 0;
        // throw new Error("TODO: Handle 6+ byte varints");
    }
};

Protobuf.prototype.readSVarint = function() {
    var num = this.readVarint();
    if (num > 2147483647) throw new Error('TODO: Handle numbers >= 2^30');
    // zigzag encoding
    return ((num >> 1) ^ -(num & 1));
};

Protobuf.prototype.readBoolean = function() {
    return Boolean(this.readVarint());
};

Protobuf.prototype.readString = function() {
    var bytes = this.readVarint();
    // TODO: bounds checking
    var chr = String.fromCharCode;
    var b = this.buf;
    var p = this.pos;
    var end = this.pos + bytes;
    var str = '';
    while (p < end) {
        if (b[p] <= 0x7F) str += chr(b[p++]);
        else if (b[p] <= 0xBF) throw new Error('Invalid UTF-8 codepoint: ' + b[p]);
        else if (b[p] <= 0xDF) str += chr((b[p++] & 0x1F) << 6 | (b[p++] & 0x3F));
        else if (b[p] <= 0xEF) str += chr((b[p++] & 0x1F) << 12 | (b[p++] & 0x3F) << 6 | (b[p++] & 0x3F));
        else if (b[p] <= 0xF7) p += 4; // We can't handle these codepoints in JS, so skip.
        else if (b[p] <= 0xFB) p += 5;
        else if (b[p] <= 0xFD) p += 6;
        else throw new Error('Invalid UTF-8 codepoint: ' + b[p]);
    }
    this.pos += bytes;
    return str;
};

Protobuf.prototype.readBuffer = function() {
    var bytes = this.readVarint();
    var buffer = this.buf.subarray(this.pos, this.pos + bytes);
    this.pos += bytes;
    return buffer;
};

Protobuf.prototype.readPacked = function(type) {
    // TODO: bounds checking
    var bytes = this.readVarint();
    var end = this.pos + bytes;
    var array = [];
    var read = this['read' + type];
    while (this.pos < end) {
        array.push(read.call(this));
    }
    return array;
};

Protobuf.prototype.skip = function(val) {
    // TODO: bounds checking
    var type = val & 0x7;

    if (type === Protobuf.Varint) {
        var buf = this.buf;
        while (buf[this.pos++] > 0x7f);

    } else if (type === Protobuf.Message) {
        var bytes = this.readVarint();
        this.pos += bytes;

    } else if (type === Protobuf.Int32) this.pos += 4;
    else if (type === Protobuf.Int64) this.pos += 8;
    else throw new Error('Unimplemented type: ' + type);
};

// === WRITING =================================================================

Protobuf.prototype.writeTag = function(tag, type) {
    this.writeVarint((tag << 3) | type);
};

Protobuf.prototype.realloc = function(min) {
    var length = this.buf.length;
    if (!length) length = 1;
    while (length < this.pos + min) length *= 2;
    if (length != this.buf.length) {
        var buf = new Buffer(length);
        this.buf.copy(buf);
        this.buf = buf;
    }
};

Protobuf.prototype.finish = function() {
    return this.buf.slice(0, this.pos);
};

Protobuf.prototype.writePacked = function(type, tag, items) {
    if (!items.length) return;

    var message = new Protobuf();
    var write = message['write' + type];
    for (var i = 0; i < items.length; i++) {
        write.call(this, items[i]);
    }
    var data = message.finish();

    this.writeTag(tag, Protobuf.Packed);
    this.writeBuffer(data);
};

Protobuf.prototype.writeUInt32 = function(val) {
    this.realloc(4);
    this.buf.writeUInt32LE(val, this.pos);
    this.pos += 4;
};

Protobuf.prototype.writeTaggedUInt32 = function(tag, val) {
    this.writeTag(tag, Protobuf.Int32);
    this.writeUInt32(val);
};

Protobuf.prototype.writeVarint = function(val) {
    val = +val;
    if (isNaN(val)) val = 0;

    if (val <= 0x7f) {
        this.realloc(1);
        this.buf[this.pos++] = val;
    } else if (val <= 0x3fff) {
        this.realloc(2);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 7) & 0x7f);
    } else if (val <= 0x1ffffff) {
        this.realloc(3);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 14) & 0x7f);
    } else if (val <= 0xfffffff) {
        this.realloc(4);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 14) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 21) & 0x7f);
    } else {
        while (val > 0) {
            var b = val & 0x7f;
            val = Math.floor(val / 128);
            if (val > 0) b |= 0x80;
            this.realloc(1);
            this.buf[this.pos++] = b;
        }
    }
};

Protobuf.prototype.writeTaggedVarint = function(tag, val) {
    this.writeTag(tag, Protobuf.Varint);
    this.writeVarint(val);
};

Protobuf.prototype.writeSVarint = function(val) {
    if (val >= 0) {
        this.writeVarint(val * 2);
    } else {
        this.writeVarint(val * -2 - 1);
    }
};

Protobuf.prototype.writeTaggedSVarint = function(tag, val) {
    this.writeTag(tag, Protobuf.Varint);
    this.writeSVarint(val);
};

Protobuf.prototype.writeBoolean = function(val) {
    this.writeVarint(Boolean(val));
};

Protobuf.prototype.writeTaggedBoolean = function(tag, val) {
    this.writeTaggedVarint(tag, Boolean(val));
};

Protobuf.prototype.writeString = function(str) {
    str = String(str);
    var bytes = Buffer.byteLength(str);
    this.writeVarint(bytes);
    this.realloc(bytes);
    this.buf.write(str, this.pos);
    this.pos += bytes;
};

Protobuf.prototype.writeTaggedString = function(tag, str) {
    this.writeTag(tag, Protobuf.String);
    this.writeString(str);
};

Protobuf.prototype.writeFloat = function(val) {
    this.realloc(4);
    this.buf.writeFloatLE(val, this.pos);
    this.pos += 4;
};

Protobuf.prototype.writeTaggedFloat = function(tag, val) {
    this.writeTag(tag, Protobuf.Int32);
    this.writeFloat(val);
};

Protobuf.prototype.writeDouble = function(val) {
    this.realloc(8);
    this.buf.writeDoubleLE(val, this.pos);
    this.pos += 8;
};

Protobuf.prototype.writeTaggedDouble = function(tag, val) {
    this.writeTag(tag, Protobuf.Int64);
    this.writeDouble(val);
};

Protobuf.prototype.writeBuffer = function(buffer) {
    var bytes = buffer.length;
    this.writeVarint(bytes);
    this.realloc(bytes);
    buffer.copy(this.buf, this.pos);
    this.pos += bytes;
};

Protobuf.prototype.writeTaggedBuffer = function(tag, buffer) {
    this.writeTag(tag, Protobuf.String);
    this.writeBuffer(buffer);
};

Protobuf.prototype.writeMessage = function(tag, protobuf) {
    var buffer = protobuf.finish();
    this.writeTag(tag, Protobuf.Message);
    this.writeBuffer(buffer);
};
<commit_msg>ditch Buffer browserify polyfill<commit_after>'use strict';

var ieee754 = require('ieee754');

module.exports = Protobuf;
function Protobuf(buf) {
    this.buf = buf;
    this.pos = 0;
}

var isNode = typeof Buffer !== 'undefined',
    Buffer = isNode ? Buffer : Uint8Array,
    bufferSlice = isNode ? Buffer.prototype.slice : Buffer.prototype.subarray;

Protobuf.prototype = {
    get length() { return this.buf.length; }
};

Protobuf.Varint = 0;
Protobuf.Int64 = 1;
Protobuf.Message = 2;
Protobuf.String = 2;
Protobuf.Packed = 2;
Protobuf.Int32 = 5;

Protobuf.prototype.destroy = function() {
    this.buf = null;
};

// === READING =================================================================

Protobuf.prototype.readUInt32 = function() {
    var val = this.buf.readUInt32LE(this.pos);
    this.pos += 4;
    return val;
};

Protobuf.prototype.readUInt64 = function() {
    var val = this.buf.readUInt64LE(this.pos);
    this.pos += 8;
    return val;
};

Protobuf.prototype.readFloat = function() {
    var val = ieee754.read(this.buf, this.pos, true, 23, 4);
    this.pos += 4;
    return val;
};

Protobuf.prototype.readDouble = function() {
    var val = ieee754.read(this.buf, this.pos, true, 52, 8);
    this.pos += 8;
    return val;
};

Protobuf.prototype.readVarint = function() {
    // TODO: bounds checking
    var pos = this.pos,
        buf = this.buf;

    if (buf[pos] <= 0x7f) {
        this.pos++;
        return buf[pos];
    } else if (buf[pos + 1] <= 0x7f) {
        this.pos += 2;
        return (buf[pos] & 0x7f) | (buf[pos + 1] << 7);
    } else if (buf[pos + 2] <= 0x7f) {
        this.pos += 3;
        return (buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2]) << 14;
    } else if (buf[pos + 3] <= 0x7f) {
        this.pos += 4;
        return (buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2] & 0x7f) << 14 | (buf[pos + 3]) << 21;
    } else if (buf[pos + 4] <= 0x7f) {
        this.pos += 5;
        return ((buf[pos] & 0x7f) | (buf[pos + 1] & 0x7f) << 7 | (buf[pos + 2] & 0x7f) << 14 | (buf[pos + 3]) << 21) + (buf[pos + 4] * 268435456);
    } else {
        this.skip(Protobuf.Varint);
        return 0;
        // throw new Error("TODO: Handle 6+ byte varints");
    }
};

Protobuf.prototype.readSVarint = function() {
    var num = this.readVarint();
    if (num > 2147483647) throw new Error('TODO: Handle numbers >= 2^30');
    // zigzag encoding
    return ((num >> 1) ^ -(num & 1));
};

Protobuf.prototype.readBoolean = function() {
    return Boolean(this.readVarint());
};

Protobuf.prototype.readString = function() {
    var bytes = this.readVarint();
    // TODO: bounds checking
    var chr = String.fromCharCode;
    var b = this.buf;
    var p = this.pos;
    var end = this.pos + bytes;
    var str = '';
    while (p < end) {
        if (b[p] <= 0x7F) str += chr(b[p++]);
        else if (b[p] <= 0xBF) throw new Error('Invalid UTF-8 codepoint: ' + b[p]);
        else if (b[p] <= 0xDF) str += chr((b[p++] & 0x1F) << 6 | (b[p++] & 0x3F));
        else if (b[p] <= 0xEF) str += chr((b[p++] & 0x1F) << 12 | (b[p++] & 0x3F) << 6 | (b[p++] & 0x3F));
        else if (b[p] <= 0xF7) p += 4; // We can't handle these codepoints in JS, so skip.
        else if (b[p] <= 0xFB) p += 5;
        else if (b[p] <= 0xFD) p += 6;
        else throw new Error('Invalid UTF-8 codepoint: ' + b[p]);
    }
    this.pos += bytes;
    return str;
};

Protobuf.prototype.readBuffer = function() {
    var bytes = this.readVarint();
    var buffer = bufferSlice.call(this.buf, this.pos, this.pos + bytes);
    this.pos += bytes;
    return buffer;
};

Protobuf.prototype.readPacked = function(type) {
    // TODO: bounds checking
    var bytes = this.readVarint();
    var end = this.pos + bytes;
    var array = [];
    var read = this['read' + type];
    while (this.pos < end) {
        array.push(read.call(this));
    }
    return array;
};

Protobuf.prototype.skip = function(val) {
    // TODO: bounds checking
    var type = val & 0x7;

    if (type === Protobuf.Varint) {
        var buf = this.buf;
        while (buf[this.pos++] > 0x7f);

    } else if (type === Protobuf.Message) {
        var bytes = this.readVarint();
        this.pos += bytes;

    } else if (type === Protobuf.Int32) this.pos += 4;
    else if (type === Protobuf.Int64) this.pos += 8;
    else throw new Error('Unimplemented type: ' + type);
};

// === WRITING =================================================================

Protobuf.prototype.writeTag = function(tag, type) {
    this.writeVarint((tag << 3) | type);
};

Protobuf.prototype.realloc = function(min) {
    var oldLength = this.buf.length,
        length = oldLength || 1;

    while (length < this.pos + min) length *= 2;

    if (length != oldLength) {
        var buf = new Protobuf.Buffer(length);
        for (var i = 0; i < oldLength; i++) {
            buf[i] = this.buf[i];
        }
        this.buf = buf;
    }
};

Protobuf.prototype.finish = function() {
    return bufferSlice.call(this.buf, 0, this.pos);
};

Protobuf.prototype.writePacked = function(type, tag, items) {
    if (!items.length) return;

    var message = new Protobuf();
    var write = message['write' + type];
    for (var i = 0; i < items.length; i++) {
        write.call(this, items[i]);
    }
    var data = message.finish();

    this.writeTag(tag, Protobuf.Packed);
    this.writeBuffer(data);
};

Protobuf.prototype.writeUInt32 = function(val) {
    this.realloc(4);
    this.buf.writeUInt32LE(val, this.pos);
    this.pos += 4;
};

Protobuf.prototype.writeTaggedUInt32 = function(tag, val) {
    this.writeTag(tag, Protobuf.Int32);
    this.writeUInt32(val);
};

Protobuf.prototype.writeVarint = function(val) {
    val = +val;
    if (isNaN(val)) val = 0;

    if (val <= 0x7f) {
        this.realloc(1);
        this.buf[this.pos++] = val;
    } else if (val <= 0x3fff) {
        this.realloc(2);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 7) & 0x7f);
    } else if (val <= 0x1ffffff) {
        this.realloc(3);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 14) & 0x7f);
    } else if (val <= 0xfffffff) {
        this.realloc(4);
        this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f);
        this.buf[this.pos++] = 0x80 | ((val >>> 14) & 0x7f);
        this.buf[this.pos++] = 0x00 | ((val >>> 21) & 0x7f);
    } else {
        while (val > 0) {
            var b = val & 0x7f;
            val = Math.floor(val / 128);
            if (val > 0) b |= 0x80;
            this.realloc(1);
            this.buf[this.pos++] = b;
        }
    }
};

Protobuf.prototype.writeTaggedVarint = function(tag, val) {
    this.writeTag(tag, Protobuf.Varint);
    this.writeVarint(val);
};

Protobuf.prototype.writeSVarint = function(val) {
    if (val >= 0) {
        this.writeVarint(val * 2);
    } else {
        this.writeVarint(val * -2 - 1);
    }
};

Protobuf.prototype.writeTaggedSVarint = function(tag, val) {
    this.writeTag(tag, Protobuf.Varint);
    this.writeSVarint(val);
};

Protobuf.prototype.writeBoolean = function(val) {
    this.writeVarint(Boolean(val));
};

Protobuf.prototype.writeTaggedBoolean = function(tag, val) {
    this.writeTaggedVarint(tag, Boolean(val));
};

Protobuf.prototype.writeString = function(str) {
    str = String(str);
    var bytes = Buffer.byteLength(str);
    this.writeVarint(bytes);
    this.realloc(bytes);
    this.buf.write(str, this.pos);
    this.pos += bytes;
};

Protobuf.prototype.writeTaggedString = function(tag, str) {
    this.writeTag(tag, Protobuf.String);
    this.writeString(str);
};

Protobuf.prototype.writeFloat = function(val) {
    this.realloc(4);
    this.buf.writeFloatLE(val, this.pos);
    this.pos += 4;
};

Protobuf.prototype.writeTaggedFloat = function(tag, val) {
    this.writeTag(tag, Protobuf.Int32);
    this.writeFloat(val);
};

Protobuf.prototype.writeDouble = function(val) {
    this.realloc(8);
    this.buf.writeDoubleLE(val, this.pos);
    this.pos += 8;
};

Protobuf.prototype.writeTaggedDouble = function(tag, val) {
    this.writeTag(tag, Protobuf.Int64);
    this.writeDouble(val);
};

Protobuf.prototype.writeBuffer = function(buffer) {
    var bytes = buffer.length;
    this.writeVarint(bytes);
    this.realloc(bytes);
    buffer.copy(this.buf, this.pos);
    this.pos += bytes;
};

Protobuf.prototype.writeTaggedBuffer = function(tag, buffer) {
    this.writeTag(tag, Protobuf.String);
    this.writeBuffer(buffer);
};

Protobuf.prototype.writeMessage = function(tag, protobuf) {
    var buffer = protobuf.finish();
    this.writeTag(tag, Protobuf.Message);
    this.writeBuffer(buffer);
};
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');

module.exports = function (opts) {
  return new Injector(opts || {});
};

function Injector(opts) {
  var self = this;
  self.fgi = opts.fgi || 'cyan';
  self.disabled = opts.disabled || [];
}

inherits(Injector, EventEmitter);

Injector.prototype.injectTo = function (tm) {
  // TODO: prevent multiple injections

  var self = this,
      old__drawRow = tm._drawRow,
      old_on = tm.on;

  tm._drawRow = function (index) {
    var isDisabled = self.disabled.indexOf(this.items[index].label) !== -1;
    var oldFg = this.colors.fg;

    if (isDisabled) {
      this.colors.fg = self.fgi;
    }

    old__drawRow.call(this, index);

    if (isDisabled) {
      this.colors.fg = oldFg;
    }
  };

  // save the onselect callback for future use. Replace
  // it with a function and route execution if the selected
  // item is not a disabled item.
  /*
  var l = tm.listeners('select');
  tm.removeAllListeners('select');
  l.forEach(function (e) {
    self.on('selectmirror', e);
  });*/
  tm.on('select', function (label, selected) {
    if (self.disabled.indexOf(label) == -1) {
      self.emit('selectmirror', label, selected);
    }
  });

  tm.on = function (type, listener) {
    if (type === 'select') {
      self.on('selectmirror', listener);
    } else {
      old_on.call(this, type, listener);
    }
  }
};
<commit_msg>Removed commented code<commit_after>var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');

module.exports = function (opts) {
  return new Injector(opts || {});
};

function Injector(opts) {
  var self = this;
  self.fgi = opts.fgi || 'cyan';
  self.disabled = opts.disabled || [];
}

inherits(Injector, EventEmitter);

Injector.prototype.injectTo = function (tm) {
  // TODO: prevent multiple injections

  var self = this,
      old__drawRow = tm._drawRow,
      old_on = tm.on;

  tm._drawRow = function (index) {
    var isDisabled = self.disabled.indexOf(this.items[index].label) !== -1;
    var oldFg = this.colors.fg;

    if (isDisabled) {
      this.colors.fg = self.fgi;
    }

    old__drawRow.call(this, index);

    if (isDisabled) {
      this.colors.fg = oldFg;
    }
  };

  // save the onselect callback for future use. Replace
  // it with a function and route execution if the selected
  // item is not a disabled item.
  tm.on('select', function (label, selected) {
    if (self.disabled.indexOf(label) == -1) {
      self.emit('selectmirror', label, selected);
    }
  });

  tm.on = function (type, listener) {
    if (type === 'select') {
      self.on('selectmirror', listener);
    } else {
      old_on.call(this, type, listener);
    }
  }
};
<|endoftext|>


<commit_before>'use strict'

let result = require('lodash.result')
let merge = require('lodash.merge')

/**
 * A function that can be used as a plugin for bookshelf
 * @param {Object} bookshelf The main bookshelf instance
 * @param {Object} [settings] Additional settings for configuring this plugin
 * @param {String} [settings.field=deleted_at] The name of the field that stores
 * the soft delete information for that model
 */
module.exports = (bookshelf, settings) => {
  // Add default settings
  settings = merge({
    field: 'deleted_at',
    events: {
      destroying: true,
      updating: false,
      saving: false,
      destroyed: true,
      updated: false,
      saved: false
    }
  }, settings)

  /**
   * Check if the operation needs to be patched for not retrieving
   * soft deleted rows
   * @param {Object} model An instantiated bookshelf model
   * @param {Object} attrs The attributes that's being queried
   * @param {Object} options The operation option
   * @param {Boolean} [options.withDeleted=false] Override the default behavior
   * and allow querying soft deleted objects
   */
  function skipDeleted (model, attrs, options) {
    if (!options.isEager || options.parentResponse) {
      let softDelete = this.model ? this.model.prototype.softDelete : this.softDelete

      if (softDelete === true && options.withDeleted !== true) {
        options.query.whereNull(`${result(this, 'tableName')}.${settings.field}`)
      }
    }
  }

  // Store prototypes for later
  let modelPrototype = bookshelf.Model.prototype
  let collectionPrototype = bookshelf.Collection.prototype

  // Extends the default collection to be able to patch relational queries
  // against a set of models
  bookshelf.Collection = bookshelf.Collection.extend({
    initialize: function () {
      collectionPrototype.initialize.call(this)

      this.on('fetching', skipDeleted.bind(this))
    }
  })

  // Extends the default model class
  bookshelf.Model = bookshelf.Model.extend({
    initialize: function () {
      modelPrototype.initialize.call(this)

      this.on('fetching', skipDeleted.bind(this))
      this.on('fetching:collection', skipDeleted.bind(this))
    },

    /**
     * Override the default destroy method to provide soft deletion logic
     * @param {Object} [options] The default options parameters from Model.destroy
     * @param {Boolean} [options.hardDelete=false] Override the default soft
     * delete behavior and allow a model to be hard deleted
     * @return {Promise} A promise that's fulfilled when the model has been
     * hard or soft deleted
     */
    destroy: function (options) {
      options = options || {}
      if (this.softDelete === true && options.hardDelete !== true) {
        // Add default values to options
        options = merge(options, {
          method: 'update',
          patch: true,
          softDelete: true
        })

        // Attributes to be passed to events
        let attrs = { [settings.field]: new Date() }

        return Promise.resolve()
        .then(() => {
          // Don't need to trigger hooks if there's no events registered
          if (!settings.events) return

          let events = []

          // Emulate all pre update events
          if (settings.events.destroying) {
            events.push(this.triggerThen('destroying', this, options).bind(this))
          }

          if (settings.events.saving) {
            events.push(this.triggerThen('saving', this, attrs, options).bind(this))
          }

          if (settings.events.updating) {
            events.push(this.triggerThen('updating', this, attrs, options).bind(this))
          }

          // Resolve all promises in parallel like bookshelf does
          return Promise.all(events)
        })
        .then(() => {
          let knex = bookshelf.knex(this.tableName)

          // Check if we need to use a transaction
          if (options.transacting) {
            knex = knex.transacting(options.transacting)
          }

          return knex.update(attrs, this.idAttribute).where(this.format(this.attributes))
        })
        .then((resp) => {
          // Check if the caller required a row to be deleted and if
          // events weren't totally disabled
          if (!resp && options.require) {
            throw new this.constructor.NoRowsDeletedError('No Rows Deleted')
          } else if (!settings.events) {
            return
          }

          // Add previous attr for reference and reset the model to pristine state
          this.set(attrs)
          options.previousAttributes = this._previousAttributes
          this._reset()

          let events = []

          // Emulate all post update events
          if (settings.events.destroyed) {
            events.push(this.triggerThen('destroyed', this, options).bind(this))
          }

          if (settings.events.saved) {
            events.push(this.triggerThen('saved', this, resp, options).bind(this))
          }

          if (settings.events.updated) {
            events.push(this.triggerThen('updated', this, resp, options).bind(this))
          }

          return Promise.all(events)
        })
        .then(() => this)
      } else {
        return modelPrototype.destroy.call(this, options)
      }
    }
  })
}
<commit_msg>handle count queries<commit_after>'use strict'

let result = require('lodash.result')
let merge = require('lodash.merge')

/**
 * A function that can be used as a plugin for bookshelf
 * @param {Object} bookshelf The main bookshelf instance
 * @param {Object} [settings] Additional settings for configuring this plugin
 * @param {String} [settings.field=deleted_at] The name of the field that stores
 * the soft delete information for that model
 */
module.exports = (bookshelf, settings) => {
  // Add default settings
  settings = merge({
    field: 'deleted_at',
    events: {
      destroying: true,
      updating: false,
      saving: false,
      destroyed: true,
      updated: false,
      saved: false
    }
  }, settings)

  /**
   * Check if the operation needs to be patched for not retrieving
   * soft deleted rows
   * @param {Object} model An instantiated bookshelf model
   * @param {Object} attrs The attributes that's being queried
   * @param {Object} options The operation option
   * @param {Boolean} [options.withDeleted=false] Override the default behavior
   * and allow querying soft deleted objects
   */
  function skipDeleted (model, attrs, options) {
    if (!options.isEager || options.parentResponse) {
      let softDelete = this.model ? this.model.prototype.softDelete : this.softDelete

      if (softDelete === true && options.withDeleted !== true) {
        options.query.whereNull(`${result(this, 'tableName')}.${settings.field}`)
      }
    }
  }

  // Store prototypes for later
  let modelPrototype = bookshelf.Model.prototype
  let collectionPrototype = bookshelf.Collection.prototype

  // Extends the default collection to be able to patch relational queries
  // against a set of models
  bookshelf.Collection = bookshelf.Collection.extend({
    initialize: function () {
      collectionPrototype.initialize.call(this)

      this.on('fetching', skipDeleted.bind(this))
      this.on('counting', (collection, options) => skipDeleted.call(this, null, null, options))
    }
  })

  // Extends the default model class
  bookshelf.Model = bookshelf.Model.extend({
    initialize: function () {
      modelPrototype.initialize.call(this)

      this.on('fetching', skipDeleted.bind(this))
      this.on('fetching:collection', skipDeleted.bind(this))
    },

    /**
     * Override the default destroy method to provide soft deletion logic
     * @param {Object} [options] The default options parameters from Model.destroy
     * @param {Boolean} [options.hardDelete=false] Override the default soft
     * delete behavior and allow a model to be hard deleted
     * @return {Promise} A promise that's fulfilled when the model has been
     * hard or soft deleted
     */
    destroy: function (options) {
      options = options || {}
      if (this.softDelete === true && options.hardDelete !== true) {
        // Add default values to options
        options = merge(options, {
          method: 'update',
          patch: true,
          softDelete: true
        })

        // Attributes to be passed to events
        let attrs = { [settings.field]: new Date() }

        return Promise.resolve()
        .then(() => {
          // Don't need to trigger hooks if there's no events registered
          if (!settings.events) return

          let events = []

          // Emulate all pre update events
          if (settings.events.destroying) {
            events.push(this.triggerThen('destroying', this, options).bind(this))
          }

          if (settings.events.saving) {
            events.push(this.triggerThen('saving', this, attrs, options).bind(this))
          }

          if (settings.events.updating) {
            events.push(this.triggerThen('updating', this, attrs, options).bind(this))
          }

          // Resolve all promises in parallel like bookshelf does
          return Promise.all(events)
        })
        .then(() => {
          let knex = bookshelf.knex(this.tableName)

          // Check if we need to use a transaction
          if (options.transacting) {
            knex = knex.transacting(options.transacting)
          }

          return knex.update(attrs, this.idAttribute).where(this.format(this.attributes))
        })
        .then((resp) => {
          // Check if the caller required a row to be deleted and if
          // events weren't totally disabled
          if (!resp && options.require) {
            throw new this.constructor.NoRowsDeletedError('No Rows Deleted')
          } else if (!settings.events) {
            return
          }

          // Add previous attr for reference and reset the model to pristine state
          this.set(attrs)
          options.previousAttributes = this._previousAttributes
          this._reset()

          let events = []

          // Emulate all post update events
          if (settings.events.destroyed) {
            events.push(this.triggerThen('destroyed', this, options).bind(this))
          }

          if (settings.events.saved) {
            events.push(this.triggerThen('saved', this, resp, options).bind(this))
          }

          if (settings.events.updated) {
            events.push(this.triggerThen('updated', this, resp, options).bind(this))
          }

          return Promise.all(events)
        })
        .then(() => this)
      } else {
        return modelPrototype.destroy.call(this, options)
      }
    }
  })
}
<|endoftext|>


<commit_before>var events = require('events');
var inherits = require('util').inherits
var bopper = require('bopper');
var ditty = require('ditty');

var loadTime = new Date().valueOf();

function Dilla (audioContext, options) {

  if (!(this instanceof Dilla)){
    return new Dilla(audioContext, options);
  }

  events.EventEmitter.call(this);

  options = options || {};

  this.upstartWait = options.upstartWait || 250;
  this.tempo = options.tempo || 120;
  this.beatsPerBar = options.beatsPerBar || 4;
  this.loopLength = options.loopLength || 2;
  this._position = '0.0.00';

  this.context = audioContext;
  this.clock = bopper(this.context);
  this.scheduler = ditty();

  this.clock.setTempo(this.tempo);
  this.clock.on('data', updatePositionFromClock.bind(this));
  this.clock.pipe(this.scheduler).on('data', emitStep.bind(this));
}

inherits(Dilla, events.EventEmitter);

function updatePositionFromClock (step) {
  var position = this.getPositionFromTime(step.time);
  if (this._position !== position) {
    this._position = position;
    this.emit('tick', { 'position': this._position, 'context': this.context });
  }
}

function getPositionFromTime (time) {
  var offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var position = this.clock.getPositionAt(time - offset);
  if (position < 0) return '0.0.00';
  var beatsPerLoop = this.loopLength * this.beatsPerBar;
  var loops = Math.floor(position / beatsPerLoop) || 0;
  position = position - (loops * beatsPerLoop);
  var bars = Math.floor(position / this.beatsPerBar);
  position = position - (bars * this.beatsPerBar);
  var beats = Math.floor(position);
  position = position - beats;
  var ticks = Math.floor(position * 96) + 1;
  if (ticks < 10) ticks = '0' + ticks;
  return ++bars + '.' + ++beats + '.' + ticks;
}

function getClockPositionFromPosition (position) {
  var parts = position.split('.');
  var bars = parseInt(parts[0], 10) - 1;
  var beats = parseInt(parts[1], 10) - 1;
  var ticks = parseInt(parts[2], 10) - 1;
  return (bars * this.beatsPerBar) + beats + (ticks / 96 * 100);
}

function getDurationFromTicks (ticks) {
  return (1 / 96) * ticks;
}

function emitStep (step) {
  var offset = step.offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  step.time = step.time + offset;
  step.clockPosition = step.position;
  step.position = this.getPositionFromTime(step.time);
  step.context = this.context;
  this.emit('step', step);
}

function set (id, events) {
  var self = this;
  events = events.filter(function (event) {
    var parts = event[0].split('.');
    var bars = parseInt(parts[0], 10) - 1;
    var beats = parseInt(parts[1], 10) - 1;
    var ticks = parseInt(parts[2], 10) - 1;
    if (ticks >= 96 || beats >= self.beatsPerBar || bars >= self.loopLength) {
      console.warn('Event is out of bounds: ' + event[0], event);
      return false;
    }
    return true;
  }).map(function (event) {
    return [self.getClockPositionFromPosition(event[0]), self.getDurationFromTicks(event[1]), null, null, event[0], event[1]].concat(event.slice(2));
  });
  this.scheduler.set(id, events, this.beatsPerBar * this.loopLength);
}

function get (id) {
  return this.scheduler.get(id);
}

function channels () {
  return this.scheduler.getIds();
}

function clear (id) {
  var self = this;
  if (id) {
    this.set(id, []);
  }
  else {
    this.scheduler.getIds().forEach(function (id) {
      self.clear(id);
    });
  }
}

function start () {
  var now = new Date().valueOf();
  var waited = now - loadTime;
  if (waited < this.upstartWait) {
    return setTimeout(start.bind(this), this.upstartWait - waited);
  }

  if (!this.clock._state.playing) {
    this.clock.start();
  }
}

function pause () {
  if (this.clock._state.playing) {
    this.clock.stop();
  }
}

function stop () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.clock.setPosition(0);
    this._position = '0.0.00';
  }
}

function position () {
  return this._position;
}

function setPosition (position) {
  this.clock.setPosition(this.getClockPositionFromPosition(position));
}

function setTempo (tempo) {
  this.clock.setTempo(tempo);
}

function setBeatsPerBar (beats) {
  this.beatsPerBar = beats;
}

function setLoopLength (bars) {
  this.loopLength = bars;
}

var proto = Dilla.prototype;
[set, get, clear, start, stop, pause, getPositionFromTime, setTempo, setPosition, getClockPositionFromPosition, getDurationFromTicks, setBeatsPerBar, setLoopLength, channels, position].forEach(function (fn) {
  proto[fn.name] = fn;
});

module.exports = Dilla;<commit_msg>getClockPositionFromPosition should not multiply ticks by hundred, fixes #4<commit_after>var events = require('events');
var inherits = require('util').inherits
var bopper = require('bopper');
var ditty = require('ditty');

var loadTime = new Date().valueOf();

function Dilla (audioContext, options) {

  if (!(this instanceof Dilla)){
    return new Dilla(audioContext, options);
  }

  events.EventEmitter.call(this);

  options = options || {};

  this.upstartWait = options.upstartWait || 250;
  this.tempo = options.tempo || 120;
  this.beatsPerBar = options.beatsPerBar || 4;
  this.loopLength = options.loopLength || 2;
  this._position = '0.0.00';

  this.context = audioContext;
  this.clock = bopper(this.context);
  this.scheduler = ditty();

  this.clock.setTempo(this.tempo);
  this.clock.on('data', updatePositionFromClock.bind(this));
  this.clock.pipe(this.scheduler).on('data', emitStep.bind(this));
}

inherits(Dilla, events.EventEmitter);

function updatePositionFromClock (step) {
  var position = this.getPositionFromTime(step.time);
  if (this._position !== position) {
    this._position = position;
    this.emit('tick', { 'position': this._position, 'context': this.context });
  }
}

function getPositionFromTime (time) {
  var offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var position = this.clock.getPositionAt(time - offset);
  if (position < 0) return '0.0.00';
  var beatsPerLoop = this.loopLength * this.beatsPerBar;
  var loops = Math.floor(position / beatsPerLoop) || 0;
  position = position - (loops * beatsPerLoop);
  var bars = Math.floor(position / this.beatsPerBar);
  position = position - (bars * this.beatsPerBar);
  var beats = Math.floor(position);
  position = position - beats;
  var ticks = Math.floor(position * 96) + 1;
  if (ticks < 10) ticks = '0' + ticks;
  return ++bars + '.' + ++beats + '.' + ticks;
}

function getClockPositionFromPosition (position) {
  var parts = position.split('.');
  var bars = parseInt(parts[0], 10) - 1;
  var beats = parseInt(parts[1], 10) - 1;
  var ticks = parseInt(parts[2], 10) - 1;
  return (bars * this.beatsPerBar) + beats + (ticks / 96);
}

function getDurationFromTicks (ticks) {
  return (1 / 96) * ticks;
}

function emitStep (step) {
  var offset = step.offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  step.time = step.time + offset;
  step.clockPosition = step.position;
  step.position = this.getPositionFromTime(step.time);
  step.context = this.context;
  this.emit('step', step);
}

function set (id, events) {
  var self = this;
  events = events.filter(function (event) {
    var parts = event[0].split('.');
    var bars = parseInt(parts[0], 10) - 1;
    var beats = parseInt(parts[1], 10) - 1;
    var ticks = parseInt(parts[2], 10) - 1;
    if (ticks >= 96 || beats >= self.beatsPerBar || bars >= self.loopLength) {
      console.warn('Event is out of bounds: ' + event[0], event);
      return false;
    }
    return true;
  }).map(function (event) {
    return [self.getClockPositionFromPosition(event[0]), self.getDurationFromTicks(event[1]), null, null, event[0], event[1]].concat(event.slice(2));
  });
  this.scheduler.set(id, events, this.beatsPerBar * this.loopLength);
}

function get (id) {
  return this.scheduler.get(id);
}

function channels () {
  return this.scheduler.getIds();
}

function clear (id) {
  var self = this;
  if (id) {
    this.set(id, []);
  }
  else {
    this.scheduler.getIds().forEach(function (id) {
      self.clear(id);
    });
  }
}

function start () {
  var now = new Date().valueOf();
  var waited = now - loadTime;
  if (waited < this.upstartWait) {
    return setTimeout(start.bind(this), this.upstartWait - waited);
  }

  if (!this.clock._state.playing) {
    this.clock.start();
  }
}

function pause () {
  if (this.clock._state.playing) {
    this.clock.stop();
  }
}

function stop () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.clock.setPosition(0);
    this._position = '0.0.00';
  }
}

function position () {
  return this._position;
}

function setPosition (position) {
  this.clock.setPosition(this.getClockPositionFromPosition(position));
}

function setTempo (tempo) {
  this.clock.setTempo(tempo);
}

function setBeatsPerBar (beats) {
  this.beatsPerBar = beats;
}

function setLoopLength (bars) {
  this.loopLength = bars;
}

var proto = Dilla.prototype;
[set, get, clear, start, stop, pause, getPositionFromTime, setTempo, setPosition, getClockPositionFromPosition, getDurationFromTicks, setBeatsPerBar, setLoopLength, channels, position].forEach(function (fn) {
  proto[fn.name] = fn;
});

module.exports = Dilla;<|endoftext|>