<commit_before>var nixt = require('nixt')
var path = require('path')
var fs = require('fs-extra')
var should = require('should')
var harp = require('../')

describe("harp init", function() {

  beforeEach(function(done){
    fs.remove(path.join('test', 'out', 'harp'), function(err){
      fs.mkdirp(path.join('test', 'out', 'harp'), done)
    })
  })

  afterEach(function(done) {
    fs.remove(path.join('test', 'out', 'harp'), done)
  })

  it("downloads the default boilerplate if it's not set", function(done) {
    this.timeout(10000);
    nixt()
      .run('node ./bin/harp init ./test/out/harp') // Tests don't work when this has a platform-specific path passed in, but it does work
      // .run('node .' + path.sep + 'bin' + path.sep + 'harp init ' + path.join('test', 'out', 'harp'))
      // .stdout(/Downloading.*harp-boilerplates\/default/)
      // .stdout(/Initialized project at \test/out\/harp/)
      .end(function () {
        fs.existsSync(path.join('test', 'out', 'harp', '404.jade')).should.not.be.false
        fs.existsSync(path.join('test', 'out', 'harp', '_layout.jade')).should.not.be.false
        fs.existsSync(path.join('test', 'out', 'harp', 'index.jade')).should.not.be.false
        fs.existsSync(path.join('test', 'out', 'harp', 'main.less')).should.not.be.false
        done()
      })
  })

  it("defaults to the harp-boilerplates github org when given a shorthand pattern", function(done) {
    this.timeout(10000);
    nixt()
      .run('node ./bin/harp init ' + path.join('test', 'out', 'harp') + ' -b hb-start')
      // .stdout(/Downloading.*harp-boilerplates\/hb-start/)
      .end(function () {
        fs.existsSync(path.join('test', 'out', 'harp', 'public', 'index.jade')).should.not.be.false
        fs.existsSync(path.join('test', 'out', 'harp', 'README.md')).should.not.be.false
        done()
      })
  })

  it("honors -b option when given a user/repo pattern", function(done) {
    this.timeout(10000);
    nixt()
      .run('./bin/harp init ' + path.join('test', 'out', 'harp') + ' -b zeke/harp-sample')
      // .stdout(/Downloading.*zeke\/harp-sample/)
      .end(function () {
        fs.existsSync(path.join('test', 'out', 'harp', 'README.md')).should.not.be.false
        fs.existsSync(path.join('test', 'out', 'harp', 'index.jade')).should.not.be.false
        done()
      })
  })

  it("doesn't overwrite an existing directory", function(done) {
    nixt()
      .run('./bin/harp init ' + path.join('test', 'out', 'harp'))
      .end(function() {
        nixt()
          .run('harp init ' + path.join('test', 'out', 'harp') + ' -b hb-default-sass')
          .end(function() {
            should.not.exist(fs.exists(path.join('test', 'out', 'harp', 'main.sass')))
            done()
          })
      })
  })

})
<commit_msg>Fixes init tests for Windows<commit_after>var nixt = require('nixt')
var path = require('path')
var fs = require('fs-extra')
var should = require('should')
var harp = require('../')
var exec = require("child_process").exec

describe("harp init", function() {

  var outputPath  = path.join(__dirname, "out/harp")

  beforeEach(function(done){
    fs.remove(outputPath, function(err){
      fs.mkdirp(outputPath, done)
    })
  })

  afterEach(function(done) {
    fs.remove(outputPath, done)
  })

  it("downloads the default boilerplate if it's not set", function(done) {
    this.timeout(10000);
    nixt()
      .run('node ./bin/harp init ./test/out/harp') // Tests don't work when this has a platform-specific path passed in, but it does work
      // .run('node .' + path.sep + 'bin' + path.sep + 'harp init ' + outputPath)
      // .stdout(/Downloading.*harp-boilerplates\/default/)
      // .stdout(/Initialized project at \test/out\/harp/)
      .end(function () {
        fs.existsSync(path.join(outputPath, '404.jade')).should.not.be.false
        fs.existsSync(path.join(outputPath, '_layout.jade')).should.not.be.false
        fs.existsSync(path.join(outputPath, 'index.jade')).should.not.be.false
        fs.existsSync(path.join(outputPath, 'main.less')).should.not.be.false
        done()
      })
  })

  it("defaults to the harp-boilerplates github org when given a shorthand pattern", function(done) {
    this.timeout(10000);
    nixt()
      .run('node ./bin/harp init ./test/out/harp -b hb-start')
      // .stdout(/Downloading.*harp-boilerplates\/hb-start/)
      .end(function () {
        fs.existsSync(path.join(outputPath, 'public', 'index.jade')).should.not.be.false
        fs.existsSync(path.join(outputPath, 'README.md')).should.not.be.false
        done()
      })
  })

  it("honors -b option when given a user/repo pattern", function(done) {
    this.timeout(10000);
    nixt()
      .run('node ./bin/harp init ./test/out/harp -b zeke/harp-sample')
      // .stdout(/Downloading.*zeke\/harp-sample/)
      .end(function () {
        fs.existsSync(path.join(outputPath, 'README.md')).should.not.be.false
        fs.existsSync(path.join(outputPath, 'index.jade')).should.not.be.false
        done()
      })
  })

  it("doesn't overwrite an existing directory", function(done) {
    nixt()
      .run('node ./bin/harp init ./test/out/harp')
      .end(function() {
        nixt()
          .run('node ./bin/harp harp init ./test/out/harp -b hb-default-sass')
          .end(function() {
            should.not.exist(fs.exists(path.join(outputPath, 'main.sass')))
            done()
          })
      })
  })

  after(function(done){
    exec("rm -rf " + outputPath, function() {
      done();
    })
  })

})
<|endoftext|>


<commit_before>import config from 'src/config'
import {GOAL_SELECTION} from 'src/common/models/cycle'
import findOpenRetroSurveysForPlayer from 'src/server/actions/findOpenRetroSurveysForPlayer'
import {
  Player,
  Vote,
  getCyclesInStateForChapter,
  getPoolByCycleIdAndPlayerId,
} from 'src/server/services/dataService'
import {
  LGNotAuthorizedError,
  LGBadRequestError,
  LGForbiddenError,
} from 'src/server/util/error'

async function _voteForGoals(user, goalDescriptors, responseURL) {
  if (!user) {
    throw new LGNotAuthorizedError()
  }

  const player = await Player.get(user.id).getJoin({chapter: true})
  if (!player) {
    throw new LGNotAuthorizedError('You are not a player in the game.')
  }

  if (goalDescriptors.length > 1 && goalDescriptors[0] === goalDescriptors[1]) {
    throw new LGBadRequestError('You cannot vote for the same goal twice.')
  }

  const cycles = await getCyclesInStateForChapter(player.chapter.id, GOAL_SELECTION)
  if (!cycles.length > 0) {
    throw new LGForbiddenError(`No cycles for ${player.chapter.name} chapter (${player.chapter.id}) in ${GOAL_SELECTION} state.`)
  }

  const openRetroSurveys = await findOpenRetroSurveysForPlayer(player.id)
  if (openRetroSurveys.length !== 0) {
    throw new LGBadRequestError(`You must complete all pending retrospective surveys before voting for a new project! For a list of open retros see ${config.server.baseURL}/retro.`)
  }

  const cycle = cycles[0]
  const pool = await getPoolByCycleIdAndPlayerId(cycle.id, player.id)
  const previousVotes = await Vote.getAll([player.id, pool.id], {index: 'playerIdAndPoolId'})

  const voteValues = {
    notYetValidatedGoalDescriptors: goalDescriptors,
    pendingValidation: true,
    responseURL,
  }
  const savedVote = previousVotes[0] ?
    await Vote.get(previousVotes[0].id).updateWithTimestamp(voteValues) :
    await Vote.save({
      ...voteValues,
      playerId: player.id,
      poolId: pool.id,
    })

  return {...savedVote, player, cycle}
}

export async function invoke(args, {user, responseURL}) {
  const attachments = []
  if (args._.length > 0) {
    await _voteForGoals(user, args._, responseURL)
    attachments.push({text: `You voted for: ${args._.join(', ')}.`})
  }

  return {
    text: `Click to see <${config.app.baseURL}/cycle-voting-results|current cycle voting results>.`,
    attachments,
  }
}
<commit_msg>Added a check to see if user has completed all reviews before voting<commit_after>import config from 'src/config'
import {GOAL_SELECTION} from 'src/common/models/cycle'
import findOpenRetroSurveysForPlayer from 'src/server/actions/findOpenRetroSurveysForPlayer'
import findUnreviewedProjectsForCoach from 'src/server/actions/findUnreviewedProjectsForCoach'
import {
  Player,
  Vote,
  getCyclesInStateForChapter,
  getPoolByCycleIdAndPlayerId,
} from 'src/server/services/dataService'
import {
  LGNotAuthorizedError,
  LGBadRequestError,
  LGForbiddenError,
} from 'src/server/util/error'

async function _voteForGoals(user, goalDescriptors, responseURL) {
  if (!user) {
    throw new LGNotAuthorizedError()
  }

  const player = await Player.get(user.id).getJoin({chapter: true})
  if (!player) {
    throw new LGNotAuthorizedError('You are not a player in the game.')
  }

  if (goalDescriptors.length > 1 && goalDescriptors[0] === goalDescriptors[1]) {
    throw new LGBadRequestError('You cannot vote for the same goal twice.')
  }

  const cycles = await getCyclesInStateForChapter(player.chapter.id, GOAL_SELECTION)
  if (!cycles.length > 0) {
    throw new LGForbiddenError(`No cycles for ${player.chapter.name} chapter (${player.chapter.id}) in ${GOAL_SELECTION} state.`)
  }

  const openRetroSurveys = await findOpenRetroSurveysForPlayer(player.id)
  if (openRetroSurveys.length !== 0) {
    throw new LGBadRequestError(`You must complete all pending retrospective surveys before voting for a new project! For a list of open retros see ${config.server.baseURL}/retro.`)
  }

  const unreviewedProjects = await findUnreviewedProjectsForCoach(player.id)
  if (unreviewedProjects.length !== 0) {
    const unreviewedNames = unreviewedProjects.map(project => project.name).join(', ')
    throw new LGBadRequestError(`You must review the projects for which you were a coach before voting for a new project! These projects have yet to be reviewed: ${unreviewedNames}`)
  }

  const cycle = cycles[0]
  const pool = await getPoolByCycleIdAndPlayerId(cycle.id, player.id)
  const previousVotes = await Vote.getAll([player.id, pool.id], {index: 'playerIdAndPoolId'})

  const voteValues = {
    notYetValidatedGoalDescriptors: goalDescriptors,
    pendingValidation: true,
    responseURL,
  }
  const savedVote = previousVotes[0] ?
    await Vote.get(previousVotes[0].id).updateWithTimestamp(voteValues) :
    await Vote.save({
      ...voteValues,
      playerId: player.id,
      poolId: pool.id,
    })

  return {...savedVote, player, cycle}
}

