<commit_before>// Post requests

var json_parser = function () {
	this.parsed = [];
	this.time_stamp = {
		start_time: Date.now(),
		end_time: 0
	}
	var frame_init = 0;
	var index = 0;
	this.post_partial = async function (exp_id, game, data) {
		var frame_last = game.time;
		var partial = JSON.stringify(game.gameStates.slice(frame_init, frame_last));
		frame_init = frame_last;

		var steps = game.steps
		var last_state = game.gameStates.length;
		var win = game.gameStates[last_state-1].win;
		var score = game.gameStates[last_state-1].score;
		$.ajax({
			type: 'PUT',
			url: "/experiment/"+exp_id,
			data: {timeStamp: JSON.stringify(this.time_stamp),
			 	   gameStates: partial,
			 	   index: index,
			 	   score: score,
			 	   win: win,
			 	   steps: steps,
			 	   data: data},
			success: function (status) {
				if (!status.success) {
					console.log('could not put experiment');
				}
			},
		})
		index ++;
	}
}

var next_experiment = function (exp_id, game, parser, data, callback) {
	$('body').addClass('loading')
	if (exp_id == '0') {
		callback();
		return;
	}
	$.ajax({
		type: 'POST',
		url: '/experiment/'+exp_id+'/next',
		data: data,
		success: function (status) {
			if (status.success) {
				callback();
			}
		}
	})
	// post_experiment(exp_id, game, parser, data, 'next', callback);
}

var retry_experiment = function (exp_id, game, parser, data, callback) {
	$('body').addClass('loading')
	if (exp_id == '0') {
		callback();
		return;
	}
	$.ajax({
		type: 'POST',
		url: '/experiment/'+exp_id+'/retry',
		success: function (status) {
			if (status.success) {
				callback();
			}
		}
	})
	// post_experiment(exp_id, game, parser, data, 'retry', callback);
}

/**
 * @fileoverview
 * Draw lines, polygons, circles, etc on the screen.
 * Render text in a certain font to the screen.
 */

var gamejs = require('gamejs');;
var vgdl_parser = VGDLParser(gamejs);
var game = vgdl_parser.playGame(vgdl_game.game, vgdl_game.level, color_scheme);
// var on_game_end = function () {
// }
// game.paused = false;
// gamejs.ready(game.run(on_game_end));
// console.log('game started');

var interval;
var parser;

var retry_game = function () {
	window.location.reload();
}

var continue_game = function () {
	next_experiment(exp_id, game, parser, data, function () {
		window.location.href = `/experiment/${exp_id}`
	});
}

var page_refresh = function () {
	game.paused = true;
	if (game.win === null) {
		retry_experiment(exp_id, game, parser, data, function () {
			console.log('game refreshed');
		})
	}
}

$(document).on('click', '#forfeit', function () {
	next_experiment(exp_id, game, parser, data, function () {
		location.reload();
	})
})

$(document).on('click', '#continue', continue_game);

$(document).on('click', '#return', function () {
	window.location.href = '/admin';
})
$(document).on('click', '#retry', retry_game);

$(document).on('click', '#pause', function () {
	game.paused = !game.paused;
})
$(window).bind('beforeunload', page_refresh);

