<commit_before>var assert = require('assert');
var util = require('util');
var net = require('net');
var EventEmitter = require('events').EventEmitter;
var zetta = require('../');
var EventSocket = require('../lib/event_socket');
var EventBroker = require('../lib/event_broker');
var PeerRegistry = require('./fixture/scout_test_mocks').MockPeerRegistry;
var PeerSocket = require('../lib/peer_socket');
var Registry = require('./fixture/scout_test_mocks').MockRegistry;

var Ws = function() {
  EventEmitter.call(this)
  this._socket = new net.Socket();
};
util.inherits(Ws, EventEmitter);
Ws.prototype.send = function(data, options, cb) {
  var r = this.emit('onsend', data, options, cb);
};

describe('EventBroker', function() {
  var app = null;
  var broker = null;
  beforeEach(function() {
    var reg = new Registry();
    var peerRegistry = new PeerRegistry();
    app = zetta({ registry: reg, peerRegistry: peerRegistry });
    broker = new EventBroker(app);
  });

  it('it should add peer by server name', function() {
    var ws = new Ws();
    var peer = new PeerSocket(ws, 'some-peer');
    broker.peer(peer);
    assert.equal(peer, broker.peers['some-peer']);
  });

  it('it should add client and subscribe to topic', function() {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);
    assert.equal(broker.clients.length, 1);
    assert.equal(broker.subscriptionCounts['some-topic'], 1);
  });

  it('it should remove subscription when client closes', function(done) {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);
    assert.equal(broker.clients.length, 1);
    assert.equal(broker.subscriptionCounts['some-topic'], 1);

    client.emit('close');

    setTimeout(function() {
      assert.equal(broker.clients.length, 0);
      assert(!broker.subscriptionCounts['some-topic']);
      done();
    }, 1);
  });

  it('it should pass data from local pubsub to clients', function(done) {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);

    var recieved = 0;
    ws.on('onsend', function(buf) {
      recieved++;
      var msg = JSON.parse(buf);
      assert.equal(msg.topic, 'some-topic');
      assert(msg.date);
      assert.deepEqual(msg.data, {somedata: 1});
    });

    setTimeout(function() {
      assert.equal(recieved, 1);
      done();
    }, 2);

    app.pubsub.publish('some-topic', {somedata: 1});
  });

  it('should keep local pubsub subscription open when more than one client is active', function(done) {
    var clientA = new EventSocket(new Ws(), 'some-topic');
    var clientB = new EventSocket(new Ws(), 'some-topic');
    broker.client(clientA);
    broker.client(clientB);

    var recievedA = 0;
    var recievedB = 0;
    clientA.ws.on('onsend', function(buf) {
      recievedA++;
    });
    clientB.ws.on('onsend', function(buf) {
      recievedB++;
    });

    setTimeout(function() {
      assert.equal(recievedA, 1);
      assert.equal(recievedB, 1);

      clientA.emit('close');

      done();
      return;

      setTimeout(function() {
        assert.equal(recievedA, 1);
        assert.equal(recievedB, 2);
        done();
      }, 2);

      app.pubsub.publish('some-topic', {somedata: 1});
    }, 2);

    app.pubsub.publish('some-topic', {somedata: 1});
  });

});
<commit_msg>Updated test to match changes in event_broker<commit_after>var assert = require('assert');
var util = require('util');
var net = require('net');
var EventEmitter = require('events').EventEmitter;
var zetta = require('../');
var EventSocket = require('../lib/event_socket');
var EventBroker = require('../lib/event_broker');
var PeerRegistry = require('./fixture/scout_test_mocks').MockPeerRegistry;
var PeerSocket = require('../lib/peer_socket');
var Registry = require('./fixture/scout_test_mocks').MockRegistry;

var Ws = function() {
  EventEmitter.call(this)
  this._socket = new net.Socket();
};
util.inherits(Ws, EventEmitter);
Ws.prototype.send = function(data, options, cb) {
  var r = this.emit('onsend', data, options, cb);
};

describe('EventBroker', function() {
  var msg = JSON.stringify({topic: 'some-topic', data: {somedata: 1}, date: new Date().getTime()});
  var app = null;
  var broker = null;
  beforeEach(function() {
    var reg = new Registry();
    var peerRegistry = new PeerRegistry();
    app = zetta({ registry: reg, peerRegistry: peerRegistry });
    broker = new EventBroker(app);
  });

  it('it should add peer by server name', function() {
    var ws = new Ws();
    var peer = new PeerSocket(ws, 'some-peer');
    broker.peer(peer);
    assert.equal(peer, broker.peers['some-peer']);
  });

  it('it should add client and subscribe to topic', function() {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);
    assert.equal(broker.clients.length, 1);
    assert.equal(broker.subscriptionCounts['some-topic'], 1);
  });

  it('it should remove subscription when client closes', function(done) {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);
    assert.equal(broker.clients.length, 1);
    assert.equal(broker.subscriptionCounts['some-topic'], 1);

    client.emit('close');

    setTimeout(function() {
      assert.equal(broker.clients.length, 0);
      assert(!broker.subscriptionCounts['some-topic']);
      done();
    }, 1);
  });

  it('it should pass data from local pubsub to clients', function(done) {
    var ws = new Ws();
    var client = new EventSocket(ws, 'some-topic');
    broker.client(client);

    var recieved = 0;
    ws.on('onsend', function(buf) {
      recieved++;
      var msg = JSON.parse(buf);
      assert.equal(msg.topic, 'some-topic');
      assert(msg.date);
      assert.deepEqual(msg.data, {somedata: 1});
    });

    setTimeout(function() {
      assert.equal(recieved, 1);
      done();
    }, 2);

    app.pubsub.publish('some-topic', msg);
  });

  it('should keep local pubsub subscription open when more than one client is active', function(done) {
    var clientA = new EventSocket(new Ws(), 'some-topic');
    var clientB = new EventSocket(new Ws(), 'some-topic');
    broker.client(clientA);
    broker.client(clientB);

    var recievedA = 0;
    var recievedB = 0;
    clientA.ws.on('onsend', function(buf) {
      recievedA++;
    });
    clientB.ws.on('onsend', function(buf) {
      recievedB++;
    });

    setTimeout(function() {
      assert.equal(recievedA, 1);
      assert.equal(recievedB, 1);

      clientA.emit('close');

      done();
      return;

      setTimeout(function() {
        assert.equal(recievedA, 1);
        assert.equal(recievedB, 2);
        done();
      }, 2);

      app.pubsub.publish('some-topic', msg);
    }, 2);

    app.pubsub.publish('some-topic', msg);
  });

});
<|endoftext|>


<commit_before>/* global $ */
$.jCanvas.defaults.fromCenter = false;

/* .getCanvasImage() don't work on Google Chrome if the page is served from a file URL (file://).
This is a limitation of Google Chrome’s sandboxing architecture, and therefore cannot be fixed */
if (window.location.protocol == 'file:' && window.navigator.vendor == "Google Inc.") {
	$('#offline_warning').show();
	$('select[name=type] option[value=menuhax2015]', "#settings").prop('disabled', true);
	$('select[name=type] option[value=menuhax2016]', "#settings").prop('disabled', true);
}

/* jCanvas has an option for write full strings but don't have a option for control letter spacing.
The font has a letter spacing of 2px, and the generator needs a spacing of 1px.
This function allows to write character by character with only 1px of spacing. */
var write = function(x, y, text, color = 'gray') {
	while (text != '') {
		var letter = text.substr(0,1);

		/* Search for specials characters */
		if (letter == '_') {
			text = text.substr(1);
			letter = text.substr(0,1);
			if (color == 'gray') color = 'white';
			else if (color == 'white') color = 'gray';
		}

		/* Draw 1 character */
		$('#topscreen').drawText({
			fillStyle: color,
			x: x+2, y: y,
			fontSize: 16,
			fontFamily: 'PerfectDOSVGA437Win',
			align: 'left',
			text: letter
		});

		/* Remove the character writed from the string, and if itn't empty, continue recursive */
		text = text.substr(1);
		x = x + 8;
	}
}

