<commit_before>describe('Pipe', function () {
  'use strict';

  var common = require('./common')
    , Compiler = require('../lib/compiler')
    , http = require('http')
    , expect = common.expect
    , Pipe = common.Pipe
    , server
    , app;

  before(function (done) {
    server = http.createServer(function () {
      throw new Error('Unhandled request');
    });

    app = new Pipe(server, {
      pagelets: __dirname +'/fixtures/pagelets',
      dist: '/tmp/dist'
    }).listen(common.port, done);
  });

  it('exposes the Pagelet constructor', function () {
    expect(Pipe.Pagelet).to.be.a('function');
    expect(Pipe.Pagelet.extend).to.be.a('function');
  });

  it('is an EvenEmitter3', function () {
    expect(app).to.be.instanceOf(require('eventemitter3'));
  });

  it('correctly resolves `pagelets` as a string to an array', function () {
    expect(app._pagelets).to.be.a('array');
    expect(app._pagelets).to.have.length(4);
  });

  it('transforms pagelets', function () {
    var Pagelet = app._pagelets[0];

    expect(Pagelet.method).to.be.a('array');
  });

  it('has supply middleware manager', function () {
    expect(app).to.have.property('middleware');
    expect(app.middleware).to.be.an('object');
    expect(app.middleware).to.be.instanceof(require('supply'));
  });

  it('has compiler for asset management', function () {
    expect(app).to.have.property('_compiler');
    expect(app._compiler).to.be.an('object');
    expect(app._compiler).to.be.instanceof(Compiler);
  });

  describe('private options', function () {
    it('has queryable options with defaults', function () {
      expect(app._options).to.be.a('function');
      expect(app._options('host')).to.equal(undefined);
      expect(app._options('host', 'localhost')).to.equal('localhost');

      var pipe = new Pipe(http.createServer(), {
          pagelets: __dirname +'/fixtures/pagelets'
        , dist: '/tmp/dist'
        , host: '127.0.0.1'
      });

      expect(pipe._options('host')).to.equal('127.0.0.1');
    });

    it('additional options can be merged, per example from a plugin', function () {
      expect(app._options.merge).to.be.a('function');
      expect(app._options('test')).to.equal(undefined);

      var pipe = new Pipe(http.createServer(), {
          pagelets: __dirname +'/fixtures/pagelets'
        , dist: '/tmp/dist'
        , host: '127.0.0.1'
      });

      expect(pipe._options('host')).to.equal('127.0.0.1');
      pipe._options.merge({ test: 'additional' });
      expect(pipe._options('test')).to.equal('additional');
    });
  });

  describe('.router', function () {
    function Request(url, method) {
      this.url = url;
      this.uri = require('url').parse(url, true);
      this.query = this.uri.query || {};
      this.method = method || 'GET';
    }

    it('finds the / pagelet', function (done) {
      app.router(new Request('/'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(200);

        done();
      });
    });

    it('doesnt find / for POST requests', function (done) {
      app.router(new Request('/', 'POST'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(404);

        done();
      });
    });

    ['GET', 'POST', 'MOO'].forEach(function (method) {
      it('finds /all for '+ method, function (done) {
        app.router(new Request('/all', method), {}, function (err, pagelet) {
          if (err) return done(err);

          expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
          expect(pagelet.statusCode).to.equal(200);

          done();
        });
      });
    });

    it('always returns a 404 page for unknown urls', function (done) {
      app.router(new Request('/'+ Math.random(), 'POST'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(404);

        done();
      });
    });

    it('adds and retrieves pagelets from a provided cache', function (done) {
      var cache = {
        get: function (url) {
          expect(url).to.equal('GET@/');
          pattern.push('get');
          return cache.pagelet;
        },
        set: function (url, pagelet) {
          expect(url).to.equal('GET@/');
          expect(pagelet).to.be.a('array');
          pattern.push('set');
          cache.pagelet = pagelet;
        }
      };

      var pattern = [];

      var local = new Pipe(server, {
        dist: '/tmp/dist',
        cache: cache
      });

      local.define(__dirname +'/fixtures/pagelets', function define() {
        local.router(new Request('/'), {}, function (err, pagelet) {
          if (err) return done(err);

          expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
          expect(pagelet.statusCode).to.equal(200);

          local.router(new Request('/'), {}, function (err, pagelet) {
            if (err) return done(err);

            expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
            expect(pagelet.statusCode).to.equal(200);
            expect(pattern.join()).to.equal('get,set,get');

            done();
          });
        });
      });
    });
  });

  describe('.define', function () {
    it('adds Pagelet to the pagelets collection', function (next) {
      var faq = require(__dirname + '/fixtures/pagelets/faq');

      app = new Pipe(server, {
        dist: '/tmp/dist'
      });

      app.define(faq, function (err) {
        if (err) return next(err);

        expect(app._pagelets).to.have.length(1);
        expect(app._pagelets[0]).to.be.an('function');

        next();
      });
    });

    it('will resolve and add the pagelets if directory', function (next) {
      app = new Pipe(server, {
        dist: '/tmp/dist'
      });

      app.define(__dirname + '/fixtures/pagelets', function (err) {
        if (err) return next(err);

        expect(app._pagelets).to.have.length(4);
        app._pagelets.forEach(function (pagelet) {
          expect(pagelet.prototype).to.have.property('id');
        });

        next();
      });
    });
  });

  describe('.discover', function () {
    it('provides default pagelets if no /404 or /500 is found', function () {
      expect(app._statusCodes[404]).to.equal(require('404-pagelet'));
      expect(app._statusCodes[500]).to.equal(require('500-pagelet'));
    });

    it('uses default bootstrap Pagelet if none is provided', function () {
      expect(app._bootstrap).to.equal(require('bootstrap-pagelet'));
    });

    it('uses provided 404 and 500 pagelets based on routes', function (done) {
      var custom = new Pipe(server, {
        dist: '/tmp/dist'
      }).define(__dirname + '/fixtures/discover', function () {
        var Fourofour = require('404-pagelet')
          , Fivehundred = require('500-pagelet');

        expect(custom._pagelets).to.have.length(0);
        expect(custom._statusCodes[404].prototype.view).to.not.equal(Fourofour.prototype.view);
        expect(custom._statusCodes[404].prototype.pagelets).to.not.equal(Fourofour.prototype.pagelets);

        expect(custom._statusCodes[500].prototype.view).to.not.equal(Fivehundred.prototype.view);
        expect(custom._statusCodes[500].prototype.pagelets).to.not.equal(Fivehundred.prototype.pagelets);
        done();
      });
    });

    it('uses provided bootstrap pagelet based on name', function (done) {
      var custom = new Pipe(server, {
        dist: '/tmp/dist'
      }).define(__dirname + '/fixtures/bootstrapper', function () {
        var Bootstrap = require('bootstrap-pagelet');

        expect(custom._pagelets).to.have.length(0);
        expect(custom._bootstrap.prototype.view).to.not.equal(Bootstrap.prototype.view);
        expect(custom._bootstrap.prototype.title).to.not.equal(Bootstrap.prototype.title);
        done();
      });;

      expect(custom._pagelets).to.have.length(0);
      expect(custom._bootstrap).to.not.equal(require('bootstrap-pagelet'));
    });
  });

  describe('.resolve', function () {
    it('omits any directories from the pagelets directory without an index.js', function () {
      app = new Pipe(server, {
        pagelets: __dirname + '/fixtures/discover',
        dist: '/tmp/dist'
      });

      app._pagelets.forEach(function (pagelets) {
        expect(pagelets.id).to.not.match(/^dummy/);
      });
    });
  });

  describe('.listen', function () {
    it('proxies event listeners', function (done) {
      //
      // Set a big timeout as we might need to lazy install dependencies
      //
      this.timeout(50E4);

      var pipe = new Pipe(http.createServer(), {
        dist: '/tmp/dist'
      });

      pipe.once('listening', function () {
        pipe._server.close(done);
      });

      pipe.listen(common.port);
    });
  });

  describe('.createServer', function () {
    it('is a function', function () {
      expect(Pipe.createServer).to.be.a('function');
      expect(Pipe.createServer.length).to.equal(2);
    });

    it('has optional port argument that defaults to 8080', function (done) {
      var pipe = Pipe.createServer({
        dist: '/tmp/dist'
      });

      expect(pipe._options('port')).to.equal(8080);
      pipe.once('listening', done);
    });

    it('will call .listen as soon as the server is completely initialized', function (done) {
      var pipe = Pipe.createServer(common.port, {
        dist: '/tmp/dist'
      });

      pipe.once('listening', done);
    });
  });

  describe('.redirect', function () {
    it('redirects to specified location', function (done) {
      var property = Object.getOwnPropertyDescriptor(Pipe.prototype, 'redirect')
        , pagelet = new Pipe.Pagelet({res: {}, pipe: app });

      expect(Pipe.prototype).to.have.property('redirect');
      expect(Pipe.prototype.redirect).to.be.a('function');
      expect(property.writable).to.equal(false);
      expect(property.enumerable).to.equal(false);
      expect(property.configurable).to.equal(false);

      pagelet._res.setHeader = function setHeader(header, value) {
        expect(header).to.equal('Location');
        expect(value).to.equal('/redirected');
      };

      pagelet._res.end = function end() {
        expect(pagelet._res.statusCode).to.equal(301);
        done();
      };

      app.redirect(pagelet, '/redirected');
    });

    it('allows to set custom statusCode', function (done) {
      var pagelet = new Pipe.Pagelet({res: {}, pipe: app });

      pagelet._res.setHeader = function setHeader(header, value) {
        expect(header).to.equal('Location');
        expect(value).to.equal('/redirected');
      };

      pagelet._res.end = function end() {
        expect(pagelet._res.statusCode).to.equal(400);
        done();
      };

      app.redirect(pagelet, '/redirected', 400);
    });
  });
});
<commit_msg>[test] zipline property<commit_after>describe('Pipe', function () {
  'use strict';

  var common = require('./common')
    , Compiler = require('../lib/compiler')
    , http = require('http')
    , expect = common.expect
    , Pipe = common.Pipe
    , server
    , app;

  before(function (done) {
    server = http.createServer(function () {
      throw new Error('Unhandled request');
    });

    app = new Pipe(server, {
      pagelets: __dirname +'/fixtures/pagelets',
      dist: '/tmp/dist'
    }).listen(common.port, done);
  });

  it('exposes the Pagelet constructor', function () {
    expect(Pipe.Pagelet).to.be.a('function');
    expect(Pipe.Pagelet.extend).to.be.a('function');
  });

  it('is an EvenEmitter3', function () {
    expect(app).to.be.instanceOf(require('eventemitter3'));
  });

  it('correctly resolves `pagelets` as a string to an array', function () {
    expect(app._pagelets).to.be.a('array');
    expect(app._pagelets).to.have.length(4);
  });

  it('transforms pagelets', function () {
    var Pagelet = app._pagelets[0];

    expect(Pagelet.method).to.be.a('array');
  });

  it('has supply middleware manager', function () {
    expect(app).to.have.property('middleware');
    expect(app.middleware).to.be.an('object');
    expect(app.middleware).to.be.instanceof(require('supply'));
  });

  it('has zipline to handle gzip compression', function () {
    expect(app).to.have.property('_zipline');
    expect(app._zipline).to.be.an('object');
    expect(app._zipline).to.be.instanceof(require('zipline'));
  });

  it('has compiler for asset management', function () {
    expect(app).to.have.property('_compiler');
    expect(app._compiler).to.be.an('object');
    expect(app._compiler).to.be.instanceof(Compiler);
  });

  describe('private options', function () {
    it('has queryable options with defaults', function () {
      expect(app._options).to.be.a('function');
      expect(app._options('host')).to.equal(undefined);
      expect(app._options('host', 'localhost')).to.equal('localhost');

      var pipe = new Pipe(http.createServer(), {
          pagelets: __dirname +'/fixtures/pagelets'
        , dist: '/tmp/dist'
        , host: '127.0.0.1'
      });

      expect(pipe._options('host')).to.equal('127.0.0.1');
    });

    it('additional options can be merged, per example from a plugin', function () {
      expect(app._options.merge).to.be.a('function');
      expect(app._options('test')).to.equal(undefined);

      var pipe = new Pipe(http.createServer(), {
          pagelets: __dirname +'/fixtures/pagelets'
        , dist: '/tmp/dist'
        , host: '127.0.0.1'
      });

      expect(pipe._options('host')).to.equal('127.0.0.1');
      pipe._options.merge({ test: 'additional' });
      expect(pipe._options('test')).to.equal('additional');
    });
  });

  describe('.router', function () {
    function Request(url, method) {
      this.url = url;
      this.uri = require('url').parse(url, true);
      this.query = this.uri.query || {};
      this.method = method || 'GET';
    }

    it('finds the / pagelet', function (done) {
      app.router(new Request('/'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(200);

        done();
      });
    });

    it('doesnt find / for POST requests', function (done) {
      app.router(new Request('/', 'POST'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(404);

        done();
      });
    });

    ['GET', 'POST', 'MOO'].forEach(function (method) {
      it('finds /all for '+ method, function (done) {
        app.router(new Request('/all', method), {}, function (err, pagelet) {
          if (err) return done(err);

          expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
          expect(pagelet.statusCode).to.equal(200);

          done();
        });
      });
    });

    it('always returns a 404 page for unknown urls', function (done) {
      app.router(new Request('/'+ Math.random(), 'POST'), {}, function (err, pagelet) {
        if (err) return done(err);

        expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
        expect(pagelet.statusCode).to.equal(404);

        done();
      });
    });

    it('adds and retrieves pagelets from a provided cache', function (done) {
      var cache = {
        get: function (url) {
          expect(url).to.equal('GET@/');
          pattern.push('get');
          return cache.pagelet;
        },
        set: function (url, pagelet) {
          expect(url).to.equal('GET@/');
          expect(pagelet).to.be.a('array');
          pattern.push('set');
          cache.pagelet = pagelet;
        }
      };

      var pattern = [];

      var local = new Pipe(server, {
        dist: '/tmp/dist',
        cache: cache
      });

      local.define(__dirname +'/fixtures/pagelets', function define() {
        local.router(new Request('/'), {}, function (err, pagelet) {
          if (err) return done(err);

          expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
          expect(pagelet.statusCode).to.equal(200);

          local.router(new Request('/'), {}, function (err, pagelet) {
            if (err) return done(err);

            expect(pagelet).to.be.instanceOf(Pipe.Pagelet);
            expect(pagelet.statusCode).to.equal(200);
            expect(pattern.join()).to.equal('get,set,get');

            done();
          });
        });
      });
    });
  });

  describe('.define', function () {
    it('adds Pagelet to the pagelets collection', function (next) {
      var faq = require(__dirname + '/fixtures/pagelets/faq');

      app = new Pipe(server, {
        dist: '/tmp/dist'
      });

      app.define(faq, function (err) {
        if (err) return next(err);

        expect(app._pagelets).to.have.length(1);
        expect(app._pagelets[0]).to.be.an('function');

        next();
      });
    });

    it('will resolve and add the pagelets if directory', function (next) {
      app = new Pipe(server, {
        dist: '/tmp/dist'
      });

      app.define(__dirname + '/fixtures/pagelets', function (err) {
        if (err) return next(err);

        expect(app._pagelets).to.have.length(4);
        app._pagelets.forEach(function (pagelet) {
          expect(pagelet.prototype).to.have.property('id');
        });

        next();
      });
    });
  });

  describe('.discover', function () {
    it('provides default pagelets if no /404 or /500 is found', function () {
      expect(app._statusCodes[404]).to.equal(require('404-pagelet'));
      expect(app._statusCodes[500]).to.equal(require('500-pagelet'));
    });

    it('uses default bootstrap Pagelet if none is provided', function () {
      expect(app._bootstrap).to.equal(require('bootstrap-pagelet'));
    });

    it('uses provided 404 and 500 pagelets based on routes', function (done) {
      var custom = new Pipe(server, {
        dist: '/tmp/dist'
      }).define(__dirname + '/fixtures/discover', function () {
        var Fourofour = require('404-pagelet')
          , Fivehundred = require('500-pagelet');

        expect(custom._pagelets).to.have.length(0);
        expect(custom._statusCodes[404].prototype.view).to.not.equal(Fourofour.prototype.view);
        expect(custom._statusCodes[404].prototype.pagelets).to.not.equal(Fourofour.prototype.pagelets);

        expect(custom._statusCodes[500].prototype.view).to.not.equal(Fivehundred.prototype.view);
        expect(custom._statusCodes[500].prototype.pagelets).to.not.equal(Fivehundred.prototype.pagelets);
        done();
      });
    });

    it('uses provided bootstrap pagelet based on name', function (done) {
      var custom = new Pipe(server, {
        dist: '/tmp/dist'
      }).define(__dirname + '/fixtures/bootstrapper', function () {
        var Bootstrap = require('bootstrap-pagelet');

        expect(custom._pagelets).to.have.length(0);
        expect(custom._bootstrap.prototype.view).to.not.equal(Bootstrap.prototype.view);
        expect(custom._bootstrap.prototype.title).to.not.equal(Bootstrap.prototype.title);
        done();
      });;

      expect(custom._pagelets).to.have.length(0);
      expect(custom._bootstrap).to.not.equal(require('bootstrap-pagelet'));
    });
  });

  describe('.resolve', function () {
    it('omits any directories from the pagelets directory without an index.js', function () {
      app = new Pipe(server, {
        pagelets: __dirname + '/fixtures/discover',
        dist: '/tmp/dist'
      });

      app._pagelets.forEach(function (pagelets) {
        expect(pagelets.id).to.not.match(/^dummy/);
      });
    });
  });

  describe('.listen', function () {
    it('proxies event listeners', function (done) {
      //
      // Set a big timeout as we might need to lazy install dependencies
      //
      this.timeout(50E4);

      var pipe = new Pipe(http.createServer(), {
        dist: '/tmp/dist'
      });

      pipe.once('listening', function () {
        pipe._server.close(done);
      });

      pipe.listen(common.port);
    });
  });

  describe('.createServer', function () {
    it('is a function', function () {
      expect(Pipe.createServer).to.be.a('function');
      expect(Pipe.createServer.length).to.equal(2);
    });

    it('has optional port argument that defaults to 8080', function (done) {
      var pipe = Pipe.createServer({
        dist: '/tmp/dist'
      });

      expect(pipe._options('port')).to.equal(8080);
      pipe.once('listening', done);
    });

    it('will call .listen as soon as the server is completely initialized', function (done) {
      var pipe = Pipe.createServer(common.port, {
        dist: '/tmp/dist'
      });

      pipe.once('listening', done);
    });
  });

  describe('.redirect', function () {
    it('redirects to specified location', function (done) {
      var property = Object.getOwnPropertyDescriptor(Pipe.prototype, 'redirect')
        , pagelet = new Pipe.Pagelet({res: {}, pipe: app });

      expect(Pipe.prototype).to.have.property('redirect');
      expect(Pipe.prototype.redirect).to.be.a('function');
      expect(property.writable).to.equal(false);
      expect(property.enumerable).to.equal(false);
      expect(property.configurable).to.equal(false);

      pagelet._res.setHeader = function setHeader(header, value) {
        expect(header).to.equal('Location');
        expect(value).to.equal('/redirected');
      };

      pagelet._res.end = function end() {
        expect(pagelet._res.statusCode).to.equal(301);
        done();
      };

      app.redirect(pagelet, '/redirected');
    });

    it('allows to set custom statusCode', function (done) {
      var pagelet = new Pipe.Pagelet({res: {}, pipe: app });

      pagelet._res.setHeader = function setHeader(header, value) {
        expect(header).to.equal('Location');
        expect(value).to.equal('/redirected');
      };

      pagelet._res.end = function end() {
        expect(pagelet._res.statusCode).to.equal(400);
        done();
      };

      app.redirect(pagelet, '/redirected', 400);
    });
  });
});
<|endoftext|>


