<commit_before>var EventEmitter = require('events').EventEmitter,
  Modem = require('docker-modem'),
  Container = require('./container'),
  Image = require('./image'),
  Exec = require('./exec'),
  util = require('./util'),
  extend = util.extend;

var Docker = function(opts) {
  if (!(this instanceof Docker)) return new Docker(opts);
  this.modem = new Modem(opts);
};

/**
 * Creates a new container
 * @param {Object}   opts     Create options
 * @param {Function} callback Callback
 */
Docker.prototype.createContainer = function(opts, callback) {
  var self = this;
  var optsf = {
    path: '/containers/create?',
    method: 'POST',
    options: opts,
    statusCodes: {
      201: true,
      404: 'no such container',
      406: 'impossible to attach',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    if(err) return callback(err, data);
    callback(err, self.getContainer(data.Id));
  });
};

/**
 * Creates a new image
 * @param {Object}   auth     Authentication (optional)
 * @param {Object}   opts     Create options
 * @param {Function} callback Callback
 */
Docker.prototype.createImage = function(auth, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = auth;
    auth = opts.authconfig || undefined;
  }

  var self = this;
  var optsf = {
    path: '/images/create?',
    method: 'POST',
    options: opts,
    authconfig: auth,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Load image
 * @param {String}   file     File
 * @param {Object}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.loadImage = function(file, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var self = this;
  var optsf = {
    path: '/images/load?',
    method: 'POST',
    options: opts,
    file: file,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Verifies auth
 * @param {Object}   opts     Options
 * @param {Function} callback Callback
 */
Docker.prototype.checkAuth = function(opts, callback) {
  var self = this;
  var optsf = {
    path: '/auth',
    method: 'POST',
    options: opts,
    statusCodes: {
      200: true,
      204: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Buils an image
 * @param {String}   file     File
 * @param {Object}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.buildImage = function(file, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var self = this;
  var optsf = {
    path: '/build?',
    method: 'POST',
    file: file,
    options: opts,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  if(opts.authconfig) {
    optsf.authconfig = optsf.options.authconfig;
    delete optsf.options.authconfig;
  }

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Fetches a Container by ID
 * @param {String} id Container's ID
 */
Docker.prototype.getContainer = function(id) {
  return new Container(this.modem, id);
};

/**
 * Fetches an Image by name
 * @param {String} name Image's name
 */
Docker.prototype.getImage = function(name) {
  return new Image(this.modem, name);
};

/**
 * Fetches an Exec instance by ID
 * @param {String} id Exec instance's ID
 */
Docker.prototype.getExec = function(id) {
  return new Exec(this.modem, id);
};

/**
 * Lists containers
 * @param {Options}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.listContainers = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/containers/json?',
    method: 'GET',
    options: args.opts,
    statusCodes: {
      200: true,
      400: 'bad parameter',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Lists images
 * @param {Options}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.listImages = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/images/json?',
    method: 'GET',
    options: args.opts,
    statusCodes: {
      200: true,
      400: 'bad parameter',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Search images
 * @param {Object}   opts     Options
 * @param {Function} callback Callback
 */
Docker.prototype.searchImages = function(opts, callback) {
  var optsf = {
    path: '/images/search?',
    method: 'GET',
    options: opts,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Info
 * @param  {Function} callback Callback with info
 */
Docker.prototype.info = function(callback) {
  var opts = {
    path: '/info',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(opts, function(err, data) {
    callback(err, data);
  });
};

/**
 * Version
 * @param  {Function} callback Callback
 */
Docker.prototype.version = function(callback) {
  var opts = {
    path: '/version',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(opts, function(err, data) {
    callback(err, data);
  });
};

/**
 * Ping
 * @param  {Function} callback Callback
 */
Docker.prototype.ping = function(callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var optsf = {
    path: '/_ping',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Events
 * @param {Object}   opts     Events options, like 'since' (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.getEvents = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/events?',
    method: 'GET',
    options: args.opts,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Pull is a wrapper around parsing out the tag from the image
 * (which create image cannot do but run can for whatever reasons) and create image overloading.
 * @param  {String}   repoTag  Repository tag
 * @param  {Object}   opts     Options (optional)
 * @param  {Function} callback Callback
 * @return {Object}            Image
 */
Docker.prototype.pull = function(repoTag, opts, callback) {
  var args = util.processArgs(opts, callback);

  var imageSrc = util.parseRepositoryTag(repoTag);
  args.opts.fromImage = imageSrc.repository;
  args.opts.tag = imageSrc.tag;

  var argsf = [args.opts, args.callback];
  return this.createImage.apply(this, argsf);
};

/**
 * Like run command from Docker's CLI
 * @param  {String}   image         Image name to be used.
 * @param  {Array}   cmd           Command to run in array format.
 * @param  {Object}   streamo       Output stream
 * @param  {Object}   createOptions Container create options (optional)
 * @param  {Object}   startOptions  Container start options (optional)
 * @param  {Function} callback      Callback
 * @return {Object}                 EventEmitter
 */
Docker.prototype.run = function(image, cmd, streamo, createOptions, startOptions, callback) {
  if (!callback && typeof createOptions === 'function') {
    callback = createOptions;
    createOptions = {};
    startOptions = {};
  } else if (!callback && typeof startOptions === 'function') {
    callback = startOptions;
    startOptions = {};
  }

  var hub = new EventEmitter();

  function handler(err, container) {
    if (err) return callback(err, container);

    hub.emit('container', container);

    container.attach({stream: true, stdout: true, stderr: true}, function handler(err, stream) {
      if (err) return callback(err, data);

      hub.emit('stream', stream);

      if (streamo) {
        if (streamo instanceof Array) {
          stream.on('end', function () {
            try { streamo[0].end(); } catch (e) {}
            try { streamo[1].end(); } catch (e) {}
          });
          container.modem.demuxStream(stream, streamo[0], streamo[1]);
        } else {
          stream.setEncoding('utf8');
          stream.pipe(streamo, {end: true});
        }
      }

      container.start(startOptions, function(err, data) {
        if(err) return callback(err, data);

        container.wait(function(err, data) {
          hub.emit('data', data);
          callback(err, data, container);
        });
      });
    });
  }

  var optsc = {
    'Hostname': '',
    'User': '',
    'AttachStdin': false,
    'AttachStdout': true,
    'AttachStderr': true,
    'Tty': true,
    'OpenStdin': false,
    'StdinOnce': false,
    'Env': null,
    'Cmd': cmd,
    'Image': image,
    'Volumes': {},
    'VolumesFrom': []
  };

  extend(optsc, createOptions);

  this.createContainer(optsc, handler);

  return hub;
};

module.exports = Docker;
<commit_msg>registryconfig<commit_after>var EventEmitter = require('events').EventEmitter,
  Modem = require('docker-modem'),
  Container = require('./container'),
  Image = require('./image'),
  Exec = require('./exec'),
  util = require('./util'),
  extend = util.extend;

var Docker = function(opts) {
  if (!(this instanceof Docker)) return new Docker(opts);
  this.modem = new Modem(opts);
};

/**
 * Creates a new container
 * @param {Object}   opts     Create options
 * @param {Function} callback Callback
 */
Docker.prototype.createContainer = function(opts, callback) {
  var self = this;
  var optsf = {
    path: '/containers/create?',
    method: 'POST',
    options: opts,
    statusCodes: {
      201: true,
      404: 'no such container',
      406: 'impossible to attach',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    if(err) return callback(err, data);
    callback(err, self.getContainer(data.Id));
  });
};

/**
 * Creates a new image
 * @param {Object}   auth     Authentication (optional)
 * @param {Object}   opts     Create options
 * @param {Function} callback Callback
 */
Docker.prototype.createImage = function(auth, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = auth;
    auth = opts.authconfig || undefined;
  }

  var self = this;
  var optsf = {
    path: '/images/create?',
    method: 'POST',
    options: opts,
    authconfig: auth,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Load image
 * @param {String}   file     File
 * @param {Object}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.loadImage = function(file, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var self = this;
  var optsf = {
    path: '/images/load?',
    method: 'POST',
    options: opts,
    file: file,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Verifies auth
 * @param {Object}   opts     Options
 * @param {Function} callback Callback
 */
Docker.prototype.checkAuth = function(opts, callback) {
  var self = this;
  var optsf = {
    path: '/auth',
    method: 'POST',
    options: opts,
    statusCodes: {
      200: true,
      204: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Buils an image
 * @param {String}   file     File
 * @param {Object}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.buildImage = function(file, opts, callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var self = this;
  var optsf = {
    path: '/build?',
    method: 'POST',
    file: file,
    options: opts,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  if(opts.registryconfig) {
    optsf.registryconfig = optsf.options.registryconfig;
    delete optsf.options.registryconfig;
  }

  //undocumented?
  if(opts.authconfig) {
    optsf.authconfig = optsf.options.authconfig;
    delete optsf.options.authconfig;
  }

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Fetches a Container by ID
 * @param {String} id Container's ID
 */
Docker.prototype.getContainer = function(id) {
  return new Container(this.modem, id);
};

/**
 * Fetches an Image by name
 * @param {String} name Image's name
 */
Docker.prototype.getImage = function(name) {
  return new Image(this.modem, name);
};

/**
 * Fetches an Exec instance by ID
 * @param {String} id Exec instance's ID
 */
Docker.prototype.getExec = function(id) {
  return new Exec(this.modem, id);
};

/**
 * Lists containers
 * @param {Options}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.listContainers = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/containers/json?',
    method: 'GET',
    options: args.opts,
    statusCodes: {
      200: true,
      400: 'bad parameter',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Lists images
 * @param {Options}   opts     Options (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.listImages = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/images/json?',
    method: 'GET',
    options: args.opts,
    statusCodes: {
      200: true,
      400: 'bad parameter',
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Search images
 * @param {Object}   opts     Options
 * @param {Function} callback Callback
 */
Docker.prototype.searchImages = function(opts, callback) {
  var optsf = {
    path: '/images/search?',
    method: 'GET',
    options: opts,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Info
 * @param  {Function} callback Callback with info
 */
Docker.prototype.info = function(callback) {
  var opts = {
    path: '/info',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(opts, function(err, data) {
    callback(err, data);
  });
};

/**
 * Version
 * @param  {Function} callback Callback
 */
Docker.prototype.version = function(callback) {
  var opts = {
    path: '/version',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(opts, function(err, data) {
    callback(err, data);
  });
};

/**
 * Ping
 * @param  {Function} callback Callback
 */
Docker.prototype.ping = function(callback) {
  if (!callback && typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  var optsf = {
    path: '/_ping',
    method: 'GET',
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    callback(err, data);
  });
};

/**
 * Events
 * @param {Object}   opts     Events options, like 'since' (optional)
 * @param {Function} callback Callback
 */
Docker.prototype.getEvents = function(opts, callback) {
  var args = util.processArgs(opts, callback);

  var optsf = {
    path: '/events?',
    method: 'GET',
    options: args.opts,
    isStream: true,
    statusCodes: {
      200: true,
      500: 'server error'
    }
  };

  this.modem.dial(optsf, function(err, data) {
    args.callback(err, data);
  });
};

/**
 * Pull is a wrapper around parsing out the tag from the image
 * (which create image cannot do but run can for whatever reasons) and create image overloading.
 * @param  {String}   repoTag  Repository tag
 * @param  {Object}   opts     Options (optional)
 * @param  {Function} callback Callback
 * @return {Object}            Image
 */
Docker.prototype.pull = function(repoTag, opts, callback) {
  var args = util.processArgs(opts, callback);

  var imageSrc = util.parseRepositoryTag(repoTag);
  args.opts.fromImage = imageSrc.repository;
  args.opts.tag = imageSrc.tag;

  var argsf = [args.opts, args.callback];
  return this.createImage.apply(this, argsf);
};

/**
 * Like run command from Docker's CLI
 * @param  {String}   image         Image name to be used.
 * @param  {Array}   cmd           Command to run in array format.
 * @param  {Object}   streamo       Output stream
 * @param  {Object}   createOptions Container create options (optional)
 * @param  {Object}   startOptions  Container start options (optional)
 * @param  {Function} callback      Callback
 * @return {Object}                 EventEmitter
 */
Docker.prototype.run = function(image, cmd, streamo, createOptions, startOptions, callback) {
  if (!callback && typeof createOptions === 'function') {
    callback = createOptions;
    createOptions = {};
    startOptions = {};
  } else if (!callback && typeof startOptions === 'function') {
    callback = startOptions;
    startOptions = {};
  }

  var hub = new EventEmitter();

  function handler(err, container) {
    if (err) return callback(err, container);

    hub.emit('container', container);

    container.attach({stream: true, stdout: true, stderr: true}, function handler(err, stream) {
      if (err) return callback(err, data);

      hub.emit('stream', stream);

      if (streamo) {
        if (streamo instanceof Array) {
          stream.on('end', function () {
            try { streamo[0].end(); } catch (e) {}
            try { streamo[1].end(); } catch (e) {}
          });
          container.modem.demuxStream(stream, streamo[0], streamo[1]);
        } else {
          stream.setEncoding('utf8');
          stream.pipe(streamo, {end: true});
        }
      }

      container.start(startOptions, function(err, data) {
        if(err) return callback(err, data);

        container.wait(function(err, data) {
          hub.emit('data', data);
          callback(err, data, container);
        });
      });
    });
  }

  var optsc = {
    'Hostname': '',
    'User': '',
    'AttachStdin': false,
    'AttachStdout': true,
    'AttachStderr': true,
    'Tty': true,
    'OpenStdin': false,
    'StdinOnce': false,
    'Env': null,
    'Cmd': cmd,
    'Image': image,
    'Volumes': {},
    'VolumesFrom': []
  };

  extend(optsc, createOptions);

  this.createContainer(optsc, handler);

  return hub;
};

module.exports = Docker;
<|endoftext|>


<commit_before>/* global describe it beforeEach */

require('./helpers/before');

var request = require('supertest');
var resetHelper = require('./helpers/reset');
var storage = require('../src/storage');
var server = require('../src/server');

describe('/search', function () {
  beforeEach(resetHelper);

  beforeEach(function (done) {
    storage.indexContent('foo/aaa', { title: 'first', body: 'all aaa', keywords: '' }, done);
  });
  beforeEach(function (done) {
    storage.indexContent('foo/bbb', { title: 'second', body: 'all bbb', keywords: '' }, done);
  });
  beforeEach(function (done) {
    storage.indexContent('foo/ccc', { title: 'third', body: 'all ccc', keywords: '' }, done);
  });

  it('returns IDs of matching documents', function (done) {
    request(server.create())
      .get('/search?q=all')
      .expect(200)
      .expect({
        total: 3,
        results: [
          {
            contentID: 'foo/aaa',
            title: 'first',
            excerpt: '...all...'
          },
          {
            contentID: 'foo/bbb',
            title: 'second',
            excerpt: '...all...'
          },
          {
            contentID: 'foo/ccc',
            title: 'third',
            excerpt: '...all...'
          }
        ]
      }, done);
  });

  it('returns an empty excerpt when a match is only in the title', function (done) {
    request(server.create())
      .get('/search?q=second')
      .expect(200)
      .expect({
        total: 1,
        results: [
          {
            contentID: 'foo/bbb',
            title: 'second',
            excerpt: ''
          }
        ]
      }, done);
  });

  it('responds with a 409 if no query is provided', function (done) {
    request(server.create())
      .get('/search')
      .expect(409, done);
  });
});
<commit_msg>More consistent failure case.<commit_after>/* global describe it beforeEach */

require('./helpers/before');

var request = require('supertest');
var resetHelper = require('./helpers/reset');
var storage = require('../src/storage');
var server = require('../src/server');

describe('/search', function () {
  beforeEach(resetHelper);

  beforeEach(function (done) {
    storage.indexContent('foo/aaa', { title: 'first', body: 'all aaa', keywords: '' }, done);
  });
  beforeEach(function (done) {
    storage.indexContent('foo/bbb', { title: 'second', body: 'all bbb', keywords: '' }, done);
  });
  beforeEach(function (done) {
    storage.indexContent('foo/ccc', { title: 'third', body: 'all ccc', keywords: '' }, done);
  });

  it('returns IDs of matching documents', function (done) {
    request(server.create())
      .get('/search?q=all')
      .expect(200)
      .expect({
        total: 3,
        results: [
          {
            contentID: 'foo/aaa',
            title: 'first',
            excerpt: '...all...'
          },
          {
            contentID: 'foo/bbb',
            title: 'second',
            excerpt: '...all...'
          },
          {
            contentID: 'foo/ccc',
            title: 'third',
            excerpt: '...all...'
          }
        ]
      }, done);
  });

  it('returns a body excerpt when a match is only in the title', function (done) {
    request(server.create())
      .get('/search?q=second')
      .expect(200)
      .expect({
        total: 1,
        results: [
          {
            contentID: 'foo/bbb',
            title: 'second',
            excerpt: 'all bbb'
          }
        ]
      }, done);
  });

  it('responds with a 409 if no query is provided', function (done) {
    request(server.create())
      .get('/search')
      .expect(409, done);
  });
});
<|endoftext|>


<commit_before>/*jslint browser: true, devel: true, bitwise: false, debug: true, eqeq: false, es5: true, evil: false, forin: false, newcap: false, nomen: true, plusplus: true, regexp: false, unparam: false, sloppy: true, stupid: false, sub: false, todo: true, vars: true, white: true */

var assert = require('assert');
var jpeg = require('./jpeg'),
	exif = require('./exif'),
	simplify = require('./simplify');

function ExifResult(startMarker, tags, imageSize, thumbnailOffset, thumbnailLength, thumbnailType, app1Offset) {
	this.startMarker = startMarker;
	this.tags = tags;
	this.imageSize = imageSize;
	this.thumbnailOffset = thumbnailOffset;
	this.thumbnailLength = thumbnailLength;
	this.thumbnailType = thumbnailType;
	this.app1Offset = app1Offset;
}

ExifResult.prototype = {
	hasThumbnail: function(mime) {
		if(!this.thumbnailOffset || !this.thumbnailLength) {
			return false;
		}
		if(typeof mime !== 'string') {
			return true;
		}
		if(mime.toLowerCase().trim() === 'image/jpeg') {
			return this.thumbnailType === 6;
		}
		if(mime.toLowerCase().trim() === 'image/tiff') {
			return this.thumbnailType === 1;
		}
		return false;
	},
	getThumbnailOffset: function() {
		return this.app1Offset + 6 + this.thumbnailOffset;
	},
	getThumbnailLength: function() {
		return this.thumbnailLength;
	},
	getThumbnailBuffer: function() {
		return this._getThumbnailStream().nextBuffer(this.thumbnailLength);
	},
	_getThumbnailStream: function() {
		return this.startMarker.openWithOffset(this.getThumbnailOffset());
	},
	getImageSize: function() {
		return this.imageSize;
	},
	getThumbnailSize: function() {
		var stream = this._getThumbnailStream(), size;
		jpeg.parseSections(stream, function(sectionType, sectionStream) {
			if(jpeg.getSectionName(sectionType).name === 'SOF') {
				size = jpeg.getSizeFromSOFSection(sectionStream);
			}
		});
		return size;
	}
};

function Parser(stream) {
	this.stream = stream;
	this.flags = {
		readBinaryTags: false,
		resolveTagNames: true,
		simplifyValues: true,
		imageSize: true,
		hidePointers: true,
		returnTags: true
	};
}

Parser.prototype = {
	enableBinaryFields: function(enable) {
		this.flags.readBinaryTags = !!enable;
		return this;
	},
	enablePointers: function(enable) {
		this.flags.hidePointers = !enable;
		return this;
	},
	enableTagNames: function(enable) {
		this.flags.resolveTagNames = !!enable;
		return this;
	},
	enableImageSize: function(enable) {
		this.flags.imageSize = !!enable;
		return this;
	},
	enableReturnTags: function(enable) {
		this.flags.returnTags = !!enable;
		return this;
	},
	enableSimpleValues: function(enable) {
		this.flags.simplifyValues = !!enable;
		return this;
	},
	parse: function() {
		var start = this.stream.mark(),
			stream = start.openWithOffset(0),
			flags = this.flags,
			tags,
			imageSize,
			thumbnailOffset,
			thumbnailLength,
			thumbnailType,
			app1Offset,
			tagNames,
			getTagValue, setTagValue;
		if(flags.resolveTagNames) {
			tagNames = require('./exif-tags');
		}
		if(flags.resolveTagNames) {
			tags = {};
			getTagValue = function(t) {
				return tags[t.name];
			};
			setTagValue = function(t, value) {
				tags[t.name] = value;
			};
		} else {
			tags = [];
			getTagValue = function(t) {
				var i;
				for(i = 0; i < tags.length; ++i) {
					if(tags[i].type === t.type && tags[i].section === t.section) {
						return tags.value;
					}
				}
			};
			setTagValue = function(t, value) {
				var i;
				for(i = 0; i < tags.length; ++i) {
					if(tags[i].type === t.type && tags[i].section === t.section) {
						tags.value = value;
						return;
					}
				}
			};
		}

		jpeg.parseSections(stream, function(sectionType, sectionStream) {
			var validExifHeaders, sectionOffset = sectionStream.offsetFrom(start);
			if(sectionType === 0xE1) {
				validExifHeaders = exif.parseTags(sectionStream, function(ifdSection, tagType, value, format) {
					//ignore binary fields if disabled
					if(!flags.readBinaryTags && format === 7) {
						return;
					}

					if(tagType === 0x0201) {
						thumbnailOffset = value[0];
						if(flags.hidePointers) {return;}
					} else if(tagType === 0x0202) {
						thumbnailLength = value[0];
						if(flags.hidePointers) {return;}
					} else if(tagType === 0x0103) {
						thumbnailType = value[0];
						if(flags.hidePointers) {return;}
					}
					//if flag is set to not store tags, return here after storing pointers
					if(!flags.returnTags) {
						return;
					}

					if(flags.simplifyValues) {
						value = simplify.simplifyValue(value, format);
					}
					if(flags.resolveTagNames) {
						var sectionTagNames = ifdSection === exif.GPSIFD ? tagNames.gps : tagNames.exif;
						var name = sectionTagNames[tagType];
						if(!name) {
							name = tagNames.exif[tagType];
						}
						tags[name] = value;
					} else {
						tags.push({
							section: ifdSection,
							type: tagType,
							value: value
						});
					}
				});
				if(validExifHeaders) {
					app1Offset = sectionOffset;
				}
			}
			else if(flags.imageSize && jpeg.getSectionName(sectionType).name === 'SOF') {
				imageSize = jpeg.getSizeFromSOFSection(sectionStream);
			}
		});

		if(flags.simplifyValues) {
			simplify.castDegreeValues(getTagValue, setTagValue);
			simplify.castDateValues(getTagValue, setTagValue);
		}

		return new ExifResult(start, tags, imageSize, thumbnailOffset, thumbnailLength, thumbnailType, app1Offset);
	}
};

module.exports = Parser;<commit_msg>remove unused import, that caused problems with the bare browser bundle<commit_after>/*jslint browser: true, devel: true, bitwise: false, debug: true, eqeq: false, es5: true, evil: false, forin: false, newcap: false, nomen: true, plusplus: true, regexp: false, unparam: false, sloppy: true, stupid: false, sub: false, todo: true, vars: true, white: true */

var jpeg = require('./jpeg'),
	exif = require('./exif'),
	simplify = require('./simplify');

function ExifResult(startMarker, tags, imageSize, thumbnailOffset, thumbnailLength, thumbnailType, app1Offset) {
	this.startMarker = startMarker;
	this.tags = tags;
	this.imageSize = imageSize;
	this.thumbnailOffset = thumbnailOffset;
	this.thumbnailLength = thumbnailLength;
	this.thumbnailType = thumbnailType;
	this.app1Offset = app1Offset;
}

ExifResult.prototype = {
	hasThumbnail: function(mime) {
		if(!this.thumbnailOffset || !this.thumbnailLength) {
			return false;
		}
		if(typeof mime !== 'string') {
			return true;
		}
		if(mime.toLowerCase().trim() === 'image/jpeg') {
			return this.thumbnailType === 6;
		}
		if(mime.toLowerCase().trim() === 'image/tiff') {
			return this.thumbnailType === 1;
		}
		return false;
	},
	getThumbnailOffset: function() {
		return this.app1Offset + 6 + this.thumbnailOffset;
	},
	getThumbnailLength: function() {
		return this.thumbnailLength;
	},
	getThumbnailBuffer: function() {
		return this._getThumbnailStream().nextBuffer(this.thumbnailLength);
	},
	_getThumbnailStream: function() {
		return this.startMarker.openWithOffset(this.getThumbnailOffset());
	},
	getImageSize: function() {
		return this.imageSize;
	},
	getThumbnailSize: function() {
		var stream = this._getThumbnailStream(), size;
		jpeg.parseSections(stream, function(sectionType, sectionStream) {
			if(jpeg.getSectionName(sectionType).name === 'SOF') {
				size = jpeg.getSizeFromSOFSection(sectionStream);
			}
		});
		return size;
	}
};

function Parser(stream) {
	this.stream = stream;
	this.flags = {
		readBinaryTags: false,
		resolveTagNames: true,
		simplifyValues: true,
		imageSize: true,
		hidePointers: true,
		returnTags: true
	};
}

Parser.prototype = {
	enableBinaryFields: function(enable) {
		this.flags.readBinaryTags = !!enable;
		return this;
	},
	enablePointers: function(enable) {
		this.flags.hidePointers = !enable;
		return this;
	},
	enableTagNames: function(enable) {
		this.flags.resolveTagNames = !!enable;
		return this;
	},
	enableImageSize: function(enable) {
		this.flags.imageSize = !!enable;
		return this;
	},
	enableReturnTags: function(enable) {
		this.flags.returnTags = !!enable;
		return this;
	},
	enableSimpleValues: function(enable) {
		this.flags.simplifyValues = !!enable;
		return this;
	},
	parse: function() {
		var start = this.stream.mark(),
			stream = start.openWithOffset(0),
			flags = this.flags,
			tags,
			imageSize,
			thumbnailOffset,
			thumbnailLength,
			thumbnailType,
			app1Offset,
			tagNames,
			getTagValue, setTagValue;
		if(flags.resolveTagNames) {
			tagNames = require('./exif-tags');
		}
		if(flags.resolveTagNames) {
			tags = {};
			getTagValue = function(t) {
				return tags[t.name];
			};
			setTagValue = function(t, value) {
				tags[t.name] = value;
			};
		} else {
			tags = [];
			getTagValue = function(t) {
				var i;
				for(i = 0; i < tags.length; ++i) {
					if(tags[i].type === t.type && tags[i].section === t.section) {
						return tags.value;
					}
				}
			};
			setTagValue = function(t, value) {
				var i;
				for(i = 0; i < tags.length; ++i) {
					if(tags[i].type === t.type && tags[i].section === t.section) {
						tags.value = value;
						return;
					}
				}
			};
		}

		jpeg.parseSections(stream, function(sectionType, sectionStream) {
			var validExifHeaders, sectionOffset = sectionStream.offsetFrom(start);
			if(sectionType === 0xE1) {
				validExifHeaders = exif.parseTags(sectionStream, function(ifdSection, tagType, value, format) {
					//ignore binary fields if disabled
					if(!flags.readBinaryTags && format === 7) {
						return;
					}

					if(tagType === 0x0201) {
						thumbnailOffset = value[0];
						if(flags.hidePointers) {return;}
					} else if(tagType === 0x0202) {
						thumbnailLength = value[0];
						if(flags.hidePointers) {return;}
					} else if(tagType === 0x0103) {
						thumbnailType = value[0];
						if(flags.hidePointers) {return;}
					}
					//if flag is set to not store tags, return here after storing pointers
					if(!flags.returnTags) {
						return;
					}

					if(flags.simplifyValues) {
						value = simplify.simplifyValue(value, format);
					}
					if(flags.resolveTagNames) {
						var sectionTagNames = ifdSection === exif.GPSIFD ? tagNames.gps : tagNames.exif;
						var name = sectionTagNames[tagType];
						if(!name) {
							name = tagNames.exif[tagType];
						}
						tags[name] = value;
					} else {
						tags.push({
							section: ifdSection,
							type: tagType,
							value: value
						});
					}
				});
				if(validExifHeaders) {
					app1Offset = sectionOffset;
				}
			}
			else if(flags.imageSize && jpeg.getSectionName(sectionType).name === 'SOF') {
				imageSize = jpeg.getSizeFromSOFSection(sectionStream);
			}
		});

		if(flags.simplifyValues) {
			simplify.castDegreeValues(getTagValue, setTagValue);
			simplify.castDateValues(getTagValue, setTagValue);
		}

		return new ExifResult(start, tags, imageSize, thumbnailOffset, thumbnailLength, thumbnailType, app1Offset);
	}
};

module.exports = Parser;<|endoftext|>


<commit_before>var URL = require('url');
var queue = require('queue-async');
var CacheDebounce = require('cache-debounce');
var typeis = require('type-is').is;
var agent = require('../utils/agent');
var debug = require('debug')('raja:dom');

module.exports = DomProxy;

function DomProxy(raja, opts) {
	if (!(this instanceof DomProxy)) return new DomProxy(raja, opts);
	this.raja = raja;
	var Dom = this.Dom = opts.dom;

	var ioreg;

	var self = this;

	Dom.use(domProxyPluginMeta, 'before');

	if (opts.disable) return;

	Dom.Handler.prototype.init = function() {
		this.opts.params = stealSession;
		this.listener = listener.bind(this);
		raja.on('message', this.listener);
	};

	var _finish = Dom.Handler.prototype.finish;
	Dom.Handler.prototype.finish = function(user, res) {
		res.set('X-Raja', opts.namespace);
		for (var name in user.headers) {
			if (name in {'Vary': 1, 'X-Grant': 1, 'ETag': 1}) {
				res.set(name, user.headers[name]);
			}
		}
		_finish.call(this, user, res);
	};

	Dom.Handler.prototype.loadLocal = raja.proxies.local.get.bind(raja.proxies.local);

	Dom.Handler.prototype.loadRemote = function(url, opts, cb) {
		raja.proxies.remote.get(url, opts, function(err, res) {
			cb(err, res && res.data);
		});
	};

	Dom.author(domProxyPlugin, 'before');
	Dom.use(domProxyPlugin, 'before');
	Dom.use(domProxyBusyPlugin, 'before');
	Dom.use(domProxyDonePlugin, 'after');

	function listener(msg) {
		var h = this;
		var reload = false;
		msg.parents.forEach(function(key) {
			raja.store.get(key, function(err, resource) {
				if (err) return raja.error(err);
				if (!resource) return;
				if (msg.key == key && msg.mtime > resource.mtime && (!resource.itime || msg.mtime > resource.itime)) {
					resource.itime = msg.mtime;
				}
				if (resource.page && reload) {
					debug("Detected change releases page", resource.key);
					Dom.pool.release(resource.page);
				}
				var contentType = resource.headers && resource.headers['Content-Type'];
				if (contentType && (typeis(contentType, '*/javascript') || typeis(contentType, 'text/html'))) {
					debug("Detected change in", key);
					reload = true;
				}
			});
		});
	}

	function domProxyPluginMeta(page, resource, req, res) {
		page.run(function(key, client, ns, done) {
			var node = document.getElementById('script');
			if (!node) node = document.createElement('script');
			node.id = 'raja';
			node.setAttribute('data-client', client);
			node.setAttribute('data-namespace', ns);
			node.setAttribute('data-room', key);
			node.type = "text/javascript";
			node.textContent = "(function(r) {if (r && r.ready) r.ready();})(window.raja);";
			if (!node.parentNode) {
				var tn = document.createTextNode("\n");
				document.head.insertBefore(node, document.head.firstChild);
				document.head.insertBefore(tn, node);
			}
			done();
		}, [resource.key, opts.client, opts.namespace]);
	}

	function domProxyPlugin(page, resource) {
		page.on('unload', function() {}); // keep it running !
		page.on('error', raja.error.bind(raja));
		page.on('request', function(req) {
			if (!resource.resources) {
				return;
			}
//			if (resource.existings && resource.existings[req.uri]) {
//				// copy back because some of them won't have response because of the cache
//				resource.depend(req.uri);
//			}

			req.headers['Cache-Control'] = 'no-cache';

			if (ioreg && ioreg.test(URL.parse(req.uri).pathname)) {
				req.ignore = true;
			}
		});
		page.on('response', function(res) {
			if (!res.uri || res.uri == "about:blank") return;
			if (res.uri == resource.url) return; // ignore view and author
			if (!resource.resources) return;
			if (res.status >= 200 && res.status < 400) {
				if (!ioreg) {
					var iopath = raja.io && raja.io.socket && raja.io.socket.io.opts.path;
					if (iopath) ioreg = new RegExp("^" + iopath);
				}
				if (ioreg && ioreg.test(URL.parse(res.uri).pathname)) {
					if (typeis(res.mime, 'javascript') == false) resource.live = true;
				} else {
					var child = raja.create(res.uri, res);
					resource.depend(child);

					// this covers the case where a resource finishes loading after idle
					if (resource.valid) {
						resource.itime = new Date();
						resource.valid = false;
						resource.save();
					}
				}
			}
		});
	}

	function domProxyBusyPlugin(page, resource) {
		page.on('busy', function() {
			if (resource.itime && resource.itime > resource.mtime) {
				delete resource.itime;
				// update resources to make sure instances loaded on server receive messages
				resource.valid = false;
				resource.save();
			}
		});
	}

	function domProxyDonePlugin(page, resource, req, res) {
		var output = resource.output;
		resource.output = function(page, cb) {
			resource.output = output;
			if (!resource.itime || resource.itime <= resource.mtime) {
				resource.valid = true;
				resource.mtime = new Date();
			} else if (!resource.mtime) {
				resource.mtime = new Date();
			}
			updateGrants(resource, function(err) {
				// must be done at the very end, since the key varies on the resources grants
				if (err) return cb(err);
				if (req.headers['X-Right'] != resource.headers['X-Grant']) {
					console.warn(
						'Permissions mismatch while accessing',
						resource.url,
						'X-Right', req.headers['X-Right'],
						'X-Grant', resource.headers['X-Grant']
					);
				}
				output.call(resource, page, cb);
			});
		};
	}

	var _get = Dom.Handler.prototype.get;
	Dom.Handler.prototype.get = function(url, depend, req, cb) {
		if (!cb) {
			cb = req;
			req = null;
		}
		if (!cb) {
			cb = depend;
			depend = null;
		}
		var obj = {url: url, builder: 'dom'};
		if (req) obj.headers = raja.headers(req);
		debug('get', obj);
		raja.upsert(obj, function(err, resource) {
			if (err) return cb(err);
			if (!resource.headers) resource.headers = {};
			if (!resource.resources) resource.resources = {};
			if (depend) resource.depend(depend);
			if (!resource.output) resource.output = function(page, cb) {
				page.html(cb);
			};
			cb(null, resource);
		});
	};
}

function updateGrants(resource, cb) {
	var q = queue();
	var grants = mergeGrants({}, resource.headers);
	// must copy X-Right headers because express proxy sets them on response,
	// but response hasn't been completed yet
	var rights = resource.headers['X-Right'];
	debug('initial resource rights', rights);
	if (rights) rights.split(',').forEach(function(right) {
		grants[right] = true;
	});
	var store = resource.raja.store;
	for (var key in resource.resources) {
		q.defer(store.get.bind(store), key);
	}
	q.awaitAll(function(err, resources) {
		if (err) return cb(err);
		resources.forEach(function(item) {
			if (item) mergeGrants(grants, item.headers);
		});
		grants = Object.keys(grants);
		if (grants.length) {
			mergeHeader(resource.headers, 'Vary', 'X-Grant');
			resource.headers['X-Grant'] = grants.sort().join(',');
		}
		cb();
	});
}

function mergeGrants(obj, headers) {
	var vary = headers.Vary;
	if (!vary || vary.split(',').indexOf('X-Grant') < 0) return obj;
	var header = headers['X-Grant'];
	if (!header) return obj;
	debug('merge grants', header);
	header.split(',').forEach(function(val) {
		obj[val.trim()] = true;
	});
	return obj;
}

function mergeHeader(headers, name, val) {
	var header = headers[name];
	header = header ? header.split(',') : [];
	if (header.indexOf(val) < 0) header.push(val);
	headers[name] = header.join(',');
}

function stealSession(opts, req) {
	var session = req.session;
	var store = req.sessionStore;
	// 1) generate a new session
	var decoy = {sessionStore: store};
	store.generate(decoy);
	// 2) give it same data
	for (var key in session) {
		if (decoy.session[key] != null || key == 'passport') continue;
		decoy.session[key] = session[key];
	}
	decoy.session.save();
	debug("hosted session", decoy.sessionID, decoy.session);
	// 3) set that session cookie into opts.cookies
	opts.cookies = agent.sessionCookie(req, decoy.sessionID, true);
}

<commit_msg>page must be ready to add a tag on it<commit_after>var URL = require('url');
var queue = require('queue-async');
var CacheDebounce = require('cache-debounce');
var typeis = require('type-is').is;
var agent = require('../utils/agent');
var debug = require('debug')('raja:dom');

module.exports = DomProxy;

function DomProxy(raja, opts) {
	if (!(this instanceof DomProxy)) return new DomProxy(raja, opts);
	this.raja = raja;
	var Dom = this.Dom = opts.dom;

	var ioreg;

	var self = this;

	Dom.use(domProxyPluginMeta, 'before');

	if (opts.disable) return;

	Dom.Handler.prototype.init = function() {
		this.opts.params = stealSession;
		this.listener = listener.bind(this);
		raja.on('message', this.listener);
	};

	var _finish = Dom.Handler.prototype.finish;
	Dom.Handler.prototype.finish = function(user, res) {
		res.set('X-Raja', opts.namespace);
		for (var name in user.headers) {
			if (name in {'Vary': 1, 'X-Grant': 1, 'ETag': 1}) {
				res.set(name, user.headers[name]);
			}
		}
		_finish.call(this, user, res);
	};

	Dom.Handler.prototype.loadLocal = raja.proxies.local.get.bind(raja.proxies.local);

	Dom.Handler.prototype.loadRemote = function(url, opts, cb) {
		raja.proxies.remote.get(url, opts, function(err, res) {
			cb(err, res && res.data);
		});
	};

	Dom.author(domProxyPlugin, 'before');
	Dom.use(domProxyPlugin, 'before');
	Dom.use(domProxyBusyPlugin, 'before');
	Dom.use(domProxyDonePlugin, 'after');

	function listener(msg) {
		var h = this;
		var reload = false;
		msg.parents.forEach(function(key) {
			raja.store.get(key, function(err, resource) {
				if (err) return raja.error(err);
				if (!resource) return;
				if (msg.key == key && msg.mtime > resource.mtime && (!resource.itime || msg.mtime > resource.itime)) {
					resource.itime = msg.mtime;
				}
				if (resource.page && reload) {
					debug("Detected change releases page", resource.key);
					Dom.pool.release(resource.page);
				}
				var contentType = resource.headers && resource.headers['Content-Type'];
				if (contentType && (typeis(contentType, '*/javascript') || typeis(contentType, 'text/html'))) {
					debug("Detected change in", key);
					reload = true;
				}
			});
		});
	}

	function domProxyPluginMeta(page, resource, req, res) {
		page.wait('ready').run(function(key, client, ns, done) {
			var node = document.getElementById('script');
			if (!node) node = document.createElement('script');
			node.id = 'raja';
			node.setAttribute('data-client', client);
			node.setAttribute('data-namespace', ns);
			node.setAttribute('data-room', key);
			node.type = "text/javascript";
			node.textContent = "(function(r) {if (r && r.ready) r.ready();})(window.raja);";
			if (!node.parentNode) {
				var tn = document.createTextNode("\n");
				document.head.insertBefore(node, document.head.firstChild);
				document.head.insertBefore(tn, node);
			}
			done();
		}, [resource.key, opts.client, opts.namespace]);
	}

	function domProxyPlugin(page, resource) {
		page.on('unload', function() {}); // keep it running !
		page.on('error', raja.error.bind(raja));
		page.on('request', function(req) {
			if (!resource.resources) {
				return;
			}
//			if (resource.existings && resource.existings[req.uri]) {
//				// copy back because some of them won't have response because of the cache
//				resource.depend(req.uri);
//			}

			req.headers['Cache-Control'] = 'no-cache';

			if (ioreg && ioreg.test(URL.parse(req.uri).pathname)) {
				req.ignore = true;
			}
		});
		page.on('response', function(res) {
			if (!res.uri || res.uri == "about:blank") return;
			if (res.uri == resource.url) return; // ignore view and author
			if (!resource.resources) return;
			if (res.status >= 200 && res.status < 400) {
				if (!ioreg) {
					var iopath = raja.io && raja.io.socket && raja.io.socket.io.opts.path;
					if (iopath) ioreg = new RegExp("^" + iopath);
				}
				if (ioreg && ioreg.test(URL.parse(res.uri).pathname)) {
					if (typeis(res.mime, 'javascript') == false) resource.live = true;
				} else {
					var child = raja.create(res.uri, res);
					resource.depend(child);

					// this covers the case where a resource finishes loading after idle
					if (resource.valid) {
						resource.itime = new Date();
						resource.valid = false;
						resource.save();
					}
				}
			}
		});
	}

	function domProxyBusyPlugin(page, resource) {
		page.on('busy', function() {
			if (resource.itime && resource.itime > resource.mtime) {
				delete resource.itime;
				// update resources to make sure instances loaded on server receive messages
				resource.valid = false;
				resource.save();
			}
		});
	}

	function domProxyDonePlugin(page, resource, req, res) {
		var output = resource.output;
		resource.output = function(page, cb) {
			resource.output = output;
			if (!resource.itime || resource.itime <= resource.mtime) {
				resource.valid = true;
				resource.mtime = new Date();
			} else if (!resource.mtime) {
				resource.mtime = new Date();
			}
			updateGrants(resource, function(err) {
				// must be done at the very end, since the key varies on the resources grants
				if (err) return cb(err);
				if (req.headers['X-Right'] != resource.headers['X-Grant']) {
					console.warn(
						'Permissions mismatch while accessing',
						resource.url,
						'X-Right', req.headers['X-Right'],
						'X-Grant', resource.headers['X-Grant']
					);
				}
				output.call(resource, page, cb);
			});
		};
	}

	var _get = Dom.Handler.prototype.get;
	Dom.Handler.prototype.get = function(url, depend, req, cb) {
		if (!cb) {
			cb = req;
			req = null;
		}
		if (!cb) {
			cb = depend;
			depend = null;
		}
		var obj = {url: url, builder: 'dom'};
		if (req) obj.headers = raja.headers(req);
		debug('get', obj);
		raja.upsert(obj, function(err, resource) {
			if (err) return cb(err);
			if (!resource.headers) resource.headers = {};
			if (!resource.resources) resource.resources = {};
			if (depend) resource.depend(depend);
			if (!resource.output) resource.output = function(page, cb) {
				page.html(cb);
			};
			cb(null, resource);
		});
	};
}

function updateGrants(resource, cb) {
	var q = queue();
	var grants = mergeGrants({}, resource.headers);
	// must copy X-Right headers because express proxy sets them on response,
	// but response hasn't been completed yet
	var rights = resource.headers['X-Right'];
	debug('initial resource rights', rights);
	if (rights) rights.split(',').forEach(function(right) {
		grants[right] = true;
	});
	var store = resource.raja.store;
	for (var key in resource.resources) {
		q.defer(store.get.bind(store), key);
	}
	q.awaitAll(function(err, resources) {
		if (err) return cb(err);
		resources.forEach(function(item) {
			if (item) mergeGrants(grants, item.headers);
		});
		grants = Object.keys(grants);
		if (grants.length) {
			mergeHeader(resource.headers, 'Vary', 'X-Grant');
			resource.headers['X-Grant'] = grants.sort().join(',');
		}
		cb();
	});
}

function mergeGrants(obj, headers) {
	var vary = headers.Vary;
	if (!vary || vary.split(',').indexOf('X-Grant') < 0) return obj;
	var header = headers['X-Grant'];
	if (!header) return obj;
	debug('merge grants', header);
	header.split(',').forEach(function(val) {
		obj[val.trim()] = true;
	});
	return obj;
}

function mergeHeader(headers, name, val) {
	var header = headers[name];
	header = header ? header.split(',') : [];
	if (header.indexOf(val) < 0) header.push(val);
	headers[name] = header.join(',');
}

function stealSession(opts, req) {
	var session = req.session;
	var store = req.sessionStore;
	// 1) generate a new session
	var decoy = {sessionStore: store};
	store.generate(decoy);
	// 2) give it same data
	for (var key in session) {
		if (decoy.session[key] != null || key == 'passport') continue;
		decoy.session[key] = session[key];
	}
	decoy.session.save();
	debug("hosted session", decoy.sessionID, decoy.session);
	// 3) set that session cookie into opts.cookies
	opts.cookies = agent.sessionCookie(req, decoy.sessionID, true);
}

<|endoftext|>


<commit_before>var log = require('logule').init(module).mute('info', 'error');
var Server = require(process.env.NNN_COV ? '../lib-cov/server' : '../');
var server = new Server();
var request = require('request');

var host = 'http://localhost:8080';

var testHandlers = [
  'GET /',
  'POST / m1 m2',
  'POST m2',
  'ALL m3 throw2',
  'GET /throwmiddleware throw',
  'ALL /throwmiddleware2 m1 m3',
  'ALL /index/*',
  'ALL /index/:id',
  'ALL /index/:id?name',
  'ALL /test?arg1&arg2',
  'ALL /test?arg1&arg2 m1'
];

testHandlers.forEach(function (handler) {
  var hs = handler.split(' ');
  server.bind(hs[1], hs[0], hs.slice(2), function (req, res) {
    var r = {
      handler   : hs[0] + ' ' + hs[1],
      method    : hs[0],
      url       : hs[1],
      middleware: hs.slice(2),
      args      : Array.prototype.slice.call(arguments, 2).map(function (arg) {
                    return typeof arg === 'function' ? '[Function]' : arg;
                  }),
      extra     : res.extra
    };
    res.end(JSON.stringify(r));
  });
});

server.on('m1', function (req, res, callback) {
  res.extra = 'm1 called';
  callback();
});

server.on('/throw', function (req, res) { throw 'handler error'; });
server.get('throw',  function (req, res) { throw 'middleware error'; });
server.post('throw2', function (req, res) {
  server.raise('404', req, res);
});

server.start();
server.cfg = {http: 8080};
server.start();

//-----------------------------------------------------------------------------

module.exports.root = function (t) {
  request.get(host+'/', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'GET /', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, [], 'arguments');

    t.done();
  });
};

module.exports.middleware = function (t) {
  request.post(host+'/', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'POST m2', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['[Function]'], 'arguments');
    t.deepEqual(r.extra, 'm1 called', 'middleware called in order');

    t.done();
  });
};

module.exports.middleware2 = function (t) {
  request.post(host+'/', function (err, res, body) {
    var r = JSON.parse(body);
    t.deepEqual(r.extra, 'm1 called', 'middleware persistence');
    t.done();
  });
};

module.exports.variable = function (t) {
  request.get(host+'/index/123', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123'], 'arguments');

    t.done();
  });
};
module.exports.catchAll = function (t) {
  request.get(host+'/index/catch/all', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/*', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['/catch/all'], 'arguments');

    t.done();
  });
};
module.exports.query = function (t) {
  request.get(host+'/index/123?name=John%20Doe', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id?name', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123', 'John Doe'], 'arguments');

    t.done();
  });
};
module.exports.query2 = function (t) {
  request.get(host+'/index/123?lol=true', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123'], 'arguments');

    t.done();
  });
};

module.exports.overwrite = function (t) {
  request.post(host+'/test?arg1=1&arg2=2', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /test?arg1&arg2', 'handler');
    t.deepEqual(r.middleware, ['m1'], 'middleware');
    t.deepEqual(r.args, ['1', '2'], 'arguments');
    t.deepEqual(r.extra, 'm1 called', 'middleware called')

    t.done();
  });
};

module.exports.notFound = function (t) {
  request.get(host+'/non-existent-url', function (err, res, body) {
    t.strictEqual(res.statusCode, 404, 'status code');
    t.strictEqual(res.statusMessage, 'Not Found', 'status message');
    t.done();
  });
};
module.exports.error = function (t) {
  request.get(host+'/throw', function (err, res, body) {
    t.strictEqual(res.statusCode, 500, 'status code');
    t.strictEqual(res.statusMessage, 'Internal Server Error', 'status message');
    t.done();
  });
};
module.exports.middlewareError = function (t) {
  request.get(host+'/throwmiddleware', function (err, res, body) {
    t.strictEqual(res.statusCode, 500, 'status code');
    t.strictEqual(res.statusMessage, 'Internal Server Error', 'status message');
    t.done();
  });
};
module.exports.middlewareError2 = function (t) {
  request.post(host+'/throwmiddleware2', function (err, res, body) {
    t.strictEqual(res.statusCode, 404, 'status code');
    t.strictEqual(res.statusMessage, 'Not Found', 'status message');
    t.done();

    server.stop();
  });
};
<commit_msg>added tests for middleware argements<commit_after>var log = require('logule').init(module).mute('info', 'error');
var Server = require(process.env.NNN_COV ? '../lib-cov/server' : '../');
var server = new Server();
var request = require('request');

var host = 'http://localhost:8080';

var testHandlers = [
  'GET /',
  'POST / m1 m2',
  'POST m2',
  'ALL m3 throw2',
  'GET /throwmiddleware throw',
  'ALL /throwmiddleware2 m1 m3',
  'ALL /index/*',
  'ALL /index/:id',
  'ALL /index/:id?name',
  'ALL /test?arg1&arg2',
  'ALL /test?arg1&arg2 m1',
  'ALL /middlewareNoArg ma',
  'ALL /middlewareArg ma/1337'
];

testHandlers.forEach(function (handler) {
  var hs = handler.split(' ');
  server.bind(hs[1], hs[0], hs.slice(2), function (req, res) {
    var r = {
      handler   : hs[0] + ' ' + hs[1],
      method    : hs[0],
      url       : hs[1],
      middleware: hs.slice(2),
      args      : Array.prototype.slice.call(arguments, 2).map(function (arg) {
                    return typeof arg === 'function' ? '[Function]' : arg;
                  }),
      extra     : res.extra
    };
    res.end(JSON.stringify(r));
  });
});

server.on('m1', function (req, res, callback) {
  res.extra = 'm1 called';
  callback();
});

server.on('ma', function (req, res, callback) {
  callback();
});
server.on('ma/:arg', function (req, res, arg, callback) {
  res.extra = arg;
  callback();
});

server.on('/throw', function (req, res) { throw 'handler error'; });
server.get('throw',  function (req, res) { throw 'middleware error'; });
server.post('throw2', function (req, res) {
  server.raise('404', req, res);
});

server.start();
server.cfg = {http: 8080};
server.start();

//-----------------------------------------------------------------------------

module.exports.root = function (t) {
  request.get(host+'/', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'GET /', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, [], 'arguments');

    t.done();
  });
};

module.exports.middleware = function (t) {
  request.post(host+'/', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'POST m2', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['[Function]'], 'arguments');
    t.deepEqual(r.extra, 'm1 called', 'middleware called in order');

    t.done();
  });
};
module.exports.middleware2 = function (t) {
  request.post(host+'/', function (err, res, body) {
    var r = JSON.parse(body);
    t.deepEqual(r.extra, 'm1 called', 'middleware persistence');
    t.done();
  });
};

module.exports.variable = function (t) {
  request.get(host+'/index/123', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123'], 'arguments');

    t.done();
  });
};
module.exports.catchAll = function (t) {
  request.get(host+'/index/catch/all', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/*', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['/catch/all'], 'arguments');

    t.done();
  });
};
module.exports.query = function (t) {
  request.get(host+'/index/123?name=John%20Doe', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id?name', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123', 'John Doe'], 'arguments');

    t.done();
  });
};
module.exports.query2 = function (t) {
  request.get(host+'/index/123?lol=true', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /index/:id', 'handler');
    t.deepEqual(r.middleware, [], 'middleware');
    t.deepEqual(r.args, ['123'], 'arguments');

    t.done();
  });
};

module.exports.overwrite = function (t) {
  request.post(host+'/test?arg1=1&arg2=2', function (err, res, body) {
    var r = JSON.parse(body);

    t.strictEqual(res.statusCode, 200, 'status code');
    t.strictEqual(res.statusMessage, 'OK', 'status message');
    t.strictEqual(r.handler, 'ALL /test?arg1&arg2', 'handler');
    t.deepEqual(r.middleware, ['m1'], 'middleware');
    t.deepEqual(r.args, ['1', '2'], 'arguments');
    t.deepEqual(r.extra, 'm1 called', 'middleware called')

    t.done();
  });
};

module.exports.notFound = function (t) {
  request.get(host+'/non-existent-url', function (err, res, body) {
    t.strictEqual(res.statusCode, 404, 'status code');
    t.strictEqual(res.statusMessage, 'Not Found', 'status message');
    t.done();
  });
};
module.exports.error = function (t) {
  request.get(host+'/throw', function (err, res, body) {
    t.strictEqual(res.statusCode, 500, 'status code');
    t.strictEqual(res.statusMessage, 'Internal Server Error', 'status message');
    t.done();
  });
};
module.exports.middlewareError = function (t) {
  request.get(host+'/throwmiddleware', function (err, res, body) {
    t.strictEqual(res.statusCode, 500, 'status code');
    t.strictEqual(res.statusMessage, 'Internal Server Error', 'status message');
    t.done();
  });
};
module.exports.middlewareError2 = function (t) {
  request.post(host+'/throwmiddleware2', function (err, res, body) {
    t.strictEqual(res.statusCode, 404, 'status code');
    t.strictEqual(res.statusMessage, 'Not Found', 'status message');
    t.done();
  });
};

module.exports.middlewareNoArg = function (t) {
  request.post(host+'/middlewareNoArg', function (err, res, body) {
    var r = JSON.parse(body);
    t.strictEqual(r.extra, undefined, 'no arguments defined');
    t.done();
  });
};
module.exports.middlewareArg = function (t) {
  request.post(host+'/middlewareArg', function (err, res, body) {
    var r = JSON.parse(body);
    t.strictEqual(r.extra, '1337', 'argument defined');
    t.done();

    server.stop();
  });
};
<|endoftext|>


<commit_before>var multiComment = false;
var multiLine = false;

var validOperators = {
    'is': ' === ',
    'not': ' !== ',
    'and':  ' && ',
    'or':  ' || ',
    'next':  '; ',
    'as':  ' = ',
    'more':  ' += ',
    'less':  ' -= ',
    'lots': ' *= ',
    'few': ' /= ',
    'very': ' var ',
    'smaller': ' < ',
    'bigger': ' > ',
    'smallerish': ' <= ',
    'biggerish': ' >= ',
    'notrly': ' ! ',
    'bigify': '++',
    'smallify': '--'
};

var assignOps = {
  'more': ' += ',
  'less': ' -= ',
  'lots': ' *= ',
  'few' : ' /= ',
  'is' : ' = '
}

var unaryOps = {
  'bigify': '++',
  'smallify': '--'
}

var controlFlowKeys = [
  'many',
  'much',
  'rly',
  'but',
  'notrly'
]

var valid = [
    'such',
    'wow',
    'wow&',
    'plz',
    '.plz',
    'dose',
    'very',
    'shh',
    'quiet',
    'loud',
    'rly',
    'notrly',
    'but',
    'many',
    'much',
    'so',
    'trained',
    'maybe',
    'pawse'
];

function containsUnary(keys)
{
  return unaryOps.hasOwnProperty(keys[0]) || unaryOps.hasOwnProperty(keys[1]);
}

var replacements = {};
replacements['dogeument']='document'
replacements['windoge']='window'
replacements['pawse']='debugger;'

module.exports = function parse (line) {

    // replace custom keywords
    Object.keys(replacements).forEach(function(key) {
        line = line.replace(new RegExp(key,'g'), replacements[key])
    });

    var keys = line.match(/'[^']+'|\S+/g);
    var statement = '';

    if (keys === null) return line + '\n';

    // not dogescript, such javascript
    if (valid.indexOf(keys[0]) === -1 && !assignOps.hasOwnProperty(keys[1]) && !containsUnary(keys) && keys[1] !== 'dose' || multiComment && keys[0] !== 'loud' || multiLine && keys[0] !== 'wow')
    {
      return line + '\n';
    }

    // trained use strict
    if (keys[0] === 'trained') {
        statement += '"use strict";\n';
    }

   // such function
    if (keys[0] === 'such') {
        statement += 'function ';
        statement += keys[1]; // set function name

        if (keys[2] === 'much') {
            statement += ' (';
            for (var i = 3; i < keys.length; i++) {
                statement += keys[i];
                if (i !== keys.length - 1) statement += ', ';
            }
            statement += ') { \n';
        } else {
            statement += ' () { \n';
        }
    }

    // wow end function and return
    if (keys[0] === 'wow' || keys[0] === 'wow&') {
        multiLine = false;
        if (typeof keys[1] !== 'undefined') {
            statement += 'return';
            for (var i = 1; i < keys.length; i++) {
                statement += ' ' + keys[i];
            }
            statement += ';\n';
            if (keys[0] === 'wow&') statement += '}) \n';
            else statement += '} \n';
        } else if (keys[0] === 'wow&') {
            statement += '}) \n';
        } else {
            statement += '} \n';
        }
    }

    // plz execute function
    if (keys[0] === 'plz' || keys[0] === '.plz' || keys[0] === 'dose' || keys[1] === 'dose') {
        if (keys[1] === 'dose') statement += keys.shift();
        if (keys[0].charAt(0) === '.' || keys[0] === 'dose') statement += '.';
        if (keys[1] === 'console.loge' || keys[1] === 'loge') keys[1] = keys[1].slice(0, -1);
        if (keys[2] === 'with') {
            statement += keys[1] + '(';
            dupe = keys.slice(0);
            for (var i = 3; i < keys.length; i++) {
                if (keys[i] === ',' || keys[i] === '&') continue;
                if (keys[i] === 'much') { // lambda functions - thanks @00Davo!

                    statement += 'function (';
                    if (keys[i + 1]) {
                        for (var j = i + 1; j < keys.length; j++) {
                            statement += keys[j];
                            if (j !== keys.length - 1) statement += ', ';
                        }
                        statement += ') {\n';
                        return statement;
                    } else {
                        statement += ') {\n';
                        return statement;
                    }
                }
                if (keys[i].substr(-1) === '&' || keys[i].substr(-1) === ',') keys[i] = keys[i].slice(0, -1);
                statement += keys[i];
                if (keys[i].substr(-1) === ':') statement += ' ';
                if (i !== keys.length - 1 && keys[i].substr(-1) !== ':') statement += ', ';
            }
            if (statement.substr(-2) === ', ') statement = statement.slice(0, -2);
            if (statement.substr(-3) === ', ]' || statement.substr(-3) === ', }' ) statement = statement.replace(statement.substr(-3), statement.substr(-1));
            if (dupe[keys.length - 1].slice(-1) === '&') statement += ')\n';
            else statement += ');\n';
        } else {
            if (keys[1].slice(-1) === '&') {
                keys[1] = keys[1].slice(0, -1);
                statement += keys[1] + '()\n';
            } else {
                statement += keys[1] + '();\n';
            }
        }
    }

    // very new variable
    if (keys[0] === 'very') {
        statement += 'var ' + keys[1] + ' = ';
        if (keys[3] === 'new') {
            statement += 'new ' + keys[4] + '(';
            if (keys[5] === 'with') {
                for (var i = 6; i < keys.length; i++) {
                    if (keys[i] === ',') continue;
                    if (keys[i].substr(-1) === ',' && keys[i].charAt(keys[i].length - 2) !== '}') keys[i] = keys[i].slice(0, -1);
                    statement += keys[i];
                    if (i !== keys.length - 1) statement += ', ';
                }
            }
            statement += ');\n';
            return statement;
        }
        if (keys[3] === 'much') {
            statement += 'function ';
            if (keys[4]) {
                statement += '(';
                for (var i = 4; i < keys.length; i++) {
                    statement += keys[i];
                    if (i !== keys.length - 1) statement += ', ';
                }
                statement += ') { \n';
            } else {
                statement += ' () { \n';
            }
            return statement;
        }
        if (keys.length > 4) {
            var recurse = '';
            for (var i = 3; i < keys.length; i++) {
                if (keys[i].substr(-1) === ',' && keys[i].charAt(keys[i].length - 2) !== '}') keys[i] = keys[i].slice(0, -1);
                recurse += keys[i] + ' ';
            }
            if (valid.indexOf(keys[3]) !== -1 || (keys[4] === 'is' || keys[4] === 'dose')) statement += parse(recurse);
            else statement += recurse + ';\n';
        } else {
            if (keys[3] === 'obj') {
                statement += '{\n';
                multiLine = true;
            } else {
                statement += keys[3] + ';\n';
            }
        }
    }

    // support any kind of assignment operator
    var assignment = keys[1]
    if(assignOps.hasOwnProperty(assignment))
    {
      statement += keys[0] + assignOps[assignment];

      if (keys[2] === 'new') {
          statement += 'new ' + keys[3] + '(';
          if (keys[4] === 'with') {
              for (var i = 5; i < keys.length; i++) {
                  if (keys[i] === ',') continue;
                  statement += keys[i];
                  if (i !== keys.length - 1) statement += ', ';
              }
          }
          statement += ');\n';
          return statement;
      }

      if (keys.length > 2) {
          var recurse = '';
          for (var i = 2; i < keys.length; i++) {
              recurse += keys[i] + ' ';
          }
          statement += parse(recurse);
      } else {
          statement += keys[2] + ';\n';
      }
    }

    // shh comment
    if (keys[0] === 'shh') {
        statement += '//';
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    // quiet start multi-line comment
    if (keys[0] === 'quiet') {
        statement += '/*';
        multiComment = true;
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    // loud end multi-line comment
    if (keys[0] === 'loud') {
        statement += '*/';
        multiComment = false;
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    var operatorParser = function (key) {
        if (validOperators.hasOwnProperty(key)) {
            statement += validOperators[key];
            return true;
        }
        else {
            return false;
        }
    }

    // parses inner operators for rly/notrly/but/
    var controlFlowParser = function(keyStart, keys)

    {
      for (var i = keyStart; i < keys.length; i++) {
          var parsed = operatorParser(keys[i]);
          if (parsed) continue;
          statement += keys[i] + ' ';
      }
    }

    // rly if
    if (keys[0] === 'rly') {
        statement += 'if (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // ntrly if
    if (keys[0] === 'notrly')
    {
      statement += 'if (!';
      controlFlowParser(1, keys);
      statement += ') {\n';
    }

    // but else
    if (keys[0] === 'but') {
        if (keys[1] === 'rly') {
          statement += '} else if (';
          controlFlowParser(2, keys);
          statement += ') {\n';
        } else if (keys[1] === 'notrly') {
            statement += '} else if (!';
            controlFlowParser(2, keys);
            statement+= ') {\n';
        } else {
          statement += '} else {\n';
        }
    }

    // many while
    if (keys[0] === 'many') {
        statement += 'while (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // much for
    if (keys[0] === 'much') {
        statement += 'for (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // so require (thanks @maxogden!)
    if (keys[0] === 'so') {
        if (keys[2] === 'as') {
            statement += 'var ' + keys[3] + ' = require(\'' + keys[1] + '\');\n';
        } else {
            // try to make a simple name
            var mod = keys[1];
            // test for relative module, optional chop extension
            var m = /^..?\/.*?([\w-]+)(\.\w+)?$/.exec(mod);
            if (m) {
                mod = m[1];
            }
            mod = mod.replace(/-/g, '_');
            statement += 'var ' + mod + ' = require(\'' + keys[1] + '\');\n';
        }
    }

    // maybe boolean operator
    if (keys[0] === 'maybe') {
        statement += '(!!+Math.round(Math.random()))';
    }

    // standalone increment/decrement
    if(unaryOps.hasOwnProperty(keys[0]) || unaryOps.hasOwnProperty(keys[1]))
    {
      // ignore operators that should have been snagged by control flow elements
      if(controlFlowKeys.indexOf(keys[0]) === -1)
      {
        // pre
        if(unaryOps.hasOwnProperty(keys[0]))
        {
          statement += unaryOps[keys[0]] + keys[1]
        }
        else {
          statement += keys[0] + unaryOps[keys[1]]
        }
      }
    }

    return statement;
}
<commit_msg>refactor check for djs source (#130)<commit_after>var multiComment = false;
var multiLine = false;

var validOperators = {
    'is': ' === ',
    'not': ' !== ',
    'and':  ' && ',
    'or':  ' || ',
    'next':  '; ',
    'as':  ' = ',
    'more':  ' += ',
    'less':  ' -= ',
    'lots': ' *= ',
    'few': ' /= ',
    'very': ' var ',
    'smaller': ' < ',
    'bigger': ' > ',
    'smallerish': ' <= ',
    'biggerish': ' >= ',
    'notrly': ' ! ',
    'bigify': '++',
    'smallify': '--'
};

var assignOps = {
  'more': ' += ',
  'less': ' -= ',
  'lots': ' *= ',
  'few' : ' /= ',
  'is' : ' = '
}

var unaryOps = {
  'bigify': '++',
  'smallify': '--'
}

var controlFlowKeys = [
  'many',
  'much',
  'rly',
  'but',
  'notrly'
]

var valid = [
    'such',
    'wow',
    'wow&',
    'plz',
    '.plz',
    'dose',
    'very',
    'shh',
    'quiet',
    'loud',
    'rly',
    'notrly',
    'but',
    'many',
    'much',
    'so',
    'trained',
    'maybe',
    'pawse'
];

function containsUnary(keys)
{
  return unaryOps.hasOwnProperty(keys[0]) || unaryOps.hasOwnProperty(keys[1]);
}

/**
 * Determines if the parsed keys should be treated as dogescript source or not.
 */
function isDogescriptSource(keys)
{

  // starts the statement with a valid key
  if (valid.indexOf(keys[0]) !== -1)
  {
    return true;
  }

  // statement applying an assignment operator
  if ( assignOps.hasOwnProperty(keys[1]) )
  {
    return true;
  }

  // applying a unary operator
  if ( containsUnary(keys) )
  {
    return true;
  }

  // calling function on Object
  if ( keys[1] === 'dose' )
  {
    return true;
  }

  // ending a multi comment block
  if (multiComment && keys[0] === 'loud' )
  {
    return true;
  }

  // closing a multi-line object creation
  if ( multiLine && keys[0] === 'wow' )
  {
    return true;
  }

  // not valid dogescript
  return false;
}

var replacements = {};
replacements['dogeument']='document'
replacements['windoge']='window'
replacements['pawse']='debugger;'

module.exports = function parse (line) {

    // replace custom keywords
    Object.keys(replacements).forEach(function(key) {
        line = line.replace(new RegExp(key,'g'), replacements[key])
    });

    var keys = line.match(/'[^']+'|\S+/g);
    var statement = '';

    if (keys === null) return line + '\n';

    // not dogescript, such javascript
    if ( !isDogescriptSource(keys) )
    {
      return line + '\n';
    }

    // trained use strict
    if (keys[0] === 'trained') {
        statement += '"use strict";\n';
    }

   // such function
    if (keys[0] === 'such') {
        statement += 'function ';
        statement += keys[1]; // set function name

        if (keys[2] === 'much') {
            statement += ' (';
            for (var i = 3; i < keys.length; i++) {
                statement += keys[i];
                if (i !== keys.length - 1) statement += ', ';
            }
            statement += ') { \n';
        } else {
            statement += ' () { \n';
        }
    }

    // wow end function and return
    if (keys[0] === 'wow' || keys[0] === 'wow&') {
        multiLine = false;
        if (typeof keys[1] !== 'undefined') {
            statement += 'return';
            for (var i = 1; i < keys.length; i++) {
                statement += ' ' + keys[i];
            }
            statement += ';\n';
            if (keys[0] === 'wow&') statement += '}) \n';
            else statement += '} \n';
        } else if (keys[0] === 'wow&') {
            statement += '}) \n';
        } else {
            statement += '} \n';
        }
    }

    // plz execute function
    if (keys[0] === 'plz' || keys[0] === '.plz' || keys[0] === 'dose' || keys[1] === 'dose') {
        if (keys[1] === 'dose') statement += keys.shift();
        if (keys[0].charAt(0) === '.' || keys[0] === 'dose') statement += '.';
        if (keys[1] === 'console.loge' || keys[1] === 'loge') keys[1] = keys[1].slice(0, -1);
        if (keys[2] === 'with') {
            statement += keys[1] + '(';
            dupe = keys.slice(0);
            for (var i = 3; i < keys.length; i++) {
                if (keys[i] === ',' || keys[i] === '&') continue;
                if (keys[i] === 'much') { // lambda functions - thanks @00Davo!

                    statement += 'function (';
                    if (keys[i + 1]) {
                        for (var j = i + 1; j < keys.length; j++) {
                            statement += keys[j];
                            if (j !== keys.length - 1) statement += ', ';
                        }
                        statement += ') {\n';
                        return statement;
                    } else {
                        statement += ') {\n';
                        return statement;
                    }
                }
                if (keys[i].substr(-1) === '&' || keys[i].substr(-1) === ',') keys[i] = keys[i].slice(0, -1);
                statement += keys[i];
                if (keys[i].substr(-1) === ':') statement += ' ';
                if (i !== keys.length - 1 && keys[i].substr(-1) !== ':') statement += ', ';
            }
            if (statement.substr(-2) === ', ') statement = statement.slice(0, -2);
            if (statement.substr(-3) === ', ]' || statement.substr(-3) === ', }' ) statement = statement.replace(statement.substr(-3), statement.substr(-1));
            if (dupe[keys.length - 1].slice(-1) === '&') statement += ')\n';
            else statement += ');\n';
        } else {
            if (keys[1].slice(-1) === '&') {
                keys[1] = keys[1].slice(0, -1);
                statement += keys[1] + '()\n';
            } else {
                statement += keys[1] + '();\n';
            }
        }
    }

    // very new variable
    if (keys[0] === 'very') {
        statement += 'var ' + keys[1] + ' = ';
        if (keys[3] === 'new') {
            statement += 'new ' + keys[4] + '(';
            if (keys[5] === 'with') {
                for (var i = 6; i < keys.length; i++) {
                    if (keys[i] === ',') continue;
                    if (keys[i].substr(-1) === ',' && keys[i].charAt(keys[i].length - 2) !== '}') keys[i] = keys[i].slice(0, -1);
                    statement += keys[i];
                    if (i !== keys.length - 1) statement += ', ';
                }
            }
            statement += ');\n';
            return statement;
        }
        if (keys[3] === 'much') {
            statement += 'function ';
            if (keys[4]) {
                statement += '(';
                for (var i = 4; i < keys.length; i++) {
                    statement += keys[i];
                    if (i !== keys.length - 1) statement += ', ';
                }
                statement += ') { \n';
            } else {
                statement += ' () { \n';
            }
            return statement;
        }
        if (keys.length > 4) {
            var recurse = '';
            for (var i = 3; i < keys.length; i++) {
                if (keys[i].substr(-1) === ',' && keys[i].charAt(keys[i].length - 2) !== '}') keys[i] = keys[i].slice(0, -1);
                recurse += keys[i] + ' ';
            }
            if (valid.indexOf(keys[3]) !== -1 || (keys[4] === 'is' || keys[4] === 'dose')) statement += parse(recurse);
            else statement += recurse + ';\n';
        } else {
            if (keys[3] === 'obj') {
                statement += '{\n';
                multiLine = true;
            } else {
                statement += keys[3] + ';\n';
            }
        }
    }

    // support any kind of assignment operator
    var assignment = keys[1]
    if(assignOps.hasOwnProperty(assignment))
    {
      statement += keys[0] + assignOps[assignment];

      if (keys[2] === 'new') {
          statement += 'new ' + keys[3] + '(';
          if (keys[4] === 'with') {
              for (var i = 5; i < keys.length; i++) {
                  if (keys[i] === ',') continue;
                  statement += keys[i];
                  if (i !== keys.length - 1) statement += ', ';
              }
          }
          statement += ');\n';
          return statement;
      }

      if (keys.length > 2) {
          var recurse = '';
          for (var i = 2; i < keys.length; i++) {
              recurse += keys[i] + ' ';
          }
          statement += parse(recurse);
      } else {
          statement += keys[2] + ';\n';
      }
    }

    // shh comment
    if (keys[0] === 'shh') {
        statement += '//';
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    // quiet start multi-line comment
    if (keys[0] === 'quiet') {
        statement += '/*';
        multiComment = true;
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    // loud end multi-line comment
    if (keys[0] === 'loud') {
        statement += '*/';
        multiComment = false;
        for (var i = 1; i < keys.length; i++) {
            statement += ' ' + keys[i];
        }
        statement += '\n';
    }

    var operatorParser = function (key) {
        if (validOperators.hasOwnProperty(key)) {
            statement += validOperators[key];
            return true;
        }
        else {
            return false;
        }
    }

    // parses inner operators for rly/notrly/but/
    var controlFlowParser = function(keyStart, keys)

    {
      for (var i = keyStart; i < keys.length; i++) {
          var parsed = operatorParser(keys[i]);
          if (parsed) continue;
          statement += keys[i] + ' ';
      }
    }

    // rly if
    if (keys[0] === 'rly') {
        statement += 'if (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // ntrly if
    if (keys[0] === 'notrly')
    {
      statement += 'if (!';
      controlFlowParser(1, keys);
      statement += ') {\n';
    }

    // but else
    if (keys[0] === 'but') {
        if (keys[1] === 'rly') {
          statement += '} else if (';
          controlFlowParser(2, keys);
          statement += ') {\n';
        } else if (keys[1] === 'notrly') {
            statement += '} else if (!';
            controlFlowParser(2, keys);
            statement+= ') {\n';
        } else {
          statement += '} else {\n';
        }
    }

    // many while
    if (keys[0] === 'many') {
        statement += 'while (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // much for
    if (keys[0] === 'much') {
        statement += 'for (';
        controlFlowParser(1, keys);
        statement += ') {\n';
    }

    // so require (thanks @maxogden!)
    if (keys[0] === 'so') {
        if (keys[2] === 'as') {
            statement += 'var ' + keys[3] + ' = require(\'' + keys[1] + '\');\n';
        } else {
            // try to make a simple name
            var mod = keys[1];
            // test for relative module, optional chop extension
            var m = /^..?\/.*?([\w-]+)(\.\w+)?$/.exec(mod);
            if (m) {
                mod = m[1];
            }
            mod = mod.replace(/-/g, '_');
            statement += 'var ' + mod + ' = require(\'' + keys[1] + '\');\n';
        }
    }

    // maybe boolean operator
    if (keys[0] === 'maybe') {
        statement += '(!!+Math.round(Math.random()))';
    }

    // standalone increment/decrement
    if(unaryOps.hasOwnProperty(keys[0]) || unaryOps.hasOwnProperty(keys[1]))
    {
      // ignore operators that should have been snagged by control flow elements
      if(controlFlowKeys.indexOf(keys[0]) === -1)
      {
        // pre
        if(unaryOps.hasOwnProperty(keys[0]))
        {
          statement += unaryOps[keys[0]] + keys[1]
        }
        else {
          statement += keys[0] + unaryOps[keys[1]]
        }
      }
    }

    return statement;
}
<|endoftext|>


<commit_before>/*
 * min-webdriver
 *
 * Copyright (c) 2014 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

var through = require('through');
var listen  = require('listen');
var http    = require('http');
var fs      = require('fs');
var request = require('./request');

function close(context, callback) {
  request(context, 'DELETE', "/window", null, function () {
    request(context, 'DELETE', '', null, function () {
      callback();
    });
  });
}

function pollLogs(context, callback) {
  request(context, 'POST', '/execute_async', {
    script : 'window._webdriver_poll(arguments[0]);',
    args   : []
  }, function (err, res) {
    if (err) {
      close(context, function () {
        callback(err);
      });
      return;
    }
    var match = res.value.match(/^WEBDRIVER_EXIT\(([0-9]+)\)$/m);
    if (match) {
      context.logs.push(res.value.substring(0, match.index));

      var browser = context.browser;
      var title   = browser.name + ' ' + (browser.version || '*');
      var line    = new Array(76).join('=').substring(title.length);
      context.out.write('= ' + title + ' ' + line + '\n');
      context.out.write(context.logs.join(''));

      close(context, function () {
        if (match[1] === '0') {
          callback();
        } else {
          callback(new Error('Build failed: ' + match[1]));
        }
      });
      return;
    }
    context.logs.push(res.value);
    pollLogs(context, callback);
  });
}

function execute(context, script, callback) {
  request(context, 'POST', '/execute', {
    script : script,
    args   : []
  }, function (err) {
    if (err) {
      close(context, function () {
        callback(err);
      });
      return;
    }
    context.logs = [];
    setTimeout(function () {
      pollLogs(context, callback);
    }, 100);
  });
}

function openUrl(context, script, callback) {
  var url = context.url;
  if (url) {
    request(context, 'POST', '/url', {
      url : url
    }, function (err) {
      if (err) {
        close(context, function () {
          callback(err);
        });
        return;
      }
      execute(context, script, callback);
    });
  } else {
    execute(context, script, callback);
  }
}

function connectBrowser(context, callback) {
  var caps = {
    browserName       : context.browser.name,
    version           : context.browser.version,
    platform          : context.browser.platform,
    javascriptEnabled : true
  };
  if (context.sauceLabs) {
    caps.username  = process.env.SAUCE_USERNAME;
    caps.accessKey = process.env.SAUCE_ACCESS_KEY;
  }
  var json = {
    desiredCapabilities : caps
  };

  request(context, 'POST', '/session', json, function (err, res) {
    if (err) {
      callback(err);
      return;
    }
    context.basePath = context.basePath + '/session/' + res.sessionId;
    request(context, 'POST', '/timeouts/async_script', {
      ms : 10000
    }, function (err) {
      if (err) {
        close(context, function () {
          callback(err);
        });
        return;
      }
      callback(null);
    });
  });
}

function createContext(options, browser, out) {
  return {
    hostname  : options.hostname,
    port      : options.port,
    url       : options.url,
    basePath  : '/wd/hub',
    browser   : browser,
    out       : out,
    sauceLabs : options.sauceLabs
  };
}

function run(options, out, runner, callback) {
  var listener = listen();
  options.browsers.forEach(function (browser) {
    var cb      = listener();
    var context = createContext(options, browser, out);
    connectBrowser(context, function (err) {
      if (err) {
        cb(err);
        return;
      }
      runner(context, cb);
    });
  });
  listener.then(callback);
}

function createRunner(input) {
  var requests = [];
  var script   = '';
  input.on('data', function (chunk) {
    script += chunk;
  });
  input.on('end', function () {
    if (!script) {
      requests.forEach(function (request) {
        close(request.context, request.callback);
      });
    } else {
      requests.forEach(function (request) {
        openUrl(request.context, script, request.callback);
      });
    }
    requests = null;
  });

  return function (context, callback) {
    if (requests) {
      requests.push({ context : context, callback : callback });
    } else {
      if (!script) {
        close(context, callback);
        return;
      }
      openUrl(context, script, callback);
    }
  };
}

module.exports = function (input, options, callback) {
  var out = through();

  run(options, out, createRunner(input), function (err) {
    out.write(null);
    callback(err);
  });

  return out;
};
<commit_msg>Stream browser output instead of buffering per browser<commit_after>/*
 * min-webdriver
 *
 * Copyright (c) 2014 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

var through = require('through');
var listen  = require('listen');
var http    = require('http');
var fs      = require('fs');
var request = require('./request');

function close(context, callback) {
  request(context, 'DELETE', "/window", null, function () {
    request(context, 'DELETE', '', null, function () {
      callback();
    });
  });
}

function pollLogs(context, callback) {
  request(context, 'POST', '/execute_async', {
    script : 'window._webdriver_poll(arguments[0]);',
    args   : []
  }, function (err, res) {
    if (err) {
      close(context, function () {
        callback(err);
      });
      return;
    }
    var match = res.value.match(/^WEBDRIVER_EXIT\(([0-9]+)\)$/m);
    if (match) {
      context.out.write(res.value.substring(0, match.index));

      close(context, function () {
        if (match[1] === '0') {
          callback();
        } else {
          callback(new Error('Build failed: ' + match[1]));
        }
      });
      return;
    }
    context.out.write(res.value);
    pollLogs(context, callback);
  });
}

function execute(context, script, callback) {
  request(context, 'POST', '/execute', {
    script : script,
    args   : []
  }, function (err) {
    if (err) {
      close(context, function () {
        callback(err);
      });
      return;
    }
    setTimeout(function () {
      pollLogs(context, callback);
    }, 100);
  });
}

function openUrl(context, script, callback) {
  var browser = context.browser;
  var title   = browser.name + ' ' + (browser.version || '*');
  var line    = new Array(76).join('=').substring(title.length);
  context.out.write('= ' + title + ' ' + line + '\n');

  var url = context.url;
  if (url) {
    request(context, 'POST', '/url', {
      url : url
    }, function (err) {
      if (err) {
        close(context, function () {
          callback(err);
        });
        return;
      }
      execute(context, script, callback);
    });
  } else {
    execute(context, script, callback);
  }
}

function connectBrowser(context, callback) {
  var caps = {
    browserName       : context.browser.name,
    version           : context.browser.version,
    platform          : context.browser.platform,
    javascriptEnabled : true
  };
  if (context.sauceLabs) {
    caps.username  = process.env.SAUCE_USERNAME;
    caps.accessKey = process.env.SAUCE_ACCESS_KEY;
  }
  var json = {
    desiredCapabilities : caps
  };

  request(context, 'POST', '/session', json, function (err, res) {
    if (err) {
      callback(err);
      return;
    }
    context.basePath = context.basePath + '/session/' + res.sessionId;
    request(context, 'POST', '/timeouts/async_script', {
      ms : 10000
    }, function (err) {
      if (err) {
        close(context, function () {
          callback(err);
        });
        return;
      }
      callback(null);
    });
  });
}

function createContext(options, browser, out) {
  return {
    hostname  : options.hostname,
    port      : options.port,
    url       : options.url,
    basePath  : '/wd/hub',
    browser   : browser,
    out       : out,
    sauceLabs : options.sauceLabs
  };
}

function pipe(streams, out) {
  if (!streams.length) {
    out.write(null);
    return;
  }
  var stream = streams.shift();
  stream.on('data', function (data) {
    out.write(data);
  });
  stream.on('end', function () {
    pipe(streams, out);
  });
  stream.resume();
}

function run(options, out, runner, callback) {
  var streams  = [];
  var listener = listen();
  options.browsers.forEach(function (browser) {
    var stream = through();
    stream.pause();
    var cb = listener(function () {
      stream.write(null);
    });
    var context = createContext(options, browser, stream);
    connectBrowser(context, function (err) {
      if (err) {
        cb(err);
        return;
      }
      runner(context, cb);
    });
    streams.push(stream);
  });
  pipe(streams, out);
  listener.then(callback);
}

function createRunner(input) {
  var requests = [];
  var script   = '';
  input.on('data', function (chunk) {
    script += chunk;
  });
  input.on('end', function () {
    if (!script) {
      requests.forEach(function (request) {
        close(request.context, request.callback);
      });
    } else {
      requests.forEach(function (request) {
        openUrl(request.context, script, request.callback);
      });
    }
    requests = null;
  });

  return function (context, callback) {
    if (requests) {
      requests.push({ context : context, callback : callback });
    } else {
      if (!script) {
        close(context, callback);
        return;
      }
      openUrl(context, script, callback);
    }
  };
}

module.exports = function (input, options, callback) {
  var out = through();

  run(options, out, createRunner(input), function (err) {
    out.write(null);
    callback(err);
  });

  return out;
};
<|endoftext|>