/* This draw the entire splash screen with any change on the form */
$("#settings input, #settings select").on('change', function() {
	var $topscreen = $('#topscreen');

	var model = $('input[name=model]:checked', "#settings").val();
	var region = $('select[name=region] option:selected', "#settings").val();
	var sd = $('select[name=sd] option:selected', "#settings").val();
	var type = $('select[name=type] option:selected', "#settings").val();

	var line1 = $('select[name=type] option:selected', "#settings").text();
	var line2 = ''; var processor = 0; var use_bootinput = false; var use_auxinput = false;

	if ($('select[name=boottool] option:selected', "#settings").val() == 'custom') {
		$('input[name=boottool]', "#settings").show();
		$('select[name=boottool]', "#settings").parent().hide();
		use_bootinput = true;
	}

	if ($('select[name=secondTool] option:selected', "#settings").val() == 'custom') {
		$('input[name=secondTool]', "#settings").show();
		$('select[name=secondTool]', "#settings").parent().hide();
		use_auxinput = true;
	}

	switch(type) {
		case 'luma2016':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2016, AuroraWright';
			break;
		case 'luma2017':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2017, AuroraWright';
			break;
		case 'luma2018':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2018, AuroraWright';
			break;
		case 'luma2019':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2019, AuroraWright';
			break;
		case 'luma2020':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2020, AuroraWright';
			break;
		case 'menuhax2015':
			$topscreen.attr('width', 800);
			line2 = 'Copyright(C) 2015, yellow8';
			break;
		case 'menuhax2016':
			$topscreen.attr('width', 800);
			line2 = 'Copyright(C) 2016, yellow8';
			break;
	}

	$topscreen.clearCanvas().drawRect({
		fillStyle: 'black',
		x: 0, y: 0,
		width: 400,
		height: 240
	}).drawImage({
		source: 'images/symbols.png',
		x: 1, y: 16,
		sWidth: 21,
		sHeight: 29,
		sx: 40, sy: 10
	});

	switch ($('select[name=logoOptions] option:selected', "#settings").val()) {
		case 'energyStar':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 16,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 0
			}).drawRect({
				fillStyle: 'black',
				x: 306, y: 26,
				width: 21,
				height: 29
			});
			break;
		case 'energyLuma':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 16,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 84
			});
			break;
		case 'lumaIcon':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 8,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 84*2
			});
			break;
	}

	write(24, 16*1, line1);
	write(24, 16*2, line2);

	switch(model) {
		case '3DS':
			write(0, 16*5, 'Nintendo 3DS CTR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case '3DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'Nintendo 3DS LL SPR-001('+region+')');
			else
				write(0, 16*5, 'Nintendo 3DS XL SPR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case '2DS':
			write(0, 16*5, 'Nintendo 2DS FTR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case 'n2DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'New Nintendo 2DS LL JAN-001('+region+')');
			else
				write(0, 16*5, 'New Nintendo 2DS XL JAN-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
		case 'n3DS':
			write(0, 16*5, 'New Nintendo 3DS KTR-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
		case 'n3DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'New Nintendo 3DS LL RED-001('+region+')');
			else
				write(0, 16*5, 'New Nintendo 3DS XL RED-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
	}

	switch(processor) {
		case 2:
			write(0, 16*7, 'Main Processor       : Dual-core ARM11 MPCore');
			write(0, 16*8, 'Memory Testing       : 131072K OK');
			break;
		case 4:
			write(0, 16*7, 'Main Processor       : Quad-core ARM11 MPCore');
			write(0, 16*8, 'Memory Testing       : 262144K OK');
			break;
	}

	write(0, 16*9,  'Detecting Primary Master ... '+ processor/2 +'G Internal Memory');
	write(0, 16*10, 'Detecting Primary Slave  ... '+ sd +' Card');

	if (!use_bootinput)
		$('input[name=boottool]', "#settings").val($('select[name=boottool] option:selected', "#settings").text());

	if (!use_auxinput)
		$('input[name=secondTool]', "#settings").val($('select[name=secondTool] option:selected', "#settings").text());

	var boot_bool = $('input[name=hold]', "#settings").is(':checked');
	var boot_keys = $('select[name=onboot] option:selected', "#settings").val();
	var boot_tool = $('input[name=boottool]', "#settings").val();
	var boot_text = '_Hold ' + boot_keys + ' '+ $('select[name=firstTime] option:selected').text() +'_ to enter _' + boot_tool + '_.';

	var aux_bool = $('input[name=secondLine]', "#settings").is(':checked');
	var aux_keys = $('select[name=secondButton] option:selected').val();
	var aux_tool = $('input[name=secondTool]').val();
	var aux_text = '_Hold ' + aux_keys + ' '+ $('select[name=secondTime] option:selected').text() +'_ to enter _' + aux_tool + '_.';

	if (boot_bool && !aux_bool)
		write(0, 16*14, boot_text);
	else if (boot_bool)
		write(0, 16*13, boot_text);

	if (aux_bool)
		write(0, 16*14, aux_text);

	if ($topscreen.width() == 800) {
		$topscreen.drawImage({
			source: $topscreen.getCanvasImage(),
			x: 400, y: 0
		});
	}

});

window.onload = function() {

	$('canvas').drawImage({
		source: 'images/symbols.png',
		x: 0, y: 0,
		load: function() {
			$("select[name=region]", "#settings").trigger('change');
			if ($('#offline_warning').is(':hidden'))
				$('#downloadPNG, #downloadBIN').removeClass('disabled');
		}
	});

};

$('input[name=boottool]', "#settings").keyup(function() { $("#settings input").trigger('change'); });
$('input[name=auxtool]', "#settings").keyup(function() { $("#settings input").trigger('change'); });

/* Create a PNG downloadable of the canvas */
/* global download */
$('#downloadPNG').click(function() {
	if (!$(this).hasClass('disabled')) {
		var filename = ($('#topscreen').width() == 400) ? 'splash.png' : 'imagedisplay.png';
		var filedata = $('#topscreen').getCanvasImage();
		download(filedata, filename, "image/png");
	}
});

$('#downloadBIN').click(function() {
	if (!$(this).hasClass('disabled')) {
		var filename = ($('#topscreen').width() == 400) ? 'splash.bin' : 'menuhax_imagedisplay.bin';

		var width = $('#topscreen').height();
		var height = $('#topscreen').width();

		var $canvas = $('<canvas/>').css({ position: 'absolute', top: 0, left: -1*width }).appendTo('body');
		$canvas.attr('width', width).attr('height', height);

		$canvas.drawImage({
			source: $('#topscreen').getCanvasImage(),
			x: width/2, y: height/2,
			fromCenter: true,
			rotate: 90
		});

		var canvasdata = $canvas.get(0).getContext('2d').getImageData(0, 0, width, height).data;
		var filedata = '';

		for(var i = 0; i < canvasdata.length; i += 4)
			filedata += String.fromCharCode(canvasdata[i+2], canvasdata[i+1], canvasdata[i]);

		$canvas.remove();
		download('data:application/octet-stream;base64,' + window.btoa(filedata), filename);
	}
});
<commit_msg>Add Copyright(C) 2022 for Luma v10.3 and superior<commit_after>/* global $ */
$.jCanvas.defaults.fromCenter = false;

/* .getCanvasImage() don't work on Google Chrome if the page is served from a file URL (file://).
This is a limitation of Google Chrome’s sandboxing architecture, and therefore cannot be fixed */
if (window.location.protocol == 'file:' && window.navigator.vendor == "Google Inc.") {
	$('#offline_warning').show();
	$('select[name=type] option[value=menuhax2015]', "#settings").prop('disabled', true);
	$('select[name=type] option[value=menuhax2016]', "#settings").prop('disabled', true);
}

/* jCanvas has an option for write full strings but don't have a option for control letter spacing.
The font has a letter spacing of 2px, and the generator needs a spacing of 1px.
This function allows to write character by character with only 1px of spacing. */
var write = function(x, y, text, color = 'gray') {
	while (text != '') {
		var letter = text.substr(0,1);

		/* Search for specials characters */
		if (letter == '_') {
			text = text.substr(1);
			letter = text.substr(0,1);
			if (color == 'gray') color = 'white';
			else if (color == 'white') color = 'gray';
		}

		/* Draw 1 character */
		$('#topscreen').drawText({
			fillStyle: color,
			x: x+2, y: y,
			fontSize: 16,
			fontFamily: 'PerfectDOSVGA437Win',
			align: 'left',
			text: letter
		});

		/* Remove the character writed from the string, and if itn't empty, continue recursive */
		text = text.substr(1);
		x = x + 8;
	}
}

/* This draw the entire splash screen with any change on the form */
$("#settings input, #settings select").on('change', function() {
	var $topscreen = $('#topscreen');

	var model = $('input[name=model]:checked', "#settings").val();
	var region = $('select[name=region] option:selected', "#settings").val();
	var sd = $('select[name=sd] option:selected', "#settings").val();
	var type = $('select[name=type] option:selected', "#settings").val();

	var line1 = $('select[name=type] option:selected', "#settings").text();
	var line2 = ''; var processor = 0; var use_bootinput = false; var use_auxinput = false;

	if ($('select[name=boottool] option:selected', "#settings").val() == 'custom') {
		$('input[name=boottool]', "#settings").show();
		$('select[name=boottool]', "#settings").parent().hide();
		use_bootinput = true;
	}

	if ($('select[name=secondTool] option:selected', "#settings").val() == 'custom') {
		$('input[name=secondTool]', "#settings").show();
		$('select[name=secondTool]', "#settings").parent().hide();
		use_auxinput = true;
	}

	switch(type) {
		case 'luma2016':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2016, AuroraWright';
			break;
		case 'luma2017':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2017, AuroraWright';
			break;
		case 'luma2018':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2018, AuroraWright';
			break;
		case 'luma2019':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2019, AuroraWright';
			break;
		case 'luma2020':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2020, AuroraWright';
			break;
		case 'luma2022':
			$topscreen.attr('width', 400);
			line2 = 'Copyright(C) 2022, AuroraWright';
			break;
		case 'menuhax2015':
			$topscreen.attr('width', 800);
			line2 = 'Copyright(C) 2015, yellow8';
			break;
		case 'menuhax2016':
			$topscreen.attr('width', 800);
			line2 = 'Copyright(C) 2016, yellow8';
			break;
	}

	$topscreen.clearCanvas().drawRect({
		fillStyle: 'black',
		x: 0, y: 0,
		width: 400,
		height: 240
	}).drawImage({
		source: 'images/symbols.png',
		x: 1, y: 16,
		sWidth: 21,
		sHeight: 29,
		sx: 40, sy: 10
	});

	switch ($('select[name=logoOptions] option:selected', "#settings").val()) {
		case 'energyStar':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 16,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 0
			}).drawRect({
				fillStyle: 'black',
				x: 306, y: 26,
				width: 21,
				height: 29
			});
			break;
		case 'energyLuma':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 16,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 84
			});
			break;
		case 'lumaIcon':
			$topscreen.drawImage({
				source: 'images/symbols.png',
				x: 266, y: 8,
				sWidth: 133,
				sHeight: 84,
				sx: 0, sy: 84*2
			});
			break;
	}

	write(24, 16*1, line1);
	write(24, 16*2, line2);

	switch(model) {
		case '3DS':
			write(0, 16*5, 'Nintendo 3DS CTR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case '3DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'Nintendo 3DS LL SPR-001('+region+')');
			else
				write(0, 16*5, 'Nintendo 3DS XL SPR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case '2DS':
			write(0, 16*5, 'Nintendo 2DS FTR-001('+region+')');
			processor = 2; sd += ' SD'
			break;
		case 'n2DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'New Nintendo 2DS LL JAN-001('+region+')');
			else
				write(0, 16*5, 'New Nintendo 2DS XL JAN-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
		case 'n3DS':
			write(0, 16*5, 'New Nintendo 3DS KTR-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
		case 'n3DSXL':
			if (region == 'JPN')
				write(0, 16*5, 'New Nintendo 3DS LL RED-001('+region+')');
			else
				write(0, 16*5, 'New Nintendo 3DS XL RED-001('+region+')');
			processor = 4; sd += ' microSD'
			break;
	}

	switch(processor) {
		case 2:
			write(0, 16*7, 'Main Processor       : Dual-core ARM11 MPCore');
			write(0, 16*8, 'Memory Testing       : 131072K OK');
			break;
		case 4:
			write(0, 16*7, 'Main Processor       : Quad-core ARM11 MPCore');
			write(0, 16*8, 'Memory Testing       : 262144K OK');
			break;
	}

	write(0, 16*9,  'Detecting Primary Master ... '+ processor/2 +'G Internal Memory');
	write(0, 16*10, 'Detecting Primary Slave  ... '+ sd +' Card');

	if (!use_bootinput)
		$('input[name=boottool]', "#settings").val($('select[name=boottool] option:selected', "#settings").text());

	if (!use_auxinput)
		$('input[name=secondTool]', "#settings").val($('select[name=secondTool] option:selected', "#settings").text());

	var boot_bool = $('input[name=hold]', "#settings").is(':checked');
	var boot_keys = $('select[name=onboot] option:selected', "#settings").val();
	var boot_tool = $('input[name=boottool]', "#settings").val();
	var boot_text = '_Hold ' + boot_keys + ' '+ $('select[name=firstTime] option:selected').text() +'_ to enter _' + boot_tool + '_.';

	var aux_bool = $('input[name=secondLine]', "#settings").is(':checked');
	var aux_keys = $('select[name=secondButton] option:selected').val();
	var aux_tool = $('input[name=secondTool]').val();
	var aux_text = '_Hold ' + aux_keys + ' '+ $('select[name=secondTime] option:selected').text() +'_ to enter _' + aux_tool + '_.';

	if (boot_bool && !aux_bool)
		write(0, 16*14, boot_text);
	else if (boot_bool)
		write(0, 16*13, boot_text);

	if (aux_bool)
		write(0, 16*14, aux_text);

	if ($topscreen.width() == 800) {
		$topscreen.drawImage({
			source: $topscreen.getCanvasImage(),
			x: 400, y: 0
		});
	}

});

window.onload = function() {

	$('canvas').drawImage({
		source: 'images/symbols.png',
		x: 0, y: 0,
		load: function() {
			$("select[name=region]", "#settings").trigger('change');
			if ($('#offline_warning').is(':hidden'))
				$('#downloadPNG, #downloadBIN').removeClass('disabled');
		}
	});

};

$('input[name=boottool]', "#settings").keyup(function() { $("#settings input").trigger('change'); });
$('input[name=auxtool]', "#settings").keyup(function() { $("#settings input").trigger('change'); });

/* Create a PNG downloadable of the canvas */
/* global download */
$('#downloadPNG').click(function() {
	if (!$(this).hasClass('disabled')) {
		var filename = ($('#topscreen').width() == 400) ? 'splash.png' : 'imagedisplay.png';
		var filedata = $('#topscreen').getCanvasImage();
		download(filedata, filename, "image/png");
	}
});

$('#downloadBIN').click(function() {
	if (!$(this).hasClass('disabled')) {
		var filename = ($('#topscreen').width() == 400) ? 'splash.bin' : 'menuhax_imagedisplay.bin';

		var width = $('#topscreen').height();
		var height = $('#topscreen').width();

		var $canvas = $('<canvas/>').css({ position: 'absolute', top: 0, left: -1*width }).appendTo('body');
		$canvas.attr('width', width).attr('height', height);

		$canvas.drawImage({
			source: $('#topscreen').getCanvasImage(),
			x: width/2, y: height/2,
			fromCenter: true,
			rotate: 90
		});

		var canvasdata = $canvas.get(0).getContext('2d').getImageData(0, 0, width, height).data;
		var filedata = '';

		for(var i = 0; i < canvasdata.length; i += 4)
			filedata += String.fromCharCode(canvasdata[i+2], canvasdata[i+1], canvasdata[i]);

		$canvas.remove();
		download('data:application/octet-stream;base64,' + window.btoa(filedata), filename);
	}
});
<|endoftext|>


<commit_before>'use strict';

exports.BattleAbilities = {
	"data": {
		id: "data",
		name: "Data",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'vaccine') {
					this.debug('Data boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'virus') {
					this.debug('Data weaken');
					return this.chainModify(0.8);
				}
			}
		},
	},
	"vaccine": {
		id: "vaccine",
		name: "Vaccine",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'virus') {
					this.debug('Vaccine boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'data') {
					this.debug('Vaccine weaken');
					return this.chainModify(0.8);
				}
			}
		},
	},
	"virus": {
		id: "virus",
		name: "Virus",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'data') {
					this.debug('Virus boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'vaccine') {
					this.debug('Virus weaken');
					return this.chainModify(0.8);
				}
			}
		},
	},
};
<commit_msg>Digimon Showdown: Add descriptions for abilities<commit_after>'use strict';