<commit_before>/* This file is excluded from coverage because the intrumented code
 * translates "self" which gives a reference error.
 */

/* istanbul ignore next */

export function workerCode() {

    self.document = {}; // Workaround for "ReferenceError: document is not defined" in hpccWasm
    var hpccWasm;

    self.onconnect = function(e) {
        const port = e.ports[0];
        port.addEventListener('message', function(event) {
            if (event.data.vizURL) {
                importScripts(event.data.vizURL);
                hpccWasm = self["@hpcc-js/wasm"];
                hpccWasm.wasmFolder(event.data.vizURL.match(/.*\//)[0]);
                // This is an alternative workaround where wasmFolder() is not needed
//                                    document = {currentScript: {src: event.data.vizURL}};
            }
            hpccWasm.graphviz.layout(event.data.dot, "svg", event.data.engine, event.data.options).then((svg) => {
                if (svg) {
                    port.postMessage({
                        type: "done",
                        svg: svg,
                    });
                } else if (event.data.vizURL) {
                    port.postMessage({
                        type: "init",
                    });
                } else {
                    port.postMessage({
                        type: "skip",
                    });
                }
            }).catch(error => {
                port.postMessage({
                    type: "error",
                    error: error.message,
                });
            });
        });
        port.start();
    }
}
<commit_msg>Avoid loading script in shared worker more than once<commit_after>/* This file is excluded from coverage because the intrumented code
 * translates "self" which gives a reference error.
 */

/* istanbul ignore next */

export function workerCode() {

    self.document = {}; // Workaround for "ReferenceError: document is not defined" in hpccWasm

    self.onconnect = function(e) {
        const port = e.ports[0];
        port.addEventListener('message', function(event) {
            let hpccWasm = self["@hpcc-js/wasm"];
            if (hpccWasm == undefined && event.data.vizURL) {
                importScripts(event.data.vizURL);
                hpccWasm = self["@hpcc-js/wasm"];
                hpccWasm.wasmFolder(event.data.vizURL.match(/.*\//)[0]);
                // This is an alternative workaround where wasmFolder() is not needed
//                                    document = {currentScript: {src: event.data.vizURL}};
            }
            hpccWasm.graphviz.layout(event.data.dot, "svg", event.data.engine, event.data.options).then((svg) => {
                if (svg) {
                    port.postMessage({
                        type: "done",
                        svg: svg,
                    });
                } else if (event.data.vizURL) {
                    port.postMessage({
                        type: "init",
                    });
                } else {
                    port.postMessage({
                        type: "skip",
                    });
                }
            }).catch(error => {
                port.postMessage({
                    type: "error",
                    error: error.message,
                });
            });
        });
        port.start();
    }
}
<|endoftext|>


<commit_before>var IncomingMessage = require('http').IncomingMessage;
var inherits = require('util').inherits;
var CRLF = '\r\n';
var CRLF_BUF = new Buffer(CRLF);
var MAX_BYTES = 1024 * 128;
var TIMEOUT = 36000;

function HttpIncomingMessage(socket) {
	if (!(this instanceof HttpIncomingMessage)) {
		return new HttpIncomingMessage(socket);
	}

	var self = this;
	var index = 0;
	var buffer, parsedHeaders, overflow, timeoutId;

	IncomingMessage.call(this, socket);
	socket.on('data', parseData);
	socket.on('error', emitError);
	socket.on('free', cleanup);

	function cleanup() {
		clearTimeout(timeoutId);
		socket.removeListener('error', emitError);
		socket.removeListener('data', parseData);
		socket.removeListener('free', cleanup);
	}

	function parseData(data) {
		clearTimeout(timeoutId);
		timeoutId = setTimeout(destroy, TIMEOUT);
		buffer = buffer ? Buffer.concat([buffer, data]) : data;
		if (parsedHeaders) {
			self._parseBody(buffer);
			return;
		}

		var endIndex = endIndexOf(buffer, index);
		if (endIndex == -1) {
			endIndex = lastIndexOfCRLF(buffer, index);
			if (endIndex != -1) {
				index = endIndex + 2;
				if (!overflow && buffer.length > MAX_BYTES) {
					overflow = true;
					self._parseHeaders(buffer.slice(0, endIndex));
					buffer = buffer.slice(endIndex);
				}
			}
			return;
		}

		endIndex += 4;
		!overflow && self._parseHeaders(buffer.slice(0, endIndex));
		parsedHeaders = true;
		var statusCode = self.statusCode;
		self._parseBody(buffer.slice(endIndex));
		buffer = null;
		self.emit('response', self);
		if (statusCode == 204 || statusCode == 304 ||
			      (100 <= statusCode && statusCode <= 199)) {
			    self._emitEnd();
		}
	}

	function emitError(err) {
		cleanup();
		self.emit('error', err);
		destroy();
	}

	function destroy() {
		socket.destroy();
	}
}

inherits(HttpIncomingMessage, IncomingMessage);

var proto = HttpIncomingMessage.prototype;

proto._parseBody = function(buffer) {
	if (this.contentLength_ == null && this.chunkedEncoding_ == null) {
		this.contentLength_ = this.headers['content-length'];
		this.chunkedEncoding_ = this.contentLength_ == null;
	}

	if (this.chunkedEncoding_) {
		this._parseChunkedBody(buffer);
		return;
	}

	this.contentLength_ -= buffer.length;
	this.push(buffer);
	if (this.contentLength_ <= 0) {
		this._emitEnd();
	}
};

proto._emitEnd = function() {
	this.socket.emit('free');
	this.push(null);
};

proto._parseChunkedBody = function(buffer) {
	buffer = this.buffer_ = this.buffer_ ? Buffer.concat([this.buffer_, buffer]) : buffer;
	if (this.contentLength_ == -1) {
		this._parseTrailers();
		return;
	}
	if (this.contentLength_ > 0) {
		this.parseChunkedBody_();
		return;
	}

	var index = indexOfCRLF(buffer);
	if (index == -1) {
		return;
	}

	var size = parseInt(buffer.slice(0, index).toString(), 16);
	if (!size) {
		if (isNaN(size)) {
			this.socket.emit('error', new Error('Parse error'))
		} else {
			this.contentLength_ = -1;
			this.buffer_ = buffer.slice(index);
			this._parseTrailers();
		}
		return;
	}

	this.contentLength_ = size + 2;
	this.buffer_ = buffer.slice(2);
	this.parseChunkedBody_();
};

proto.parseChunkedBody_ = function() {
	var buffer = this.buffer_;
	var len = buffer.length;
	if (this.contentLength_ <= len) {
		this.buffer_ = buffer.slice(this.contentLength_);
		this.push(buffer.slice(0, this.contentLength_ - 2));
		this.contentLength_ = 0;
	} else {
		len--;
		this.push(buffer.slice(0, len));
		this.buffer_ = buffer.slice(len);
		this.contentLength_ -= len;
	}
};

proto._parseTrailers = function() {
	var index = endIndexOf(this.buffer_);
	if (index != -1) {
		parsePairs(this.trailers, this.buffer_.slice(0, index).toString()
				.trim().split(/\r\n/g));
		this._emitEnd();
	}
};

proto._parseHeaders = function(buffer) {
	buffer = buffer.toString().trim().split(/\r\n/g);
	var firstLine = getPair(buffer[0]);
	if (firstLine) {
		this.httpVersion = firstLine.key.split('/')[1];
		this.statusCode = parseInt(firstLine.value.split(/\s+/g)[0], 10) || 0;
	}
	parsePairs(this.headers, buffer, 1);
	return this;
};

function getPair(line) {
	if (!(line = line && line.trim())) {
		return;
	}

	var index = line.indexOf(':');
	return index != -1 ? {
		key: line.substring(0, index).trim().toLowerCase(),
		value: line.substring(index + 1).trim()
	} : null;
}

function indexOfCRLF(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (; start < end; start++) {
		if (buffer[start] == CRLF_BUF[0] && buffer[start + 1] == CRLF_BUF[1]) {
			return start;
		}
	}

	return -1;
}

function lastIndexOfCRLF(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (--end; end >= start; end--) {
		if (buffer[end - 1] == CRLF_BUF[0] && buffer[end] == CRLF_BUF[1]) {
			return end - 1;
		}
	}

	return -1;
}

function endIndexOf(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (; start < end; start++) {
		if (buffer[start] == CRLF_BUF[0] && buffer[start + 1] == CRLF_BUF[1]
		&& buffer[start + 2] == CRLF_BUF[0] && buffer[start + 3] == CRLF_BUF[1]) {
			return start;
		}
	}

	return -1;
}

function parsePairs(pairs, buffer, start) {
	for (var i = start || 0, len = buffer.length; i < len; i++) {
		var pair = getPair(buffer[i]);
		if (pair) {
			var value = pairs[pair.key];
			if (value) {
				if (!Array.isArray(value)) {
					value = [value];
				}
				value.push(pair.value);
			}
			pairs[pair.key] = value || pair.value;
		}
	}

	return pairs;
}

module.exports = HttpIncomingMessage;<commit_msg>https-proxy<commit_after>var IncomingMessage = require('http').IncomingMessage;
var inherits = require('util').inherits;
var CRLF = '\r\n';
var CRLF_BUF = new Buffer(CRLF);
var MAX_BYTES = 1024 * 128;
var TIMEOUT = 36000;

function HttpIncomingMessage(socket) {
	if (!(this instanceof HttpIncomingMessage)) {
		return new HttpIncomingMessage(socket);
	}

	var self = this;
	var index = 0;
	var buffer, parsedHeaders, overflow, timeoutId;

	IncomingMessage.call(this, socket);
	socket.on('data', parseData);
	socket.on('error', emitError);
	socket.on('free', cleanup);

	function cleanup() {
		clearTimeout(timeoutId);
		socket.removeListener('error', emitError);
		socket.removeListener('data', parseData);
		socket.removeListener('free', cleanup);
	}

	function parseData(data) {
		clearTimeout(timeoutId);
		timeoutId = setTimeout(destroy, TIMEOUT);
		if (parsedHeaders) {
			self._parseBody(data);
			return;
		}

		buffer = buffer ? Buffer.concat([buffer, data]) : data;
		var endIndex = endIndexOf(buffer, index);
		if (endIndex == -1) {
			endIndex = lastIndexOfCRLF(buffer, index);
			if (endIndex != -1) {
				index = endIndex + 2;
				if (!overflow && buffer.length > MAX_BYTES) {
					overflow = true;
					self._parseHeaders(buffer.slice(0, endIndex));
					buffer = buffer.slice(endIndex);
				}
			}
			return;
		}

		endIndex += 4;
		!overflow && self._parseHeaders(buffer.slice(0, endIndex));
		parsedHeaders = true;
		var statusCode = self.statusCode;
		self._parseBody(buffer.slice(endIndex));
		buffer = null;
		self.emit('response', self);
		if (statusCode == 204 || statusCode == 304 ||
			      (100 <= statusCode && statusCode <= 199)) {
			    self._emitEnd();
		}
	}

	function emitError(err) {
		cleanup();
		self.emit('error', err);
		destroy();
	}

	function destroy() {
		socket.destroy();
	}
}

inherits(HttpIncomingMessage, IncomingMessage);

var proto = HttpIncomingMessage.prototype;

proto._parseBody = function(buffer) {
	if (this.contentLength_ == null && this.chunkedEncoding_ == null) {
		this.contentLength_ = this.headers['content-length'];
		this.chunkedEncoding_ = this.contentLength_ == null;
	}

	if (this.chunkedEncoding_) {
		this._parseChunkedBody(buffer);
		return;
	}

	this.push(buffer);
	this.contentLength_ -= buffer.length;
	if (this.contentLength_ <= 0) {
		this._emitEnd();
	}
};

proto._emitEnd = function() {
	this.socket.emit('free');
	this.push(null);
};

proto._parseChunkedBody = function(buffer) {
	buffer = this.buffer_ = this.buffer_ ? Buffer.concat([this.buffer_, buffer]) : buffer;
	if (this.contentLength_ == -1) {
		this._parseTrailers();
		return;
	}
	if (this.contentLength_ > 0) {
		this.parseChunkedBody_();
		return;
	}

	var index = indexOfCRLF(buffer);
	if (index == -1) {
		return;
	}

	var size = parseInt(buffer.slice(0, index).toString(), 16);
	if (!size) {
		if (isNaN(size)) {
			this.socket.emit('error', new Error('Parse error'))
		} else {
			this.contentLength_ = -1;
			this.buffer_ = buffer.slice(index);
			this._parseTrailers();
		}
		return;
	}

	this.contentLength_ = size + 2;
	this.buffer_ = buffer.slice(2);
	this.parseChunkedBody_();
};

proto.parseChunkedBody_ = function() {
	var buffer = this.buffer_;
	var len = buffer.length;
	if (this.contentLength_ <= len) {
		this.buffer_ = buffer.slice(this.contentLength_);
		this.push(buffer.slice(0, this.contentLength_ - 2));
		this.contentLength_ = 0;
	} else {
		len--;
		this.push(buffer.slice(0, len));
		this.buffer_ = buffer.slice(len);
		this.contentLength_ -= len;
	}
};

proto._parseTrailers = function() {
	var index = endIndexOf(this.buffer_);
	if (index != -1) {
		parsePairs(this.trailers, this.buffer_.slice(0, index).toString()
				.trim().split(/\r\n/g));
		this._emitEnd();
	}
};

proto._parseHeaders = function(buffer) {
	buffer = buffer.toString().trim().split(/\r\n/g);
	var firstLine = getPair(buffer[0]);
	if (firstLine) {
		this.httpVersion = firstLine.key.split('/')[1];
		this.statusCode = parseInt(firstLine.value.split(/\s+/g)[0], 10) || 0;
	}
	parsePairs(this.headers, buffer, 1);
	return this;
};

function getPair(line) {
	if (!(line = line && line.trim())) {
		return;
	}

	var index = line.indexOf(':');
	return index != -1 ? {
		key: line.substring(0, index).trim().toLowerCase(),
		value: line.substring(index + 1).trim()
	} : null;
}

function indexOfCRLF(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (; start < end; start++) {
		if (buffer[start] == CRLF_BUF[0] && buffer[start + 1] == CRLF_BUF[1]) {
			return start;
		}
	}

	return -1;
}

function lastIndexOfCRLF(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (--end; end >= start; end--) {
		if (buffer[end - 1] == CRLF_BUF[0] && buffer[end] == CRLF_BUF[1]) {
			return end - 1;
		}
	}

	return -1;
}

function endIndexOf(buffer, start, end) {
	start = start || 0;
	end = end || buffer.length;
	for (; start < end; start++) {
		if (buffer[start] == CRLF_BUF[0] && buffer[start + 1] == CRLF_BUF[1]
		&& buffer[start + 2] == CRLF_BUF[0] && buffer[start + 3] == CRLF_BUF[1]) {
			return start;
		}
	}

	return -1;
}

function parsePairs(pairs, buffer, start) {
	for (var i = start || 0, len = buffer.length; i < len; i++) {
		var pair = getPair(buffer[i]);
		if (pair) {
			var value = pairs[pair.key];
			if (value) {
				if (!Array.isArray(value)) {
					value = [value];
				}
				value.push(pair.value);
			}
			pairs[pair.key] = value || pair.value;
		}
	}

	return pairs;
}

module.exports = HttpIncomingMessage;<|endoftext|>


<commit_before>steal('can/util',function(can) {
	// ##string.js
	// _Miscellaneous string utility functions._

	// Several of the methods in this plugin use code adapated from Prototype
	// Prototype JavaScript framework, version 1.6.0.1.
	// © 2005-2007 Sam Stephenson
	var undHash     = /_|-/,
		colons      = /\=\=/,
		words       = /([A-Z]+)([A-Z][a-z])/g,
		lowUp       = /([a-z\d])([A-Z])/g,
		dash        = /([a-z\d])([A-Z])/g,
		replacer    = /\{([^\}]+)\}/g,
		quote       = /"/g,
		singleQuote = /'/g,

		// Returns the `prop` property from `obj`.
		// If `add` is true and `prop` doesn't exist in `obj`, create it as an
		// empty object.
		getNext = function( obj, prop, add ) {
			return prop in obj ?
				obj[ prop ] :
				( add && ( obj[ prop ] = {} ));
		},

		// Returns `true` if the object can have properties (no `null`s).
		isContainer = function( current ) {
			return (/^f|^o/).test( typeof current );
		};

		can.extend(can, {
			// Escapes strings for HTML.
			/**
			 * @function can.esc
			 * @parent can.util
			 *
			 * `can.esc(string)` escapes a string for insertion into html.
			 *
			 *     can.esc( "<foo>&<bar>" ) //-> "<foo<&<bar<"
			 */
			esc : function( content ) {
				return ( "" + content )
					.replace(/&/g, '&')
					.replace(/</g, '<')
					.replace(/>/g, '>')
					.replace(quote, '"')
					.replace(singleQuote, "'");
			},

			/**
			 * @function can.getObject
			 * @parent can.util
			 * Gets an object from a string.  It can also modify objects on the
			 * 'object path' by removing or adding properties.
			 *
			 *     Foo = {Bar: {Zar: {"Ted"}}}
			 *     can.getObject("Foo.Bar.Zar") //-> "Ted"
			 *
			 * @param {String} name the name of the object to look for
			 * @param {Array} [roots] an array of root objects to look for the
			 *   name.  If roots is not provided, the window is used.
			 * @param {Boolean} [add] true to add missing objects to
			 *  the path. false to remove found properties. undefined to
			 *  not modify the root object
			 * @return {Object} The object.
			 */
			getObject : function( name, roots, add ) {

				// The parts of the name we are looking up
				// `['App','Models','Recipe']`
				var	parts = name ? name.split('.') : [],
					length =  parts.length,
					current,
					r = 0,
					ret, i;

				// Make sure roots is an `array`.
				roots = can.isArray(roots) ? roots : [roots || window];

				if ( ! length ) {
					return roots[0];
				}

				// For each root, mark it as current.
				while ( roots[r] ) {
					current = roots[r];

					// Walk current to the 2nd to last object or until there
					// is not a container.
					for (i =0; i < length - 1 && isContainer( current ); i++ ) {
						current = getNext( current, parts[i], add );
					}

					// If we can get a property from the 2nd to last object...
					if( isContainer(current) ) {

						// Get (and possibly set) the property.
						ret = getNext(current, parts[i], add);

						// If there is a value, we exit.
						if ( ret !== undefined ) {
							// If `add` is `false`, delete the property
							if ( add === false ) {
								delete current[parts[i]];
							}
							return ret;

						}
					}
					r++;
				}
			},
			// Capitalizes a string.
			/**
			 * @function can.capitalize
			 * @parent can.util
			 * `can.capitalize(string)` capitalizes the first letter of the string passed.
			 *
			 *		can.capitalize('candy is fun!'); //-> Returns: 'Candy is fun!'
			 *
			 * @param {String} s the string.
			 * @return {String} a string with the first character capitalized.
			 */
			capitalize: function( s, cache ) {
				// Used to make newId.
				return s.charAt(0).toUpperCase() + s.slice(1);
			},

			// Underscores a string.
			/**
			 * @function can.underscore
			 * @parent can.util
			 *
			 * Underscores a string.
			 *
			 *     can.underscore("OneTwo") //-> "one_two"
			 *
			 * @param {String} s
			 * @return {String} the underscored string
			 */
			underscore: function( s ) {
				return s
					.replace(colons, '/')
					.replace(words, '$1_$2')
					.replace(lowUp, '$1_$2')
					.replace(dash, '_')
					.toLowerCase();
			},
			// Micro-templating.
			/**
			 * @function can.sub
			 * @parent can.util
			 *
			 * Returns a string with {param} replaced values from data.
			 *
			 *     can.sub("foo {bar}",{bar: "far"})
			 *     //-> "foo far"
			 *
			 * @param {String} s The string to replace
			 * @param {Object} data The data to be used to look for properties.  If it's an array, multiple
			 * objects can be used.
			 * @param {Boolean} [remove] if a match is found, remove the property from the object
			 */
			sub: function( str, data, remove ) {

				var obs = [];

				obs.push( str.replace( replacer, function( whole, inside ) {

					// Convert inside to type.
					var ob = can.getObject( inside, data, remove === undefined? remove : !remove );

					// If a container, push into objs (which will return objects found).
					if ( isContainer( ob ) ) {
						obs.push( ob );
						return "";
					} else {
						return "" + ob;
					}
				}));

				return obs.length <= 1 ? obs[0] : obs;
			},

			// These regex's are used throughout the rest of can, so let's make
			// them available.
			replacer : replacer,
			undHash : undHash
		});
	return can;
});
<commit_msg>Escaping falsy values should yield an empty string<commit_after>steal('can/util',function(can) {
	// ##string.js
	// _Miscellaneous string utility functions._

	// Several of the methods in this plugin use code adapated from Prototype
	// Prototype JavaScript framework, version 1.6.0.1.
	// © 2005-2007 Sam Stephenson
	var undHash     = /_|-/,
		colons      = /\=\=/,
		words       = /([A-Z]+)([A-Z][a-z])/g,
		lowUp       = /([a-z\d])([A-Z])/g,
		dash        = /([a-z\d])([A-Z])/g,
		replacer    = /\{([^\}]+)\}/g,
		quote       = /"/g,
		singleQuote = /'/g,

		// Returns the `prop` property from `obj`.
		// If `add` is true and `prop` doesn't exist in `obj`, create it as an
		// empty object.
		getNext = function( obj, prop, add ) {
			return prop in obj ?
				obj[ prop ] :
				( add && ( obj[ prop ] = {} ));
		},

		// Returns `true` if the object can have properties (no `null`s).
		isContainer = function( current ) {
			return (/^f|^o/).test( typeof current );
		};

		can.extend(can, {
			// Escapes strings for HTML.
			/**
			 * @function can.esc
			 * @parent can.util
			 *
			 * `can.esc(string)` escapes a string for insertion into html.
			 *
			 *     can.esc( "<foo>&<bar>" ) //-> "<foo<&<bar<"
			 */
			esc : function( content ) {
				return ( "" + (content || '') )
					.replace(/&/g, '&')
					.replace(/</g, '<')
					.replace(/>/g, '>')
					.replace(quote, '"')
					.replace(singleQuote, "'");
			},

			/**
			 * @function can.getObject
			 * @parent can.util
			 * Gets an object from a string.  It can also modify objects on the
			 * 'object path' by removing or adding properties.
			 *
			 *     Foo = {Bar: {Zar: {"Ted"}}}
			 *     can.getObject("Foo.Bar.Zar") //-> "Ted"
			 *
			 * @param {String} name the name of the object to look for
			 * @param {Array} [roots] an array of root objects to look for the
			 *   name.  If roots is not provided, the window is used.
			 * @param {Boolean} [add] true to add missing objects to
			 *  the path. false to remove found properties. undefined to
			 *  not modify the root object
			 * @return {Object} The object.
			 */
			getObject : function( name, roots, add ) {

				// The parts of the name we are looking up
				// `['App','Models','Recipe']`
				var	parts = name ? name.split('.') : [],
					length =  parts.length,
					current,
					r = 0,
					ret, i;

				// Make sure roots is an `array`.
				roots = can.isArray(roots) ? roots : [roots || window];

				if ( ! length ) {
					return roots[0];
				}

				// For each root, mark it as current.
				while ( roots[r] ) {
					current = roots[r];

					// Walk current to the 2nd to last object or until there
					// is not a container.
					for (i =0; i < length - 1 && isContainer( current ); i++ ) {
						current = getNext( current, parts[i], add );
					}

					// If we can get a property from the 2nd to last object...
					if( isContainer(current) ) {

						// Get (and possibly set) the property.
						ret = getNext(current, parts[i], add);

						// If there is a value, we exit.
						if ( ret !== undefined ) {
							// If `add` is `false`, delete the property
							if ( add === false ) {
								delete current[parts[i]];
							}
							return ret;

						}
					}
					r++;
				}
			},
			// Capitalizes a string.
			/**
			 * @function can.capitalize
			 * @parent can.util
			 * `can.capitalize(string)` capitalizes the first letter of the string passed.
			 *
			 *		can.capitalize('candy is fun!'); //-> Returns: 'Candy is fun!'
			 *
			 * @param {String} s the string.
			 * @return {String} a string with the first character capitalized.
			 */
			capitalize: function( s, cache ) {
				// Used to make newId.
				return s.charAt(0).toUpperCase() + s.slice(1);
			},

			// Underscores a string.
			/**
			 * @function can.underscore
			 * @parent can.util
			 *
			 * Underscores a string.
			 *
			 *     can.underscore("OneTwo") //-> "one_two"
			 *
			 * @param {String} s
			 * @return {String} the underscored string
			 */
			underscore: function( s ) {
				return s
					.replace(colons, '/')
					.replace(words, '$1_$2')
					.replace(lowUp, '$1_$2')
					.replace(dash, '_')
					.toLowerCase();
			},
			// Micro-templating.
			/**
			 * @function can.sub
			 * @parent can.util
			 *
			 * Returns a string with {param} replaced values from data.
			 *
			 *     can.sub("foo {bar}",{bar: "far"})
			 *     //-> "foo far"
			 *
			 * @param {String} s The string to replace
			 * @param {Object} data The data to be used to look for properties.  If it's an array, multiple
			 * objects can be used.
			 * @param {Boolean} [remove] if a match is found, remove the property from the object
			 */
			sub: function( str, data, remove ) {

				var obs = [];

				obs.push( str.replace( replacer, function( whole, inside ) {

					// Convert inside to type.
					var ob = can.getObject( inside, data, remove === undefined? remove : !remove );

					// If a container, push into objs (which will return objects found).
					if ( isContainer( ob ) ) {
						obs.push( ob );
						return "";
					} else {
						return "" + ob;
					}
				}));

				return obs.length <= 1 ? obs[0] : obs;
			},

			// These regex's are used throughout the rest of can, so let's make
			// them available.
			replacer : replacer,
			undHash : undHash
		});
	return can;
});
<|endoftext|>


<commit_before>;(function() {
  'use strict';

  /** Environment shortcut */
  var env = process.env;

  if (isFinite(env.TRAVIS_PULL_REQUEST)) {
    console.error('Testing skipped for pull requests');
    process.exit(0);
  }

  /** Load Node.js modules */
  var http = require('http'),
      path = require('path'),
      url = require('url');

  /** Load other modules */
  var _ = require('../lodash.js'),
      ecstatic = require('ecstatic'),
      request = require('request'),
      SauceTunnel = require('sauce-tunnel');

  /** Used by `logInline` to clear previously logged messages */
  var prevLine = '';

  /** Used to display the wait throbber */
  var throbberId,
      throbberDelay = 500,
      waitCount = -1;

  /** Used as request `auth` and `options` values */
  var accessKey = env.SAUCE_ACCESS_KEY,
      build = env.TRAVIS_COMMIT.slice(0, 10),
      port = 9001,
      tunnelId = 'lodash_' + env.TRAVIS_JOB_NUMBER,
      username = env.SAUCE_USERNAME;

  var compatMode = process.argv.reduce(function(result, value) {
    return optionToValue('compatMode', value) || result;
  }, null);

  var runner = process.argv.reduce(function(result, value) {
    value = optionToValue('runner', value);
    return value == null
      ? result
      : '/' + value.replace(/^\W+/, '');
  }, '/test/index.html');

  var sessionName = process.argv.reduce(function(result, value) {
    return optionToValue('name', value) || result;
  }, 'lodash tests');

  var tags = process.argv.reduce(function(result, value) {
    value = optionToArray('tags', value);
    return value.length
      ? _.union(result, value)
      : result;
  }, []);

  /** List of platforms to load the runner on */
  var platforms = [
    ['Windows 8.1', 'chrome', '31'],
    ['Windows 8.1', 'chrome', '28'],
    ['Windows 8.1', 'chrome', '26'],
    ['OS X 10.6', 'firefox', '25'],
    ['OS X 10.6', 'firefox', '20'],
    ['OS X 10.6', 'firefox', '10'],
    ['OS X 10.6', 'firefox', '6'],
    ['OS X 10.6', 'firefox', '4'],
    ['Windows 7', 'firefox', '3.6'],
    ['Windows 8.1', 'internet explorer', '11'],
    ['Windows 8', 'internet explorer', '10'],
    ['Windows 7', 'internet explorer', '9'],
    ['Windows 7', 'internet explorer', '8'],
    ['Windows XP', 'internet explorer', '7'],
    ['Windows XP', 'internet explorer', '6'],
    //['Windows 7', 'opera', '12'],
    //['Windows 7', 'opera', '11'],
    ['OS X 10.8', 'safari', '6'],
    ['Windows 7', 'safari', '5'],
    ['Windows XP', 'safari', '4']
  ];

  /** Used to tailor the `platforms` array */
  var runnerQuery = url.parse(runner, true).query,
      isBackbone = /\bbackbone\b/i.test(runner),
      isMobile = /\bmobile\b/i.test(runnerQuery.build),
      isModern = /\bmodern\b/i.test(runnerQuery.build);

  // platforms to test IE compat mode
  if (compatMode) {
    platforms = [
      ['Windows 8.1', 'internet explorer', '11'],
      ['Windows 8', 'internet explorer', '10'],
      ['Windows 7', 'internet explorer', '9'],
      ['Windows 7', 'internet explorer', '8']
    ];
  }
  // platforms for Backbone tests
  if (isBackbone) {
    platforms = platforms.filter(function(platform) {
      var browser = platform[1],
          version = +platform[2];

      switch (browser) {
        case 'firefox': return version >= 4;
        case 'opera': return version >= 12;
      }
      return true;
    });
  }
  // platforms for mobile and modern builds
  if (isMobile || isModern) {
    platforms = platforms.filter(function(platform) {
      var browser = platform[1],
          version = +platform[2];

      switch (browser) {
        case 'firefox': return version >= 10;
        case 'internet explorer': return version >= 9;
        case 'opera': return version >= 12;
        case 'safari': return version >= (isMobile ? 3 : 6);
      }
      return true;
    });
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Writes an inline message to standard output.
   *
   * @private
   * @param {string} text The text to log.
   */
  function logInline(text) {
    var blankLine = repeat(' ', prevLine.length);
    if (text.length > 40) {
      text = text.slice(0, 37) + '...';
    }
    prevLine = text;
    process.stdout.write(text + blankLine.slice(text.length) + '\r');
  }

  /**
   * Writes the wait throbber to standard output.
   *
   * @private
   */
  function logThrobber() {
    logInline('Please wait' + repeat('.', (++waitCount % 3) + 1));
  }

  /**
   * Converts a comma separated option value into an array.
   *
   * @private
   * @param {string} name The name of the option to inspect.
   * @param {string} string The options string.
   * @returns {Array} Returns the new converted array.
   */
  function optionToArray(name, string) {
    return _.compact(_.isArray(string)
      ? string
      : _.invoke((optionToValue(name, string) || '').split(/, */), 'trim')
    );
  }

  /**
   * Extracts the option value from an option string.
   *
   * @private
   * @param {string} name The name of the option to inspect.
   * @param {string} string The options string.
   * @returns {string|undefined} Returns the option value, else `undefined`.
   */
  function optionToValue(name, string) {
    var result = (result = string.match(RegExp('^' + name + '=([\\s\\S]+)$'))) && result[1].trim();
    return result || undefined;
  }

  /**
   * Creates a string with `text` repeated `n` number of times.
   *
   * @private
   * @param {string} text The text to repeat.
   * @param {number} n The number of times to repeat `text`.
   * @returns {string} The created string.
   */
  function repeat(text, n) {
    return Array(n + 1).join(text);
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Processes the result object of the test session.
   *
   * @private
   * @param {Object} results The result object to process.
   */
  function handleTestResults(results) {
    var failingTests = results.filter(function(test) {
      var result = test.result;
      return !result || result.failed || /\berror\b/i.test(result.message);
    });

    var failingPlatforms = failingTests.map(function(test) {
      return test.platform;
    });

    if (!failingTests.length) {
      console.log('Tests passed');
    }
    else {
      console.error('Tests failed on platforms: ' + JSON.stringify(failingPlatforms));

      failingTests.forEach(function(test) {
        var result = test.result || {},
            details = 'See ' + test.url + ' for details.',
            failed = result.failed,
            platform = JSON.stringify(test.platform);

        if (failed) {
          console.error(failed + ' failures on ' + platform + '. ' + details);
        } else {
          var message = result.message || 'no results available. ' + details;
          console.error('Testing on ' + platform + ' failed; ' + message);
        }
      });
    }

    clearInterval(throbberId);
    console.log('Shutting down Sauce Connect tunnel...');

    tunnel.stop(function() {
      process.exit(failingTests.length ? 1 : 0);
    });
  }

  /**
   * Makes a request for Sauce Labs to start the test session.
   *
   * @private
   */
  function runTests() {
    var options = {
      'build': build,
      'framework': 'qunit',
      'name': sessionName,
      'public': 'public',
      'platforms': platforms,
      'record-screenshots': false,
      'tags': tags,
      'tunnel': 'tunnel-identifier:' + tunnelId,
      'url': 'http://localhost:' + port + runner,
      'video-upload-on-pass': false
    };

    console.log('Starting saucelabs tests: ' + JSON.stringify(options));

    request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests', {
      'auth': { 'user': username, 'pass': accessKey },
      'json': options
    }, function(error, response, body) {
      var statusCode = response && response.statusCode;
      if (statusCode == 200) {
        waitForTestCompletion(body);
      } else {
        console.error('Failed to submit test to Sauce Labs; status: ' +  statusCode + ', body:\n' + JSON.stringify(body));
        if (error) {
          console.error(error);
        }
        process.exit(3);
      }
    });

    // initialize the wait throbber
    if (!throbberId) {
      throbberId = setInterval(logThrobber, throbberDelay);
      logThrobber();
    }
  }

  /**
   * Checks the status of the test session. If the session has completed it
   * passes the result object to `handleTestResults`, else it checks the status
   * again in five seconds.
   *
   * @private
   * @param {Object} testIdentifier The object used to identify the session.
   */
  function waitForTestCompletion(testIdentifier) {
    request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests/status', {
      'auth': { 'user': username, 'pass': accessKey },
      'json': testIdentifier
    }, function(error, response, body) {
        var statusCode = response && response.statusCode;
        if (statusCode == 200) {
          if (body.completed) {
            logInline('');
            handleTestResults(body['js tests']);
          }
          else {
            setTimeout(function() {
              waitForTestCompletion(testIdentifier);
            }, 5000);
          }
        } else {
          logInline('');
          console.error('Failed to check test status on Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
          if (error) {
            console.error(error);
          }
          process.exit(4);
        }
    });
  }

  /*--------------------------------------------------------------------------*/

  // create a web server for the local dir
  var mount = ecstatic({
    'cache': false,
    'root': process.cwd()
  });

  http.createServer(function(req, res) {
    // see http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx
    if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') {
      res.setHeader('X-UA-Compatible', 'IE=' + compatMode);
    }
    mount(req, res);
  }).listen(port);

  // set up Sauce Connect so we can use this server from Sauce Labs
  var tunnelTimeout = 10000,
      tunnel = new SauceTunnel(username, accessKey, tunnelId, true, tunnelTimeout);

  console.log('Opening Sauce Connect tunnel...');

  tunnel.start(function(success) {
    if (success) {
      console.log('Sauce Connect tunnel opened');
      runTests();
    } else {
      console.error('Failed to open Sauce Connect tunnel');
      process.exit(2);
    }
  });
}());
<commit_msg>Increase sauce idle-timeout from the default of `90` to `300`.<commit_after>;(function() {
  'use strict';

  /** Environment shortcut */
  var env = process.env;

  if (isFinite(env.TRAVIS_PULL_REQUEST)) {
    console.error('Testing skipped for pull requests');
    process.exit(0);
  }

  /** Load Node.js modules */
  var http = require('http'),
      path = require('path'),
      url = require('url');

  /** Load other modules */
  var _ = require('../lodash.js'),
      ecstatic = require('ecstatic'),
      request = require('request'),
      SauceTunnel = require('sauce-tunnel');

  /** Used by `logInline` to clear previously logged messages */
  var prevLine = '';

  /** Used to display the wait throbber */
  var throbberId,
      throbberDelay = 500,
      waitCount = -1;

  /** Used as request `auth` and `options` values */
  var accessKey = env.SAUCE_ACCESS_KEY,
      build = env.TRAVIS_COMMIT.slice(0, 10),
      port = 9001,
      tunnelId = 'lodash_' + env.TRAVIS_JOB_NUMBER,
      username = env.SAUCE_USERNAME;

  var compatMode = process.argv.reduce(function(result, value) {
    return optionToValue('compatMode', value) || result;
  }, null);

  var runner = process.argv.reduce(function(result, value) {
    value = optionToValue('runner', value);
    return value == null
      ? result
      : '/' + value.replace(/^\W+/, '');
  }, '/test/index.html');

  var sessionName = process.argv.reduce(function(result, value) {
    return optionToValue('name', value) || result;
  }, 'lodash tests');

  var tags = process.argv.reduce(function(result, value) {
    value = optionToArray('tags', value);
    return value.length
      ? _.union(result, value)
      : result;
  }, []);

  /** List of platforms to load the runner on */
  var platforms = [
    ['Windows 8.1', 'chrome', '31'],
    ['Windows 8.1', 'chrome', '28'],
    ['Windows 8.1', 'chrome', '26'],
    ['OS X 10.6', 'firefox', '25'],
    ['OS X 10.6', 'firefox', '20'],
    ['OS X 10.6', 'firefox', '10'],
    ['OS X 10.6', 'firefox', '6'],
    ['OS X 10.6', 'firefox', '4'],
    ['Windows 7', 'firefox', '3.6'],
    ['Windows 8.1', 'internet explorer', '11'],
    ['Windows 8', 'internet explorer', '10'],
    ['Windows 7', 'internet explorer', '9'],
    ['Windows 7', 'internet explorer', '8'],
    ['Windows XP', 'internet explorer', '7'],
    ['Windows XP', 'internet explorer', '6'],
    //['Windows 7', 'opera', '12'],
    //['Windows 7', 'opera', '11'],
    ['OS X 10.8', 'safari', '6'],
    ['Windows 7', 'safari', '5'],
    ['Windows XP', 'safari', '4']
  ];

  /** Used to tailor the `platforms` array */
  var runnerQuery = url.parse(runner, true).query,
      isBackbone = /\bbackbone\b/i.test(runner),
      isMobile = /\bmobile\b/i.test(runnerQuery.build),
      isModern = /\bmodern\b/i.test(runnerQuery.build);

  // platforms to test IE compat mode
  if (compatMode) {
    platforms = [
      ['Windows 8.1', 'internet explorer', '11'],
      ['Windows 8', 'internet explorer', '10'],
      ['Windows 7', 'internet explorer', '9'],
      ['Windows 7', 'internet explorer', '8']
    ];
  }
  // platforms for Backbone tests
  if (isBackbone) {
    platforms = platforms.filter(function(platform) {
      var browser = platform[1],
          version = +platform[2];

      switch (browser) {
        case 'firefox': return version >= 4;
        case 'opera': return version >= 12;
      }
      return true;
    });
  }
  // platforms for mobile and modern builds
  if (isMobile || isModern) {
    platforms = platforms.filter(function(platform) {
      var browser = platform[1],
          version = +platform[2];

      switch (browser) {
        case 'firefox': return version >= 10;
        case 'internet explorer': return version >= 9;
        case 'opera': return version >= 12;
        case 'safari': return version >= (isMobile ? 3 : 6);
      }
      return true;
    });
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Writes an inline message to standard output.
   *
   * @private
   * @param {string} text The text to log.
   */
  function logInline(text) {
    var blankLine = repeat(' ', prevLine.length);
    if (text.length > 40) {
      text = text.slice(0, 37) + '...';
    }
    prevLine = text;
    process.stdout.write(text + blankLine.slice(text.length) + '\r');
  }

  /**
   * Writes the wait throbber to standard output.
   *
   * @private
   */
  function logThrobber() {
    logInline('Please wait' + repeat('.', (++waitCount % 3) + 1));
  }

  /**
   * Converts a comma separated option value into an array.
   *
   * @private
   * @param {string} name The name of the option to inspect.
   * @param {string} string The options string.
   * @returns {Array} Returns the new converted array.
   */
  function optionToArray(name, string) {
    return _.compact(_.isArray(string)
      ? string
      : _.invoke((optionToValue(name, string) || '').split(/, */), 'trim')
    );
  }

  /**
   * Extracts the option value from an option string.
   *
   * @private
   * @param {string} name The name of the option to inspect.
   * @param {string} string The options string.
   * @returns {string|undefined} Returns the option value, else `undefined`.
   */
  function optionToValue(name, string) {
    var result = (result = string.match(RegExp('^' + name + '=([\\s\\S]+)$'))) && result[1].trim();
    return result || undefined;
  }

  /**
   * Creates a string with `text` repeated `n` number of times.
   *
   * @private
   * @param {string} text The text to repeat.
   * @param {number} n The number of times to repeat `text`.
   * @returns {string} The created string.
   */
  function repeat(text, n) {
    return Array(n + 1).join(text);
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Processes the result object of the test session.
   *
   * @private
   * @param {Object} results The result object to process.
   */
  function handleTestResults(results) {
    var failingTests = results.filter(function(test) {
      var result = test.result;
      return !result || result.failed || /\berror\b/i.test(result.message);
    });

    var failingPlatforms = failingTests.map(function(test) {
      return test.platform;
    });

    if (!failingTests.length) {
      console.log('Tests passed');
    }
    else {
      console.error('Tests failed on platforms: ' + JSON.stringify(failingPlatforms));

      failingTests.forEach(function(test) {
        var result = test.result || {},
            details = 'See ' + test.url + ' for details.',
            failed = result.failed,
            platform = JSON.stringify(test.platform);

        if (failed) {
          console.error(failed + ' failures on ' + platform + '. ' + details);
        } else {
          var message = result.message || 'no results available. ' + details;
          console.error('Testing on ' + platform + ' failed; ' + message);
        }
      });
    }

    clearInterval(throbberId);
    console.log('Shutting down Sauce Connect tunnel...');

    tunnel.stop(function() {
      process.exit(failingTests.length ? 1 : 0);
    });
  }

  /**
   * Makes a request for Sauce Labs to start the test session.
   *
   * @private
   */
  function runTests() {
    var options = {
      'build': build,
      'framework': 'qunit',
      'idle-timeout': 300,
      'name': sessionName,
      'public': 'public',
      'platforms': platforms,
      'record-screenshots': false,
      'tags': tags,
      'tunnel': 'tunnel-identifier:' + tunnelId,
      'url': 'http://localhost:' + port + runner,
      'video-upload-on-pass': false
    };

    console.log('Starting saucelabs tests: ' + JSON.stringify(options));

    request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests', {
      'auth': { 'user': username, 'pass': accessKey },
      'json': options
    }, function(error, response, body) {
      var statusCode = response && response.statusCode;
      if (statusCode == 200) {
        waitForTestCompletion(body);
      } else {
        console.error('Failed to submit test to Sauce Labs; status: ' +  statusCode + ', body:\n' + JSON.stringify(body));
        if (error) {
          console.error(error);
        }
        process.exit(3);
      }
    });

    // initialize the wait throbber
    if (!throbberId) {
      throbberId = setInterval(logThrobber, throbberDelay);
      logThrobber();
    }
  }

  /**
   * Checks the status of the test session. If the session has completed it
   * passes the result object to `handleTestResults`, else it checks the status
   * again in five seconds.
   *
   * @private
   * @param {Object} testIdentifier The object used to identify the session.
   */
  function waitForTestCompletion(testIdentifier) {
    request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests/status', {
      'auth': { 'user': username, 'pass': accessKey },
      'json': testIdentifier
    }, function(error, response, body) {
        var statusCode = response && response.statusCode;
        if (statusCode == 200) {
          if (body.completed) {
            logInline('');
            handleTestResults(body['js tests']);
          }
          else {
            setTimeout(function() {
              waitForTestCompletion(testIdentifier);
            }, 5000);
          }
        } else {
          logInline('');
          console.error('Failed to check test status on Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
          if (error) {
            console.error(error);
          }
          process.exit(4);
        }
    });
  }

  /*--------------------------------------------------------------------------*/

  // create a web server for the local dir
  var mount = ecstatic({
    'cache': false,
    'root': process.cwd()
  });

  http.createServer(function(req, res) {
    // see http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx
    if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') {
      res.setHeader('X-UA-Compatible', 'IE=' + compatMode);
    }
    mount(req, res);
  }).listen(port);

  // set up Sauce Connect so we can use this server from Sauce Labs
  var tunnelTimeout = 10000,
      tunnel = new SauceTunnel(username, accessKey, tunnelId, true, tunnelTimeout);

  console.log('Opening Sauce Connect tunnel...');

  tunnel.start(function(success) {
    if (success) {
      console.log('Sauce Connect tunnel opened');
      runTests();
    } else {
      console.error('Failed to open Sauce Connect tunnel');
      process.exit(2);
    }
  });
}());
<|endoftext|>