$(document).ready(function () {

	var cont_button = $('<button id="continue">Continue</button>');
	var return_button = $('<button id="return">Return</button>');

	var forfeit_div = $('

')
	var forfeit_text = $('
If you want to forfeit the entire level and try a new one, press "Forfeit".
');
	var forfeit_button = $('<button id="forfeit">Forfeit</button>');

	var retry_container = $('

');
	var retry_text = $('
If you get stuck, you can press "Retry" to reset this level.
')
	var retry_button = $('<button id="retry">Retry</button>')
	retry_container.append(retry_text)
	retry_container.append(retry_button)

	forfeit_div.append(forfeit_text);
	forfeit_div.append(forfeit_button);

	var end_game_delay = 1000;
	var retry_delay = 40000;
	// var forfeit_delay = 60000*2;
	var ended = false;

	var on_game_end = function () {

		clearInterval(interval);
		game.paused = true;
		ended = true
		$('#retry-div').remove()
		var show_status = function () {
			var status_text = '';
			if (game.win) {
				var container = $('

');
				if (exp_id != '0') {
					var button = cont_button;
				} else {
					var button = return_button;
				}
			}
			else {
				var container = retry_container;
				var button = retry_button;
			}

			container.append(button);
			$('body').append(container)
			$('#forfeit-div').remove();
			$('#retry-text').remove();
		}

		if (game.win) {
			$('#title').text('Game Won!')
			show_status()

		} else {
			$('#title').text('Game Lost!')
			window.setTimeout(show_status, end_game_delay);
		}
		parser.post_partial(exp_id, game, data);
	}

	var begin_game = function () {
		parser = new json_parser();
		interval = window.setInterval(function(){
		  parser.post_partial(exp_id, game, data)
		}, 1000);

		$('#start-div').remove();
		game.paused = false;
		window.setTimeout(function () {
			if (!ended)
				$('body').append(retry_container)
		}, retry_delay);
		console.log(data.round);
		if (data.round >= 3) {
			$('body').append(forfeit_div);
		}
		// window.setTimeout(function () {
		// 	if (!ended)
		// 		$('#retry-div').append(forfeit_div);
		// }, forfeit_delay);
	}

	$('#gjs-canvas').focus();
	$('#start').click(begin_game)

	// start_modal.style.display = 'none';
	// game.paused = true;
	gamejs.ready(game.run(on_game_end));

	begin_game();

});

// // gamejs.ready will call your main function
// // once all components and resources are ready.
// gamejs.ready(main);
<commit_msg>now there's enough time to win<commit_after>// Post requests

var json_parser = function () {
	this.parsed = [];
	this.time_stamp = {
		start_time: Date.now(),
		end_time: 0
	}
	var frame_init = 0;
	var index = 0;
	this.post_partial = async function (exp_id, game, data) {
		var frame_last = game.time;
		var partial = JSON.stringify(game.gameStates.slice(frame_init, frame_last));
		frame_init = frame_last;

		var steps = game.steps
		var last_state = game.gameStates.length;
		var win = game.gameStates[last_state-1].win;
		var score = game.gameStates[last_state-1].score;
		$.ajax({
			type: 'PUT',
			url: "/experiment/"+exp_id,
			data: {timeStamp: JSON.stringify(this.time_stamp),
			 	   gameStates: partial,
			 	   index: index,
			 	   score: score,
			 	   win: win,
			 	   steps: steps,
			 	   data: data},
			success: function (status) {
				if (!status.success) {
					console.log('could not put experiment');
				}
			},
		})
		index ++;
	}
}

var next_experiment = function (exp_id, game, parser, data, callback) {
	$('body').addClass('loading')
	if (exp_id == '0') {
		callback();
		return;
	}
	$.ajax({
		type: 'POST',
		url: '/experiment/'+exp_id+'/next',
		data: data,
		success: function (status) {
			if (status.success) {
				callback();
			}
		}
	})
	// post_experiment(exp_id, game, parser, data, 'next', callback);
}

var retry_experiment = function (exp_id, game, parser, data, callback) {
	$('body').addClass('loading')
	if (exp_id == '0') {
		callback();
		return;
	}
	$.ajax({
		type: 'POST',
		url: '/experiment/'+exp_id+'/retry',
		success: function (status) {
			if (status.success) {
				callback();
			}
		}
	})
	// post_experiment(exp_id, game, parser, data, 'retry', callback);
}

/**
 * @fileoverview
 * Draw lines, polygons, circles, etc on the screen.
 * Render text in a certain font to the screen.
 */

var gamejs = require('gamejs');;
var vgdl_parser = VGDLParser(gamejs);
var game = vgdl_parser.playGame(vgdl_game.game, vgdl_game.level, color_scheme);
// var on_game_end = function () {
// }
// game.paused = false;
// gamejs.ready(game.run(on_game_end));
// console.log('game started');

var interval;
var parser;

var retry_game = function () {
	window.location.reload();
}

var continue_game = function () {
	next_experiment(exp_id, game, parser, data, function () {
		window.location.href = `/experiment/${exp_id}`
	});
}

var page_refresh = function () {
	game.paused = true;
	if (game.win === null) {
		retry_experiment(exp_id, game, parser, data, function () {
			console.log('game refreshed');
		})
	}
}

$(document).on('click', '#forfeit', function () {
	next_experiment(exp_id, game, parser, data, function () {
		location.reload();
	})
})

$(document).on('click', '#continue', continue_game);

$(document).on('click', '#return', function () {
	window.location.href = '/admin';
})
$(document).on('click', '#retry', retry_game);

$(document).on('click', '#pause', function () {
	game.paused = !game.paused;
})
$(window).bind('beforeunload', page_refresh);

$(document).ready(function () {

	var cont_button = $('<button id="continue">Continue</button>');
	var return_button = $('<button id="return">Return</button>');

	var forfeit_div = $('

')
	var forfeit_text = $('
If you want to forfeit the entire level and try a new one, press "Forfeit".
');
	var forfeit_button = $('<button id="forfeit">Forfeit</button>');

	var retry_container = $('

');
	var retry_text = $('
If you get stuck, you can press "Retry" to reset this level.
')
	var retry_button = $('<button id="retry">Retry</button>')
	retry_container.append(retry_text)
	retry_container.append(retry_button)

	forfeit_div.append(forfeit_text);
	forfeit_div.append(forfeit_button);

	var end_game_delay = 1000;
	var retry_delay = 60000;
	// var forfeit_delay = 60000*2;
	var ended = false;

	var on_game_end = function () {

		clearInterval(interval);
		game.paused = true;
		ended = true
		$('#retry-div').remove()
		var show_status = function () {
			var status_text = '';
			if (game.win) {
				var container = $('

');
				if (exp_id != '0') {
					var button = cont_button;
				} else {
					var button = return_button;
				}
			}
			else {
				var container = retry_container;
				var button = retry_button;
			}

			container.append(button);
			$('body').append(container)
			$('#forfeit-div').remove();
			$('#retry-text').remove();
		}

		if (game.win) {
			$('#title').text('Game Won!')
			show_status()

		} else {
			$('#title').text('Game Lost!')
			window.setTimeout(show_status, end_game_delay);
		}
		parser.post_partial(exp_id, game, data);
	}

	var begin_game = function () {
		parser = new json_parser();
		interval = window.setInterval(function(){
		  parser.post_partial(exp_id, game, data)
		}, 1000);

		$('#start-div').remove();
		game.paused = false;
		window.setTimeout(function () {
			if (!ended)
				$('body').append(retry_container)
		}, retry_delay);
		console.log(data.round);
		if (data.round >= 3) {
			$('body').append(forfeit_div);
		}
		// window.setTimeout(function () {
		// 	if (!ended)
		// 		$('#retry-div').append(forfeit_div);
		// }, forfeit_delay);
	}

	$('#gjs-canvas').focus();
	$('#start').click(begin_game)

	// start_modal.style.display = 'none';
	// game.paused = true;
	gamejs.ready(game.run(on_game_end));

	begin_game();

});

// // gamejs.ready will call your main function
// // once all components and resources are ready.
// gamejs.ready(main);
<|endoftext|>


<commit_before>/**
 * Created by yangm11 on 4/7/2017.
 */
'use strict';

// generate a list of numbers
function range(n) {
  let result = [];
  for (let i = 0; i < n; i++) {
    result.push(i);
  }
  return result;
}

// get one item from an array randomly
function sample(arr, n) {
  n = typeof n === 'undefined' ? 1 : n;
  if (typeof n !== 'number') {
    throw new Error('The second parameter should be number!');
  }
  var t;
  if (n === 1) {
    t = Math.floor(arr.length * Math.random());
    return arr[t];
  } else if (n > 1 && n < arr.length) {
    let idxList = [];
    do {
      t = Math.floor(arr.length * Math.random());
      if (idxList.indexOf(t) === -1) {
        idxList.push(t);
      }
    } while (idxList.length < n);
    let result = [];
    for (let i = 0; i < n; i++) {
      result.push(arr[idxList[i]]);
    }
    return result;
  } else {
    throw new Error('Out of range!');
  }
}

// shuffle an array
function shuffle(arr) {
  var result = [];
  var len = arr.length;
  var cp = arr.slice();
  for (var i = 0; i < len; i++) {
    var idx = Math.floor(cp.length * Math.random());
    result.push(cp.splice(idx, 1)[0]);
  }
  return result;
}

// console.log(shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]));

function findUnique(arr) {
  let uniq = [];
  let dupl = [];

  for (let i = 0; i < arr.length; i++) {
    let elem = arr[i];
    let count = 1;
    for (let j = i + 1; j < arr.length - 1; j++) {
      if (elem === arr[j]) {
        count += 1;
      }
    }
    if (count === 1) {
      uniq.push(elem);
    } else {
      dupl.push({
        elem: elem,
        count: count
      });
    }
  }
  return {
    unique: uniq,
    duplicate: dupl
  };
}

function sum(arr) {
  let s = 0;
  for (let i = 0; i < arr.length; i++) {
    s += arr[i];
  }
  return typeof s === 'number' ? s : NaN;
}

function mean(arr) {
  return sum(arr) / arr.length;
}

function median(arr) {
  // for (let i = 0; i < arr.length; i++) {
  //   if (typeof arr[i] !== 'number') {
  //     throw new Error('All must be numbers!');
  //   }
  // }
  let cp = arr.slice();
  cp.sort((a, b) => a - b );
  let m = cp.length;
  return m % 2 ? cp[(m - 1) / 2] : (cp[m / 2 - 1] + cp[m / 2]) / 2;
}

function max(arr) {
  let m = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (m < arr[i]) {
      m = arr[i];
    }
  }
  return m;
}

function min(arr) {
  let m = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (m > arr[i]) {
      m = arr[i];
    }
  }
  return m;
}

function variance(arr) {
  let u = mean(arr);
  // let na = arr.map((d) => (d - u) * (d - u));
  let s = 0;
  let c;
  for (let i = 0; i < arr.length; i++) {
    c = arr[i];
    s += (c - u) * (c - u);
  }
  return {
    pV: s / arr.length,
    sV: s / (arr.length - 1)
  };
}

// import * from 'tdArray'

let a = [1, 6, 4, 3, 7, 2, 8, 30, 50, 9, 10, 5, 60];
// console.log(a.length);
// console.log(median(a));
// console.log(mean(a));
// console.log(a.slice().sort((a, b) => a - b));
// console.log(a.filter((d) => d < 5));
// console.log(a.filter((d) => d > 5));
// console.log(max(a));
// console.log(min(a));
// console.log(sum(a));
// console.log(shuffle(a));

// const request = require('request');
// const fs = require('fs');
// let url = 'https://raw.githubusercontent.com/genomicsclass/dagdata/master/inst/extdata/femaleControlsPopulation.csv';
// request(url).pipe(fs.createWriteStream('femaleControlPopulation.csv'));
// let csv = fs.readFileSync('femaleControlPopulation.csv', 'utf8');
// csv = csv.split('\n');
// csv = csv.slice(1).map((d) => +d.trim());
// // console.log(csv);
// let start = Date.now();
// let nu = [];
// for (let i = 0; i < 10000; i++) {
//   nu.push(mean(sample(csv, 12)) - mean(sample(csv, 12)));
// }
// console.log(mean(nu));
// console.log(Date.now() - start);

if (typeof module) {
  if (module.parent) {
    module.exports = {
      max: max,
      min: min,
      mean: mean,
      median: median,
      sum: sum,
      sample: sample,
      shuffle: shuffle,
      unique: findUnique
    }
  }
} else if (typeof window) {
  console.log('Running in browser!');
}<commit_msg>stats.js bugfix for find unique elements<commit_after>/**
 * Created by yangm11 on 4/7/2017.
 */
'use strict';

// generate a list of numbers
const range = function (n) {
  let result = [];
  for (let i = 0; i < n; i++) {
    result.push(i);
  }
  return result;
};

// get one item from an array randomly
const sample = function (arr, n) {
  n = typeof n === 'undefined' ? 1 : n;
  if (typeof n !== 'number') {
    throw new Error('The second parameter should be number!');
  }
  var t;
  if (n === 1) {
    t = Math.floor(arr.length * Math.random());
    return arr[t];
  } else if (n > 1 && n < arr.length) {
    let idxList = [];
    do {
      t = Math.floor(arr.length * Math.random());
      if (idxList.indexOf(t) === -1) {
        idxList.push(t);
      }
    } while (idxList.length < n);
    let result = [];
    for (let i = 0; i < n; i++) {
      result.push(arr[idxList[i]]);
    }
    return result;
  } else {
    throw new Error('Out of range!');
  }
};

// shuffle an array
const shuffle = function (arr) {
  var result = [];
  var len = arr.length;
  var cp = arr.slice();
  for (var i = 0; i < len; i++) {
    var idx = Math.floor(cp.length * Math.random());
    result.push(cp.splice(idx, 1)[0]);
  }
  return result;
};

// console.log(shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]));

const findUnique = function (arr) {
  let uniq = [];
  let dupl = [];

  for (let i = 0; i < arr.length; i++) {
    let elem = arr[i];
    if (dupl.find(d => d.elem === elem)) {
      continue;
    }
    let count = 1;
    for (let j = i + 1; j < arr.length; j++) {
      if (elem === arr[j]) {
        count += 1;
      }
    }
    if (count === 1) {
      uniq.push(elem);
    } else {
      dupl.push({
        elem: elem,
        count: count
      });
    }
  }
  return {
    unique: uniq,
    duplicate: dupl
  };
};

const sum = function (arr) {
  let s = 0;
  for (let i = 0; i < arr.length; i++) {
    s += arr[i];
  }
  return typeof s === 'number' ? s : NaN;
};

const mean = function (arr) {
  return sum(arr) / arr.length;
};

const median = function (arr) {
  // for (let i = 0; i < arr.length; i++) {
  //   if (typeof arr[i] !== 'number') {
  //     throw new Error('All must be numbers!');
  //   }
  // }
  let cp = arr.slice();
  cp.sort((a, b) => a - b );
  let m = cp.length;
  return m % 2 ? cp[(m - 1) / 2] : (cp[m / 2 - 1] + cp[m / 2]) / 2;
};

const max = function (arr) {
  let m = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (m < arr[i]) {
      m = arr[i];
    }
  }
  return m;
};

const min = function (arr) {
  let m = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (m > arr[i]) {
      m = arr[i];
    }
  }
  return m;
};

const arithmetic = function (sign, arr1, arr2) {
  if (typeof arr2 === 'number') {
    let t = arr2;
    arr2 = arr1.map(d => t);
  }
  if (arr1.length !== arr2.length) {
    throw new Error('The two arrays should be of the same length.');
  }
  if (typeof sign === 'string') {
    switch (sign) {
      case '+':
        return arr1.map((d, i) => d + arr2[i]);
      case '-':
        return arr1.map((d, i) => d - arr2[i]);
      case '*':
        return arr1.map((d, i) => d * arr2[i]);
      case '/':
        return arr1.map((d, i) => d / arr2[i]);
      case '%':
        return arr1.map((d, i) => d % arr2[i]);
      case '//':
        return arr1.map((d, i) => Math.floor(d / arr2[i]));
      case '^':
        return arr1.map((d, i) => Math.pow(d, arr2[i]));
      default:
        throw new Error('The sign is not supported.');
    }
  } else if (typeof sign === 'function') {
    return arr1.map((d, i) => sign(d, arr2[i]));
  } else {
    throw new Error('The first parameter should be a sign of arithmetic' +
      ' operator or function.');
  }
};

const variance = function (arr) {
  let u = mean(arr);
  // let na = arr.map((d) => (d - u) * (d - u));
  let s = 0;
  let c;
  for (let i = 0; i < arr.length; i++) {
    c = arr[i];
    s += (c - u) * (c - u);
  }
  return {
    pV: s / arr.length,
    sV: s / (arr.length - 1)
  };
};

// import * from 'tdArray'

let a = [1, 6, 4, 3, 7, 2, 8, 3, 5, 9, 10, 5, 5];
// console.log(a.length);
// console.log(median(a));
// console.log(mean(a));
// console.log(a.slice().sort((a, b) => a - b));
// console.log(a.filter((d) => d < 5));
// console.log(a.filter((d) => d > 5));
// console.log(max(a));
// console.log(min(a));
// console.log(sum(a));
// console.log(shuffle(a));
// console.log(arithmetic((d1, d2) => d1*d1 + d2*d2, a, 5));
// console.log(arithmetic('^', a, 3));
// console.log(variance(a));
// console.log(findUnique(a));

// const request = require('request');
// const fs = require('fs');
// let url = 'https://raw.githubusercontent.com/genomicsclass/dagdata/master/inst/extdata/femaleControlsPopulation.csv';
// request(url).pipe(fs.createWriteStream('femaleControlPopulation.csv'));
// let csv = fs.readFileSync('femaleControlPopulation.csv', 'utf8');
// csv = csv.split('\n');
// csv = csv.slice(1).map((d) => +d.trim());
// // console.log(csv);
// let start = Date.now();
// let nu = [];
// for (let i = 0; i < 10000; i++) {
//   nu.push(mean(sample(csv, 12)) - mean(sample(csv, 12)));
// }
// console.log(mean(nu));
// console.log(Date.now() - start);

if (typeof module !== 'undefined') {
  if (module.parent) {
    module.exports = {
      max: max,
      min: min,
      mean: mean,
      median: median,
      sum: sum,
      sample: sample,
      shuffle: shuffle,
      unique: findUnique,
      arithmetic: arithmetic
    }
  }
} else if (typeof window !== 'undefined') {
  console.log('Running in browser!');
}<|endoftext|>


<commit_before>/**
 * corridor.js
 */
(function(window, document, undefined){
'use strict';

var

  slice = Array.prototype.slice,
  toString = Object.prototype.toString,

  /**
   * Internal logging function.
   * Will only have side-effects if corridor.log has been set to something.
   * Ex: corridor.log = true; // enables internal corridor debug logging
   * If corridor.log is set to a function, it will be called
   */
  log = function() {
    if (typeof corridor.log === 'function') {
      return corridor.log.apply(null, arguments)
    } else if (corridor.log) {
      return console.log.apply(console, arguments);
    }
  },

  /**
   * Extract data from DOM or insert values back into it.
   * @param {HTMLElement} elem The element to scan for data (defaults to document)
   * @param {mixed} data The data to insert (optional)
   */
  corridor = window['corridor'] = function(elem, data) {
    elem = elem || document;
    return data ? insert(elem, data) : extract(elem);
  },

  /**
   * Extract data from DOM values under the specified element.
   * @param {HTMLElement} root The root element to scan for data.
   */
  extract = corridor.extract = function(root) {

    var

      data = {},

      fields =
        slice.call(root.querySelectorAll('[data-field]'))
        .filter(function(elem) {
          var enabled = true;
          upwalk(elem.parentNode, root, function(parent, field, opts) {
            if (opts.role === 'toggleable' && !toggled(parent)) {
              enabled = false;
              return false; // short-circuit upwalk();
            }
          });
          return enabled;
        });

    fields.forEach(function(elem) {

      var
        opts = options(elem, defaults),
        value = val(elem);

      if (opts.type === 'boolean') {
        value = !!value;
      } else if (opts.type === 'number') {
        value = parseFloat(value);
      } else if (opts.type === 'list') {
        value = parseList(value);
      }

      if (opts.type === 'json') {
        throw Error('JSON processing not yet implemented.');
      } else {
        value = JSON.stringify(value);
      }

      upwalk(elem, root, function(elem, field, opts) {
        if (field !== undefined) {
          value = field.replace('$$$', value);
        }
      });
      log(value);
    });

  },

  /**
   * Insert data into the DOM under the specified element from provided data.
   * @param {HTMLElement} elem The element to scan for data.
   * @param {mixed} data The data to insert.
   */
  insert = corridor.insert = function(elem, data) {

    var

      fields = elem.querySelectorAll('[data-field]');

    console.log(fields);

  },

  /**
   * Default values applied to data-opts.
   */
  defaults = corridor.defaults = {

    /**
     * If the field has a falsey value, this option determines whether it still contributes to the output.
     * Recognized choices are:
     *  - omit - do not add the field at all (default)
     *  - include - include the value in the output
     */
    empty: "omit",

    /**
     * The role that this element plays in corridor operations.
     * Recognized choices are:
     *  - field - this element is a field whose value will contribute to extracted data (default)
     *  - toggleable - this element contains fields and may be toggled on or off
     *  - toggle - this element is a checkbox which toggles its nearest parent toggleable
     */
    role: "field",

    /**
     * The kind of field this is.
     * Recognized choices are:
     *  - string - treate the value as a string (default)
     *  - boolean - coerce this value to something true/false
     *  - number - parse this value as a number
     *  - json - leave this value as-is (will choke if it's not actually valid JSON)
     *  - list - parse this value as a list of values
     */
    type: "string"

  },

  /**
   * Visit each corridor ancestor element up from the specified starting node.
   * An element is a corridor element if it has a data-field or data-opts attribute.
   *
   * The provided starting element is visited first.
   * If this isn't desired, send elem.parentNode to upwalk instead.
   *
   * @param {HTMLElement} elem The element to start from.
   * @param {HTMLElement} root Element to stop on / topmost element (may be null).
   * @param {function} callback Function to invoke with each parent.
   * Callback will be passed three parameters:
   *  - elem - The ancestor element,
   *  - field - The string value of the data-field attribute (or undefined)
   *  - opts - Object of options (always an object, may have no keys)
   * If the callback returns boolean false, no further ancestors will be visited.
   *
   * @return {boolean} False if the callback ever returned false, otherwise true.
   */
  upwalk = corridor.upwalk = function(elem, root, callback) {
    var field, opts, res;
    while (elem !== null && elem.getAttribute) {
      if (elem.hasAttribute('data-field') || elem.hasAttribute('data-opts')) {
        field = elem.getAttribute('data-field') || undefined;
        opts = options(elem, defaults);
        res = callback(elem, field, opts);
        if (res === false) {
          return false;
        }
      }
      elem = (elem === root) ? null : elem.parentNode;
    }
    return true;
  },

  /**
   * Parse a given string as a list of items.
   * By default, parseList() makes a best guess for the separator between items.
   * But you can explicitly specify a separator in the options.
   *
   * @param {string} text The text to parse.
   * @param {object} opts Additional parsing options (optional).
   *  - separator - string or regex used for splitting the text
   *  - trim - true or false, determines whether values are whitespace chomped
   */
  parseList = corridor.parseList = function(text, opts) {
    if (!text) {
      return [];
    }
    opts = opts || {};
    var sep =
      opts.separator ? opts.separator :      // prefer specified separator
      text.indexOf("\n") !== -1 ? /\r?\n/ :  // use line breaks if there are any
      text.indexOf(",") !== -1 ? ',' :       // or use commas if there are any
      /\s+/;                                 // last resort - any whitespace
    if (!('trim' in opts) || opts.trim) {
      return text.split(sep).map(function(part) {
        return part.replace(/^\s+|\s+$/g, '');
      });
    }
    return text.split(sep);
  },

  /**
   * Given a toggleable element, find out if it's toggled off.
   * A toggleable element is an element with "role" set to "toggleable" in its data-opts.
   * It's is toggled value is taken from its nearest child with "role" set to "toggle" is checked.
   *
   * @param {HTMLElement} elem The element to check.
   * @return {mixed} The value of the nearest descendent with "role" set to "toggle".
   */
  toggled = corridor.toggled = function(elem) {

    var

      // find all the candidate "toggle" elements.
      // to be a candidate, the descendent's nearest parent "toggleable" must be elem.
      candidates = slice.call(elem.querySelectorAll('[data-opts]'))
        .filter(function(child){
          if (options(child).role !== 'toggle') {
            return false;
          }
          var found = false;
          upwalk(child.parentNode, elem, function(parent, field, opts) {
            if (opts.role === 'toggleable') {
              found = (parent === elem);
              return false; // short-circuit upwalk()
            }
          });
          return found;
        });

    if (!candidates.length) {
      throw Error('No child "toggle" element found for toggelable.');
    }

    if (candidates.length > 1) {
      throw Error('Multiple "toggle" elements have been found for toggleable.');
    }

    return val(candidates[0]);

  },

  /**
   * Get the options for a given element know to have a data-opts attribute.
   * @param {HTMLElement} elem The element to inspect.
   * @param {mixed} defs Optional defaults object to start from.
   */
  options = corridor.options = function(elem, defs) {
    return extend({}, defs || {}, JSON.parse(elem.getAttribute('data-opts') || '{}'));
  },

  /**
   * Get or set the value of the specified DOM element.
   * @param {HTMLElement} elem The element whose value is to be determined or set.
   * @param {mixed} value The value to set (optional).
   */
  val = corridor.val = function(elem, value) {
    if (value === undefined) {
      return getVal(elem);
    }
    return setVal(elem, value);
  },

  /**
   * Get the value of the specified DOM element.
   * @param {HTMLElement} elem The element whose value is to be determined.
   */
  getVal = val.getVal = function(elem) {

    var
      tag = elem.tagName.toLowerCase(),
      type = (tag === 'input') ? elem.getAttribute('type') || 'text' : tag,
      miss = {},
      val = (
        type === 'checkbox' ? elem.checked :
        type === 'text' ? elem.value :
        type === 'textarea' ? elem.value :
        miss
      );

    if (val === miss) {
      throw Error("There is no known way to extract a value from the specified element.");
    }

    return val;
  },

  /**
   * Set the value of the specified DOM element to the provided value.
   * @param {HTMLElement} elem The element whose value is to be set.
   * @param {mixed} value The value to set (optional).
   */
  setVal = val.setVal = function(elem, value) {
    elem.value = value;
  },

  /**
   * Copy properties from one or more objects onto a target.
   */
  extend = corridor.extend = function(obj /* arg1, arg2, ... argN */) {
    var i, ii, arg, k;
    for (i = 1, ii = arguments.length; i < ii; i++) {
      arg = arguments[i];
      for (k in arg) {
        if (arg.hasOwnProperty(k)) {
          obj[k] = arg[k];
        }
      }
    }
    return obj;
  };

})(window, document);
<commit_msg>adding deep merge function and some rudimentary unit tests<commit_after>/**
 * corridor.js
 */
(function(window, document, undefined){
'use strict';

var

  slice = Array.prototype.slice,
  toString = Object.prototype.toString,

  /**
   * Internal logging function.
   * Will only have side-effects if corridor.log has been set to something.
   * Ex: corridor.log = true; // enables internal corridor debug logging
   * If corridor.log is set to a function, it will be called
   */
  log = function() {
    if (typeof corridor.log === 'function') {
      return corridor.log.apply(null, arguments)
    } else if (corridor.log) {
      return console.log.apply(console, arguments);
    }
  },

  /**
   * Extract data from DOM or insert values back into it.
   * @param {HTMLElement} elem The element to scan for data (defaults to document)
   * @param {mixed} data The data to insert (optional)
   */
  corridor = window['corridor'] = function(elem, data) {
    elem = elem || document;
    return data ? insert(elem, data) : extract(elem);
  },

  /**
   * Extract data from DOM values under the specified element.
   * @param {HTMLElement} root The root element to scan for data.
   */
  extract = corridor.extract = function(root) {

    var

      data = {},

      fields =
        slice.call(root.querySelectorAll('[data-field]'))
        .filter(function(elem) {
          var enabled = true;
          upwalk(elem.parentNode, root, function(parent, field, opts) {
            if (opts.role === 'toggleable' && !toggled(parent)) {
              enabled = false;
              return false; // short-circuit upwalk();
            }
          });
          return enabled;
        });

    fields.forEach(function(elem) {

      var
        opts = options(elem, defaults),
        value = val(elem);

      if (opts.type === 'boolean') {
        value = !!value;
      } else if (opts.type === 'number') {
        value = parseFloat(value);
      } else if (opts.type === 'list') {
        value = parseList(value);
      }

      if (opts.type === 'json') {
        throw Error('JSON processing not yet implemented.');
      } else {
        value = JSON.stringify(value);
      }

      upwalk(elem, root, function(elem, field, opts) {
        if (field !== undefined) {
          value = field.replace('$$$', value);
        }
      });

      // TODO: deep merge value into data

    });

  },

  /**
   * Insert data into the DOM under the specified element from provided data.
   * @param {HTMLElement} elem The element to scan for data.
   * @param {mixed} data The data to insert.
   */
  insert = corridor.insert = function(elem, data) {

    var

      fields = elem.querySelectorAll('[data-field]');

    console.log(fields);

  },

  /**
   * Default values applied to data-opts.
   */
  defaults = corridor.defaults = {

    /**
     * If the field has a falsey value, this option determines whether it still contributes to the output.
     * Recognized choices are:
     *  - omit - do not add the field at all (default)
     *  - include - include the value in the output
     */
    empty: "omit",

    /**
     * The role that this element plays in corridor operations.
     * Recognized choices are:
     *  - field - this element is a field whose value will contribute to extracted data (default)
     *  - toggleable - this element contains fields and may be toggled on or off
     *  - toggle - this element is a checkbox which toggles its nearest parent toggleable
     */
    role: "field",

    /**
     * The kind of field this is.
     * Recognized choices are:
     *  - string - treate the value as a string (default)
     *  - boolean - coerce this value to something true/false
     *  - number - parse this value as a number
     *  - json - leave this value as-is (will choke if it's not actually valid JSON)
     *  - list - parse this value as a list of values
     */
    type: "string"

  },

  /**
   * Visit each corridor ancestor element up from the specified starting node.
   * An element is a corridor element if it has a data-field or data-opts attribute.
   *
   * The provided starting element is visited first.
   * If this isn't desired, send elem.parentNode to upwalk instead.
   *
   * @param {HTMLElement} elem The element to start from.
   * @param {HTMLElement} root Element to stop on / topmost element (may be null).
   * @param {function} callback Function to invoke with each parent.
   * Callback will be passed three parameters:
   *  - elem - The ancestor element,
   *  - field - The string value of the data-field attribute (or undefined)
   *  - opts - Object of options (always an object, may have no keys)
   * If the callback returns boolean false, no further ancestors will be visited.
   *
   * @return {boolean} False if the callback ever returned false, otherwise true.
   */
  upwalk = corridor.upwalk = function(elem, root, callback) {
    var field, opts, res;
    while (elem !== null && elem.getAttribute) {
      if (elem.hasAttribute('data-field') || elem.hasAttribute('data-opts')) {
        field = elem.getAttribute('data-field') || undefined;
        opts = options(elem, defaults);
        res = callback(elem, field, opts);
        if (res === false) {
          return false;
        }
      }
      elem = (elem === root) ? null : elem.parentNode;
    }
    return true;
  },

  /**
   * Parse a given string as a list of items.
   * By default, parseList() makes a best guess for the separator between items.
   * But you can explicitly specify a separator in the options.
   *
   * @param {string} text The text to parse.
   * @param {object} opts Additional parsing options (optional).
   *  - separator - string or regex used for splitting the text
   *  - trim - true or false, determines whether values are whitespace chomped
   */
  parseList = corridor.parseList = function(text, opts) {
    if (!text) {
      return [];
    }
    opts = opts || {};
    var sep =
      opts.separator ? opts.separator :      // prefer specified separator
      text.indexOf("\n") !== -1 ? /\r?\n/ :  // use line breaks if there are any
      text.indexOf(",") !== -1 ? ',' :       // or use commas if there are any
      /\s+/;                                 // last resort - any whitespace
    if (!('trim' in opts) || opts.trim) {
      return text.split(sep).map(function(part) {
        return part.replace(/^\s+|\s+$/g, '');
      });
    }
    return text.split(sep);
  },

  /**
   * Given a toggleable element, find out if it's toggled off.
   * A toggleable element is an element with "role" set to "toggleable" in its data-opts.
   * It's is toggled value is taken from its nearest child with "role" set to "toggle" is checked.
   *
   * @param {HTMLElement} elem The element to check.
   * @return {mixed} The value of the nearest descendent with "role" set to "toggle".
   */
  toggled = corridor.toggled = function(elem) {

    var

      // find all the candidate "toggle" elements.
      // to be a candidate, the descendent's nearest parent "toggleable" must be elem.
      candidates = slice.call(elem.querySelectorAll('[data-opts]'))
        .filter(function(child){
          if (options(child).role !== 'toggle') {
            return false;
          }
          var found = false;
          upwalk(child.parentNode, elem, function(parent, field, opts) {
            if (opts.role === 'toggleable') {
              found = (parent === elem);
              return false; // short-circuit upwalk()
            }
          });
          return found;
        });

    if (!candidates.length) {
      throw Error('No child "toggle" element found for toggelable.');
    }

    if (candidates.length > 1) {
      throw Error('Multiple "toggle" elements have been found for toggleable.');
    }

    return val(candidates[0]);

  },

  /**
   * Get the options for a given element know to have a data-opts attribute.
   * @param {HTMLElement} elem The element to inspect.
   * @param {mixed} defs Optional defaults object to start from.
   */
  options = corridor.options = function(elem, defs) {
    return extend({}, defs || {}, JSON.parse(elem.getAttribute('data-opts') || '{}'));
  },

  /**
   * Get or set the value of the specified DOM element.
   * @param {HTMLElement} elem The element whose value is to be determined or set.
   * @param {mixed} value The value to set (optional).
   */
  val = corridor.val = function(elem, value) {
    if (value === undefined) {
      return getVal(elem);
    }
    return setVal(elem, value);
  },

  /**
   * Get the value of the specified DOM element.
   * @param {HTMLElement} elem The element whose value is to be determined.
   */
  getVal = val.getVal = function(elem) {

    var
      tag = elem.tagName.toLowerCase(),
      type = (tag === 'input') ? elem.getAttribute('type') || 'text' : tag,
      miss = {},
      val = (
        type === 'checkbox' ? elem.checked :
        type === 'text' ? elem.value :
        type === 'textarea' ? elem.value :
        miss
      );

    if (val === miss) {
      throw Error("There is no known way to extract a value from the specified element.");
    }

    return val;
  },

  /**
   * Set the value of the specified DOM element to the provided value.
   * @param {HTMLElement} elem The element whose value is to be set.
   * @param {mixed} value The value to set (optional).
   */
  setVal = val.setVal = function(elem, value) {
    elem.value = value;
  },

  /**
   * Copy properties from one or more objects onto a target.
   */
  extend = corridor.extend = function(obj /* arg1, arg2, ... argN */) {
    var i, ii, arg, k;
    for (i = 1, ii = arguments.length; i < ii; i++) {
      arg = arguments[i];
      for (k in arg) {
        if (arg.hasOwnProperty(k)) {
          obj[k] = arg[k];
        }
      }
    }
    return obj;
  },

  /**
   * Deep merge two plain object heirarchies.
   * Does not check for hasOwnProperty.
   * Does not deal with cyclical references (at all).
   * Concatenates arrays (rather than trying to merge their elements).
   * Doesn't guarantee that new cyclical relationships won't be created.
   * Doesn't guarantee good behavior when asymentrical types are encountered.
   */
  merge = corridor.merge = function(obj, other) {

    var key;

    if (toString.call(other) === '[object Array]') {
      if (toString.call(obj) === '[object Array]') {
        other.forEach(function(item){
          obj.push(item);
        });
      } else {
        other.forEach(function(item, index) {
          if (index in obj && typeof obj[index] === 'object' && obj[index] !== null) {
            merge(obj[index], item);
          } else {
            obj[index] = item;
          }
        });
      }
    } else {
      for (key in other) {
        if (key in obj && typeof obj[key] === 'object' && obj[key] !== null) {
          merge(obj[key], other[key]);
        } else {
          obj[key] = other[key];
        }
      }
    }

    return obj;
  },

  /**
   * TODO: move this to a test suite.
   */
  testMerge = corridor.testMerge = function() {
    ([
      {
        obj: ['a'],
        other: ['b'],
        expected: ['a', 'b']
      },
      {
        obj: [{a: 'hi'}],
        other: [{b: 'there'}],
        expected: [{a: 'hi'}, {b: 'there'}]
      },
      {
        obj: {list: ['hi']},
        other: {list: ['there']},
        expected: {list: ['hi','there']}
      },
      {
        obj: {list: ['hi'], foo: 7},
        other: {foo: 8, list: ['there']},
        expected: {list: ['hi','there'], foo: 8}
      },
      {
        obj: {},
        other: { b: 'hi' },
        expected: { b: 'hi' }
      },
      {
        obj: { a: 'whut' },
        other: { b: 'hi' },
        expected: { a: 'whut', b: 'hi' }
      },
    ]).forEach(function(test) {
      var actual = merge(test.obj, test.other);
      if (JSON.stringify(actual) !== JSON.stringify(test.expected)) {
        console.log(["FAILED", test.expected, actual]);
      }
    });
    console.log("PASS");
  };

})(window, document);
<|endoftext|>


<commit_before>function startup() {
  // Set the time zone to UTC.
  var env = Components.classes["@mozilla.org/process/environment;1"]
                            .getService(Components.interfaces.nsIEnvironment);
  env.set('TZ', 'UTC');

  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
                    .getService(Components.interfaces.nsIPrefBranch);

  var myPanel = document.getElementById("my-panel");
  var strbundle = document.getElementById("strings");
  if (prefs.getBoolPref("extensions.torbirdy.protected"))
  {
    var type = prefs.getIntPref("extensions.torbirdy.proxy");
    myPanel.style.color = "green";
    // Tor.
    if (type === 0)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.tor");
    }
    // JonDo.
    if (type === 1)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.jondo");
    }
    // Custom.
    if (type === 2)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.custom");
    }
  } else {
    myPanel.label = strbundle.getString("torbirdy.enabled.disabled");
    myPanel.style.color = "red";
  }
}

window.addEventListener("load", startup, false);
<commit_msg>Select the Local Folders on startup instead of last selected account<commit_after>(function initOverlayWindow() {
  function selectFolderOnInit(initialUri) {
    var startupFolder = GetMsgFolderFromUri("mailbox://nobody@Local%20Folders");
    if (startupFolder) {
      initialUri = startupFolder.URI;
      var folderTree = document.getElementById("folderTree");
      if (window.gFolderTreeView)
        gFolderTreeView.selectFolder(startupFolder);
    }
  }
  window.loadStartFolder = selectFolderOnInit;
})();

function startup() {
  // Set the time zone to UTC.
  var env = Components.classes["@mozilla.org/process/environment;1"]
                            .getService(Components.interfaces.nsIEnvironment);
  env.set('TZ', 'UTC');

  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
                    .getService(Components.interfaces.nsIPrefBranch);

  var myPanel = document.getElementById("my-panel");
  var strbundle = document.getElementById("strings");
  if (prefs.getBoolPref("extensions.torbirdy.protected"))
  {
    var type = prefs.getIntPref("extensions.torbirdy.proxy");
    myPanel.style.color = "green";
    // Tor.
    if (type === 0)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.tor");
    }
    // JonDo.
    if (type === 1)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.jondo");
    }
    // Custom.
    if (type === 2)
    {
      myPanel.label = strbundle.getString("torbirdy.enabled.custom");
    }
  } else {
    myPanel.label = strbundle.getString("torbirdy.enabled.disabled");
    myPanel.style.color = "red";
  }
}

window.addEventListener("load", startup, false);
<|endoftext|>


<commit_before>'use strict';

/**
 * The post processing step that steps through all currently indexed assets
 * and deletes every asset that was not indexed during this run of the update to
 * the index.
 */

var Q = require('q');

module.exports = function(state) {
  // TODO: Consider enabling this for state.mode === 'catalog' as well.
  if (state.mode === 'all') {
    var deletionPromises = state.queries.map(function(query) {
      console.log('Deleting every asset in the index, except',
                  query.indexedAssetIds.length);

      var idsToBeRemoved = [];

      // first we do a search, and specify a scroll timeout
      return state.es.search({
        index: state.index,
        // Set to 30 seconds because we are calling right back
        scroll: '30s',
        size: 1000,
        fields: ['id']
      }).then(function getMoreUntilDone(response) {
        // Loop through each of these and collect the assets ID in case it was not
        // indexed in this run of indexing.
        response.hits.hits.forEach(function(hit) {
          if (query.indexedAssetIds.indexOf(hit._id) === -1) {
            idsToBeRemoved.push(hit._id);
          }
        });

        if (response.hits.hits.length > 0) {
          var scrollId = response._scroll_id; // jscs: disable
          // now we can call scroll over and over
          return state.es.scroll({
            scrollId: scrollId,
            scroll: '30s'
          }).then(getMoreUntilDone);
        } else {
          return idsToBeRemoved;
        }
      }).then(function(idsToBeRemoved) {
        console.log('Removing', idsToBeRemoved.length, 'assets from the index.');
        return state.es.deleteByQuery({
          index: state.index,
          body: {
            query: {
              ids: {
                values: idsToBeRemoved
              }
            }
          }
        });
      })
    });

    return Q.all(deletionPromises).then(function() {
      return state;
    });
  } else {
    // TODO: Consider implementing the deletion of assets when in catalog mode
    // as well.
    console.log('Removed assets will only be deleted when in all mode.');
    return state;
  }
};
<commit_msg>Fixing the delete assets when in all or catalog mode.<commit_after>'use strict';

/**
 * The post processing step that steps through all currently indexed assets
 * and deletes every asset that was not indexed during this run of the update to
 * the index.
 */

var Q = require('q');

module.exports = function(state) {
  var activity = 'Post-processing to delete removed assets';
  console.log('\n=== ' + activity + ' ===\n');

  if (state.mode === 'all' || state.mode === 'catalog') {
    return state.queries.map(function(query) {
      if (query.offset > 0) {
        console.log('Skipping a query that had a non-zero offset.');
        return;
      }

      console.log('Deleting every asset in the',
                  query.catalogAlias,
                  'catalog except the',
                  query.indexedAssetIds.length,
                  'assets that was just indexed');
      // Scroll search for all assets in the catalog that was not indexed.
      var deletedAssetIds = [];

      return state.es.scrollSearch({
        'query': {
          'bool': {
            'must': {
              'match': {
                'catalog': query.catalogAlias
              }
            },
            'must_not': {
              'ids': {
                'values': query.indexedAssetIds
              }
            }
          }
        }
      }, function(deletedAsset) {
        deletedAssetIds.push(deletedAsset._id);
      }).then(function() {
        var actions = deletedAssetIds.map(function(deletedAssetId) {
          return {delete: {_id: deletedAssetId}};
        });
        return state.es.bulk({
          index: state.index,
          type: 'asset',
          body: actions
        });
      });
    }).reduce(Q.when, null).then(function() {
      return state;
    });
  } else {
    console.log('Removed assets gets deleted only in "all" or "catalog" mode.');
    return state;
  }
};
<|endoftext|>


<commit_before>var _ = require('lodash'),
    assert = require('assert');

describe('Association Interface', function() {

  describe('1:1 Association', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var users, profiles;

    before(function(done) {
      Associations.User_resource.createEach([{ name: 'foo' }, { name: 'bar' }], function(err, models) {
        if(err) return done(err);

        users = models;

        var profileRecords = [
          { name: 'profile one', user: users[0].id },
          { name: 'profile two', user: users[1].id }
        ];

        Associations.Profile.createEach(profileRecords, function(err, models) {
          if(err) return done(err);

          Associations.User_resource.update({ name: 'foo' }, { profile: models[0].id }).exec(function(err, user) {
            if(err) return done(err);

            Associations.User_resource.update({ name: 'bar' }, { profile: models[1].id }).exec(function(err, user) {
              if(err) return done(err);
              profiles = models;
              done();
            });
          });
        });
      });
    });

    describe('.find()', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      it('should return user when the populate criteria is added on profile', function(done) {
        Associations.Profile.find()
        .populate('user')
        .exec(function(err, profiles) {
          assert(!err);

          assert(profiles[0].user);
          assert(profiles[1].user);

          assert(profiles[0].user.name === 'foo');
          assert(profiles[1].user.name === 'bar');

          done();
        });
      });

      it('should return profile when the populate criteria is added on user', function(done) {
        Associations.User_resource.find()
        .populate('profile')
        .exec(function(err, users) {
          assert(!err);

          assert(users[0].profile);
          assert(users[1].profile);

          assert(users[0].profile.name === 'profile one');
          assert(users[1].profile.name === 'profile two');

          done();
        });
      });

      it.only('should return a user object when the profile is undefined', function(done) {
        Associations.User_resource.create({ name: 'foobar', profile: undefined }).exec(function(err, usr) {
          assert(!err, err);

          Associations.User_resource.find({ name: 'foobar' })
          .populate('profile')
          .exec(function(err, users) {
            assert(!err, err);

            assert(users[0].name);
            assert(!users[0].profile, 'Expected `users[0].profile` to be falsy, but instead users[0] looks like ==> '+require('util').inspect(users[0], false, null));
            done();
          });
        });
      });

    });

  });
});
<commit_msg>Remove one last it.only()<commit_after>var _ = require('lodash'),
    assert = require('assert');