export async function invoke(args, {user, responseURL}) {
  const attachments = []
  if (args._.length > 0) {
    await _voteForGoals(user, args._, responseURL)
    attachments.push({text: `You voted for: ${args._.join(', ')}.`})
  }

  return {
    text: `Click to see <${config.app.baseURL}/cycle-voting-results|current cycle voting results>.`,
    attachments,
  }
}
<|endoftext|>


<commit_before>UI.once('init', function(){
	var UI = this
	,   user = {}
	,   delay = 1500
	,   missed_messages = 0
	,   standard_title = document.title
	,   last_sound_time = 0;

	var titleAlternator = {
		start: function(){
			if(this.timer) return;
			this.show_standard = false
			this.timer = setInterval(this.alternate.bind(this), delay);
			this.alternate();
		},

		stop: function(){
			clearInterval(this.timer);
			this.timer = null;
			/* Changing the title within the onFocus event doesn't seem to have any effect */
			setTimeout(this.alternate.bind(this), 100);
		},

		alternate: function(){
			document.title = !this.timer || this.show_standard ? standard_title : (missed_messages + " Unread Messages");
			this.show_standard = !this.show_standard;
		}
	}

	UI.on('user_message', function(data){
		missed_messages += $.isArray(data) ? data.length : 1;
		if(user.away)	titleAlternator.start();
	});

	function onBlur(){
		user.away = true;
	}

	function onFocus(){
		user.away = false;
		titleAlternator.stop();
		missed_messages = 0;
	}

	if($.browser.msie){
		document.onfocusin = onFocus;
		document.onfocusout = onBlur;
	}else{
		window.onfocus = onFocus;
		window.onblur = onBlur;
	}

	if(window.Audio){
		var sound;
		function ding(){
			if(!sound) sound = new Audio("/sounds/missed-message.wav");
			sound.play();
		}

		UI.on('user_message', function(data){
			if(user.away){
				var now = (new Date()).getTime();
				if(now - last_sound_time >= 3000){
					last_sound_time = now;
					ding();
					/* This seems to fix the issues we were having with Chrome */
					setTimeout(function(){sound.pause(); sound.currentTime =0;}, 2000)
				}
			}
		});
	}
});

<commit_msg>Bugfix: notifications were messing up the missed_messages count<commit_after>UI.once('init', function(){
	var UI = this
	,   user = {}
	,   delay = 1500
	,   missed_messages = 0
	,   standard_title = document.title
	,   last_sound_time = 0;

	var titleAlternator = {
		start: function(){
			if(this.timer) return;
			this.show_standard = false
			this.timer = setInterval(this.alternate.bind(this), delay);
			this.alternate();
		},

		stop: function(){
			clearInterval(this.timer);
			this.timer = null;
			/* Changing the title within the onFocus event doesn't seem to have any effect */
			setTimeout(this.alternate.bind(this), 100);
		},

		alternate: function(){
			document.title = !this.timer || this.show_standard ? standard_title : (missed_messages + " Unread Messages");
			this.show_standard = !this.show_standard;
		}
	}

	UI.on('user_message', function(data){
		missed_messages += $.isArray(data) ? data.length : 1;
		if(user.away)	titleAlternator.start();
	});

	function onBlur(){
		user.away = true;
		missed_messages = 0;
	}

	function onFocus(){
		user.away = false;
		titleAlternator.stop();
	}

	if($.browser.msie){
		document.onfocusin = onFocus;
		document.onfocusout = onBlur;
	}else{
		window.onfocus = onFocus;
		window.onblur = onBlur;
	}

	if(window.Audio){
		var sound;
		function ding(){
			if(!sound) sound = new Audio("/sounds/missed-message.wav");
			sound.play();
		}

		UI.on('user_message', function(data){
			if(user.away){
				var now = (new Date()).getTime();
				if(now - last_sound_time >= 3000){
					last_sound_time = now;
					ding();
					/* This seems to fix the issues we were having with Chrome */
					setTimeout(function(){sound.pause(); sound.currentTime =0;}, 2000)
				}
			}
		});
	}
});

<|endoftext|>


<commit_before>"use strict";
/* eslint-env node,mocha */

const expect = require('expect.js');

const url    = require('url');
const util   = require('util');
const fs     = require('fs');

const fetch       = require('../http/fetch');
//const get         = require('../http/get');
const getContents = require('../http/getContents');
//const request     = require('../http/request');

const pipe        = require('../stream/pipe');
const tmppath     = require('../fs/tmppath');

describe("Testing http", function() {

  var port;
  var http   = require('http');
  var server = http.createServer(function(req, resp) {
    if(req.url == "/ping")
      return resp.end("pong");

    resp.statusCode = 500;
    resp.end("bye");
  });

  it("should start a dummy http instance", function(done) {
    server.listen(function() {
      port = server.address().port;
      done();
    });
  });

  it("Should fetch dummy cotents", function(done) {
    var testurl = util.format("http://127.0.0.1:%d/ping", port);
    getContents(testurl, function(err, ip) {
      expect(err).not.to.be.ok();
      expect(("" + ip).trim()).to.be("pong");
      done();
    });
  });

  it("Should test fetch ", function(done) {
    var tmp_file = tmppath();
    var dest = fs.createWriteStream(tmp_file);
    var testurl = util.format("http://127.0.0.1:%d/ping", port);
    pipe(fetch(testurl), dest).then(function() {
      var body = fs.readFileSync(tmp_file, 'utf-8');
      expect(body).to.be("pong");
      done();
    });
  });

  it("Should fetch missing resource", function(done) {
    var testurl = util.format("http://127.0.0.1:%d/missing", port);
    getContents(testurl, function(err) {
      expect(err).to.be.ok();
      done();
    });
  });

  it("Should fetch dummy error", function(done) {
    var testurl = url.parse(util.format("https://127.0.0.1:%d/ping", port + 1));
    getContents(testurl, function(err) {
      expect(err).to.be.ok();
      done();
    });
  });

});
<commit_msg>test Request/http<commit_after>"use strict";
/* eslint-env node,mocha */

const expect = require('expect.js');

const url    = require('url');
const util   = require('util');
const fs     = require('fs');

const fetch       = require('../http/fetch');
const getContents = require('../http/getContents');
const request     = require('../http/request');

const pipe        = require('../stream/pipe');
const drain       = require('../stream/drain');
const tmppath     = require('../fs/tmppath');