<commit_before>import { parser as saxParser } from 'sax';
import Queue from './queue.js';

function isAllowedType(type) {
  switch(type) {
    case 'text': case 'opentag': case 'closetag': case 'doctype':
    case 'processinginstruction': case 'attribute': case 'comment':
    case 'opencdata': case 'closecdata': case 'opennamespace':
    case 'closenamespace': return true;
    default: return false;
  }
}

class XMLPulley {
  constructor(xml, options) {
    if(!options) options = {};
    let types = options.types || ['opentag', 'closetag', 'text'];
    let queue = this.queue = new Queue();
    let parser = saxParser(true, {
      xmlns: options.xmlns,
      position: false
    });
    let skipWS = options.skipWhitespaceOnly;
    let trim = options.trim, normalize = options.normalize;
    function textOpts(t) {
      if(trim)
        t = t.trim();
      if(normalize)
        t = t.replace(/\s+/g, " ")
      return t;
    }
    let text = null, rawText = null;
    let flushText = () => {
      if(text !== null) {
        this.queue.enqueue({
          type: 'text',
          text: text,
          rawText: rawText
        });
        text = rawText = null;
      }
    };
    parser.onerror = (err) => {
      throw err;
    };
    types.forEach((type) => {
      if(type === 'text') {
        parser.ontext = (t) => {
          if(!skipWS || /\S/.test(t)) {
            let pt = textOpts(t);
            if(text) {
              text += pt; rawText += t;
            } else {
              text = pt; rawText = t;
            }
          }
        };
        parser.oncdata = (t) => {
          if(text) {
            text += t; rawText += t;
          } else {
            text = rawText = t;
          }
        };
      } else if(type === 'comment' && (trim || normalize)) {
        parser.oncomment = (t) => {
          flushText();
          queue.enqueue({
            type: 'comment',
            text: textOpts(t),
            rawText: t
          });
        }
      } else if(type === 'closetag') {
        parser.onclosetag = (t) => {
          flushText();
          queue.enqueue({
            type: 'closetag',
            name: t
          });
        }
      } else if(isAllowedType(type)) {
        parser['on'+type] = (data) => {
          flushText();
          data.type = type;
          queue.enqueue(data);
        }
      } else {
        throw new Error(`${type} isn't an allowed type!`);
      }
    });
    parser.write(xml).close();
    flushText();
  }
  next() {
    return this.queue.dequeue();
  }
  peek() {
    return this.queue.peek();
  }
  expect(type) {
    let out = this.peek();
    if(out === undefined) {
      throw new Error(`Expected ${type}; got end of file!`);
    } else if(out.type !== type) {
      throw new Error(`Expected ${type}; got ${out.type}!`);
    }
    this.next();
    return out;
  }
  forEach(callback, tagName) {
    var node;
    while((node = this.next()).type !== 'closetag') {
      callback(node, this);
    }
    if(tagName)
      assertName(node, tagName);
  }
}