exports.BattleAbilities = {
	"data": {
		id: "data",
		name: "Data",
		desc: "If the target's ability is Vaccine the user's Attack is boosted by 1.2x, if the target's ability is Virus the user's Attack is weakened by 0.8x.",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'vaccine') {
					this.debug('Data boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'virus') {
					this.debug('Data weaken');
					return this.chainModify(0.8);
				}
			}
		},
	},
	"vaccine": {
		id: "vaccine",
		name: "Vaccine",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'virus') {
					this.debug('Vaccine boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'data') {
					this.debug('Vaccine weaken');
					return this.chainModify(0.8);
				}
			}
		},
		desc: "If the target's ability is Virus the user's Attack is boosted by 1.2x, if the target's ability is Data the user's Attack is weakened by 0.8x.",
	},
	"virus": {
		id: "virus",
		name: "Virus",
		onBasePowerPriority: 8,
		onBasePower: function (basePower, attacker, move) {
			if (attacker.ability) {
				if (attacker.ability === 'data') {
					this.debug('Virus boost');
					return this.chainModify(1.2);
				} else
				if (attacker.ability === 'vaccine') {
					this.debug('Virus weaken');
					return this.chainModify(0.8);
				}
			}
		},
		desc: "If the target's ability is Data the user's Attack is boosted by 1.2x, if the target's ability is Vaccine the user's Attack is weakened by 0.8x.",
	},
};
<|endoftext|>


<commit_before>import { withProps } from 'recompose';

import HeaderComponent from './header-component';