describe("Testing http", function() {

  var getHashParams = function(base) {

    var hashParams = {};
    var e;
    var a = /\+/g;  // Regex for replacing addition symbol with a space
    var r = /([^&;=]+)=?([^&;]*)/g;
    var d = function (s) { return decodeURIComponent(s.replace(a, " ")); };
    var q = base;

    while ((e = r.exec(q))) {
      hashParams[d(e[1])] = d(e[2]);
    }
    return hashParams;
  };

  var port;
  var http   = require('http');
  var server = http.createServer(async function(req, resp) {
    let current_url = url.parse(req.url);
    let hash        = current_url.query ? getHashParams(current_url.query) : {};

    if(current_url.pathname == "/ping")
      return resp.end("pong");

    if (current_url.pathname == "/request")
      return resp.end(JSON.stringify(hash));

    if (current_url.pathname == "/show_cookies")
      return resp.end(req.headers.cookie);

    if (current_url.pathname == '/throwme') {
      resp.statusCode = 500;
      resp.end('Nop');
    }
    if (current_url.pathname == '/stream') {
      let result = '' + (await drain(req));
      resp.end(result);
      return;
    }

    resp.statusCode = 500;
    resp.end("bye");
  });

  it("should start a dummy http instance", function(done) {
    server.listen(function() {
      port = server.address().port;
      done();
    });
  });

  it("Should fetch dummy cotents", function(done) {
    var testurl = util.format("http://127.0.0.1:%d/ping", port);
    getContents(testurl, function(err, ip) {
      expect(err).not.to.be.ok();
      expect(("" + ip).trim()).to.be("pong");
      done();
    });
  });

  it("Should test fetch ", function(done) {
    var tmp_file = tmppath();
    var dest = fs.createWriteStream(tmp_file);
    var testurl = util.format("http://127.0.0.1:%d/ping", port);
    pipe(fetch(testurl), dest).then(function() {
      var body = fs.readFileSync(tmp_file, 'utf-8');
      expect(body).to.be("pong");
      done();
    });
  });

  it("Should fetch missing resource", function(done) {
    var testurl = util.format("http://127.0.0.1:%d/missing", port);
    getContents(testurl, function(err) {
      expect(err).to.be.ok();
      done();
    });
  });

  it("Should fetch dummy error", function(done) {
    var testurl = url.parse(util.format("https://127.0.0.1:%d/ping", port + 1));
    getContents(testurl, function(err) {
      expect(err).to.be.ok();
      done();
    });
  });

  it("Should test request with target as string", function(done) {
    var target = util.format("http://127.0.0.1:%d/ping", port);

    //this is for coverage, used to force POST method from a String URL
    let data = {
      name : 'Jean Lebon'
    };

    request(target, data, async function(err, data) {
      expect(err).to.be(null);

      var body = '' + (await drain(data));
      expect(body).to.be("pong");

      done();
    });
  });

  it("Should test request with target as Url", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/ping", port));

    request(target, async function(err, data) {
      expect(err).to.be(null);

      var body = '' + (await drain(data));
      expect(body).to.be("pong");
      done();
    });
  });

  it("Should test request with GET args", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/request?get_var=melon", port));

    request(target, async function(err, data) {
      expect(err).to.be(null);

      var body = JSON.parse(await drain(data));
      expect(body).to.eql({get_var : 'melon'});
      done();
    });
  });

  it("Should test jar header", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/show_cookies", port));

    var key_1         = 'first';
    var key_2         = 'second';
    var expected_1    = 'Jean=Lebon';
    var expected_2    = 'Juan=Elbueno';
    var expected_full = `;${key_1}="${expected_1}"; ${key_2}="${expected_2}"`;

    target.jar = {
      [key_1] : {
        value : expected_1,
        date  : Date.now()
      },
      [key_2] : {
        value : expected_2,
        date  : Date.now()
      }
    };

    request(target, async function(err, data) {
      expect(err).to.be(null);

      var body = '' + (await drain(data));
      expect(body).to.be(expected_full);
      done();
    });
  });

  it("Should test request with forced Headers & Method", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/ping", port));

    target.headers = {};
    target.method  = 'GET';

    request(target, async function(err, data) {
      expect(err).to.be(null);

      var body = '' + (await drain(data));
      expect(body).to.be("pong");
      done();
    });
  });

  it("Should test request with Query String flag on", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/request", port));

    var expected = {
      firstname : 'Jean'
    };

    target.qs = expected;

    request(target, async function(err, data) {
      expect(err).to.be(null);

      var body = JSON.parse(await drain(data));
      expect(body).to.eql(expected);
      done();
    });
  });

  it("Should test request with Query String AND QUERY STRING (and it should explode)", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/request?lastname=Lebon", port));

    var expected = {
      firstname : 'Jean'
    };

    target.qs = expected;

    request(target, async function(err/*, data*/) {
      expect(err).to.be.ok;
      done();
    });
  });

  it("Should test request and throw", function(done) {
    var throw_path = '/throwme';
    var code       = 500;

    var target = url.parse(util.format("http://127.0.0.1:%d%s", port, throw_path));

    request(target, async function(err) {
      expect(err.err).to.be(`Invalid status code '${code}' for '${throw_path}'`);

      var body = '' + (await drain(err.res));
      expect(body).to.be('Nop');
      done();
    });
  });

  it("Should test request with data as Stream", function(done) {
    var target       = url.parse(util.format("http://127.0.0.1:%d/stream", port));
    var file_content = "dummy";
    var tmp_file     = tmppath();

    fs.writeFileSync(tmp_file, file_content);

    var dest = fs.createReadStream(tmp_file);

    request(target, dest, async function(err, data) {
      expect(err).to.be(null);

      var body = '' + (await drain(data));
      expect(body).to.be(file_content);
      fs.unlinkSync(tmp_file);
      done();
    });

  });

  it("Should test request with json flag On", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/stream", port));

    target.json = true;

    let data = {
      name : 'Juan Elbueno'
    };

    request(target, data, async function(err, resp) {
      expect(err).to.be(null);

      var body = JSON.parse(await drain(resp));
      expect(body).to.eql(data);
      done();
    });
  });

  it("Should test request with data as string", function(done) {
    var target = url.parse(util.format("http://127.0.0.1:%d/stream", port));

    let data = "name='Juan Elbueno'";

    request(target, data, async function(err, resp) {
      expect(err).to.be(null);

      var body = '' + await drain(resp);
      expect(body).to.be(data);
      done();
    });
  });

  it("Should test request with https endpoint", function(done) {
    var target = url.parse(util.format("https://127.0.0.1:%d/ping", port));

    request(target, async function(err) {
      expect(err).to.be.ok;
      // server shouldn't work with https endpoint, but request still answer socket error.
      done();
    });
  });

});
<|endoftext|>


<commit_before>UI.once('init', function(){
	var UI = this
		, should_notify = false
		, notify_cycle = true
		, interval_id = null
		, missed_messages = 0
		, standard_title = document.title;

	if(/*@cc_on!@*/false){ // check for Internet Explorer
		document.onfocusin = function() {should_notify = false;};
		document.onfocusout = function() {should_notify = true;};
	}else{
		window.onfocus = function() {should_notify = false;};
		window.onblur = function() {should_notify = true;};
	}

	UI.on('after_append', function(data){
		if(should_notify){
			missed_messages += $.isArray(data) ? data.length : 1;
			if(!interval_id){
				interval_id = setInterval(function(){
					if(should_notify){
						document.title = notify_cycle ? missed_messages + " Unread Messages" : standard_title;
						notify_cycle = !notify_cycle;
					}else{
						document.title = standard_title;
						notify_cycle = false;
						missed_messages = 0;
						clearInterval(interval_id);
					}
				}, 1000);
			}
		}
	});
});

<commit_msg>Refactor notifications<commit_after>UI.once('init', function(){
	var UI = this
		, should_notify = false
		, notify_cycle = true
		, interval_id = null
		, missed_messages = 0
		, standard_title = document.title;

	var me = {
		blurred: function(){
			should_notify = true;
			if(interval_id == null){
				interval_id = setInterval(function(){
					if(should_notify && missed_messages > 0){
						document.title = notify_cycle ? missed_messages + " Unread Messages" : standard_title;
						notify_cycle = !notify_cycle;
					}
				}, 1000);
			}
		},

		focused: function(){
			should_notify = false;
			document.title = standard_title;
			notify_cycle = false;
			missed_messages = 0;
			if(!interval_id){
				clearInterval(interval_id);
				interval_id = null;
			}
		}
	};

	if($.browser.msie){
		document.onfocusin = me.focused;
		document.onfocusout = me.blurred;
	}else{
		window.onfocus = me.focused;
		window.onblur = me.blurred;
	}

	UI.on('after_append', function(data){
		if(should_notify){
			missed_messages += $.isArray(data) ? data.length : 1;
		}
	});
});