export function makePulley(xml, options) {
  return new XMLPulley(xml, options);
}

export function assertName(tag, name, error) {
  if(tag.name !== name) {
    throw error ||
          new Error(`${tag.type} had type ${tag.name} instead of ${name}!`);
  }
}
<commit_msg>Renamed forEach to nextAll and added expectAll<commit_after>import { parser as saxParser } from 'sax';
import Queue from './queue.js';

function isAllowedType(type) {
  switch(type) {
    case 'text': case 'opentag': case 'closetag': case 'doctype':
    case 'processinginstruction': case 'attribute': case 'comment':
    case 'opencdata': case 'closecdata': case 'opennamespace':
    case 'closenamespace': return true;
    default: return false;
  }
}

class XMLPulley {
  constructor(xml, options) {
    if(!options) options = {};
    let types = options.types || ['opentag', 'closetag', 'text'];
    let queue = this.queue = new Queue();
    let parser = saxParser(true, {
      xmlns: options.xmlns,
      position: false
    });
    let skipWS = options.skipWhitespaceOnly;
    let trim = options.trim, normalize = options.normalize;
    function textOpts(t) {
      if(trim)
        t = t.trim();
      if(normalize)
        t = t.replace(/\s+/g, " ")
      return t;
    }
    let text = null, rawText = null;
    let flushText = () => {
      if(text !== null) {
        this.queue.enqueue({
          type: 'text',
          text: text,
          rawText: rawText
        });
        text = rawText = null;
      }
    };
    parser.onerror = (err) => {
      throw err;
    };
    types.forEach((type) => {
      if(type === 'text') {
        parser.ontext = (t) => {
          if(!skipWS || /\S/.test(t)) {
            let pt = textOpts(t);
            if(text) {
              text += pt; rawText += t;
            } else {
              text = pt; rawText = t;
            }
          }
        };
        parser.oncdata = (t) => {
          if(text) {
            text += t; rawText += t;
          } else {
            text = rawText = t;
          }
        };
      } else if(type === 'comment' && (trim || normalize)) {
        parser.oncomment = (t) => {
          flushText();
          queue.enqueue({
            type: 'comment',
            text: textOpts(t),
            rawText: t
          });
        }
      } else if(type === 'closetag') {
        parser.onclosetag = (t) => {
          flushText();
          queue.enqueue({
            type: 'closetag',
            name: t
          });
        }
      } else if(isAllowedType(type)) {
        parser['on'+type] = (data) => {
          flushText();
          data.type = type;
          queue.enqueue(data);
        }
      } else {
        throw new Error(`${type} isn't an allowed type!`);
      }
    });
    parser.write(xml).close();
    flushText();
  }
  next() {
    return this.queue.dequeue();
  }
  peek() {
    return this.queue.peek();
  }
  expect(type) {
    let out = this.peek();
    if(out === undefined) {
      throw new Error(`Expected ${type}; got end of file!`);
    } else if(out.type !== type) {
      throw new Error(`Expected ${type}; got ${out.type}!`);
    }
    this.next();
    return out;
  }
  nextAll(callback, tagName) {
    var node;
    while((node = this.peek()).type !== 'closetag') {
      if(callback(node, this))
        break;
      this.next();
    }
    if(tagName)
      assertName(this.next(), tagName);
  }
  expectAll(callback, type, tagName) {
    var node;
    while((node = this.peek()).type !== 'closetag') {
      if(node.type !== type)
        throw new Error(`Expected ${type}; got ${node.type}!`);
      if(callback(node, this))
        break;
      this.next();
    }
    if(tagName)
      assertName(this.next(), tagName);
  }
}