describe('Association Interface', function() {

  describe('1:1 Association', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var users, profiles;

    before(function(done) {
      Associations.User_resource.createEach([{ name: 'foo' }, { name: 'bar' }], function(err, models) {
        if(err) return done(err);

        users = models;

        var profileRecords = [
          { name: 'profile one', user: users[0].id },
          { name: 'profile two', user: users[1].id }
        ];

        Associations.Profile.createEach(profileRecords, function(err, models) {
          if(err) return done(err);

          Associations.User_resource.update({ name: 'foo' }, { profile: models[0].id }).exec(function(err, user) {
            if(err) return done(err);

            Associations.User_resource.update({ name: 'bar' }, { profile: models[1].id }).exec(function(err, user) {
              if(err) return done(err);
              profiles = models;
              done();
            });
          });
        });
      });
    });

    describe('.find()', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      it('should return user when the populate criteria is added on profile', function(done) {
        Associations.Profile.find()
        .populate('user')
        .exec(function(err, profiles) {
          assert(!err);

          assert(profiles[0].user);
          assert(profiles[1].user);

          assert(profiles[0].user.name === 'foo');
          assert(profiles[1].user.name === 'bar');

          done();
        });
      });

      it('should return profile when the populate criteria is added on user', function(done) {
        Associations.User_resource.find()
        .populate('profile')
        .exec(function(err, users) {
          assert(!err);

          assert(users[0].profile);
          assert(users[1].profile);

          assert(users[0].profile.name === 'profile one');
          assert(users[1].profile.name === 'profile two');

          done();
        });
      });

      it('should return a user object when the profile is undefined', function(done) {
        Associations.User_resource.create({ name: 'foobar', profile: undefined }).exec(function(err, usr) {
          assert(!err, err);

          Associations.User_resource.find({ name: 'foobar' })
          .populate('profile')
          .exec(function(err, users) {
            assert(!err, err);

            assert(users[0].name);
            assert(!users[0].profile, 'Expected `users[0].profile` to be falsy, but instead users[0] looks like ==> '+require('util').inspect(users[0], false, null));
            done();
          });
        });
      });

    });

  });
});
<|endoftext|>