<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.search',
  name: 'GroupBySearchView',
  extends: 'foam.u2.View',

  requires: [
    'foam.mlang.Constant',
    'foam.mlang.predicate.True',
    'foam.mlang.sink.Count',
    'foam.mlang.sink.GroupBy',
    'foam.dao.FnSink',
    'foam.u2.view.ChoiceView'
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function CSS() {/*
        ^ select {
          min-width: 220px;
        }
      */}
    })
  ],

  properties: [
    {
      name: 'view'
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'viewSpec',
      value: { class: 'foam.u2.view.ChoiceView', size: 10 }
    },
    {
      class: 'foam.dao.DAOProperty',
      name: 'dao',
      required: true,
    },
    {
      name: 'property',
      required: true
    },
    {
      name: 'name',
      expression: function(property) {
        return property.name;
      }
    },
    {
      class: 'Class',
      name: 'op',
      value: 'foam.mlang.predicate.Eq'
    },
    {
      name: 'predicate',
      factory: function() {
        return this.True.create();
      }
    },
    {
      class: 'Int',
      name: 'width',
      value: 17
    },
    {
      class: 'String',
      name: 'label',
      expression: function(property) {
        return property.label;
      }
    },
    {
      class: 'Function',
      name: 'aFormatLabel',
      value: function(key) { return Promise.resolve(''+key); }
    }
  ],

  methods: [
    function clear() {
      this.view.data = '';
    },

    function initE() {
      this
        .addClass(this.myClass())
        .tag(this.viewSpec, {
          label$: this.label$,
          alwaysFloatLabel: true
        }, this.view$)
        .onDetach(
          this.dao$proxy.listen(
            this.FnSink.create({fn: this.updateDAO})
          )
        );

      this.updateDAO();

      this.view.data$.sub(this.updatePredicate);
    },

    function updatePredicate_(choice) {
      var exists = typeof choice !== 'undefined' && choice !== '';
      this.predicate = exists ? this.op.create({
        arg1: this.property,
        arg2: this.Constant.create({ value: choice })
      }) : this.True.create();
    },

    function formatLabels(keys) {
      return Promise.all(keys.map(this.aFormatLabel.bind(this)));
    }
  ],

  listeners: [
    {
      name: 'updateDAO',
      isMerged: true,
      mergeDelay: 100,
      code: function() {
        var self = this;
        this.dao.select(this.GroupBy.create({
          arg1: this.property,
          arg2: this.Count.create()
        })).then(function(groups) {
          var options = [];
          var selected;
          var sortedKeys = groups.sortedKeys();
          self.formatLabels(sortedKeys).then(function (labels) {
            for ( var i = 0 ; i < sortedKeys.length ; i++ ) {
              var key = sortedKeys[i];
              if ( typeof key === 'undefined' ) continue;
              if ( key === '' ) continue;
              var count = foam.String.intern(
                  '(' + groups.groups[key].value + ')');
              var subKey = labels[i].substring(0, self.width - count.length - 3);
              // ???: Why do we need to clean the key?
              var cleanKey = foam.core.Enum.isInstance(self.property) ?
                  self.property.of[key].label :
                  subKey.replace(/</g, '<').replace(/>/g, '>')
                      .replace(/"/g, '"');

              if ( self.view && self.view.data === key ) {
                selected = key;
              }

              options.push([
                key,
                cleanKey + foam.String.intern(
                    Array(self.width - subKey.length - count.length).join(' ')) +
                    count
              ]);
            }

            options.splice(0, 0, [ '', '--' ]);

            self.view.choices = options;
            if ( typeof selected !== 'undefined' ) {
              var oldData = self.view.data;
              self.view.data = selected;
              if ( typeof oldData === 'undefined' || oldData === '' ) {
                self.updatePredicate_(selected);
              }
            }
          });
        });
      }
    },
    {
      name: 'updatePredicate',
      code: function(_, __, ___, slot) {
        this.updatePredicate_(slot.get());
      }
    }
  ]
});
<commit_msg>Added hover/preview mode to GroupBySearchView.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.search',
  name: 'GroupBySearchView',
  extends: 'foam.u2.View',

  requires: [
    'foam.mlang.Constant',
    'foam.mlang.predicate.True',
    'foam.mlang.sink.Count',
    'foam.mlang.sink.GroupBy',
    'foam.dao.FnSink',
    'foam.u2.view.ChoiceView'
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function CSS() {/*
        ^ select {
          min-width: 220px;
        }
      */}
    })
  ],

  properties: [
    {
      name: 'view'
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'viewSpec',
      value: { class: 'foam.u2.view.ChoiceView', size: 10 }
    },
    {
      class: 'foam.dao.DAOProperty',
      name: 'dao',
      required: true,
    },
    {
      name: 'property',
      required: true
    },
    {
      name: 'name',
      expression: function(property) {
        return property.name;
      }
    },
    {
      class: 'Class',
      name: 'op',
      value: 'foam.mlang.predicate.Eq'
    },
    {
      name: 'predicate',
      factory: function() {
        return this.True.create();
      }
    },
    {
      class: 'Int',
      name: 'width',
      value: 17
    },
    {
      class: 'String',
      name: 'label',
      expression: function(property) {
        return property.label;
      }
    },
    {
      class: 'Function',
      name: 'aFormatLabel',
      value: function(key) { return Promise.resolve(''+key); }
    },
    'previewMode',
    'hardData'
  ],

  methods: [
    function clear() {
      this.view.data = '';
    },

    function initE() {
      var self = this;

      this
        .addClass(this.myClass())
        .tag(this.viewSpec, {
          label$: this.label$,
          alwaysFloatLabel: true
        }, this.view$)
        .on('click', function(e) {
          self.previewMode = false;
          var data         = self.view.choices[e.target.value][0];
          self.hardData    = data;
        })
        .on('mouseover', function(e) {
          var data = self.view.choices[e.target.value][0];

          if ( ! self.previewMode ) {
            self.previewMode = true;
            self.hardData = self.view.data;
          }

          self.view.data = data;
        })
        .on('mouseout', function(e) {
          if ( e.relatedTarget.nodeName === 'OPTION' ) return;
          self.view.data   = self.hardData;
          self.hardData    = undefined;
          self.previewMode = false;
        })
        .onDetach(
          this.dao$proxy.listen(
            this.FnSink.create({fn: this.updateDAO})
          )
        );

      this.updateDAO();

      this.view.data$.sub(this.updatePredicate);
    },

    function updatePredicate_(choice) {
      var exists = typeof choice !== 'undefined' && choice !== '';
      this.predicate = exists ? this.op.create({
        arg1: this.property,
        arg2: this.Constant.create({ value: choice })
      }) : this.True.create();
    },

    function formatLabels(keys) {
      return Promise.all(keys.map(this.aFormatLabel.bind(this)));
    }
  ],

  listeners: [
    {
      name: 'updateDAO',
      isMerged: true,
      mergeDelay: 100,
      code: function() {
        var self = this;
        this.dao.select(this.GroupBy.create({
          arg1: this.property,
          arg2: this.Count.create()
        })).then(function(groups) {
          var options = [];
          var selected;
          var sortedKeys = groups.sortedKeys();
          self.formatLabels(sortedKeys).then(function (labels) {
            for ( var i = 0 ; i < sortedKeys.length ; i++ ) {
              var key = sortedKeys[i];
              if ( typeof key === 'undefined' ) continue;
              if ( key === '' ) continue;
              var count = foam.String.intern(
                  '(' + groups.groups[key].value + ')');
              var subKey = labels[i].substring(0, self.width - count.length - 3);
              // ???: Why do we need to clean the key?
              var cleanKey = foam.core.Enum.isInstance(self.property) ?
                  self.property.of[key].label :
                  subKey.replace(/</g, '<').replace(/>/g, '>')
                      .replace(/"/g, '"');

              if ( self.view && self.view.data === key ) {
                selected = key;
              }

              options.push([
                key,
                cleanKey + foam.String.intern(
                    Array(self.width - subKey.length - count.length).join(' ')) +
                    count
              ]);
            }

            options.splice(0, 0, [ '', '--' ]);

            self.view.choices = options;
            if ( typeof selected !== 'undefined' ) {
              var oldData = self.view.data;
              self.view.data = selected;
              if ( typeof oldData === 'undefined' || oldData === '' ) {
                self.updatePredicate_(selected);
              }
            }
          });
        });
      }
    },
    {
      name: 'updatePredicate',
      code: function(_, __, ___, slot) {
        this.updatePredicate_(slot.get());
      }
    }
  ]
});
<|endoftext|>