export function makePulley(xml, options) {
  return new XMLPulley(xml, options);
}

export function assertName(tag, name, error) {
  if(tag.name !== name) {
    throw error ||
          new Error(`${tag.type} had type ${tag.name} instead of ${name}!`);
  }
}
<|endoftext|>


<commit_before>/* Ractive application */

define(function(require) {
  var Ractive = require('Ractive');
  require('ractive-decorators-slip');
  require('ractive-events-tap');
  var reqwest = require('reqwest');

  var page = new Ractive({
    el: document.body,
    template: require('rv!template'),
    data: {
      favorites: decodeFavorites(location.hash),
      isFavorite: function(stop) {
        return this.get('favorites').some(function(fav) {
          return fav.id === stop.id;
        });
      },
    },
  });

  page.on('done', function() {
    // Send the user back to the Pebble app.
    var favorites = this.get('favorites');
    location.href = 'pebblejs://close#' + encodeURIComponent(JSON.stringify({favorites: favorites}));
  });

  page.on('search', function(event, name) {
    getStops(name).then(function(stops) {
      page.set('stops', stops);
    });
    event.original.preventDefault();
  });

  page.on('reset', function(event) {
    this.set('searchterm', '');
    this.set('stops', null);
    event.original.preventDefault();
  });

  page.on('add', function(event, stop, duplicate) {
    if (!duplicate)
      page.get('favorites').push(stop);
  });

  function getStops(name) {
    return reqwest({
      url: '/api/stops/' + encodeURIComponent(name),
      type: 'json'
    })
    .then(function(response) {
      return response.stops;
    });
  }

  function decodeFavorites(hash) {
    var favorites;
    try {
      favorites = JSON.parse(decodeURIComponent(hash.slice(1))).favorites;
    } catch (e) {
      favorites = [];
    }
    return favorites;
  }
});
<commit_msg>Use Base64 to fix encoding issues<commit_after>/* Ractive application */