function importAllImagesFromFolder(r) {
  const images = {};
  const keys = r.keys();
  if (keys.length) {
    keys.forEach(item => {
      images[item.replace('./', '').replace('.jpg', '')] = r(item);
    });
  }
  return images;
}

const images = importAllImagesFromFolder(
  require.context('assets/headers', false, /\.(png|jpe?g)$/)
);

const withBgByRoute = withProps(({ route }) => {
  if (!route || !route.headerImage) return null;

  return {
    image: images[route.headerImage] ? images[route.headerImage] : images.home
  };
});

export default withBgByRoute(HeaderComponent);
<commit_msg>make header themeable<commit_after>import { withProps } from 'recompose';
import { themr } from 'react-css-themr';
import HeaderComponent from './header-component';
import styles from './header-styles.scss';

function importAllImagesFromFolder(r) {
  const images = {};
  const keys = r.keys();
  if (keys.length) {
    keys.forEach(item => {
      images[item.replace('./', '').replace('.jpg', '')] = r(item);
    });
  }
  return images;
}

const images = importAllImagesFromFolder(
  require.context('assets/headers', false, /\.(png|jpe?g)$/)
);

const withBgByRoute = withProps(({ route }) => {
  if (!route || !route.headerImage) return null;

  return {
    image: images[route.headerImage] ? images[route.headerImage] : images.home
  };
});

export default themr('HeaderComponent', styles)(withBgByRoute(HeaderComponent));
<|endoftext|>


<commit_before><commit_msg>Implement descriptionOrganizer<commit_after>import * as PIXI from "pixi.js";
import {default as h} from "../../helpers";
import {default as bottomDescriptionBuilder} from "../builders/bottomDescriptionBuilder";
import {default as cuDescriptionBuilder} from "../builders/cuDescriptionBuilder";

export default function descriptionOrganizer(
  state={global: {mode: "IDLE", step: 0}}
) {
  let container = new PIXI.Container();
  const text = h.jsonParser.descriptionInterpreter(state);
  const bottomSprite = bottomDescriptionBuilder(text.bottomDescription);
  const cuSprite = cuDescriptionBuilder(text.cuDescription);

  container.addChild(bottomSprite, cuSprite);
  return container;
}
<|endoftext|>


<commit_before>var PluginInstance = require(__core + "PluginInstance.js");
var slack = new PluginInstance();

var http = require("http");
var request = require("request");
var fs = require("fs");
var path = require("path");
var SlackUser = require("./SlackUser.js");

slack.init = function () {
    this.plug = this.manager.getPlugin("plug").plug; //TODO: implement better method

    var Slack = require("node-slackr");
    this.slack = new Slack(this.config.webhookuri, {
        channel: this.config.channel,
        username: this.config.username
    });

    if (this.config.server !== undefined) {
        this.server = http.createServer((function (that) {
            return function () {
                that.slackRequest.apply(that, arguments);
            };
        })(this));
        this.server.listen(this.config.server.port, this.config.server.host);
    }

    if (this.config.usertoken) {
        this.pollTimer = setInterval((function (slack) {
            return function () {
                slack.fetchUsers.apply(slack, arguments);
            };
        })(this), (this.config.fetchInterval || 30) * 1000);
        this.fetchUsers();
    }

    this.slackEmotes = JSON.parse(fs.readFileSync(path.join(__dirname, "emotes.json")));
};

slack.events.onUnload = function () {
    if (this.server) {
        this.server.close();
    }
    if (this.pollTimer) {
        clearTimer(this.pollTimer);
    }
};

slack.fetchUsers = function () {
    request("https://slack.com/api/users.list?token=" + this.config.usertoken, function (error, response, body) {
        if (!error && response.statusCode === 200) {
            this.slackUsers = JSON.parse(body);
        }
        else {
            console.log(response);
        }
    });
};

slack.plugToSlack = function (message) {
    if (this.slackUsers) {
        for (var i = 0; i < this.slackUsers.members.length; i++) {
            var user = this.slackUsers.members[i];
            message = message.replace("@" + user.name, "<@" + user.id + "|" + user.name + ">");
        }
    }

    for (var k in this.slackEmotes) {
        if (this.slackEmotes.hasOwnProperty(k)) {
            var emote = this.slackEmotes[k];
            message = message.replace(k, ":" + emote + ":");
        }
    }

    return message;
};

slack.slackToPlug = function (message) {
    if (this.slackUsers) {
        for (var i = 0; i < this.slackUsers.members.length; i++) {
            var user = this.slackUsers.members[i];
            //TODO: replace with a regex
            message = message.replace("<@" + user.id + "|" + user.name + ">", "@" + user.name);
            message = message.replace("<@" + user.id + ">", "@" + user.name);
        }
    }
    for (var k in this.slackEmotes) {
        if (this.slackEmotes.hasOwnProperty(k)) {
            var emote = this.slackEmotes[k];
            message = message.replace(":" + emote + ":", k);
        }
    }

    return message;
};

slack.events.plug_join = function (user) {

};

slack.events.plug_chat = function (message) {
    var content = slack.plugToSlack(message.message);

    if (this.config.ignoreself === true) {
        if (message.command) {
            return;
        }

        if (message.from.username === this.plug.getSelf().username) {
            return;
        }
    }

    var parts = content.split(" ");
    if (parts[0] === "/me") {
        parts.shift();
        content = "_" + parts.join(" ") + " _";
    }

    slack.slack.notify({
        username: message.from.username,
        icon_url: "https://www.d3s.co/plug/badges/" + message.from.badge + ".png",
        text: content
    });
};

slack.events.plug_advance = function (track) {
    // on start: lastPlay: { dj: null, media: null, score: null }

    var message = [];

    if (track.lastPlay !== undefined && track.lastPlay.dj) {
        message.push({
            text: "*Last play:-* Woots: " + track.lastPlay.score.positive + ", Grabs: " + track.lastPlay.score.grabs
            + ", Mehs: " + track.lastPlay.score.negative,
            color: "#99004c",
            author_name: track.lastPlay.dj.username,
            author_icon: "https://www.d3s.co/plug/badges/" + track.lastPlay.dj.badge + ".png",
            mrkdwn_in: ["text", "pretext"]
        });
    }
    if (track.currentDJ) {
        message.push({
            text: "*" + track.currentDJ.username + "* has started playing *" + track.media.author + "* - *"
            + track.media.title + "*",
            color: "#36a64f",
            author_name: track.currentDJ.username,
            author_icon: "https://www.d3s.co/plug/badges/" + track.currentDJ.badge + ".png",
            image_url: track.media.image,
            mrkdwn_in: ["text", "pretext"]
        });
    }
    else {
        message.push({
            text: "*No track playing*",
            color: "#ff0000",
            mrkdwn_in: ["text", "pretext"]
        });
    }

    slack.slack.notify({
        username: "Events",
        attachments: message
    });

};

slack.slackRequest = function (req, res) {
    var that = this;
    if (req.method !== "POST") {
        res.writeHead("403", "Fuck off");
        res.end();
        req.connection.destroy();
        return;
    }

    var body = "";
    req.on("data", function (data) {
        body += data;
    });
    req.on("end", function () {
        var qs = require("querystring");
        that.receivedSlackMessage(qs.parse(body));
    });

    res.writeHead(200);
    res.end();
};

slack.receivedSlackMessage = function (message) {
    if (!message.token || (this.config.server.token && message.token !== this.config.server.token)) {
        return;
    }

    if (message.user_id === "USLACKBOT") {
        return;
    }

    // command
    if (message.text[0] === "!") {
        var cmd = message.text.substr(1).split(" ")[0];
        var args = message.text.substr(1 + cmd.length + 1).split(" ");

        this.manager.fireEvent("command_" + cmd, {
            command: cmd,
            args: args,
            message: message.text,
            from: new SlackUser(message, slack)
        });
    }
    else {
        this.plug.sendChat("<`" + message.user_name + "@slack`> " + this.slackToPlug(message.text));
    }

    this.plugin.manager.fireEvent("chat", {
        message: message.text,
        from: new SlackUser(message, this)
    });

};