<commit_before>(function () {
	window.equals = window.equal;
	window.same = window.deepEqual;

	// Store the old counts so that we only assert on tests that have actually leaked,
	// instead of asserting every time a test has leaked sometime in the past
	var oldCacheLength = 0,
		oldFragmentsLength = 0,
		oldTimersLength = 0,
		oldActive = 0;

	/**
	 * Ensures that tests have cleaned up properly after themselves. Should be passed as the
	 * teardown function on all modules' lifecycle object.
	 */
	this.moduleTeardown = function () {
		var i, fragmentsLength = 0, cacheLength = 0;

		// Allow QUnit.reset to clean up any attached elements before checking for leaks
		QUnit.reset();

		for ( i in jQuery.cache ) {
			++cacheLength;
		}

		jQuery.fragments = {};

		for ( i in jQuery.fragments ) {
			++fragmentsLength;
		}

		// Because QUnit doesn't have a mechanism for retrieving the number of expected assertions for a test,
		// if we unconditionally assert any of these, the test will fail with too many assertions :|
		if ( cacheLength !== oldCacheLength ) {
			equals( cacheLength, oldCacheLength, "No unit tests leak memory in jQuery.cache" );
			oldCacheLength = cacheLength;
		}
		if ( fragmentsLength !== oldFragmentsLength ) {
			equals( fragmentsLength, oldFragmentsLength, "No unit tests leak memory in jQuery.fragments" );
			oldFragmentsLength = fragmentsLength;
		}
		if ( jQuery.timers.length !== oldTimersLength ) {
			equals( jQuery.timers.length, oldTimersLength, "No timers are still running" );
			oldTimersLength = jQuery.timers.length;
		}
		if ( jQuery.active !== oldActive ) {
			equals( jQuery.active, 0, "No AJAX requests are still active" );
			oldActive = jQuery.active;
		}
	}
}());
<commit_msg>Adds missing semicolon.<commit_after>(function () {
	window.equals = window.equal;
	window.same = window.deepEqual;

	// Store the old counts so that we only assert on tests that have actually leaked,
	// instead of asserting every time a test has leaked sometime in the past
	var oldCacheLength = 0,
		oldFragmentsLength = 0,
		oldTimersLength = 0,
		oldActive = 0;

	/**
	 * Ensures that tests have cleaned up properly after themselves. Should be passed as the
	 * teardown function on all modules' lifecycle object.
	 */
	this.moduleTeardown = function () {
		var i, fragmentsLength = 0, cacheLength = 0;

		// Allow QUnit.reset to clean up any attached elements before checking for leaks
		QUnit.reset();

		for ( i in jQuery.cache ) {
			++cacheLength;
		}

		jQuery.fragments = {};

		for ( i in jQuery.fragments ) {
			++fragmentsLength;
		}

		// Because QUnit doesn't have a mechanism for retrieving the number of expected assertions for a test,
		// if we unconditionally assert any of these, the test will fail with too many assertions :|
		if ( cacheLength !== oldCacheLength ) {
			equals( cacheLength, oldCacheLength, "No unit tests leak memory in jQuery.cache" );
			oldCacheLength = cacheLength;
		}
		if ( fragmentsLength !== oldFragmentsLength ) {
			equals( fragmentsLength, oldFragmentsLength, "No unit tests leak memory in jQuery.fragments" );
			oldFragmentsLength = fragmentsLength;
		}
		if ( jQuery.timers.length !== oldTimersLength ) {
			equals( jQuery.timers.length, oldTimersLength, "No timers are still running" );
			oldTimersLength = jQuery.timers.length;
		}
		if ( jQuery.active !== oldActive ) {
			equals( jQuery.active, 0, "No AJAX requests are still active" );
			oldActive = jQuery.active;
		}
	};
}());
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.search',
  name: 'GroupBySearchView',
  extends: 'foam.u2.View',

  requires: [
    'foam.mlang.Constant',
    'foam.mlang.predicate.True',
    'foam.mlang.sink.Count',
    'foam.mlang.sink.GroupBy',
    'foam.dao.FnSink',
    'foam.u2.view.ChoiceView'
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function CSS() {/*
        ^ select {
          min-width: 220px;
        }
      */}
    })
  ],

  properties: [
    {
      name: 'view'
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'viewSpec',
      value: { class: 'foam.u2.view.ChoiceView', size: 10 }
    },
    {
      class: 'foam.dao.DAOProperty',
      name: 'dao',
      required: true,
    },
    {
      name: 'property',
      required: true
    },
    {
      name: 'name',
      expression: function(property) {
        return property.name;
      }
    },
    {
      class: 'Class',
      name: 'op',
      value: 'foam.mlang.predicate.Eq'
    },
    {
      name: 'predicate',
      factory: function() {
        return this.True.create();
      }
    },
    {
      class: 'Int',
      name: 'width',
      value: 17
    },
    {
      class: 'String',
      name: 'label',
      expression: function(property) {
        return property.label;
      }
    },
    {
      class: 'Function',
      name: 'aFormatLabel',
      value: function(key) { return Promise.resolve(''+key); }
    },
    'previewMode',
    'hardData'
  ],

  methods: [
    function clear() {
      this.view.data = '';
    },

    function initE() {
      var self = this;

      this
        .addClass(this.myClass())
        .tag(this.viewSpec, {
          label$: this.label$,
          alwaysFloatLabel: true
        }, this.view$)
        .on('click', function(e) {
          try {
            self.previewMode = false;
            var data         = self.view.choices[e.target.value][0];
            self.hardData    = data;
          } catch(x) {}
        })
        .on('mouseover', function(e) {
          try {
            var data = self.view.choices[e.target.value][0];

            if ( ! self.previewMode ) {
              self.previewMode = true;
              self.hardData = self.view.data;
            }

            self.view.data = data;
          } catch(x) {}
        })
        .on('mouseout', function(e) {
          if ( e.relatedTarget && e.relatedTarget.nodeName === 'OPTION' ) return;
          self.view.data   = self.hardData;
          self.hardData    = undefined;
          self.previewMode = false;
        })
        .onDetach(
          this.dao$proxy.listen(
            this.FnSink.create({fn: this.updateDAO})
          )
        );

      this.updateDAO();

      this.view.data$.sub(this.updatePredicate);
    },

    function updatePredicate_(choice) {
      var exists = typeof choice !== 'undefined' && choice !== '';
      this.predicate = exists ? this.op.create({
        arg1: this.property,
        arg2: this.Constant.create({ value: choice })
      }) : this.True.create();
    },

    function formatLabels(keys) {
      return Promise.all(keys.map(this.aFormatLabel.bind(this)));
    }
  ],

  listeners: [
    {
      name: 'updateDAO',
      isMerged: true,
      mergeDelay: 100,
      code: function() {
        var self = this;
        this.dao.select(this.GroupBy.create({
          arg1: this.property,
          arg2: this.Count.create()
        })).then(function(groups) {
          var options = [];
          var selected;
          var sortedKeys = groups.sortedKeys();
          self.formatLabels(sortedKeys).then(function (labels) {
            for ( var i = 0 ; i < sortedKeys.length ; i++ ) {
              var key = sortedKeys[i];
              if ( typeof key === 'undefined' ) continue;
              if ( key === '' ) continue;
              var count = foam.String.intern(
                  '(' + groups.groups[key].value + ')');
              var subKey = labels[i].substring(0, self.width - count.length - 3);
              // ???: Why do we need to clean the key?
              var cleanKey = foam.core.Enum.isInstance(self.property) ?
                  self.property.of[key].label :
                  subKey.replace(/</g, '<').replace(/>/g, '>')
                      .replace(/"/g, '"');

              if ( self.view && self.view.data === key ) {
                selected = key;
              }

              options.push([
                key,
                cleanKey + foam.String.intern(
                    Array(self.width - subKey.length - count.length).join(' ')) +
                    count
              ]);
            }

            options.splice(0, 0, [ '', '--' ]);

            self.view.choices = options;
            if ( typeof selected !== 'undefined' ) {
              var oldData = self.view.data;
              self.view.data = selected;
              if ( typeof oldData === 'undefined' || oldData === '' ) {
                self.updatePredicate_(selected);
              }
            }
          });
        });
      }
    },
    {
      name: 'updatePredicate',
      code: function(_, __, ___, slot) {
        this.updatePredicate_(slot.get());
      }
    }
  ]
});
<commit_msg>Updated CSS to new style.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.search',
  name: 'GroupBySearchView',
  extends: 'foam.u2.View',

  requires: [
    'foam.mlang.Constant',
    'foam.mlang.predicate.True',
    'foam.mlang.sink.Count',
    'foam.mlang.sink.GroupBy',
    'foam.dao.FnSink',
    'foam.u2.view.ChoiceView'
  ],

  css: `
    ^ select {
      min-width: 220px;
    }
  `,

  properties: [
    {
      name: 'view'
    },
    {
      class: 'foam.u2.ViewSpec',
      name: 'viewSpec',
      value: { class: 'foam.u2.view.ChoiceView', size: 10 }
    },
    {
      class: 'foam.dao.DAOProperty',
      name: 'dao',
      required: true,
    },
    {
      name: 'property',
      required: true
    },
    {
      name: 'name',
      expression: function(property) { return property.name; }
    },
    {
      class: 'Class',
      name: 'op',
      value: 'foam.mlang.predicate.Eq'
    },
    {
      name: 'predicate',
      factory: function() {
        return this.True.create();
      }
    },
    {
      class: 'Int',
      name: 'width',
      value: 17
    },
    {
      class: 'String',
      name: 'label',
      expression: function(property) {
        return property.label;
      }
    },
    {
      class: 'Function',
      name: 'aFormatLabel',
      value: function(key) { return Promise.resolve(''+key); }
    },
    'previewMode',
    'hardData'
  ],

  methods: [
    function clear() {
      this.view.data = '';
    },

    function initE() {
      var self = this;

      this
        .addClass(this.myClass())
        .tag(this.viewSpec, {
          label$: this.label$,
          alwaysFloatLabel: true
        }, this.view$)
        .on('click', function(e) {
          try {
            self.previewMode = false;
            var data         = self.view.choices[e.target.value][0];
            self.hardData    = data;
          } catch(x) {}
        })
        .on('mouseover', function(e) {
          try {
            var data = self.view.choices[e.target.value][0];

            if ( ! self.previewMode ) {
              self.previewMode = true;
              self.hardData = self.view.data;
            }

            self.view.data = data;
          } catch(x) {}
        })
        .on('mouseout', function(e) {
          if ( e.relatedTarget && e.relatedTarget.nodeName === 'OPTION' ) return;
          self.view.data   = self.hardData;
          self.hardData    = undefined;
          self.previewMode = false;
        })
        .onDetach(
          this.dao$proxy.listen(
            this.FnSink.create({fn: this.updateDAO})
          )
        );

      this.updateDAO();

      this.view.data$.sub(this.updatePredicate);
    },

    function updatePredicate_(choice) {
      var exists = typeof choice !== 'undefined' && choice !== '';
      this.predicate = exists ? this.op.create({
        arg1: this.property,
        arg2: this.Constant.create({ value: choice })
      }) : this.True.create();
    },

    function formatLabels(keys) {
      return Promise.all(keys.map(this.aFormatLabel.bind(this)));
    }
  ],

  listeners: [
    {
      name: 'updateDAO',
      isMerged: true,
      mergeDelay: 100,
      code: function() {
        var self = this;
        this.dao.select(this.GroupBy.create({
          arg1: this.property,
          arg2: this.Count.create()
        })).then(function(groups) {
          var options = [];
          var selected;
          var sortedKeys = groups.sortedKeys();
          self.formatLabels(sortedKeys).then(function (labels) {
            for ( var i = 0 ; i < sortedKeys.length ; i++ ) {
              var key = sortedKeys[i];
              if ( typeof key === 'undefined' ) continue;
              if ( key === '' ) continue;
              var count = foam.String.intern(
                  '(' + groups.groups[key].value + ')');
              var subKey = labels[i].substring(0, self.width - count.length - 3);
              // ???: Why do we need to clean the key?
              var cleanKey = foam.core.Enum.isInstance(self.property) ?
                  self.property.of[key].label :
                  subKey.replace(/</g, '<').replace(/>/g, '>')
                      .replace(/"/g, '"');

              if ( self.view && self.view.data === key ) {
                selected = key;
              }

              options.push([
                key,
                cleanKey + foam.String.intern(
                    Array(self.width - subKey.length - count.length).join(' ')) +
                    count
              ]);
            }

            options.splice(0, 0, [ '', '--' ]);

            self.view.choices = options;
            if ( typeof selected !== 'undefined' ) {
              var oldData = self.view.data;
              self.view.data = selected;
              if ( typeof oldData === 'undefined' || oldData === '' ) {
                self.updatePredicate_(selected);
              }
            }
          });
        });
      }
    },
    {
      name: 'updatePredicate',
      code: function(_, __, ___, slot) {
        this.updatePredicate_(slot.get());
      }
    }
  ]
});
<|endoftext|>


<commit_before>module.exports = require('should');

var DataSource = require('loopback-datasource-juggler').DataSource;

var config = require('rc')('loopback', {test: {mongodb: {}}}).test.mongodb;

if (process.env.CI) {
  config = {
    host: 'localhost',
    database: 'lb-ds-mongodb-test-' + (
      process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER || '1'
    ),
  };
}

global.getDataSource = global.getSchema = function (customConfig) {
  var db = new DataSource(require('../'), customConfig || config);
  db.log = function (a) {
    console.log(a);
  };

  return db;
};

global.sinon = require('sinon');
<commit_msg>Add env variable for mongodb server<commit_after>module.exports = require('should');

var DataSource = require('loopback-datasource-juggler').DataSource;

var config = require('rc')('loopback', {test: {mongodb: {}}}).test.mongodb;

if (process.env.CI) {
  config = {
    host: process.env.MONGODB_HOST || 'localhost',
    database: 'lb-ds-mongodb-test-' + (
      process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER || '1'
    ),
  };
}

global.getDataSource = global.getSchema = function (customConfig) {
  var db = new DataSource(require('../'), customConfig || config);
  db.log = function (a) {
    console.log(a);
  };

  return db;
};