define(function(require) {
  var Ractive = require('Ractive');
  require('ractive-decorators-slip');
  require('ractive-events-tap');
  var reqwest = require('reqwest');

  var page = new Ractive({
    el: document.body,
    template: require('rv!template'),
    data: {
      favorites: decodeFavorites(location.hash),
      isFavorite: function(stop) {
        return this.get('favorites').some(function(fav) {
          return fav.id === stop.id;
        });
      },
    },
  });

  page.on('done', function() {
    // Send the user back to the Pebble app.
    var favorites = this.get('favorites');
    location.href = 'pebblejs://close#' + utf8_to_b64(JSON.stringify({favorites: favorites}));
  });

  page.on('search', function(event, name) {
    getStops(name).then(function(stops) {
      page.set('stops', stops);
    });
    event.original.preventDefault();
  });

  page.on('reset', function(event) {
    this.set('searchterm', '');
    this.set('stops', null);
    event.original.preventDefault();
  });

  page.on('add', function(event, stop, duplicate) {
    if (!duplicate)
      page.get('favorites').push(stop);
  });

  function getStops(name) {
    return reqwest({
      url: '/api/stops/' + encodeURIComponent(name),
      type: 'json'
    })
    .then(function(response) {
      return response.stops;
    });
  }

  function decodeFavorites(hash) {
    var favorites;
    try {
      favorites = JSON.parse(b64_to_utf8(hash.slice(1))).favorites;
    } catch (e) {
      favorites = [];
    }
    return favorites;
  }

  function utf8_to_b64( str ) {
    return window.btoa(unescape(encodeURIComponent( str )));
  }

  function b64_to_utf8( str ) {
    return decodeURIComponent(escape(window.atob( str )));
  }
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('chai').assert
  , SLIP = require('../src/slip.js')
  , fs = require('fs')
  , conf = JSON.parse(fs.readFileSync('test/test-config.json', {encoding: 'utf8'}))

describe('SLIP class', function () {

  it('exists', function(){
    assert.isFunction(SLIP)
  })

  it('inherits SerialPort class', function(){
    assert.isFunction(SLIP.prototype.write)
  })

  describe('SLIP instance', function () {

    var slip = null
    before(function () {
      slip = new SLIP(conf.serailPort.path, conf.serailPort.options, conf.protocol)
    })

    it('has same methods as SerialPort instances via inheritance', function(){
      assert.isFunction(slip.write)
    })

    it('has protocol_ defined', function(){
      assert.isObject(slip.protocol_)
    })

    it('has sendMessage method', function(){
      assert.isFunction(slip.sendMessage)
    })

    it('has collectDataAndFireMessageEvent_ method', function(done){
      slip.on('message', function (buf) {
        assert.isTrue(buf.equals(new Buffer([0x20, 0x24])))
        done()
      })
      slip.collectDataAndFireMessageEvent_(new Buffer([0x20, 0x24, 0xc0, 0x22, 0x21]))
    })

  })

})
<commit_msg>Better coverage for SLIP class<commit_after>'use strict';

var assert = require('chai').assert
  , SLIP = require('../src/slip.js')
  , fs = require('fs')
  , conf = JSON.parse(fs.readFileSync('test/test-config.json', {encoding: 'utf8'}))

describe('SLIP class', function () {

  it('exists', function(){
    assert.isFunction(SLIP)
  })

  it('inherits SerialPort class', function(){
    assert.isFunction(SLIP.prototype.write)
  })

  describe('SLIP instance', function () {

    var slip = null
    before(function () {
      slip = new SLIP(conf.serailPort.path, conf.serailPort.options, conf.protocol)
    })

    it('has same methods as SerialPort instances via inheritance', function(){
      assert.isFunction(slip.write)
    })

    it('has protocol_ defined', function(){
      assert.isObject(slip.protocol_)
    })

    it('has sendMessage method that send message to seriaport', function(done){
      assert.isFunction(slip.sendMessage)
      slip.sendMessage(new Buffer([0]), function (err) {
        assert.isTrue(err.message == 'Serialport not open.')
        done()
      })
    })

    it('has collectDataAndFireMessageEvent_ method', function(done){
      slip.collectDataAndFireMessageEvent_(new Buffer([0x22]))
      slip.on('message', function (buf) {
        assert.isTrue(buf.equals(new Buffer([0x22, 0x20, 0x24])))
        done()
      })
      slip.collectDataAndFireMessageEvent_(new Buffer([0x20, 0x24, 0xc0, 0x22, 0x21]))
    })

  })

})
<|endoftext|>


<commit_before>import Analyzer from 'parser/core/Analyzer';
import SPELLS from 'common/SPELLS';
import TalentStatisticBox, { STATISTIC_ORDER } from 'interface/others/TalentStatisticBox';
import React from 'react';
import ItemHealingDone from 'interface/others/ItemHealingDone';

const GUARDIAN_SPIRIT_HEALING_MULTIPLIER = .4;

// Example Log: /report/mFarpncVW9ALwTq4/7-Mythic+Zek'voz+-+Kill+(8:52)/14-Praydien
class GuardianAngel extends Analyzer {
  guardianSpiritCasts = 0;
  guardianSpiritRemovals = 0;
  guardianSpiritHeals = 0;
  guardianSpiritHealing = 0;
  guardianSpiritBonusHealingFromSelf = 0;
  guardianSpiritBonusHealingFromOther = 0;

  spiritedTarget = null;

  get guardianSpiritRefreshes() {
    return this.guardianSpiritRemovals - this.guardianSpiritHeals;
  }

  get guardianSpiritSelfHealing() {
    return this.guardianSpiritHealing + this.guardianSpiritBonusHealingFromSelf;
  }

  get guardianSpiritEffectiveHealing() {
    return this.guardianSpiritHealing + this.guardianSpiritBonusHealingFromSelf + this.guardianSpiritBonusHealingFromOther;
  }

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.GUARDIAN_ANGEL_TALENT.id);
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT.id) {
      this.guardianSpiritCasts++;
      this.spiritedTarget = event.targetID;
    }
  }

  on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT.id) {
      this.guardianSpiritRemovals++;
      this.spiritedTarget = null;
    }
  }

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT_HEAL.id) {
      this.guardianSpiritHeals++;
      this.guardianSpiritHealing += event.amount || 0;
    }

    if (this.spiritedTarget != null) {
      // TODO: This is not accurate, but it's close enough for now.
      this.guardianSpiritBonusHealingFromSelf += event.amount * GUARDIAN_SPIRIT_HEALING_MULTIPLIER;
    }
  }

  statistic() {
    return (

      <TalentStatisticBox
        talent={SPELLS.GUARDIAN_ANGEL_TALENT.id}
        value={(
          <ItemHealingDone amount={this.guardianSpiritSelfHealing} />
        )}
        tooltip={`
          Total Guardian Spirits Cast: ${this.guardianSpiritCasts}

          Total Guardian Spirit Resets: ${this.guardianSpiritRefreshes}
        `}
        position={STATISTIC_ORDER.CORE(3)}
      />

    );
  }
}