<commit_before>var keyCodes = {
  LEFT : 37,
  RIGHT : 39,
  SPACE : 32
};
var keyDown = {
  LEFT : false,
  RIGHT : false,
  SPACE : false
};
window.onkeydown = function(e){
  if(e.keyCode === keyCodes.LEFT) { keyDown.LEFT = true; }
  if(e.keyCode === keyCodes.RIGHT){ keyDown.RIGHT = true; }
  if(e.keyCode === keyCodes.SPACE){ keyDown.SPACE = true; }
};

window.onkeyup = function(e){
  if(e.keyCode === keyCodes.LEFT) { keyDown.LEFT = false; }
  if(e.keyCode === keyCodes.RIGHT){ keyDown.RIGHT = false; }
  if(e.keyCode === keyCodes.SPACE){ keyDown.SPACE = false; }
};<commit_msg>add keydown event listeners<commit_after>var keyCodes = {
  LEFT : 37,
  RIGHT : 39,
  SPACE : 32,
  P : 80,
  R : 82
};
var keyDown = {
  LEFT : false,
  RIGHT : false,
  SPACE : false
};
var keyboard = (function(){
  var listeners = [];

  document.addEventListener('keydown', function(e){
    listeners.forEach(function(listener){
      if(e.which === listener.keycode){
        listener.fn();
      }
    });
  });

  return {
    on : function(keycode, fn){
      listeners.push({keycode : keycode, fn : fn});
    }
  };
}());
window.onkeydown = function(e){
  if(e.keyCode === keyCodes.LEFT) { keyDown.LEFT = true; }
  if(e.keyCode === keyCodes.RIGHT){ keyDown.RIGHT = true; }
  if(e.keyCode === keyCodes.SPACE){ keyDown.SPACE = true; }
};