module.exports = slack;<commit_msg>Slack bug fixes (resolves #33)<commit_after>var PluginInstance = require(__core + "PluginInstance.js");
var slack = new PluginInstance();

var http = require("http");
var request = require("request");
var fs = require("fs");
var path = require("path");
var SlackUser = require("./SlackUser.js");

slack.init = function () {
    this.plug = this.manager.getPlugin("plug").plug; //TODO: implement better method

    var Slack = require("node-slackr");
    this.slack = new Slack(this.config.webhookuri, {
        channel: this.config.channel,
        username: this.config.username
    });

    if (this.config.server !== undefined) {
        this.server = http.createServer(this.slackRequest.bind(this));
        this.server.listen(this.config.server.port, this.config.server.host);
    }

    if (this.config.usertoken) {
        this.pollTimer = setInterval(this.fetchUsers.bind(this), (this.config.fetchInterval || 30) * 1000);
        this.fetchUsers.bind(this)();
    }

    this.slackEmotes = JSON.parse(fs.readFileSync(path.join(__dirname, "emotes.json")));
};

slack.events.onUnload = function () {
    if (this.server) {
        this.server.close();
    }
    if (this.pollTimer) {
        clearTimeout(this.pollTimer);
    }
};

slack.fetchUsers = function () {
    //console.log("users", this);
    console.log("fetching users");
    request("https://slack.com/api/users.list?token=" + this.config.usertoken, function (error, response, body) {
        if (!error && response.statusCode === 200) {
            slack.slackUsers = JSON.parse(body);
        }
        else {
            console.log(response);
        }
    });
};

slack.plugToSlack = function (message) {
    function escape(text) {
        return (text).replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
    }

    if (this.slackUsers) {
        for (var i = 0; i < this.slackUsers.members.length; i++) {
            var user = this.slackUsers.members[i];
            message = message.replace("@" + user.name, "<@" + user.id + "|" + user.name + ">");
        }
    }

    for (var k in this.slackEmotes) {
        if (this.slackEmotes.hasOwnProperty(k)) {
            var emote = this.slackEmotes[k];
            var replace = new RegExp("(^|\\s)" + escape(k) + "(?=$|\\s)", "g");
            message = message.replace(replace, "$1:" + emote + ":");
        }
    }
    return message;
};

slack.slackToPlug = function (message) {
    /*if (this.slackUsers) {
        for (var i = 0; i < this.slackUsers.members.length; i++) {
            var user = this.slackUsers.members[i];
            //TODO: replace with a regex
            message = message.replace("<@" + user.id + "|" + user.name + ">", "@" + user.name);
            message = message.replace("<@" + user.id + ">", "@" + user.name);
        }
    }*/

    //console.log("message", this);

    message = message.replace(/<(.*?)>/g, (function (match, p1) {
        console.log(match);
        var parts = p1.split("|");
        var link = parts[0];
        var text = parts[1];

        if (link[0] == "@") { //userid
            if (this.slackUsers) {
                //find and return the user
                for (var i = 0; i < this.slackUsers.members.length; i++) {
                    var user = this.slackUsers.members[i];
                    if ("@" + user.id == link) {
                        return "@" + user.name;
                    }
                }
            }
            //we haven't found the user, try returning just the text
            if (text) {
                return text;
            }
            else {
                //else.. make do with the id :/
                return link;
            }
        }
        else { //regular link
            if (text && text != link) {
                return link + "(" + text + ")";
            }
            return link;
        }
    }).bind(this));

    for (var k in this.slackEmotes) {
        if (this.slackEmotes.hasOwnProperty(k)) {
            var emote = this.slackEmotes[k];
            message = message.replace(":" + emote + ":", k);
        }
    }

    return message;
};

slack.events.plug_join = function (user) {

};

slack.events.plug_chat = function (message) {
    var content = slack.plugToSlack(message.message);

    if (this.config.ignoreself === true) {
        if (message.command) {
            return;
        }

        if (message.from.username === this.plug.getSelf().username) {
            return;
        }
    }

    var parts = content.split(" ");
    if (parts[0] === "/me") {
        parts.shift();
        content = "_" + parts.join(" ") + " _";
    }

    slack.slack.notify({
        username: message.from.username,
        icon_url: "https://www.d3s.co/plug/badges/" + message.from.badge + ".png",
        text: content
    });
};

slack.events.plug_advance = function (track) {
    // on start: lastPlay: { dj: null, media: null, score: null }

    var message = [];

    if (track.lastPlay !== undefined && track.lastPlay.dj) {
        message.push({
            text: "*Last play:-* Woots: " + track.lastPlay.score.positive + ", Grabs: " + track.lastPlay.score.grabs
            + ", Mehs: " + track.lastPlay.score.negative,
            color: "#99004c",
            author_name: track.lastPlay.dj.username,
            author_icon: "https://www.d3s.co/plug/badges/" + track.lastPlay.dj.badge + ".png",
            mrkdwn_in: ["text", "pretext"]
        });
    }
    if (track.currentDJ) {
        message.push({
            text: "*" + track.currentDJ.username + "* has started playing *" + track.media.author + "* - *"
            + track.media.title + "*",
            color: "#36a64f",
            author_name: track.currentDJ.username,
            author_icon: "https://www.d3s.co/plug/badges/" + track.currentDJ.badge + ".png",
            image_url: track.media.image,
            mrkdwn_in: ["text", "pretext"]
        });
    }
    else {
        message.push({
            text: "*No track playing*",
            color: "#ff0000",
            mrkdwn_in: ["text", "pretext"]
        });
    }

    slack.slack.notify({
        username: "Events",
        attachments: message
    });

};

slack.slackRequest = function (req, res) {
    var that = this;
    if (req.method !== "POST") {
        res.writeHead("403", "Fuck off");
        res.end();
        req.connection.destroy();
        return;
    }

    var body = "";
    req.on("data", function (data) {
        body += data;
    });
    req.on("end", function () {
        var qs = require("querystring");
        that.receivedSlackMessage(qs.parse(body));
    });

    res.writeHead(200);
    res.end();
};

slack.receivedSlackMessage = function (message) {
    if (!message.token || (this.config.server.token && message.token !== this.config.server.token)) {
        return;
    }

    if (message.user_id === "USLACKBOT") {
        return;
    }

    // command
    if (message.text[0] === "!") {
        var cmd = message.text.substr(1).split(" ")[0];
        var args = message.text.substr(1 + cmd.length + 1).split(" ");

        this.manager.fireEvent("command_" + cmd, {
            command: cmd,
            args: args,
            message: message.text,
            from: new SlackUser(message, slack)
        });
    }
    else {
        this.plug.sendChat("<`" + message.user_name + "@slack`> " + this.slackToPlug.bind(slack)(message.text));
    }

    this.plugin.manager.fireEvent("chat", {
        message: message.text,
        from: new SlackUser(message, this)
    });

};

module.exports = slack;<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

// use chipper's gruntfile
module.exports = require( '../chipper/js/grunt/Gruntfile.js' );
<commit_msg>Updating require.js documentation and associated linting/build changes, see https://github.com/phetsims/chipper/issues/905<commit_after>// Copyright 2016, University of Colorado Boulder

/* eslint-env node */

// use chipper's gruntfile
module.exports = require( '../chipper/js/grunt/Gruntfile.js' );
<|endoftext|>


<commit_before>/**
* This factory produces a worker function that processes an html template with
* an object.
* 1. The data is merged with the template
* 2. The template is converted to an html element
* 3. If tags are processed
* 4. Repeat tags are processed
* 5. Bind input tags
* @factory
*/
function _SimpleTemplate(promise, createElement, simpleExpression, findWatcher, simpleMixin) {
    var TAG_PATT = /\{\:(.*?)\:\}/g
    , WSP_PATT = /^[ \t\n\r]+$/
    , TRIM_PATT = /^[\n\r\t ]+(.*?)[\n\r\t ]+$/
    , LN_END_PATT = /\r?\n/g
    , SPC_PATT = /[ ][ ]+/g
    , TAB_PATT = /\t/g
    , cnsts = {
        "value": "$value"
        , "destroy": "$destroy"
        , "watch": "$watch"
        , "unwatch": "$unwatch"
    }
    ;

    /**
    * Converts the html string into html elements wrapped in a span
    * @function
    */
    function convertHtml(template) {
        var el = createElement('div');
        el.innerHTML = template;
        return el;
    }
    /**
    * Begins the element processing, resolves/rejects the promise
    * @function
    */
    function process(node, data) {
        //create the starting context object and start processing the node
        if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
            processElement(node, createContext(data, node));
        }
    }
    /**
    * Create the context object, making data the prototype
    * @function
    */
    function createContext(data, element) {
        return Object.create(data, {
            "$parentElement": {
                "enumerable": true
                , "value": element
            }
        });
    }
    /**
    * Processes the element including special tags, if and repeat, and
    * processes it's shildren
    * @function
    */
    function processElement(element, context) {
        //set the element on the context
        context["$element"] = element;
        //a temporary container for watchers
        element.watchers = [];
        //see if this is a repeat
        if (element.nodeName === "REPEAT") {
            processRepeatElement(element, context);
        }
        else if (element.nodeName === "IF") {
            processIfElement(element, context)
        }
        else if (element.nodeName === "ELSE") {
            //remove the else
            element.parentNode.removeChild(element);
        }
        else if (element.nodeName === "#text") {
            processTextNode(element, context)
        }
        else {
            if (element.hasAttribute("repeat")) {
                processRepeatAttrib(element, context);
            }
            else if (element.hasAttribute("if")) {
                processIfAttrib(element, context);
            }
            else {
                processAttributes(element, context);
                processChildren(element, context);
                //add any mixins
                simpleMixin(element, context);
                //this is a work around for the proper option to be selected
                if (element.tagName === "SELECT") {
                    element.innerHTML = element.innerHTML;
                }
            }
        }

        //create the destroy method
        createDestroyMethod(element);
    }
    /**
    * Resolves the repeat expression, creats a context chain, and then processes
    * the childNodes for each iteration.
    * @function
    */
    function processRepeatElement(element, context) {
        var expr = element.getAttribute("expr")
        , template = element.innerHTML
        ;

        if (!!expr) {
            doRepeat(element.parentNode.tagName, element, template, expr, context);
        }
        //remove the repeat
        element.parentNode.removeChild(element);
    }
    /**
    * Processes an element with a repeat attribute
    * @function
    */
    function processRepeatAttrib(element, context) {
        var parentTag = element.parentNode.tagName
        , template
        , expr = element.getAttribute("repeat")
        ;
        //remove the repeat attribute
        element.removeAttribute("repeat");
        //set the innerHTML
        template = element.outerHTML
        //execute the repeat
        doRepeat(parentTag, element, template, expr, context);
        //destroy the template element
        element.parentNode.removeChild(element);
    }
    /**
    * Resolves the if expression, if true then inserts the if children
    * @function
    */
    function processIfElement(element, context) {
        var expr = element.getAttribute("expr")
        , elseEl = element.nextElementSibling
        , elseNodes
        ;

        if (!!elseEl && elseEl.nodeName === "ELSE") {
            elseNodes = elseEl.childNodes;
        }

        doIf(element, expr, element.childNodes, elseNodes, context);

        //remove the if
        element.parentNode.removeChild(element);
    }
    /**
    * Evaluates the if expression found in the if attribute
    * @function
    */
    function processIfAttrib(element, context) {
        var expr = element.getAttribute("if")
        , elseEl = element.nextElementSibling
        , pass
        ;

        element.removeAttribute("if");

        if (!!elseEl) {
            if (!elseEl.hasAttribute("else")) {
                elseEl = null;
            }
            else {
                elseEl.removeAttribute("else");
            }
        }

        pass = doIf(element, expr, [element], [elseEl], context);

        if(!pass) {
            element.parentNode.removeChild(element);
        }
        else if (!!elseEl) {
            elseEl.parentNode.removeChild(elseEl);
        }
    }
    /**
    * Evaluates the if expression, if fails, removes the element and all of it's
    * children. If the next sibling is an else, and the if passed, then it and
    * all of it's children
    * @function
    */
    function doIf(element, expr, ifNodes, elseNodes, context) {
        var pass = !!simpleExpression(expr.replace(TAG_PATT, "$1"), context).result
        , nodes;

        //if pass then use the if children
        if (pass) {
            nodes = insertNodes(element, ifNodes);
        }
        else if (!!elseNodes) {
            nodes = insertNodes(element, elseNodes);
        }

        //process the nodes
        if (!!nodes) {
            nodes.forEach(function forEachNode(node) {
                if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
                    processElement(node, context);
                }
            });
        }

        return pass;
    }
    /**
    * Processes a text node
    * @function
    */
    function processTextNode(textNode, context) {
        //get the text node's value
        var value =  textNode.nodeValue.replace(TRIM_PATT, "$1")
        //process the value and see if we have any keys
        , result = processValue(value, context)
        //reference to the parent element
        , parent = textNode.parentNode
        //create/get an el tag to hold the text
        , el = isEmpty(value) && null
            || parent.childNodes.length === 1 && parent
            || createElement('span')
        ;

        if (!isEmpty(value)) {
            //replace the text node with the el
            if (el !== parent) {
                el.watchers = [];
                parent.replaceChild(el, textNode);
            }

            //set the node value to the result
            el.innerHTML = result.value
                .replace(LN_END_PATT, "<br>")
                .replace(SPC_PATT, " ")
                .replace(TAB_PATT, "	");

            //add the watchers
            if (result.keys.length > 0) {
                watchKeys(el, context, result.keys, function () {
                    el.innerHTML = processValue(value, context).value;
                });
            }
        }
    }
    /**
    * Processes each attribute of the element
    * @function
    */
    function processAttributes(element, context) {
        if (!!element.attributes) {
            var removeList = []
            , attribs = Array.prototype.slice.apply(element.attributes)
            , repeatExpr
            ;

            attribs.forEach(function forEachAttr(attr) {
                //reset the regex
                TAG_PATT.lastIndex = 0;
                //check for on{event} attributes
                if (attr.name.indexOf("on") === 0 && TAG_PATT.exec(attr.value) !== null) {
                    addEventHandler(element, attr, context);
                    removeList.push(attr);
                }
                else {
                    processAttribute(element, context, attr);
                }
            });
            //remove any on attributes that we added handlers for
            removeList.forEach(function forEachRem(attr) {
                element.removeAttributeNode(attr);
            });
        }
    }
    /**
    * Processes the attribute, evaluating any expressions, adding any watch
    * handlers, and 2 way binding for input elements if the attribute is bind
    * @function
    */
    function processAttribute(element, context, attr) {
        //process the attrib value and see if we have keys
        var expr = attr.value
        , name = attr.name
        , result = processValue(attr.value, context);

        //add the watch handler for each key
        if(result.keys.length > 0) {
            watchKeys(element, context, result.keys, function watchHandler(key, value) {
                setAttribute(processValue(expr, context));
            });
        }

        setAttribute(result);

        function setAttribute(result) {
            var value = result.value;
            //if the values array has only one, then use that because it will
            // have the actual object or function rather than a string representation
            if (!result.hybrid && result.values.length === 1) {
                value = result.values[0];
            }
            if (isObject(value) || isFunc(value)) {
                element.getAttributeNode(attr.name)[cnsts.value] = value;
                element.setAttribute(name, "$value");
            }
            else if (!isNill(value)) {
                element.setAttribute(name, value);
            }
            else {
                element.removeAttribute(name);
            }
        }
    }
    /**
    * Adds an event handler to the element using the attribute name for the
    * event and evaluates the attribute value for the handler function.
    * @function
    */
    function addEventHandler(element, attr, context) {
        //reset the regEx
        TAG_PATT.lastIndex = 0;
        //the event name is the attribute name minus the on
        var name = attr.name.substring(2)
        //extract the expression
        , expr = TAG_PATT.exec(attr.value)
        , func
        ;
        //if there is a match resove the expression, should resolve a function
        if (!!expr) {
            func = simpleExpression(expr[1], context).result;
        }
        //if func is a function then create the handler
        if (isFunc(func)) {
            element.addEventListener(name, func);
        }
    }
    /**
    * Performs the repeat operation
    * @function
    */
    function doRepeat(parentTag, beforeEl, template, expr, context) {
        //evaluate the expression and get an iterator
        var repeatContext
        , element = createElement(parentTag)
        , iter = simpleExpression(expr.replace(TAG_PATT, "$1"), context).iterator
        , nodes;
        //make sure this evalutated to an iterator
        if (!!iter.next) {
            while(!isNill(repeatContext = iter.next())) {
                element.innerHTML = template;
                nodes = processChildren(element, repeatContext);
                insertNodes(beforeEl, nodes);
            }
        }
    }
    /**
    * Inserts the nodes before the beforeEl
    * @function
    */
    function insertNodes(beforeEl, nodes) {
        var parent = beforeEl.parentNode;
        //copy the node array because we are going to move elements from the node collection
        nodes = Array.prototype.slice.apply(nodes);
        //loop over the nodes an insert before
        nodes.forEach(function forEachNode(node) {
            //if (node.nodeType !== 3 || !WSP_PATT.test(node.nodeValue)) {
            parent.insertBefore(node, beforeEl);
            //}
        });
        return nodes;
    }
    /**
    * Finds all {:expressions:}, evaluates them, and then replaces the
    * {:expression:} with the result.
    * @function
    */
    function processValue(value, context) {
        var result = {
            "keys": []
            , "values": []
            , "hybrid": !!value.replace(TAG_PATT, "")
        };

        result.value = value.replace(TAG_PATT, function forEachMatch(tag, expr) {
            var expr = simpleExpression(expr, context);
            result.keys = result.keys.concat(expr.keys);
            result.values.push(expr.result);
            if (isObject(expr.result) || isFunc(expr.result)) {
                return "";
            }
            return expr.result;
        });

        if (!result.hybrid && result.values.length === 1) {
            if (result.value === "null" || result.value === "undefined") {
                result.values[0] = eval(result.value);
            }
        }

        return result;
    }
    /**
    * Adds the watch `handler` for each key, if it's parent is a watcher
    * @function
    */
    function watchKeys(element, context, keys, handler) {
        var watchers = [];

        keys.forEach(function forEachKey(key) {
            var obj = resolvePath(key, context)
            , guids
            , watcher = findWatcher(obj.parent, obj.index);
            if (!!watcher) {
                watchers.push({
                    "key": obj.index
                    , "parent": watcher
                    , "guids": watcher[cnsts.watch](obj.index, handler)
                });
            }
        });

        element.watchers = element.watchers.concat(watchers);
    }
    /**
    * Processes each childNode of the element
    * @function
    */
    function processChildren(element, context) {
        var node = element.firstChild, sibling;
        if (!!node) {
            do {
                sibling = node.nextSibling;
                if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
                    processElement(node, context);
                }
                else if (!!node.parentNode){
                    node.parentNode.removeChild(node);
                }
            }
            while((node = sibling));
        }
        return element.childNodes;
    }
    /**
    * Creates the closure that destroys the element and it's children
    * @function
    */
    function createDestroyMethod(element) {
        //add the destroy function
        var watchers = element.watchers;
        delete element.watchers;
        element[cnsts.destroy] = function destroy() {
            //destroy the elements watchers
            watchers.forEach(function (watcher) {
                watcher.parent[cnsts.unwatch](watcher.guids);
            });
            //destroy the children
            destroyChildren(element);
        };
    }
    /**
    * Loops through and destroys the child nodes
    * @function
    */
    function destroyChildren(element) {
        //run the destroy on the children or decend
        for (var i = 0, l = element.childNodes.length; i < l; i++) {
            if (element.childNodes[i].hasOwnProperty(cnsts.destroy)) {
                element.childNodes[i][cnsts.destroy]();
            }
            else {
                destroyChildren(element.childNodes[i]);
            }
        }
    }

    /**
    * @worker
    */
    return function SimpleTemplate(template, data) {
        //template could ben an array
        if(isArray(template)) {
            template = template.join("\n");
        }

        var element = convertHtml(template);

        process(element, data);

        return element.childNodes;
    };
}<commit_msg>Fixed issue in if attribute with undef else<commit_after>/**
* This factory produces a worker function that processes an html template with
* an object.
* 1. The data is merged with the template
* 2. The template is converted to an html element
* 3. If tags are processed
* 4. Repeat tags are processed
* 5. Bind input tags
* @factory
*/
function _SimpleTemplate(promise, createElement, simpleExpression, findWatcher, simpleMixin) {
    var TAG_PATT = /\{\:(.*?)\:\}/g
    , WSP_PATT = /^[ \t\n\r]+$/
    , TRIM_PATT = /^[\n\r\t ]+(.*?)[\n\r\t ]+$/
    , LN_END_PATT = /\r?\n/g
    , SPC_PATT = /[ ][ ]+/g
    , TAB_PATT = /\t/g
    , cnsts = {
        "value": "$value"
        , "destroy": "$destroy"
        , "watch": "$watch"
        , "unwatch": "$unwatch"
    }
    ;

    /**
    * Converts the html string into html elements wrapped in a span
    * @function
    */
    function convertHtml(template) {
        var el = createElement('div');
        el.innerHTML = template;
        return el;
    }
    /**
    * Begins the element processing, resolves/rejects the promise
    * @function
    */
    function process(node, data) {
        //create the starting context object and start processing the node
        if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
            processElement(node, createContext(data, node));
        }
    }
    /**
    * Create the context object, making data the prototype
    * @function
    */
    function createContext(data, element) {
        return Object.create(data, {
            "$parentElement": {
                "enumerable": true
                , "value": element
            }
        });
    }
    /**
    * Processes the element including special tags, if and repeat, and
    * processes it's shildren
    * @function
    */
    function processElement(element, context) {
        //set the element on the context
        context["$element"] = element;
        //a temporary container for watchers
        element.watchers = [];
        //see if this is a repeat
        if (element.nodeName === "REPEAT") {
            processRepeatElement(element, context);
        }
        else if (element.nodeName === "IF") {
            processIfElement(element, context)
        }
        else if (element.nodeName === "ELSE") {
            //remove the else
            element.parentNode.removeChild(element);
        }
        else if (element.nodeName === "#text") {
            processTextNode(element, context)
        }
        else {
            if (element.hasAttribute("repeat")) {
                processRepeatAttrib(element, context);
            }
            else if (element.hasAttribute("if")) {
                processIfAttrib(element, context);
            }
            else {
                processAttributes(element, context);
                processChildren(element, context);
                //add any mixins
                simpleMixin(element, context);
                //this is a work around for the proper option to be selected
                if (element.tagName === "SELECT") {
                    element.innerHTML = element.innerHTML;
                }
            }
        }

        //create the destroy method
        createDestroyMethod(element);
    }
    /**
    * Resolves the repeat expression, creats a context chain, and then processes
    * the childNodes for each iteration.
    * @function
    */
    function processRepeatElement(element, context) {
        var expr = element.getAttribute("expr")
        , template = element.innerHTML
        ;

        if (!!expr) {
            doRepeat(element.parentNode.tagName, element, template, expr, context);
        }
        //remove the repeat
        element.parentNode.removeChild(element);
    }
    /**
    * Processes an element with a repeat attribute
    * @function
    */
    function processRepeatAttrib(element, context) {
        var parentTag = element.parentNode.tagName
        , template
        , expr = element.getAttribute("repeat")
        ;
        //remove the repeat attribute
        element.removeAttribute("repeat");
        //set the innerHTML
        template = element.outerHTML
        //execute the repeat
        doRepeat(parentTag, element, template, expr, context);
        //destroy the template element
        element.parentNode.removeChild(element);
    }
    /**
    * Resolves the if expression, if true then inserts the if children
    * @function
    */
    function processIfElement(element, context) {
        var expr = element.getAttribute("expr")
        , elseEl = element.nextElementSibling
        , elseNodes
        ;

        if (!!elseEl && elseEl.nodeName === "ELSE") {
            elseNodes = elseEl.childNodes;
        }

        doIf(element, expr, element.childNodes, elseNodes, context);

        //remove the if
        element.parentNode.removeChild(element);
    }
    /**
    * Evaluates the if expression found in the if attribute
    * @function
    */
    function processIfAttrib(element, context) {
        var expr = element.getAttribute("if")
        , elseEl = element.nextElementSibling
        , pass
        ;

        element.removeAttribute("if");

        if (!!elseEl) {
            if (!elseEl.hasAttribute("else")) {
                elseEl = null;
            }
            else {
                elseEl.removeAttribute("else");
            }
        }

        pass = doIf(element, expr, [element], !!elseEl && [elseEl], context);

        if(!pass) {
            element.parentNode.removeChild(element);
        }
        else if (!!elseEl) {
            elseEl.parentNode.removeChild(elseEl);
        }
    }
    /**
    * Evaluates the if expression, if fails, removes the element and all of it's
    * children. If the next sibling is an else, and the if passed, then it and
    * all of it's children
    * @function
    */
    function doIf(element, expr, ifNodes, elseNodes, context) {
        var pass = !!simpleExpression(expr.replace(TAG_PATT, "$1"), context).result
        , nodes;

        //if pass then use the if children
        if (pass) {
            nodes = insertNodes(element, ifNodes);
        }
        else if (!!elseNodes) {
            nodes = insertNodes(element, elseNodes);
        }

        //process the nodes
        if (!!nodes) {
            nodes.forEach(function forEachNode(node) {
                if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
                    processElement(node, context);
                }
            });
        }

        return pass;
    }
    /**
    * Processes a text node
    * @function
    */
    function processTextNode(textNode, context) {
        //get the text node's value
        var value =  textNode.nodeValue.replace(TRIM_PATT, "$1")
        //process the value and see if we have any keys
        , result = processValue(value, context)
        //reference to the parent element
        , parent = textNode.parentNode
        //create/get an el tag to hold the text
        , el = isEmpty(value) && null
            || parent.childNodes.length === 1 && parent
            || createElement('span')
        ;

        if (!isEmpty(value)) {
            //replace the text node with the el
            if (el !== parent) {
                el.watchers = [];
                parent.replaceChild(el, textNode);
            }

            //set the node value to the result
            el.innerHTML = result.value
                .replace(LN_END_PATT, "<br>")
                .replace(SPC_PATT, " ")
                .replace(TAB_PATT, "	");

            //add the watchers
            if (result.keys.length > 0) {
                watchKeys(el, context, result.keys, function () {
                    el.innerHTML = processValue(value, context).value;
                });
            }
        }
    }
    /**
    * Processes each attribute of the element
    * @function
    */
    function processAttributes(element, context) {
        if (!!element.attributes) {
            var removeList = []
            , attribs = Array.prototype.slice.apply(element.attributes)
            , repeatExpr
            ;

            attribs.forEach(function forEachAttr(attr) {
                //reset the regex
                TAG_PATT.lastIndex = 0;
                //check for on{event} attributes
                if (attr.name.indexOf("on") === 0 && TAG_PATT.exec(attr.value) !== null) {
                    addEventHandler(element, attr, context);
                    removeList.push(attr);
                }
                else {
                    processAttribute(element, context, attr);
                }
            });
            //remove any on attributes that we added handlers for
            removeList.forEach(function forEachRem(attr) {
                element.removeAttributeNode(attr);
            });
        }
    }
    /**
    * Processes the attribute, evaluating any expressions, adding any watch
    * handlers, and 2 way binding for input elements if the attribute is bind
    * @function
    */
    function processAttribute(element, context, attr) {
        //process the attrib value and see if we have keys
        var expr = attr.value
        , name = attr.name
        , result = processValue(attr.value, context);

        //add the watch handler for each key
        if(result.keys.length > 0) {
            watchKeys(element, context, result.keys, function watchHandler(key, value) {
                setAttribute(processValue(expr, context));
            });
        }

        setAttribute(result);

        function setAttribute(result) {
            var value = result.value;
            //if the values array has only one, then use that because it will
            // have the actual object or function rather than a string representation
            if (!result.hybrid && result.values.length === 1) {
                value = result.values[0];
            }
            if (isObject(value) || isFunc(value)) {
                element.getAttributeNode(attr.name)[cnsts.value] = value;
                element.setAttribute(name, "$value");
            }
            else if (!isNill(value)) {
                element.setAttribute(name, value);
            }
            else {
                element.removeAttribute(name);
            }
        }
    }
    /**
    * Adds an event handler to the element using the attribute name for the
    * event and evaluates the attribute value for the handler function.
    * @function
    */
    function addEventHandler(element, attr, context) {
        //reset the regEx
        TAG_PATT.lastIndex = 0;
        //the event name is the attribute name minus the on
        var name = attr.name.substring(2)
        //extract the expression
        , expr = TAG_PATT.exec(attr.value)
        , func
        ;
        //if there is a match resove the expression, should resolve a function
        if (!!expr) {
            func = simpleExpression(expr[1], context).result;
        }
        //if func is a function then create the handler
        if (isFunc(func)) {
            element.addEventListener(name, func);
        }
    }
    /**
    * Performs the repeat operation
    * @function
    */
    function doRepeat(parentTag, beforeEl, template, expr, context) {
        //evaluate the expression and get an iterator
        var repeatContext
        , element = createElement(parentTag)
        , iter = simpleExpression(expr.replace(TAG_PATT, "$1"), context).iterator
        , nodes;
        //make sure this evalutated to an iterator
        if (!!iter.next) {
            while(!isNill(repeatContext = iter.next())) {
                element.innerHTML = template;
                nodes = processChildren(element, repeatContext);
                insertNodes(beforeEl, nodes);
            }
        }
    }
    /**
    * Inserts the nodes before the beforeEl
    * @function
    */
    function insertNodes(beforeEl, nodes) {
        var parent = beforeEl.parentNode;
        //copy the node array because we are going to move elements from the node collection
        nodes = Array.prototype.slice.apply(nodes);
        //loop over the nodes an insert before
        nodes.forEach(function forEachNode(node) {
            //if (node.nodeType !== 3 || !WSP_PATT.test(node.nodeValue)) {
            parent.insertBefore(node, beforeEl);
            //}
        });
        return nodes;
    }
    /**
    * Finds all {:expressions:}, evaluates them, and then replaces the
    * {:expression:} with the result.
    * @function
    */
    function processValue(value, context) {
        var result = {
            "keys": []
            , "values": []
            , "hybrid": !!value.replace(TAG_PATT, "")
        };

        result.value = value.replace(TAG_PATT, function forEachMatch(tag, expr) {
            var expr = simpleExpression(expr, context);
            result.keys = result.keys.concat(expr.keys);
            result.values.push(expr.result);
            if (isObject(expr.result) || isFunc(expr.result)) {
                return "";
            }
            return expr.result;
        });

        if (!result.hybrid && result.values.length === 1) {
            if (result.value === "null" || result.value === "undefined") {
                result.values[0] = eval(result.value);
            }
        }

        return result;
    }
    /**
    * Adds the watch `handler` for each key, if it's parent is a watcher
    * @function
    */
    function watchKeys(element, context, keys, handler) {
        var watchers = [];

        keys.forEach(function forEachKey(key) {
            var obj = resolvePath(key, context)
            , guids
            , watcher = findWatcher(obj.parent, obj.index);
            if (!!watcher) {
                watchers.push({
                    "key": obj.index
                    , "parent": watcher
                    , "guids": watcher[cnsts.watch](obj.index, handler)
                });
            }
        });

        element.watchers = element.watchers.concat(watchers);
    }
    /**
    * Processes each childNode of the element
    * @function
    */
    function processChildren(element, context) {
        var node = element.firstChild, sibling;
        if (!!node) {
            do {
                sibling = node.nextSibling;
                if (node.nodeType === 1 || (node.nodeType === 3 && !WSP_PATT.test(node.nodeValue))) {
                    processElement(node, context);
                }
                else if (!!node.parentNode){
                    node.parentNode.removeChild(node);
                }
            }
            while((node = sibling));
        }
        return element.childNodes;
    }
    /**
    * Creates the closure that destroys the element and it's children
    * @function
    */
    function createDestroyMethod(element) {
        //add the destroy function
        var watchers = element.watchers;
        delete element.watchers;
        element[cnsts.destroy] = function destroy() {
            //destroy the elements watchers
            watchers.forEach(function (watcher) {
                watcher.parent[cnsts.unwatch](watcher.guids);
            });
            //destroy the children
            destroyChildren(element);
        };
    }
    /**
    * Loops through and destroys the child nodes
    * @function
    */
    function destroyChildren(element) {
        //run the destroy on the children or decend
        for (var i = 0, l = element.childNodes.length; i < l; i++) {
            if (element.childNodes[i].hasOwnProperty(cnsts.destroy)) {
                element.childNodes[i][cnsts.destroy]();
            }
            else {
                destroyChildren(element.childNodes[i]);
            }
        }
    }

    /**
    * @worker
    */
    return function SimpleTemplate(template, data) {
        //template could ben an array
        if(isArray(template)) {
            template = template.join("\n");
        }

        var element = convertHtml(template);

        process(element, data);

        return element.childNodes;
    };
}<|endoftext|>