export default GuardianAngel;
<commit_msg>Fixing bug with GA<commit_after>import Analyzer from 'parser/core/Analyzer';
import SPELLS from 'common/SPELLS';
import TalentStatisticBox, { STATISTIC_ORDER } from 'interface/others/TalentStatisticBox';
import React from 'react';
import ItemHealingDone from 'interface/others/ItemHealingDone';

const GUARDIAN_SPIRIT_HEALING_MULTIPLIER = .6;

// Example Log: /report/mFarpncVW9ALwTq4/7-Mythic+Zek'voz+-+Kill+(8:52)/14-Praydien
class GuardianAngel extends Analyzer {
  guardianSpiritCasts = 0;
  guardianSpiritRemovals = 0;
  guardianSpiritHeals = 0;
  guardianSpiritHealing = 0;
  guardianSpiritBonusHealingFromSelf = 0;
  guardianSpiritBonusHealingFromOther = 0;

  spiritedTarget = null;

  get guardianSpiritRefreshes() {
    return this.guardianSpiritRemovals - this.guardianSpiritHeals;
  }

  get guardianSpiritSelfHealing() {
    return this.guardianSpiritHealing + this.guardianSpiritBonusHealingFromSelf;
  }

  get guardianSpiritEffectiveHealing() {
    return this.guardianSpiritHealing + this.guardianSpiritBonusHealingFromSelf + this.guardianSpiritBonusHealingFromOther;
  }

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.GUARDIAN_ANGEL_TALENT.id);
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT.id) {
      this.guardianSpiritCasts++;
      this.spiritedTarget = event.targetID;
    }
  }

  on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT.id) {
      this.guardianSpiritRemovals++;
      this.spiritedTarget = null;
    }
  }

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;
    if (spellId === SPELLS.GUARDIAN_SPIRIT_HEAL.id) {
      this.guardianSpiritHeals++;
      this.guardianSpiritHealing += event.amount || 0;
    }

    if (this.spiritedTarget != null && this.spiritedTarget === event.targetID) {
      this.guardianSpiritBonusHealingFromSelf += (event.amount * (1 - GUARDIAN_SPIRIT_HEALING_MULTIPLIER));
    }
  }

  statistic() {
    return (
      <TalentStatisticBox
        talent={SPELLS.GUARDIAN_ANGEL_TALENT.id}
        value={(
          <ItemHealingDone amount={this.guardianSpiritSelfHealing} />
        )}
        tooltip={`
          Total Guardian Spirits Cast: ${this.guardianSpiritCasts}

          Total Guardian Spirit Resets: ${this.guardianSpiritRefreshes}
        `}
        position={STATISTIC_ORDER.CORE(3)}
      />

    );
  }
}