global.sinon = require('sinon');
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.wizard',
  name: 'StepWizardletView',
  extends: 'foam.u2.View',

  documentation: `Displays wizardlets in individual screens.`,

  imports: [
    'notify',
    'stack',
    'theme'
  ],

  requires: [
    'foam.core.Action',
    'foam.u2.dialog.Popup',
    'foam.u2.dialog.SimpleActionDialog',
    'foam.u2.stack.Stack',
    'foam.u2.stack.StackView',
    'foam.u2.detail.VerticalDetailView',
    'foam.u2.layout.Grid',
    'foam.u2.layout.GUnit',
    'foam.u2.wizard.StepWizardletStepsView',
    'foam.u2.tag.CircleIndicator'
  ],

  implements: [
    'foam.mlang.Expressions'
  ],

  messages: [
    { name: 'ACTION_LABEL', message: 'Submit' },
    { name: 'CANCEL_LABEL', message: 'Cancel' },
    { name: 'SAVE_IN_PROGRESS', message: 'Saving...' },
    { name: 'ERROR_MSG', message: 'Information was not successfully submitted, please try again later' },
    { name: 'ERROR_MSG_DRAFT', message: 'An error occured while saving your progress.' },
    { name: 'SUCCESS_MSG', message: 'Information successfully submitted.' },
    { name: 'SUCCESS_MSG_DRAFT', message: 'Your progress has been saved.' },
  ],

  css: `
    ^ {
      position: relative;
      height: auto;
      background-color: %GREY5%;
      max-height: 95vh;
      height: 100%;
    }
    ^status {
      background-color: %WHITE%;
      padding: 50px;
      overflow-y: scroll;
      display: flex;
      flex-direction: column;
    }
    ^rightside {
      display: flex;
      flex-direction: column;
      background-color: %GREY5%;
      overflow-y: hidden;
    }
    ^rightside ^entry {
      flex-grow: 1;
      -webkit-mask-image: -webkit-gradient(linear, left 15, left top, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
      overflow-y: scroll;
      padding: 0 50px;
    }
    ^rightside ^top-buttons {
      text-align: right;
      margin-bottom: 15px;
      padding: 50px;
      padding-bottom: 0;
    }
    ^rightside ^bottom-buttons {
      background-color: %GREY6%;
      padding: 25px 50px;
      text-align: right;
    }
    ^ .foam-u2-stack-StackView {
      height: auto;
      margin-bottom: 30px;
    }
    ^fix-grid {
      height: 100%;
    }
    ^fix-grid.foam-u2-layout-Grid {
      grid-gap: 0;
    }
  `,

  properties: [
    {
      name: 'onClose',
      class: 'Function',
      factory: () => () => {}
    }
  ],

  methods: [
    function initE() {
      var btn = { size: 'LARGE' };
      var self = this;

      this
        .addClass(this.myClass())
        .start(this.Grid)
          .addClass(this.myClass('fix-grid'))
          .start(this.GUnit, { columns: 4 })
            .addClass(this.myClass('status'))
            .add(
              this.slot(function (data, data$currentWizardlet) {
                return this.StepWizardletStepsView.create({
                  data: data,
                });
              })
            )
          .end()
          .start(this.GUnit, { columns: 8 })
            .addClass(this.myClass('rightside'))
            .start().addClass(this.myClass('top-buttons'))
              .start(this.CircleIndicator, {
                label: 'X',
                borderThickness: 2,
                borderColor: this.theme.grey2,
                borderColorHover: this.theme.primary1,
                clickable: true
              })
                .on('click', function () {
                  self.showExitPrompt();
                })
              .end()
            .end()
            .start()
              .addClass(this.myClass('entry'))
              .start()
                .add(this.data.SUB_STACK)
              .end()
            .end()
            .start()
              .addClass(this.myClass('bottom-buttons'))
              .add(this.slot(function (data$isLastWizardlet) {
                return this.E()
                  .startContext({ data: self })
                  .addClass(self.myClass('buttons'))
                  .tag(this.GO_PREV, btn)
                  .tag(this.GO_NEXT,
                    data$isLastWizardlet
                      ? { ...btn, label: this.ACTION_LABEL }
                      : btn
                  )
                  .endContext();
              }))
            .end()
          .end()
        .end()
        ;
    },
    function showExitPrompt() {
      var prompt = null;
      var actionWrap = action => {
        let a = action.clone();
        a.code = action.code.bind(this, this.__subSubContext__);
        return a;
      }
      prompt = this.Popup.create().tag(this.SimpleActionDialog, {
        title: 'Confirm Wizard Cancellation',
        body: 'You are closing this wizard. How do you wish to proceed?',
        actions: [
          actionWrap(this.DISCARD),
          actionWrap(this.SAVE_AND_CLOSE),
          this.Action.create({
            name: 'cancel',
            label: 'Cancel',
            code: () => {
              prompt.close();
            }
          })
        ]
      });
      ctrl.add(prompt);
    }
  ],

  actions: [
    {
      name: 'discard',
      label: 'Discard Changes',
      confirmationRequired: true,
      code: function(x) {
        this.onClose(x);
      }
    },
    {
      name: 'saveAndClose',
      label: 'Save for Later',
      code: function(x) {
        this.data.saveProgress().then(() => {
          this.onClose(x);
        }).catch(e => {
          console.error(e);
          x.ctrl.notify(this.ERROR_MSG_DRAFT, 'error');
        });
      }
    },
    {
      name: 'goPrev',
      label: 'back',
      isEnabled: function (data$canGoBack) {
        return data$canGoBack;
      },
      code: function() {
        this.data.back();
      }
    },
    {
      name: 'goNext',
      label: 'next',
      isEnabled: function (data$isLastWizardlet, data$currentWizardlet) {
        return data$isLastWizardlet || data$currentWizardlet.validate();
      },
      code: function(x) {
        this.data.next().then((isFinished) => {
          if ( isFinished ) {
            this.onClose(x);
          }
        }).catch(e => {
          console.error(e);
          x.ctrl.notify(this.ERROR_MSG);
        });
      }
    }
  ]
});<commit_msg>Disable discard changes button by default<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.wizard',
  name: 'StepWizardletView',
  extends: 'foam.u2.View',

  documentation: `Displays wizardlets in individual screens.`,

  imports: [
    'notify',
    'stack',
    'theme'
  ],

  requires: [
    'foam.core.Action',
    'foam.u2.dialog.Popup',
    'foam.u2.dialog.SimpleActionDialog',
    'foam.u2.stack.Stack',
    'foam.u2.stack.StackView',
    'foam.u2.detail.VerticalDetailView',
    'foam.u2.layout.Grid',
    'foam.u2.layout.GUnit',
    'foam.u2.wizard.StepWizardletStepsView',
    'foam.u2.tag.CircleIndicator'
  ],

  implements: [
    'foam.mlang.Expressions'
  ],

  messages: [
    { name: 'ACTION_LABEL', message: 'Submit' },
    { name: 'CANCEL_LABEL', message: 'Cancel' },
    { name: 'SAVE_IN_PROGRESS', message: 'Saving...' },
    { name: 'ERROR_MSG', message: 'Information was not successfully submitted, please try again later' },
    { name: 'ERROR_MSG_DRAFT', message: 'An error occured while saving your progress.' },
    { name: 'SUCCESS_MSG', message: 'Information successfully submitted.' },
    { name: 'SUCCESS_MSG_DRAFT', message: 'Your progress has been saved.' },
  ],

  css: `
    ^ {
      position: relative;
      height: auto;
      background-color: %GREY5%;
      max-height: 95vh;
      height: 100%;
    }
    ^status {
      background-color: %WHITE%;
      padding: 50px;
      overflow-y: scroll;
      display: flex;
      flex-direction: column;
    }
    ^rightside {
      display: flex;
      flex-direction: column;
      background-color: %GREY5%;
      overflow-y: hidden;
    }
    ^rightside ^entry {
      flex-grow: 1;
      -webkit-mask-image: -webkit-gradient(linear, left 15, left top, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
      overflow-y: scroll;
      padding: 0 50px;
    }
    ^rightside ^top-buttons {
      text-align: right;
      margin-bottom: 15px;
      padding: 50px;
      padding-bottom: 0;
    }
    ^rightside ^bottom-buttons {
      background-color: %GREY6%;
      padding: 25px 50px;
      text-align: right;
    }
    ^ .foam-u2-stack-StackView {
      height: auto;
      margin-bottom: 30px;
    }
    ^fix-grid {
      height: 100%;
    }
    ^fix-grid.foam-u2-layout-Grid {
      grid-gap: 0;
    }
  `,

  properties: [
    {
      name: 'onClose',
      class: 'Function',
      factory: () => () => {}
    },
    {
      name: 'showDiscardOption',
      class: 'Boolean',
      value: false
    }
  ],

  methods: [
    function initE() {
      var btn = { size: 'LARGE' };
      var self = this;

      this
        .addClass(this.myClass())
        .start(this.Grid)
          .addClass(this.myClass('fix-grid'))
          .start(this.GUnit, { columns: 4 })
            .addClass(this.myClass('status'))
            .add(
              this.slot(function (data, data$currentWizardlet) {
                return this.StepWizardletStepsView.create({
                  data: data,
                });
              })
            )
          .end()
          .start(this.GUnit, { columns: 8 })
            .addClass(this.myClass('rightside'))
            .start().addClass(this.myClass('top-buttons'))
              .start(this.CircleIndicator, {
                label: 'X',
                borderThickness: 2,
                borderColor: this.theme.grey2,
                borderColorHover: this.theme.primary1,
                clickable: true
              })
                .on('click', function () {
                  self.showExitPrompt();
                })
              .end()
            .end()
            .start()
              .addClass(this.myClass('entry'))
              .start()
                .add(this.data.SUB_STACK)
              .end()
            .end()
            .start()
              .addClass(this.myClass('bottom-buttons'))
              .add(this.slot(function (data$isLastWizardlet) {
                return this.E()
                  .startContext({ data: self })
                  .addClass(self.myClass('buttons'))
                  .tag(this.GO_PREV, btn)
                  .tag(this.GO_NEXT,
                    data$isLastWizardlet
                      ? { ...btn, label: this.ACTION_LABEL }
                      : btn
                  )
                  .endContext();
              }))
            .end()
          .end()
        .end()
        ;
    },
    function showExitPrompt() {
      var prompt = null;
      var actionWrap = action => {
        let a = action.clone();
        a.code = action.code.bind(this, this.__subSubContext__);
        return a;
      }
      prompt = this.Popup.create().tag(this.SimpleActionDialog, {
        title: 'Confirm Wizard Cancellation',
        body: 'You are closing this wizard. How do you wish to proceed?',
        actions: [
          actionWrap(this.DISCARD),
          actionWrap(this.SAVE_AND_CLOSE),
          this.Action.create({
            name: 'cancel',
            label: 'Cancel',
            code: () => {
              prompt.close();
            }
          })
        ]
      });
      ctrl.add(prompt);
    }
  ],

  actions: [
    {
      name: 'discard',
      label: 'Discard Changes',
      isAvailable: function () {
        return this.showDiscardOption;
      },
      confirmationRequired: true,
      code: function(x) {
        this.onClose(x);
      }
    },
    {
      name: 'saveAndClose',
      label: 'Save for Later',
      code: function(x) {
        this.data.saveProgress().then(() => {
          this.onClose(x);
        }).catch(e => {
          console.error(e);
          x.ctrl.notify(this.ERROR_MSG_DRAFT, 'error');
        });
      }
    },
    {
      name: 'goPrev',
      label: 'back',
      isEnabled: function (data$canGoBack) {
        return data$canGoBack;
      },
      code: function() {
        this.data.back();
      }
    },
    {
      name: 'goNext',
      label: 'next',
      isEnabled: function (data$isLastWizardlet, data$currentWizardlet) {
        return data$isLastWizardlet || data$currentWizardlet.validate();
      },
      code: function(x) {
        this.data.next().then((isFinished) => {
          if ( isFinished ) {
            this.onClose(x);
          }
        }).catch(e => {
          console.error(e);
          x.ctrl.notify(this.ERROR_MSG);
        });
      }
    }
  ]
});<|endoftext|>