window.onkeyup = function(e){
  if(e.keyCode === keyCodes.LEFT) { keyDown.LEFT = false; }
  if(e.keyCode === keyCodes.RIGHT){ keyDown.RIGHT = false; }
  if(e.keyCode === keyCodes.SPACE){ keyDown.SPACE = false; }
};<|endoftext|>


<commit_before>// ========================== KeySnail Init File =========================== //
// You can preserve your code in this area when generating the init file using GUI.
// Put all your code except special key, set*key, hook, blacklist.
// ========================================================================= //
//{{%PRESERVE%
// Put your codes here
//}}%PRESERVE%
// ========================================================================= //

// ========================= Special key settings ========================== //

key.quitKey              = "undefined";
key.helpKey              = "undefined";
key.escapeKey            = "C-v";
key.macroStartKey        = "undefined";
key.macroEndKey          = "undefined";
key.universalArgumentKey = "undefined";
key.negativeArgument1Key = "undefined";
key.negativeArgument2Key = "undefined";
key.negativeArgument3Key = "undefined";
key.suspendKey           = "S-ESC";

// ================================= Hooks ================================= //

// ============================= Key bindings ============================== //

// some convenience variables
var bmui              = window.BookmarkingUI;
var secho             = display.echoStatusBar;
var gcpt              = command.getClipboardText;
var scpt              = command.setClipboardText;
var closeNonPinnedTab = function () {
    if ( !getBrowser().selectedTab.pinned ) {
        BrowserCloseTabOrWindow();
    } else {
        secho('Cannot close pinned tab');
    }
}