export default GuardianAngel;
<|endoftext|>


<commit_before>describe('Map Hash Test', function () {
  var el;

  beforeEach(function () {
    el = document.createElement('div');
    document.body.appendChild(el);
  });

  afterEach(function () {
    el.parentNode.removeChild(el);
  })

  describe('Leaflet Versions', function () {
    it('check which Leaflet version it is', function () {
      expect(L.version).to.equal('0.7.7');
    });
  });

  describe('Hash Working', function () {
    it('checks that hash for coord is working', function () {
      var map = L.Mapzen.map(el);
      map.setView([51.505, -0.09], 13);
      L.Mapzen.hash({
        map: map
      });
      var zoom = map.getZoom();
      var center = map.getCenter();

      var getPrecision = function (z) {
        return Math.max(0, Math.ceil(Math.log(z) / Math.LN2));
      };
      var precision = getPrecision(zoom);

      var hashLat = center.lat.toFixed(precision);
      var hashLng = center.lng.toFixed(precision);
      expect(window.location.hash).to.equal('#lat=' + hashLat + '&lng=' + hashLng + '&z=' + zoom);
    });
  })
});
<commit_msg>making test for not Tangramp use not tangramp map<commit_after>describe('Map Hash Test', function () {
  var el;

  beforeEach(function () {
    el = document.createElement('div');
    document.body.appendChild(el);
  });

  afterEach(function () {
    el.parentNode.removeChild(el);
  })

  describe('Leaflet Versions', function () {
    it('check which Leaflet version it is', function () {
      expect(L.version).to.equal('0.7.7');
    });
  });

  describe('Hash Working', function () {
    it('checks that hash for coord is working', function () {
      var map = L.Mapzen.map(el,{
        useTangram: false
      });
      map.setView([51.505, -0.09], 13);
      L.Mapzen.hash({
        map: map
      });
      var zoom = map.getZoom();
      var center = map.getCenter();

      var getPrecision = function (z) {
        return Math.max(0, Math.ceil(Math.log(z) / Math.LN2));
      };
      var precision = getPrecision(zoom);

      var hashLat = center.lat.toFixed(precision);
      var hashLng = center.lng.toFixed(precision);
      expect(window.location.hash).to.equal('#lat=' + hashLat + '&lng=' + hashLng + '&z=' + zoom);
    });
  })
});
<|endoftext|>


<commit_before>'use strict';

var path = require('path'),
    mongooseService = require(path.resolve('./config/lib/mongoose')),
    chalk = require('chalk'),
    faker = require('faker'),
    mongoose = require('mongoose');

var addTribes = function (max) {
  var index = 0;

  // Add tribes
  console.log('Generating ' + max + ' tribes...');
  if (max > 2000) {
    console.log('...this might really take a while... go grab some coffee!');
  }

  console.log(chalk.white('--'));
  console.log(chalk.green('Trustroots test tribes data'));
  console.log(chalk.white('--'));

  // Bootstrap db connection
  mongooseService.connect(function () {
    mongooseService.loadModels(function () {
      var Tribe = mongoose.model('Tribe');

      (function addNextTribe() {
        var tribe = new Tribe();

        tribe.label = faker.random.word() + '_' + index;
        tribe.labelHistory = faker.random.words();
        tribe.slugHistory = faker.random.words();
        tribe.synonyms = faker.random.words();
        tribe.color = faker.internet.color().slice(1);
        tribe.count = 0;
        tribe.created = Date.now();
        tribe.modified = Date.now();
        tribe.public = true;
        // tribe.image_UUID = faker.random.uuid();
        tribe.attribution = faker.name.findName();
        tribe.attribution_url = faker.internet.url();
        tribe.description = faker.lorem.sentences();

        tribe.save(function (err) {
          if (err != null) {
            console.log(err);
          }
          else {
            if (index >= max) {
              console.log(chalk.green('Done with ' + max + ' test tribes!'));
              console.log(chalk.white('')); // Reset to white
              process.exit(0);
            }
          }
        });
        index+=1;
        if (index < max) {
          addNextTribe();
        }
      }());
    });
  });
};

// Number of tribes is required
if (process.argv[2] == null || process.argv[2] < 1) {
  console.log(chalk.red('Usage: node fillTestTribesData.js <number of tribes to add>'));
} else {
  var numberOfTribes= process.argv[2];
  addTribes(numberOfTribes);
}
<commit_msg>Seed data: add random tribe background images from CDN data (#786)<commit_after>'use strict';

var _ = require('lodash'),
    path = require('path'),
    mongooseService = require(path.resolve('./config/lib/mongoose')),
    chalk = require('chalk'),
    faker = require('faker'),
    mongoose = require('mongoose');

var tribeImageUUIDs = [
  '171433b0-853b-4d19-a8b4-44def956696d',
  '22028fde-5302-4172-954d-f54949afd7e4',
  'e69eb05f-773f-423c-9246-43629b5a8baf',
  '3c8bb9f1-e313-4baa-bf4c-1d8994fd6c6c',
  'd5563f29-669f-4f18-9802-d1924ff31364',
  '4ff6463d-c482-4be6-9a49-294fc8712d83',
  'e4466aa6-46f1-460f-94ef-8cec882d7103',
  '12a2c124-a38a-4df8-8987-e01ee3741727',
  'e23060e2-393d-4b4a-b469-450053538f8a',
  '6274fd88-9178-4cea-8bb4-60f22e4cc904',
  'fb2b6d50-9d51-4755-9b44-1395fae4cf5d',
  '656e4872-15a4-4be4-8059-6e7c39b07c5d',
  'e060263a-9684-4065-85f3-460e9fffbd40',
  'ad2062d0-aadd-475d-bf85-2cd2e30a9d38',
  'bfaf468a-2c48-4798-b1bb-bffd0c6b716b',
  '0fd49df4-88e7-4380-b38a-3625e4b02dde',
  'cef34c15-b527-4f89-a7a5-456f62ff9ce2',
  'c84f93f1-421d-4339-a61f-a5efc2d24297',
  'd4a04ce4-3aeb-43a4-882b-43b1974d86e0',
  '310f68af-3e77-451e-96a7-09132d26fdb4',
  'dcb0ed04-cdd6-45ea-b773-e09320a4f759',
  '434018c8-4f4f-4054-9bd2-6618e9d5a77f',
  '0ce0abdf-6898-4191-9a86-4f03807291b5',
  '0ebcabec-2bc5-4eee-ab17-991b9dd52eae',
  '4f7805e7-b5e6-4b40-bb32-3aafbe1bbc74',
  '69a500a4-a16e-4c4d-9981-84fbe310d531'
];

var addTribes = function (max) {
  var index = 0;

  // Add tribes
  console.log('Generating ' + max + ' tribes...');
  if (max > 2000) {
    console.log('...this might really take a while... go grab some coffee!');
  }

  console.log(chalk.white('--'));
  console.log(chalk.green('Trustroots test tribes data'));
  console.log(chalk.white('--'));

  // Bootstrap db connection
  mongooseService.connect(function () {
    mongooseService.loadModels(function () {
      var Tribe = mongoose.model('Tribe');

      (function addNextTribe() {
        var tribe = new Tribe();

        tribe.label = faker.random.word() + '_' + index;
        tribe.labelHistory = faker.random.words();
        tribe.slugHistory = faker.random.words();
        tribe.synonyms = faker.random.words();
        tribe.color = faker.internet.color().slice(1);
        tribe.count = 0;
        tribe.created = Date.now();
        tribe.modified = Date.now();
        tribe.public = true;
        tribe.image_UUID = _.sample(tribeImageUUIDs);
        tribe.attribution = faker.name.findName();
        tribe.attribution_url = faker.internet.url();
        tribe.description = faker.lorem.sentences();

        tribe.save(function (err) {
          if (err != null) {
            console.log(err);
          }
          else {
            if (index >= max) {
              console.log(chalk.green('Done with ' + max + ' test tribes!'));
              console.log(chalk.white('')); // Reset to white
              process.exit(0);
            }
          }
        });
        index+=1;
        if (index < max) {
          addNextTribe();
        }
      }());
    });
  });
};

// Number of tribes is required
if (process.argv[2] == null || process.argv[2] < 1) {
  console.log(chalk.red('Usage: node fillTestTribesData.js <number of tribes to add>'));
} else {
  var numberOfTribes= process.argv[2];
  addTribes(numberOfTribes);
}
<|endoftext|>