<commit_before>
var connect = require('connect');
var assert = require('assert');
var request = require('supertest');

var bodyParser = require('..');

var app = connect();

app.use(bodyParser.json({ limit: '1mb' }));

app.use(function(req, res){
  res.end(JSON.stringify(req.body));
});

app.use(function(err, req, res, next){
  res.statusCode = err.status;
  res.end(err.message);
});

describe('bodyParser.json()', function(){
  it('should parse JSON', function(done){
    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user":"tobi"}')
    .end(function(err, res){
      res.text.should.equal('{"user":"tobi"}');
      done();
    });
  })

  it('should fail gracefully', function(done){
    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user"')
    .end(function(err, res){
      res.text.should.equal('Unexpected end of input');
      done();
    });
  })

  it('should handle Content-Length: 0', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(Object.keys(req.body).length ? '' : 'empty');
    });

    request(app)
    .get('/')
    .set('Content-Type', 'application/json')
    .set('Content-Length', '0')
    .end(function(err, res){
      res.should.have.status(200);
      res.text.should.equal('empty');
      done();
    });
  })

  it('should 400 on malformed JSON', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"foo')
    .expect(400, done);
  })

  it('should 400 when no body is given', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .end(function(err, res){
      res.should.have.status(400);
      res.text.should.include("invalid json, empty body");
      done();
    })
  })

  it('should support all http methods', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .get('/')
    .set('Content-Type', 'application/json')
    .set('Content-Length', '["foo"]'.length)
    .send('["foo"]')
    .expect('["foo"]', done);
  })

  describe('when strict is false', function(){
    it('should parse primitives', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: false }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .expect('true', done);
    })
  })

  describe('when strict is true', function(){
    it('should not parse primitives', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: true }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .end(function(err, res){
        res.should.have.status(400);
        res.text.should.include('invalid json');
        done();
      });
    })

    it('should allow leading whitespaces in JSON', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: true }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('   { "user": "tobi" }')
      .end(function(err, res){
        res.should.have.status(200);
        res.text.should.include('{"user":"tobi"}');
        done();
      });
    })
  })

  describe('by default', function(){
    it('should 400 on primitives', function(done){
      var app = connect();
      app.use(bodyParser.json());

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .expect(400, done);
    })
  })

  it('should support utf-8', function(done){
    var app = connect();

    app.use(bodyParser.json());

    app.use(function(req, res, next){
      res.end(req.body.name);
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json; charset=utf-8')
    .send('{"name":"论"}')
    .expect('论', done);
  })

  it('should support {"test":"å"}', function (done) {
    // https://github.com/visionmedia/express/issues/1816

    var app = connect();
    app.use(bodyParser.json());
    app.use(function(req, res, next){
      res.end(req.body.test);
    })

    request(app)
    .post('/')
    .set('Content-Type', 'application/json; charset=utf-8')
    .set('Content-Length', '13')
    .send('{"test":"å"}')
    .expect('å', done);
  })

  it('should parse JSON with limit and after next tick', function(done){
    var app = connect();

    app.use(function(req, res, next) {
      setTimeout(next, 10);
    });

    app.use(bodyParser.json({ limit: '1mb' }));

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    app.use(function(err, req, res, next){
      res.statusCode = err.status;
      res.end(err.message);
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user":"tobi"}')
    .end(function(err, res){
      res.text.should.equal('{"user":"tobi"}');
      done();
    });
  })
})
<commit_msg>Add test for absense of message-body<commit_after>
var connect = require('connect');
var assert = require('assert');
var request = require('supertest');

var bodyParser = require('..');

var app = connect();

app.use(bodyParser.json({ limit: '1mb' }));

app.use(function(req, res){
  res.end(JSON.stringify(req.body));
});

app.use(function(err, req, res, next){
  res.statusCode = err.status;
  res.end(err.message);
});

describe('bodyParser.json()', function(){
  it('should parse JSON', function(done){
    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user":"tobi"}')
    .end(function(err, res){
      res.text.should.equal('{"user":"tobi"}');
      done();
    });
  })

  it('should fail gracefully', function(done){
    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user"')
    .end(function(err, res){
      res.text.should.equal('Unexpected end of input');
      done();
    });
  })

  it('should handle Content-Length: 0', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(Object.keys(req.body).length ? '' : 'empty');
    });

    request(app)
    .get('/')
    .set('Content-Type', 'application/json')
    .set('Content-Length', '0')
    .end(function(err, res){
      res.should.have.status(200);
      res.text.should.equal('empty');
      done();
    });
  })

  it('should handle no message-body', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(Object.keys(req.body).length ? '' : 'empty');
    });

    request(app)
    .get('/')
    .set('Content-Type', 'application/json')
    .unset('Transfer-Encoding')
    .end(function(err, res){
      res.should.have.status(200);
      res.text.should.equal('empty');
      done();
    });
  })

  it('should 400 on malformed JSON', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"foo')
    .expect(400, done);
  })

  it('should 400 when no body is given', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .set('Transfer-Encoding', 'chunked')
    .end(function(err, res){
      res.should.have.status(400);
      res.text.should.include("invalid json, empty body");
      done();
    })
  })

  it('should support all http methods', function(done){
    var app = connect();
    app.use(bodyParser.json());

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    request(app)
    .get('/')
    .set('Content-Type', 'application/json')
    .set('Content-Length', '["foo"]'.length)
    .send('["foo"]')
    .expect('["foo"]', done);
  })

  describe('when strict is false', function(){
    it('should parse primitives', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: false }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .expect('true', done);
    })
  })

  describe('when strict is true', function(){
    it('should not parse primitives', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: true }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .end(function(err, res){
        res.should.have.status(400);
        res.text.should.include('invalid json');
        done();
      });
    })

    it('should allow leading whitespaces in JSON', function(done){
      var app = connect();
      app.use(bodyParser.json({ strict: true }));

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('   { "user": "tobi" }')
      .end(function(err, res){
        res.should.have.status(200);
        res.text.should.include('{"user":"tobi"}');
        done();
      });
    })
  })

  describe('by default', function(){
    it('should 400 on primitives', function(done){
      var app = connect();
      app.use(bodyParser.json());

      app.use(function(req, res){
        res.end(JSON.stringify(req.body));
      });

      request(app)
      .post('/')
      .set('Content-Type', 'application/json')
      .send('true')
      .expect(400, done);
    })
  })

  it('should support utf-8', function(done){
    var app = connect();

    app.use(bodyParser.json());

    app.use(function(req, res, next){
      res.end(req.body.name);
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json; charset=utf-8')
    .send('{"name":"论"}')
    .expect('论', done);
  })

  it('should support {"test":"å"}', function (done) {
    // https://github.com/visionmedia/express/issues/1816

    var app = connect();
    app.use(bodyParser.json());
    app.use(function(req, res, next){
      res.end(req.body.test);
    })

    request(app)
    .post('/')
    .set('Content-Type', 'application/json; charset=utf-8')
    .set('Content-Length', '13')
    .send('{"test":"å"}')
    .expect('å', done);
  })

  it('should parse JSON with limit and after next tick', function(done){
    var app = connect();

    app.use(function(req, res, next) {
      setTimeout(next, 10);
    });

    app.use(bodyParser.json({ limit: '1mb' }));

    app.use(function(req, res){
      res.end(JSON.stringify(req.body));
    });

    app.use(function(err, req, res, next){
      res.statusCode = err.status;
      res.end(err.message);
    });

    request(app)
    .post('/')
    .set('Content-Type', 'application/json')
    .send('{"user":"tobi"}')
    .end(function(err, res){
      res.text.should.equal('{"user":"tobi"}');
      done();
    });
  })
})
<|endoftext|>


<commit_before>var t = require('./littlelisp').littleLisp;

var is = function(input, type) {
  return Object.prototype.toString.call(input) === '[object ' + type + ']';
};

// takes an AST and replaces type annotated nodes with raw values
var unannotate = function(input) {
  if (is(input, 'Array')) {
    if (input[0] === undefined) {
      return [];
    } else if (is(input[0], 'Array')) {
      return [unannotate(input[0])].concat(unannotate(input.slice(1)));
    } else {
      return unannotate(input[0]).concat(unannotate(input.slice(1)));
    }
  } else {
    return [input.value];
  }
};