<commit_before>'use strict';

// MODULES //

var tape = require( 'tape' );
var RE = require( './../lib' );

// TESTS //

tape( 'main export is a regular expression', function test( t ) {
	t.ok( true, __filename );
	t.equal( RE instanceof RegExp, true, 'main export is a regular expression' );
	t.end();
});

tape( 'the regular expression detects a regular expression string', function test( t ) {
	var values;
	var i;

	values = [
		'/beep/',
		'/(?:)/',
		'/whatever/',
		'/this/g',
		'/that/i',
		'/again/mgi',
		'/^.*$/ig',
		'/^\\/([^\\/]+)\\/(.*)$/',
		'/^\\/((?:\\\\\/|[^\\/])+)\\/(.*)$/'
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( RE.test( values[i] ), true, values[i] );
	}
	t.end();
});

tape( 'the regular expression detects a non-regular expression string', function test( t ) {
	var values;
	var i;

	values = [
		'beep',
		'5',
		'',
		'/dir',
		'/dir//',
		'/dir/goo'
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( RE.test( values[i] ), false, values[i] );
	}
	t.end();
});
<commit_msg>Disable lint rule<commit_after>'use strict';

// MODULES //

var tape = require( 'tape' );
var RE = require( './../lib' );

// TESTS //

tape( 'main export is a regular expression', function test( t ) {
	t.ok( true, __filename );
	t.equal( RE instanceof RegExp, true, 'main export is a regular expression' );
	t.end();
});

tape( 'the regular expression detects a regular expression string', function test( t ) {
	var values;
	var i;

	values = [
		'/beep/',
		'/(?:)/',
		'/whatever/',
		'/this/g',
		'/that/i',
		'/again/mgi',
		'/^.*$/ig',
		'/^\\/([^\\/]+)\\/(.*)$/',
		'/^\\/((?:\\\\\/|[^\\/])+)\\/(.*)$/' // eslint-disable-line no-useless-escape
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( RE.test( values[i] ), true, values[i] );
	}
	t.end();
});

tape( 'the regular expression detects a non-regular expression string', function test( t ) {
	var values;
	var i;

	values = [
		'beep',
		'5',
		'',
		'/dir',
		'/dir//',
		'/dir/goo'
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( RE.test( values[i] ), false, values[i] );
	}
	t.end();
});
<|endoftext|>


<commit_before>// reset assigned jQuery
window.jQuery = (__jQuery) ? __jQuery : window.jQuery || undefined;
window.$ = window.jQuery;
<commit_msg>adds variable to post [ci skip]<commit_after>// reset assigned jQuery
var __jQuery;
window.jQuery = (__jQuery) ? __jQuery : window.jQuery || undefined;
window.$ = window.jQuery;
<|endoftext|>