var viewKs =
[ [ 'h',       ()     => { goDoCommand('cmd_scrollLeft');                                    }, 'Scroll Left'     ]
, [ 'j',       ()     => { goDoCommand('cmd_scrollLineDown');                                }, 'Scroll Down'     ]
, [ 'k',       ()     => { goDoCommand('cmd_scrollLineUp');                                  }, 'Scroll Up'       ]
, [ 'l',       ()     => { goDoCommand('cmd_scrollRight');                                   }, 'Scroll Right'    ]
, [ ['g','g'], ()     => { goDoCommand('cmd_scrollTop');                                     }, 'Scroll Top'      ]
, [ 'G',       ()     => { goDoCommand('cmd_scrollBottom');                                  }, 'Scroll Bottom'   ]
, [ 'H',       ()     => { BrowserBack();                                                    }, 'Hist Back'       ]
, [ 'J',       ()     => { getBrowser().mTabContainer.advanceSelectedTab( 1, true);          }, 'Next Tab'        ]
, [ 'K',       ()     => { getBrowser().mTabContainer.advanceSelectedTab(-1, true);          }, 'Prev Tab'        ]
, [ 'L',       ()     => { BrowserForward();                                                 }, 'Hist Forward'    ]
, [ ':',       (e, a) => { shell.input(null, a);                                             }, 'Command Mode'    ]
, [ 'r',       ()     => { BrowserReload();                                                  }, 'Reload'          ]
, [ 'R',       ()     => { BrowserReloadSkipCache();                                         }, 'Reload (cache)'  ]
, [ 'd',       ()     => { closeNonPinnedTab();                                              }, 'Close Tab'       ]
, [ 'u',       ()     => { undoCloseTab();                                                   }, 'Unclose Tab'     ]
, [ 't',       ()     => { shell.input('tabopen ');                                          }, 'Tabopen'         ]
, [ 'T',       ()     => { shell.input('tabopen ' + bmui._uri.asciiSpec);                    }, 'Tabopen URL'     ]
, [ 'o',       ()     => { shell.input('open ');                                             }, 'Open'            ]
, [ 'O',       ()     => { shell.input('open ' + bmui._uri.asciiSpec);                       }, 'Open URL'        ]
, [ 'y',       ()     => { var url = bmui._uri.asciiSpec; scpt(url); secho('Yanked ' + url); }, 'Yank URL'        ]
, [ 'p',       ()     => { gBrowser.loadURI(gcpt(), null, null);                             }, 'Open Yanked'     ]
, [ 'P',       ()     => { gBrowser.loadOneTab(gcpt(), null, null, null, false);             }, 'Tabopen Yanked'  ]
, [ '/',       ()     => { command.iSearchForward();                                         }, 'Search Forward'  ]
, [ '?',       ()     => { command.iSearchBackward();                                        }, 'Search Backward' ]
, [ '[',       ()     => { gBrowser.loadOneTab('about:about', null, null, null, false);      }, 'about:about'     ]
, [ ['Z','Q'], ()     => { goQuitApplication();                                              }, 'Close Firefox'   ]
, [ ['Z','R'], ()     => { command.restartApp();                                             }, 'Restart Firefox' ]
]

for ( var i = 0; i < viewKs.length; ++ i ) {
    key.setViewKey(viewKs[i][0], viewKs[i][1], viewKs[i][2]);
}

var editKs =
[ [ 'C-u',     ()     => { goDoCommand('cmd_deleteToBeginningOfLine');                       }, 'Backline'        ]
, [ 'C-w',     ()     => { goDoCommand('cmd_deleteWordBackward');                            }, 'Backword'        ]
, [ 'ESC',     ()     => { document.activeElement.blur();                                    }, 'Escape Focus'    ]
]

for ( var i = 0; i < editKs.length; ++ i ) {
    key.setEditKey(editKs[i][0], editKs[i][1], editKs[i][2]);
}
<commit_msg>prefer let for scoped variables<commit_after>// ========================== KeySnail Init File =========================== //
// You can preserve your code in this area when generating the init file using GUI.
// Put all your code except special key, set*key, hook, blacklist.
// ========================================================================= //
//{{%PRESERVE%
// Put your codes here
//}}%PRESERVE%
// ========================================================================= //

// ========================= Special key settings ========================== //

key.quitKey              = "undefined";
key.helpKey              = "undefined";
key.escapeKey            = "C-v";
key.macroStartKey        = "undefined";
key.macroEndKey          = "undefined";
key.universalArgumentKey = "undefined";
key.negativeArgument1Key = "undefined";
key.negativeArgument2Key = "undefined";
key.negativeArgument3Key = "undefined";
key.suspendKey           = "S-ESC";

// ================================= Hooks ================================= //

// ============================= Key bindings ============================== //

// some convenience variables
var bmui              = window.BookmarkingUI;
var secho             = display.echoStatusBar;
var gcpt              = command.getClipboardText;
var scpt              = command.setClipboardText;
var closeNonPinnedTab = function () {
    if ( !getBrowser().selectedTab.pinned ) {
        BrowserCloseTabOrWindow();
    } else {
        secho('Cannot close pinned tab');
    }
}

var viewKs =
[ [ 'h',       ()     => { goDoCommand('cmd_scrollLeft');                                    }, 'Scroll Left'     ]
, [ 'j',       ()     => { goDoCommand('cmd_scrollLineDown');                                }, 'Scroll Down'     ]
, [ 'k',       ()     => { goDoCommand('cmd_scrollLineUp');                                  }, 'Scroll Up'       ]
, [ 'l',       ()     => { goDoCommand('cmd_scrollRight');                                   }, 'Scroll Right'    ]
, [ ['g','g'], ()     => { goDoCommand('cmd_scrollTop');                                     }, 'Scroll Top'      ]
, [ 'G',       ()     => { goDoCommand('cmd_scrollBottom');                                  }, 'Scroll Bottom'   ]
, [ 'H',       ()     => { BrowserBack();                                                    }, 'Hist Back'       ]
, [ 'J',       ()     => { getBrowser().mTabContainer.advanceSelectedTab( 1, true);          }, 'Next Tab'        ]
, [ 'K',       ()     => { getBrowser().mTabContainer.advanceSelectedTab(-1, true);          }, 'Prev Tab'        ]
, [ 'L',       ()     => { BrowserForward();                                                 }, 'Hist Forward'    ]
, [ ':',       (e, a) => { shell.input(null, a);                                             }, 'Command Mode'    ]
, [ 'r',       ()     => { BrowserReload();                                                  }, 'Reload'          ]
, [ 'R',       ()     => { BrowserReloadSkipCache();                                         }, 'Reload (cache)'  ]
, [ 'd',       ()     => { closeNonPinnedTab();                                              }, 'Close Tab'       ]
, [ 'u',       ()     => { undoCloseTab();                                                   }, 'Unclose Tab'     ]
, [ 't',       ()     => { shell.input('tabopen ');                                          }, 'Tabopen'         ]
, [ 'T',       ()     => { shell.input('tabopen ' + bmui._uri.asciiSpec);                    }, 'Tabopen URL'     ]
, [ 'o',       ()     => { shell.input('open ');                                             }, 'Open'            ]
, [ 'O',       ()     => { shell.input('open ' + bmui._uri.asciiSpec);                       }, 'Open URL'        ]
, [ 'y',       ()     => { let url = bmui._uri.asciiSpec; scpt(url); secho('Yanked ' + url); }, 'Yank URL'        ]
, [ 'p',       ()     => { gBrowser.loadURI(gcpt(), null, null);                             }, 'Open Yanked'     ]
, [ 'P',       ()     => { gBrowser.loadOneTab(gcpt(), null, null, null, false);             }, 'Tabopen Yanked'  ]
, [ '/',       ()     => { command.iSearchForward();                                         }, 'Search Forward'  ]
, [ '?',       ()     => { command.iSearchBackward();                                        }, 'Search Backward' ]
, [ '[',       ()     => { gBrowser.loadOneTab('about:about', null, null, null, false);      }, 'about:about'     ]
, [ ['Z','Q'], ()     => { goQuitApplication();                                              }, 'Close Firefox'   ]
, [ ['Z','R'], ()     => { command.restartApp();                                             }, 'Restart Firefox' ]
]

for ( let i = 0; i < viewKs.length; ++ i ) {
    key.setViewKey(viewKs[i][0], viewKs[i][1], viewKs[i][2]);
}

var editKs =
[ [ 'C-u',     ()     => { goDoCommand('cmd_deleteToBeginningOfLine');                       }, 'Backline'        ]
, [ 'C-w',     ()     => { goDoCommand('cmd_deleteWordBackward');                            }, 'Backword'        ]
, [ 'ESC',     ()     => { document.activeElement.blur();                                    }, 'Escape Focus'    ]
]

for ( let i = 0; i < editKs.length; ++ i ) {
    key.setEditKey(editKs[i][0], editKs[i][1], editKs[i][2]);
}
<|endoftext|>


<commit_before>import React from "react";
import { render } from "react-dom";
import { createStore, combineReducers } from "redux";
import { Provider } from "react-redux";
import { Router, Route, browserHistory } from "react-router";
// import { syncHistoryWithStore, routerReducer } from "react-router-redux";

import EvictionMap from "components/eviction_map";
import Sidebar from "components/sidebar";
import StoryMap from "components/story_map";
import eastBostonEvictions from "data/east_boston_evictions";
import exampleEvictionContent from "./data/example_eviction_content";
import eastBostonStories from "./data/east_boston_stories";
import updateMapState from "./reducers/reducers";
import { setStories, setFocusedStory } from "./actions/actions";
require("./stylesheets/main.scss");

// check for different divs, render the appropriate map
if (document.getElementById('east_boston_tenant_association_map')) {
  let domElement = document.getElementById('east_boston_tenant_association_map');
  let store = createStore(updateMapState);

  // const mapApp = combineReducers({
  //   ...updateMapState,
  //   router: routerReducer
  // });

  // let store = createStore(mapApp);

  store.dispatch(setStories(eastBostonStories));
  store.dispatch(setFocusedStory(0));

  const StoryMapWrapper = () => (
    <StoryMap
      position={[42.37, -71.03]}
      zoom={14}
    />
  );

  // generate the routes for stories
  const SidebarWrapper = (story) => (
    <Sidebar story={story} />
  )
  const storyRoute = (story, index) => (
    <Route path={story.url} key={index} component={SidebarWrapper.bind(story)} />
  );
  const createStoryRoutes = (stories) => {
    let storyRoutes = [];
    stories.forEach((story, index) => storyRoutes.push(storyRoute(story, index)));
    return storyRoutes;
  };

  render(
    <Provider store={store}>
      <Router history={browserHistory}>
        <Route path="/" component={StoryMapWrapper}>
          <Route path="/:address" component={Sidebar} />
        </Route>
      </Router>
    </Provider>,
    domElement
  );
}
else if (document.getElementById('fake_data_map')) {
  for (var eviction of eastBostonEvictions) {
    eviction.content = exampleEvictionContent;
  }
  let basicFakeDataMap =
    <EvictionMap
      position={[42.37, -71.03]}
      zoom={14}
      evictions={eastBostonEvictions} />
}
<commit_msg>remove fake map<commit_after>import React from "react";
import { render } from "react-dom";
import { createStore, combineReducers } from "redux";
import { Provider } from "react-redux";
import { Router, Route, browserHistory } from "react-router";
// import { syncHistoryWithStore, routerReducer } from "react-router-redux";

import EvictionMap from "components/eviction_map";
import Sidebar from "components/sidebar";
import StoryMap from "components/story_map";
import eastBostonStories from "./data/east_boston_stories";
import updateMapState from "./reducers/reducers";
import { setStories, setFocusedStory } from "./actions/actions";
require("./stylesheets/main.scss");