describe('littleLisp', function() {
  describe('parse', function() {
    it('should lex an atom in a list', function() {
      expect(unannotate(t.parse("()"))).toEqual([]);
    });

    it('should lex multi atom list', function() {
      expect(unannotate(t.parse("(hi you)"))).toEqual(["hi", "you"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("((x))"))).toEqual([["x"]]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (x))"))).toEqual(["x", ["x"]]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x y)"))).toEqual(["x", "y"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (y) z)"))).toEqual(["x", ["y"], "z"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (y) (a b c))"))).toEqual(["x", ["y"], ["a", "b", "c"]]);
    });

    describe('atoms', function() {
      it('should parse out numbers', function() {
        expect(unannotate(t.parse("(1 (a 2))"))).toEqual([1, ["a", 2]]);
      });
    });
  });

  describe('interpret', function() {
    describe('lists', function() {
      it('should return list of strings', function() {
        expect(t.interpret(t.parse('("hi" "mary" "rose")'))).toEqual(['hi', "mary", "rose"]);
      });

      it('should return list of numbers', function() {
        expect(t.interpret(t.parse('(1 2 3)'))).toEqual([1, 2, 3]);
      });

      it('should return list of numbers in strings as strings', function() {
        expect(t.interpret(t.parse('("1" "2" "3")'))).toEqual(["1", "2", "3"]);
      });
    });

    describe('atoms', function() {
      it('should return string atom', function() {
        expect(t.interpret(t.parse('"a"'))).toEqual("a");
      });

      it('should return string with space atom', function() {
        expect(t.interpret(t.parse('"a b"'))).toEqual("a b");
      });

      it('should return number atom', function() {
        expect(t.interpret(t.parse('123'))).toEqual(123);
      });
    });

    describe('invocation', function() {
      it('should run print on an int', function() {
        expect(t.interpret(t.parse("(print 1)"))).toEqual(1);
      });

      it('should return first element of list', function() {
        expect(t.interpret(t.parse("(first (1 2 3))"))).toEqual(1);
      });

      it('should return rest of list', function() {
        expect(t.interpret(t.parse("(rest (1 2 3))"))).toEqual([2, 3]);
      });
    });

    describe('lambdas', function() {
      it('should return correct result when invoke lambda w no params', function() {
        expect(t.interpret(t.parse("((lambda () (rest (1 2))))"))).toEqual([2]);
      });

      it('should return correct result for lambda that takes and returns arg', function() {
        expect(t.interpret(t.parse("((lambda (x) x) 1)"))).toEqual(1);
      });

      it('should return correct result for lambda that returns list of vars', function() {
        expect(t.interpret(t.parse("((lambda (x y) (x y)) 1 2)"))).toEqual([1, 2]);
      });

      it('should get correct result for lambda that returns list of lits + vars', function() {
        expect(t.interpret(t.parse("((lambda (x y) (0 x y)) 1 2)"))).toEqual([0, 1, 2]);
      });

      it('should return correct result when invoke lambda w params', function() {
        expect(t.interpret(t.parse("((lambda (x) (first (x))) 1)")))
          .toEqual(1);
      });
    });

    describe('let', function() {
      it('should eval inner expression w names bound', function() {
        expect(t.interpret(t.parse("(let ((x 1) (y 2)) (x y))"))).toEqual([1, 2]);
      });

      it('should not expose parallel bindings to each other', function() {
        // Expecting undefined for y to be consistent with normal
        // identifier resolution in littleLisp.
        expect(t.interpret(t.parse("(let ((x 1) (y x)) (x y))"))).toEqual([1, undefined]);
      });

      it('should accept empty binding list', function() {
        expect(t.interpret(t.parse("(let () 42)"))).toEqual(42);
      });
    });

    describe('if', function() {
      it('should choose the right branch', function() {
        expect(t.interpret(t.parse("(if 1 42 4711)"))).toEqual(42);
        expect(t.interpret(t.parse("(if 0 42 4711)"))).toEqual(4711);
      });
    });
  });
});
<commit_msg>Add test for parsing a single atom.<commit_after>var t = require('./littlelisp').littleLisp;

var is = function(input, type) {
  return Object.prototype.toString.call(input) === '[object ' + type + ']';
};

// takes an AST and replaces type annotated nodes with raw values
var unannotate = function(input) {
  if (is(input, 'Array')) {
    if (input[0] === undefined) {
      return [];
    } else if (is(input[0], 'Array')) {
      return [unannotate(input[0])].concat(unannotate(input.slice(1)));
    } else {
      return unannotate(input[0]).concat(unannotate(input.slice(1)));
    }
  } else {
    return [input.value];
  }
};

describe('littleLisp', function() {
  describe('parse', function() {
    it('should lex a single atom', function() {
      expect(t.parse("a").value).toEqual("a");
    });

    it('should lex an atom in a list', function() {
      expect(unannotate(t.parse("()"))).toEqual([]);
    });

    it('should lex multi atom list', function() {
      expect(unannotate(t.parse("(hi you)"))).toEqual(["hi", "you"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("((x))"))).toEqual([["x"]]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (x))"))).toEqual(["x", ["x"]]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x y)"))).toEqual(["x", "y"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (y) z)"))).toEqual(["x", ["y"], "z"]);
    });

    it('should lex list containing list', function() {
      expect(unannotate(t.parse("(x (y) (a b c))"))).toEqual(["x", ["y"], ["a", "b", "c"]]);
    });

    describe('atoms', function() {
      it('should parse out numbers', function() {
        expect(unannotate(t.parse("(1 (a 2))"))).toEqual([1, ["a", 2]]);
      });
    });
  });

  describe('interpret', function() {
    describe('lists', function() {
      it('should return list of strings', function() {
        expect(t.interpret(t.parse('("hi" "mary" "rose")'))).toEqual(['hi', "mary", "rose"]);
      });

      it('should return list of numbers', function() {
        expect(t.interpret(t.parse('(1 2 3)'))).toEqual([1, 2, 3]);
      });

      it('should return list of numbers in strings as strings', function() {
        expect(t.interpret(t.parse('("1" "2" "3")'))).toEqual(["1", "2", "3"]);
      });
    });

    describe('atoms', function() {
      it('should return string atom', function() {
        expect(t.interpret(t.parse('"a"'))).toEqual("a");
      });

      it('should return string with space atom', function() {
        expect(t.interpret(t.parse('"a b"'))).toEqual("a b");
      });

      it('should return number atom', function() {
        expect(t.interpret(t.parse('123'))).toEqual(123);
      });
    });

    describe('invocation', function() {
      it('should run print on an int', function() {
        expect(t.interpret(t.parse("(print 1)"))).toEqual(1);
      });

      it('should return first element of list', function() {
        expect(t.interpret(t.parse("(first (1 2 3))"))).toEqual(1);
      });

      it('should return rest of list', function() {
        expect(t.interpret(t.parse("(rest (1 2 3))"))).toEqual([2, 3]);
      });
    });

    describe('lambdas', function() {
      it('should return correct result when invoke lambda w no params', function() {
        expect(t.interpret(t.parse("((lambda () (rest (1 2))))"))).toEqual([2]);
      });

      it('should return correct result for lambda that takes and returns arg', function() {
        expect(t.interpret(t.parse("((lambda (x) x) 1)"))).toEqual(1);
      });

      it('should return correct result for lambda that returns list of vars', function() {
        expect(t.interpret(t.parse("((lambda (x y) (x y)) 1 2)"))).toEqual([1, 2]);
      });

      it('should get correct result for lambda that returns list of lits + vars', function() {
        expect(t.interpret(t.parse("((lambda (x y) (0 x y)) 1 2)"))).toEqual([0, 1, 2]);
      });

      it('should return correct result when invoke lambda w params', function() {
        expect(t.interpret(t.parse("((lambda (x) (first (x))) 1)")))
          .toEqual(1);
      });
    });

    describe('let', function() {
      it('should eval inner expression w names bound', function() {
        expect(t.interpret(t.parse("(let ((x 1) (y 2)) (x y))"))).toEqual([1, 2]);
      });

      it('should not expose parallel bindings to each other', function() {
        // Expecting undefined for y to be consistent with normal
        // identifier resolution in littleLisp.
        expect(t.interpret(t.parse("(let ((x 1) (y x)) (x y))"))).toEqual([1, undefined]);
      });

      it('should accept empty binding list', function() {
        expect(t.interpret(t.parse("(let () 42)"))).toEqual(42);
      });
    });

    describe('if', function() {
      it('should choose the right branch', function() {
        expect(t.interpret(t.parse("(if 1 42 4711)"))).toEqual(42);
        expect(t.interpret(t.parse("(if 0 42 4711)"))).toEqual(4711);
      });
    });
  });
});
<|endoftext|>


<commit_before>//parse arguments passed from command line (or more likely, from rails)
var system = require('system');
var args = system.args;
if (args.length <= 1) {
  phantom.exit();
  throw new Error("no arguments supplied on command line");
}//if

//configurable variables - CHANGE ME
var mapID = args[1];
var url = 'http://metamaps.herokuapp.com/maps/' + mapID;
var width = 940;
var height = 630;

//set up page and the area we'll render as a PNG
var page = require('webpage').create();
page.viewportSize = {
  width: width,
  height: height
};

page.open(url, function (status) {
  if (status === 'success') {
    //since this isn't evaluateAsync, it should also ensure the asynchronous
    //js stuff is loaded too, hopefully?

    page.onCallback = function(data){

      //pass to ruby
      console.log(page.renderBase64('PNG'));

      //render to the metamaps_gen002 directory for debug
      //page.render('map1.png', 'PNG');

      phantom.exit();
    };

    page.evaluate(function() {
      $(document).on(Metamaps.JIT.events.animationDone, function(){
        $('.upperLeftUI, .upperRightUI, .mapControls, .infoAndHelp, .uv-icon, .footer').hide();
        Metamaps.JIT.zoomExtents();
        if (typeof window.callPhantom === 'function') {
          window.callPhantom();
        }
      });//document.on animationDone
    });//page.evaluate
  } else {
    //failed to load
    phantom.exit();
  }//if
});
<commit_msg>progress<commit_after>//parse arguments passed from command line (or more likely, from rails)
var system = require('system');
var args = system.args;
if (args.length <= 1) {
  phantom.exit();
  throw new Error("no arguments supplied on command line");
}//if

//configurable variables - CHANGE ME
var mapID = args[1];
var url = 'http://metamaps.herokuapp.com/maps/' + mapID;
var width = 940;
var height = 630;

//set up page and the area we'll render as a PNG
var page = require('webpage').create();
page.viewportSize = {
  width: width,
  height: height
};

page.open(url, function (status) {
  if (status === 'success') {
    //since this isn't evaluateAsync, it should also ensure the asynchronous
    //js stuff is loaded too, hopefully?

    page.onCallback = function(data){

      //pass to ruby
      console.log(page.renderBase64('PNG'));

      //render to the metamaps_gen002 directory for debug
      //page.render('map1.png', 'PNG');

      phantom.exit();
    };

    page.evaluate(function() {

      $(document).ready(function () {
          //$(document).on(Metamaps.JIT.events.animationDone, function() {
          setTimeout(function(){
            $('.upperLeftUI, .upperRightUI, .mapControls, .infoAndHelp, .uv-icon, .footer').hide();
            Metamaps.JIT.zoomExtents();
            window.callPhantom();
          }, 5000);
      });

    });//page.evaluate

  } else {
    //failed to load
    phantom.exit();
  }//if
});
<|endoftext|>