// check for different divs, render the appropriate map
if (document.getElementById('east_boston_tenant_association_map')) {
  let domElement = document.getElementById('east_boston_tenant_association_map');
  let store = createStore(updateMapState);

  // const mapApp = combineReducers({
  //   ...updateMapState,
  //   router: routerReducer
  // });

  // let store = createStore(mapApp);

  store.dispatch(setStories(eastBostonStories));
  store.dispatch(setFocusedStory(0));

  const StoryMapWrapper = () => (
    <StoryMap
      position={[42.37, -71.03]}
      zoom={14}
    />
  );

  // generate the routes for stories
  const SidebarWrapper = (story) => (
    <Sidebar story={story} />
  )
  const storyRoute = (story, index) => (
    <Route path={story.url} key={index} component={SidebarWrapper.bind(story)} />
  );
  const createStoryRoutes = (stories) => {
    let storyRoutes = [];
    stories.forEach((story, index) => storyRoutes.push(storyRoute(story, index)));
    return storyRoutes;
  };

  render(
    <Provider store={store}>
      <Router history={browserHistory}>
        <Route path="/" component={StoryMapWrapper}>
          <Route path="/:address" component={Sidebar} />
        </Route>
      </Router>
    </Provider>,
    domElement
  );
}
<|endoftext|>


<commit_before>const assert = require('assert');
const axios = require('axios');
const https = require('https');
const {spawn} = require('child_process');
const waitOn = require('wait-on');
const jwt = require('jsonwebtoken');
const colors = require('colors');
const path = require("path");
const fs = require("fs");

const BROWSER_OPTIONS = {
    ignoreHTTPSErrors: true,
    headless: process.env.CI === "true" || process.env.HEADLESS === "true",
    devtools: process.env.CI !== "true",
    defaultViewport: null,
    slowMo: process.env.CI === "true" ? 0 : 10,
    args: ['--start-maximized', "--window-size=1920,1080"]
};

exports.browserOptions = () => BROWSER_OPTIONS;
exports.browserOptions = (opt) => {
    return {
        ...BROWSER_OPTIONS,
        ...opt
    };
};

exports.removeDirectory = async(directory) => {
    console.log(colors.green(`Removing directory ${directory}`));
    fs.rmdir(directory, { recursive: true }, () => {});
}

exports.click = async (page, button) => {
    await page.evaluate((button) => {
        document.querySelector(button).click();
    }, button);
}

exports.clickLast = async (page, button) => {
    await page.evaluate((button) => {
        let buttons = document.querySelectorAll(button);
        buttons[buttons.length - 1].click();
    }, button);
}

exports.innerText = async (page, selector) => {
    let text = await page.$eval(selector, el => el.innerText.trim());
    console.log(`Text for selector [${selector}] is: [${text}]`);
    return text;
}

exports.textContent = async (page, selector) => {
    let element = await page.$(selector);
    let text = await page.evaluate(element => element.textContent.trim(), element);
    console.log(`Text content for selector [${selector}] is: [${text}]`);
    return text;
}

exports.inputValue = async (page, selector) => {
    let element = await page.$(selector);
    let text = await page.evaluate(element => element.value, element);
    console.log(`Input value for selector [${selector}] is: [${text}]`);
    return text;
}

exports.loginWith = async (page, user, password,
                           usernameField = "#username",
                           passwordField = "#password") => {
    console.log(`Logging in with ${user} and ${password}`);
    await this.type(page, usernameField, user);
    await this.type(page, passwordField, password);
    await page.keyboard.press('Enter');
    await page.waitForNavigation();
}

exports.isVisible = async (page, selector) => {
    let element = await page.$(selector);
    console.log(`Checking visibility for ${selector}`);
    return (element != null && await element.boundingBox() != null);
}

exports.assertVisibility = async (page, selector) => {
    assert(await this.isVisible(page, selector));
}

exports.assertInvisibility = async (page, selector) => {
    let element = await page.$(selector);
    console.log(`Checking invisibility for ${selector}`);
    assert(element == null || await element.boundingBox() == null);
}

exports.assertTicketGrantingCookie = async (page) => {
    let tgc = (await page.cookies()).filter(value => value.name === "TGC");
    console.log(`Asserting ticket-granting cookie: ${tgc}`);
    assert(tgc.length !== 0);
}

exports.assertNoTicketGrantingCookie = async (page) => {
    let tgc = (await page.cookies()).filter(value => value.name === "TGC");
    console.log(`Asserting no ticket-granting cookie: ${tgc}`);
    assert(tgc.length === 0);
}

exports.submitForm = async (page, selector) => {
    console.log(`Submitting form ${selector}`);
    await page.$eval(selector, form => form.submit());
    await page.waitForTimeout(2500)
}

exports.type = async (page, selector, value) => {
    console.log(`Typing ${value} in field ${selector}`);
    await page.$eval(selector, el => el.value = '');
    await page.type(selector, value);
}

exports.newPage = async (browser) => {
    console.clear();
    let page = (await browser.pages())[0];
    if (page === undefined) {
        page = await browser.newPage();
    }
    await page.setDefaultNavigationTimeout(0);
    // await page.setRequestInterception(true);
    await page.bringToFront();
    return page;
}

exports.assertParameter = async (page, param) => {
    console.log(`Asserting parameter ${param} in URL: ${page.url()}`);
    let result = new URL(page.url());
    let value = result.searchParams.get(param);
    console.log(`Parameter ${param} with value ${value}`);
    assert(value != null);
    return value;
}

exports.assertMissingParameter = async (page, param) => {
    let result = new URL(page.url());
    assert(result.searchParams.has(param) === false);
}

exports.sleep = async (ms) => {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

exports.assertTicketParameter = async (page) => {
    console.log(`Page URL: ${page.url()}`);
    let result = new URL(page.url());
    assert(result.searchParams.has("ticket"))
    let ticket = result.searchParams.get("ticket");
    console.log(`Ticket: ${ticket}`);
    assert(ticket != null);
    return ticket;
}

exports.doRequest = async (url, method = "GET", headers = {}, statusCode = 200, requestBody = undefined) => {
    return new Promise((resolve, reject) => {
        let options = {
            method: method,
            rejectUnauthorized: false,
            headers: headers
        };
        console.log(`Contacting ${url} via ${method}`)
        const handler = (res) => {
            console.log(`Response status code: ${res.statusCode}`)
            if (statusCode > 0) {
                assert(res.statusCode === statusCode);
            }
            res.setEncoding("utf8");
            const body = [];
            res.on("data", chunk => body.push(chunk));
            res.on("end", () => resolve(body.join("")));
        };

        if (requestBody !== undefined) {
            let request = https.request(url, options, res => {
                handler(res);
            }).on("error", reject);
            request.write(requestBody);
        } else {
            https.get(url, options, res => {
                handler(res);
            }).on("error", reject);
        }
    });
}

exports.doGet = async (url, successHandler, failureHandler) => {
    const instance = axios.create({
        httpsAgent: new https.Agent({
            rejectUnauthorized: false
        })
    });
    await instance
        .get(url)
        .then(res => {
            console.log(res.data);
            successHandler(res);
        })
        .catch(error => {
            failureHandler(error);
        })
}

exports.doPost = async (url, params, headers, successHandler, failureHandler) => {
    const instance = axios.create({
        httpsAgent: new https.Agent({
            rejectUnauthorized: false
        })
    });
    let urlParams = params instanceof URLSearchParams ? params : new URLSearchParams(params);
    await instance
        .post(url, urlParams, {headers: headers})
        .then(res => {
            console.log(res.data);
            successHandler(res);
        })
        .catch(error => {
            failureHandler(error);
        })
}

exports.waitFor = async (url, successHandler, failureHandler) => {
    let opts = {
        resources: [url],
        delay: 1000,
        interval: 2000,
        timeout: 120000
    };
    await waitOn(opts)
        .then(function () {
            successHandler("good")
        })
        .catch(function (err) {
            failureHandler(err);
        });
}

exports.launchSamlSp = async (idpMetadataPath, samlSpDir, samlOpts) => {
    let args = ['-q', '-x', 'test', '--no-daemon',
        '-DidpMetadataType=idpMetadataFile',
        `-DidpMetadata=${idpMetadataPath}`,
        `-Dsp.sslKeystorePath=${process.env.CAS_KEYSTORE}`];
    args = args.concat(samlOpts);
    console.log(`Launching SAML2 SP in ${samlSpDir} with ${args}`);
    const exec = spawn('./gradlew', args, {cwd: samlSpDir});

    exec.stdout.on('data', (data) => {
        console.log(data.toString());
    });
    exec.stderr.on('data', (data) => {
        console.error(data.toString());
    });
    exec.on('exit', (code) => {
        console.log(`Child process exited with code ${code}`);
    });
    return exec;
}

exports.assertInnerTextStartsWith = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header.startsWith(value));
}

exports.assertInnerTextContains = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header.includes(value));
}

exports.assertInnerText = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header === value)
}

exports.assertPageTitle = async (page, value) => {
    const title = await page.title();
    console.log(`Page Title: ${title}`);
    assert(title === value)
}

exports.decodeJwt = async (token, complete = false) => {
    console.log(`Decoding token ${token}`);
    let decoded = jwt.decode(token, {complete: complete});
    if (complete) {
        console.log(`Decoded token header: ${colors.green(decoded.header)}`);
        console.log("Decoded token payload:");
        console.log(colors.green(decoded.payload));
    } else {
        console.log("Decoded token payload:");
        console.log(colors.green(decoded));
    }
    return decoded;
}

exports.uploadSamlMetadata = async(page, metadata) => {
    await page.goto("https://samltest.id/upload.php");
    await page.waitForTimeout(1000)
    const fileElement = await page.$("input[type=file]");
    console.log(`Metadata file: ${metadata}`);
    await fileElement.uploadFile(metadata);
    await page.waitForTimeout(1000)
    await this.click(page, "input[name='submit']")
    await page.waitForNavigation();
    await page.waitForTimeout(2000)
}
<commit_msg>clean up puppeteer scripts<commit_after>const assert = require('assert');
const axios = require('axios');
const https = require('https');
const {spawn} = require('child_process');
const waitOn = require('wait-on');
const jwt = require('jsonwebtoken');
const colors = require('colors');
const fs = require("fs");

const BROWSER_OPTIONS = {
    ignoreHTTPSErrors: true,
    headless: process.env.CI === "true" || process.env.HEADLESS === "true",
    devtools: process.env.CI !== "true",
    defaultViewport: null,
    slowMo: process.env.CI === "true" ? 0 : 10,
    args: ['--start-maximized', "--window-size=1920,1080"]
};

exports.browserOptions = () => BROWSER_OPTIONS;
exports.browserOptions = (opt) => {
    return {
        ...BROWSER_OPTIONS,
        ...opt
    };
};

exports.removeDirectory = async(directory) => {
    console.log(colors.green(`Removing directory ${directory}`));
    fs.rmdir(directory, { recursive: true }, () => {});
}

exports.click = async (page, button) => {
    await page.evaluate((button) => {
        document.querySelector(button).click();
    }, button);
}

exports.clickLast = async (page, button) => {
    await page.evaluate((button) => {
        let buttons = document.querySelectorAll(button);
        buttons[buttons.length - 1].click();
    }, button);
}

exports.innerText = async (page, selector) => {
    let text = await page.$eval(selector, el => el.innerText.trim());
    console.log(`Text for selector [${selector}] is: [${text}]`);
    return text;
}

exports.textContent = async (page, selector) => {
    let element = await page.$(selector);
    let text = await page.evaluate(element => element.textContent.trim(), element);
    console.log(`Text content for selector [${selector}] is: [${text}]`);
    return text;
}

exports.inputValue = async (page, selector) => {
    let element = await page.$(selector);
    let text = await page.evaluate(element => element.value, element);
    console.log(`Input value for selector [${selector}] is: [${text}]`);
    return text;
}

exports.loginWith = async (page, user, password,
                           usernameField = "#username",
                           passwordField = "#password") => {
    console.log(`Logging in with ${user} and ${password}`);
    await this.type(page, usernameField, user);
    await this.type(page, passwordField, password);
    await page.keyboard.press('Enter');
    await page.waitForNavigation();
}

exports.isVisible = async (page, selector) => {
    let element = await page.$(selector);
    console.log(`Checking visibility for ${selector}`);
    return (element != null && await element.boundingBox() != null);
}

exports.assertVisibility = async (page, selector) => {
    assert(await this.isVisible(page, selector));
}

exports.assertInvisibility = async (page, selector) => {
    let element = await page.$(selector);
    console.log(`Checking invisibility for ${selector}`);
    assert(element == null || await element.boundingBox() == null);
}

exports.assertTicketGrantingCookie = async (page) => {
    let tgc = (await page.cookies()).filter(value => value.name === "TGC");
    console.log(`Asserting ticket-granting cookie: ${tgc}`);
    assert(tgc.length !== 0);
}

exports.assertNoTicketGrantingCookie = async (page) => {
    let tgc = (await page.cookies()).filter(value => value.name === "TGC");
    console.log(`Asserting no ticket-granting cookie: ${tgc}`);
    assert(tgc.length === 0);
}

exports.submitForm = async (page, selector) => {
    console.log(`Submitting form ${selector}`);
    await page.$eval(selector, form => form.submit());
    await page.waitForTimeout(2500)
}

exports.type = async (page, selector, value) => {
    console.log(`Typing ${value} in field ${selector}`);
    await page.$eval(selector, el => el.value = '');
    await page.type(selector, value);
}

exports.newPage = async (browser) => {
    console.clear();
    let page = (await browser.pages())[0];
    if (page === undefined) {
        page = await browser.newPage();
    }
    await page.setDefaultNavigationTimeout(0);
    // await page.setRequestInterception(true);
    await page.bringToFront();
    return page;
}

exports.assertParameter = async (page, param) => {
    console.log(`Asserting parameter ${param} in URL: ${page.url()}`);
    let result = new URL(page.url());
    let value = result.searchParams.get(param);
    console.log(`Parameter ${param} with value ${value}`);
    assert(value != null);
    return value;
}

exports.assertMissingParameter = async (page, param) => {
    let result = new URL(page.url());
    assert(result.searchParams.has(param) === false);
}

exports.sleep = async (ms) => {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

exports.assertTicketParameter = async (page) => {
    console.log(`Page URL: ${page.url()}`);
    let result = new URL(page.url());
    assert(result.searchParams.has("ticket"))
    let ticket = result.searchParams.get("ticket");
    console.log(`Ticket: ${ticket}`);
    assert(ticket != null);
    return ticket;
}

exports.doRequest = async (url, method = "GET", headers = {}, statusCode = 200, requestBody = undefined) => {
    return new Promise((resolve, reject) => {
        let options = {
            method: method,
            rejectUnauthorized: false,
            headers: headers
        };
        console.log(`Contacting ${url} via ${method}`)
        const handler = (res) => {
            console.log(`Response status code: ${res.statusCode}`)
            if (statusCode > 0) {
                assert(res.statusCode === statusCode);
            }
            res.setEncoding("utf8");
            const body = [];
            res.on("data", chunk => body.push(chunk));
            res.on("end", () => resolve(body.join("")));
        };

        if (requestBody !== undefined) {
            let request = https.request(url, options, res => {
                handler(res);
            }).on("error", reject);
            request.write(requestBody);
        } else {
            https.get(url, options, res => {
                handler(res);
            }).on("error", reject);
        }
    });
}

exports.doGet = async (url, successHandler, failureHandler) => {
    const instance = axios.create({
        httpsAgent: new https.Agent({
            rejectUnauthorized: false
        })
    });
    await instance
        .get(url)
        .then(res => {
            console.log(res.data);
            successHandler(res);
        })
        .catch(error => {
            failureHandler(error);
        })
}

exports.doPost = async (url, params, headers, successHandler, failureHandler) => {
    const instance = axios.create({
        httpsAgent: new https.Agent({
            rejectUnauthorized: false
        })
    });
    let urlParams = params instanceof URLSearchParams ? params : new URLSearchParams(params);
    await instance
        .post(url, urlParams, {headers: headers})
        .then(res => {
            console.log(res.data);
            successHandler(res);
        })
        .catch(error => {
            failureHandler(error);
        })
}

exports.waitFor = async (url, successHandler, failureHandler) => {
    let opts = {
        resources: [url],
        delay: 1000,
        interval: 2000,
        timeout: 120000
    };
    await waitOn(opts)
        .then(function () {
            successHandler("good")
        })
        .catch(function (err) {
            failureHandler(err);
        });
}

exports.launchSamlSp = async (idpMetadataPath, samlSpDir, samlOpts) => {
    let args = ['-q', '-x', 'test', '--no-daemon',
        '-DidpMetadataType=idpMetadataFile',
        `-DidpMetadata=${idpMetadataPath}`,
        `-Dsp.sslKeystorePath=${process.env.CAS_KEYSTORE}`];
    args = args.concat(samlOpts);
    console.log(`Launching SAML2 SP in ${samlSpDir} with ${args}`);
    const exec = spawn('./gradlew', args, {cwd: samlSpDir});

    exec.stdout.on('data', (data) => {
        console.log(data.toString());
    });
    exec.stderr.on('data', (data) => {
        console.error(data.toString());
    });
    exec.on('exit', (code) => {
        console.log(`Child process exited with code ${code}`);
    });
    return exec;
}

exports.assertInnerTextStartsWith = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header.startsWith(value));
}

exports.assertInnerTextContains = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header.includes(value));
}

exports.assertInnerText = async (page, selector, value) => {
    const header = await this.innerText(page, selector);
    assert(header === value)
}

exports.assertPageTitle = async (page, value) => {
    const title = await page.title();
    console.log(`Page Title: ${title}`);
    assert(title === value)
}

exports.decodeJwt = async (token, complete = false) => {
    console.log(`Decoding token ${token}`);
    let decoded = jwt.decode(token, {complete: complete});
    if (complete) {
        console.log(`Decoded token header: ${colors.green(decoded.header)}`);
        console.log("Decoded token payload:");
        console.log(colors.green(decoded.payload));
    } else {
        console.log("Decoded token payload:");
        console.log(colors.green(decoded));
    }
    return decoded;
}

exports.uploadSamlMetadata = async(page, metadata) => {
    await page.goto("https://samltest.id/upload.php");
    await page.waitForTimeout(1000)
    const fileElement = await page.$("input[type=file]");
    console.log(`Metadata file: ${metadata}`);
    await fileElement.uploadFile(metadata);
    await page.waitForTimeout(1000)
    await this.click(page, "input[name='submit']")
    await page.waitForNavigation();
    await page.waitForTimeout(2000)
}
<|endoftext|>


<commit_before>import loadScript from '../../src/index'
import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { expect } from 'chai'
import browserMock from 'mock-browser'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'

const MockBrowser = browserMock.mocks.MockBrowser

chai.use(sinonChai)
chai.use(chaiAsPromised)

const URL = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'
describe('dynamic script loader', () => {
  describe('when run on serverside', () => {
    it('should fail with a promise rejection', () => {
      expect(loadScript()).to.be.rejectedWith('sorry bro client side only')
    })
  })

  describe('when src is not set', () => {
    beforeEach(() => {
      global.window = new MockBrowser().getWindow()
      global.document = new MockBrowser().getDocument()
    })

    afterEach(() => {
      global.window = {}
      global.document = {}
    })

    it('should fail with a promise rejection', () => {
      expect(loadScript()).to.be.rejectedWith('src must be set!')
    })
  })

  describe('initial callback', () => {
    let callback
    let thennable

    beforeEach(() => {
      callback = sinon.spy()
      thennable = sinon.spy()
      global.window = new MockBrowser().getWindow()
      global.document = new MockBrowser().getDocument()
    })

    afterEach(() => {
      global.window = {}
      global.document = {}
    })

    it('it runs initial callback', (done) => {
      loadScript({ src: URL }, callback)
        .then(() => {
          expect(callback).to.have.been.called
          done()
        })
    })

    it('if script has been set it returns a promise', (done) => {
      loadScript({ src: URL }, callback)
        .then(thennable)

      loadScript({ src: URL }, callback)
        .then(thennable)
        .then(() => {
          expect(callback).to.have.been.calledOnce
          expect(thennable).to.have.been.calledTwice
          done()
        })
    })
  })

})<commit_msg>Add unit test for thennable<commit_after>import loadScript from '../../src/index'
import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { expect } from 'chai'
import browserMock from 'mock-browser'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'

const MockBrowser = browserMock.mocks.MockBrowser

chai.use(sinonChai)
chai.use(chaiAsPromised)

const URL = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'
describe('dynamic script loader', () => {
  describe('when run on serverside', () => {
    it('should fail with a promise rejection', () => {
      expect(loadScript()).to.be.rejectedWith('sorry bro client side only')
    })
  })

  describe('when src is not set', () => {
    beforeEach(() => {
      global.window = new MockBrowser().getWindow()
      global.document = new MockBrowser().getDocument()
    })

    afterEach(() => {
      global.window = {}
      global.document = {}
    })

    it('should fail with a promise rejection', () => {
      expect(loadScript()).to.be.rejectedWith('src must be set!')
    })
  })

  describe('initial callback', () => {
    let callback
    let thennable

    beforeEach(() => {
      callback = sinon.spy()
      thennable = sinon.spy()
      global.window = new MockBrowser().getWindow()
      global.document = new MockBrowser().getDocument()
    })

    afterEach(() => {
      global.window = {}
      global.document = {}
    })

    it('it runs initial callback', (done) => {
      loadScript({ src: URL }, callback)
        .then(() => {
          expect(callback).to.have.been.called
          done()
        })
    })

    it('loader runs callback only once', (done) => {
      loadScript({ src: URL }, callback)
        .then(thennable)

      loadScript({ src: URL }, callback)
        .then(thennable)
        .then(() => {
          expect(callback).to.have.been.calledOnce
          done()
        })
    })

    it('loader runs then after each load call', (done) => {
      loadScript({ src: URL }, callback)
        .then(thennable)

      loadScript({ src: URL }, callback)
        .then(thennable)
        .then(() => {
          expect(thennable).to.have.been.calledTwice
          done()
        })
    })
  })

})<|endoftext|>