<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const execSync = require('child_process').execSync;
const os = require('os');

function convertPowershellDate(date) {
  const parts = date.toString().split(' ');
  return `${parts[0]} ${parts[1]} ${parts[2]} ${parts[3]} ${parts[4]}`;
}

function processLogEvent(event) {
  console.log('event', event);
  let createdAtMilis = event.TimeCreated.replace(/\//g, '').replace('Date(', '').replace(')', '');
  createdAtMilis = parseInt(createdAtMilis, 10);
  return {
    id: event.Id,
    providerName: event.ProviderName,
    providerId: event.ProviderId,
    logName: event.LogName,
    processId: event.ProcessId,
    threadId: event.threadId,
    machineName: event.MachineName,
    timeCreated: new Date(createdAtMilis),
    levelDisplayName: event.LevelDisplayName,
    message: event.Message
  };
}

function parseLogData(data) {
  let events;
  try {
    events = JSON.parse(data);
  } catch (e) {
    throw e;
  }

  return Array.isArray(events) ?
    events.map(event => processLogEvent(event)) :
    [processLogEvent(events)];
}

class WinEventEmitter extends EventEmitter {
  constructor (options) {
    super();

    if (!/win/gi.test(os.platform())) {
      throw new Error('Only Windows is supported');
    }

    const defaultOptions = {
      providers: ['Microsoft-Windows-DNS-Client'],
      maxEvents: 100,
      frequency: 10000
    };
    this.options = Object.assign({}, defaultOptions, options);
    this.options.startTime || (this.options.startTime = Date.now());
    this.options.endTime  || (this.options.endTime = new Date(Date.now() + this.options.frequency));
  }

  start () {
    setTimeout(() => {
      const providers = `'${this.options.providers.join('\', \'')}'`;
      const startTime = convertPowershellDate(this.options.startTime), endTime = convertPowershellDate(this.options.endTime);

      let powershellCmd = `powershell "Get-WinEvent -FilterHashTable @{ProviderName=${providers}; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}`;

      if (this.options.computerName) {
        powershellCmd += ` -ComputerName ${this.options.computerName}`;
      }

      powershellCmd += ' | ConvertTo-Json"';

      let data;
      try {
        data = execSync(powershellCmd, {stdio: [1]}).toString();
      } catch (e) {
        this.emit('error', e);
      }

      if (data) {
        this.emit('data', parseLogData(data));
      }

      if (this._stop) { return; }

      this.options.startTime = new Date(Date.now());
      this.options.endTime = new Date(Date.now() + this.options.frequency);
      this.start();
    }, this.options.frequency);
  }

  stop () {
    this._stop = true;
    this.emit('close');
  }
}

module.exports = WinEventEmitter;
<commit_msg>fix(startDate) - fixing startDate initial value<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const execSync = require('child_process').execSync;
const os = require('os');

function convertPowershellDate(date) {
  const parts = date.toString().split(' ');
  return `${parts[0]} ${parts[1]} ${parts[2]} ${parts[3]} ${parts[4]}`;
}

function processLogEvent(event) {
  console.log('event', event);
  let createdAtMilis = event.TimeCreated.replace(/\//g, '').replace('Date(', '').replace(')', '');
  createdAtMilis = parseInt(createdAtMilis, 10);
  return {
    id: event.Id,
    providerName: event.ProviderName,
    providerId: event.ProviderId,
    logName: event.LogName,
    processId: event.ProcessId,
    threadId: event.threadId,
    machineName: event.MachineName,
    timeCreated: new Date(createdAtMilis),
    levelDisplayName: event.LevelDisplayName,
    message: event.Message
  };
}

function parseLogData(data) {
  let events;
  try {
    events = JSON.parse(data);
  } catch (e) {
    throw e;
  }

  return Array.isArray(events) ?
    events.map(event => processLogEvent(event)) :
    [processLogEvent(events)];
}

class WinEventEmitter extends EventEmitter {
  constructor (options) {
    super();

    if (!/win/gi.test(os.platform())) {
      throw new Error('Only Windows is supported');
    }

    const defaultOptions = {
      providers: ['Microsoft-Windows-DNS-Client'],
      maxEvents: 100,
      frequency: 10000
    };
    this.options = Object.assign({}, defaultOptions, options);
    this.options.startTime || (this.options.startTime = new Date());
    this.options.endTime  || (this.options.endTime = new Date(Date.now() + this.options.frequency));
  }

  start () {
    setTimeout(() => {
      const providers = `'${this.options.providers.join('\', \'')}'`;
      const startTime = convertPowershellDate(this.options.startTime), endTime = convertPowershellDate(this.options.endTime);

      let powershellCmd = `powershell "Get-WinEvent -FilterHashTable @{ProviderName=${providers}; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}`;

      if (this.options.computerName) {
        powershellCmd += ` -ComputerName ${this.options.computerName}`;
      }

      powershellCmd += ' | ConvertTo-Json"';

      let data;
      try {
        data = execSync(powershellCmd, {stdio: [1]}).toString();
      } catch (e) {
        // Ignore missing events
        if (!e.message.indexOf('Get-WinEvent : No events were found that match the specified selection criteria.')) {
          this.emit('error', e);
        }
      }

      if (data) {
        this.emit('data', parseLogData(data));
      }

      if (this._stop) { return; }

      this.options.startTime = new Date(Date.now());
      this.options.endTime = new Date(Date.now() + this.options.frequency);
      this.start();
    }, this.options.frequency);
  }

  stop () {
    this._stop = true;
    this.emit('close');
  }
}

module.exports = WinEventEmitter;
<|endoftext|>


<commit_before>
//= require <widgets/natives/box>

Ergo.declare('Ergo.widgets.UploadBox', 'Ergo.widgets.Box', {

	defaults: {
		cls: 'e-upload-box',
		style: {'position': 'relative', 'display': 'inline-block'},
		events: {
			'mousedown': function(e, w) { w.content.states.set('clicked'); },
			'mouseup': function(e, w) { w.content.states.unset('clicked'); },
			'mouseenter': function(e, w) { w.content.states.set('hovered'); },
			'mouseleave': function(e, w) { w.content.states.unset('hovered'); }
		},

		transitions: {
			'> disabled': function() {
				this._uploader.content.el.attr('disabled', true);
			},
			'disabled >': function() {
				this._uploader.content.el.attr('disabled', false);
			}
		},

		components: {
			content: {
				weight: 10
			},
			_uploader: {
				opacity: 0,
				weight: 20,
				html: '<form name="file_uploader" method="POST" enctype="multipart/form-data"/>',
				style: {'overflow': 'hidden', 'position': 'absolute', 'left': 0, 'top': 0, 'right': 0, 'bottom': 0},
				content: {
					etype: 'file',
					html: '<input name="file" type="file" size="1">',
					style: {'font-size': 300, 'right': 0, 'top': 0, 'position': 'absolute', 'cursor': 'pointer'},
					opacity: 0,
					events: {
						'change': function(e, w) {
							var val = $(this).val();
							if(val)
//								w.events.bubble('action', {file: val}, e);
								w.events.bubble('fileSelect', {file: val}, e);
						}
					}
				}
			}/*,
			_target: {
				html: '<iframe name="uploader_target" frameborder="no" src="about:blank"/>',
				height: 0,
				width: 0,
				events: {
					'load': function(e, w) {
						//FIXME это работает не для всех браузеров
						var text = w.el[0].contentWindow.document.body.innerHTML;
						if(text) {
							var m = text.match(/^<pre.*>(.*)<\/pre>$/);
							text = m[1];
//							text = text.substring(5, text.length-6);
							w.events.bubble('upload', {textData: text});
						}
					}
				}
			}*/
		}
	},

	upload: function(path, data) {

		var target_name = '_target'+Ergo.timestamp();

		var result = $.Deferred();

		this.components.set(target_name, {
			etype: 'box',
			html: '<iframe name="upload'+target_name+'" frameborder="no" src="about:blank"/>',
			height: 0,
			width: 0,
			events: {
				'load': function(e, w) {
					//FIXME это работает не для всех браузеров
					var text = w.el[0].contentWindow.document.body.innerHTML;
					//FIXME проверка на text == null некорректна
					if(text) {
						var m = text.match(/^<pre.*>(.*)<\/pre>$/);
						var text2 = (m) ? m[1] : null;

//						w.events.bubble('upload', {textData: text, data: data});

						result.resolve({rawData: text, textData: text2});
//						w.destroy();
					}
				}
			}
		});

		this._uploader.el.attr('action', path);
		this._uploader.el.attr('target', 'upload'+target_name);

		if(data) {
			for(var name in data) {
				var val = data[name];
				var data_el = $('<input name="'+name+'"/>');
				data_el.val(val);
				this._uploader.el.append(data_el);
			}

			// var data_el = $('<input name="data"/>');
			// data_el.val(JSON.stringify(data));
			// this._uploader.el.append(data_el);
		}

		this._uploader.el.submit();

		return result;
	}

//	setDisabled: function(v) {
//	}

}, 'upload-box');
<commit_msg>fix upload<commit_after>
//= require <widgets/natives/box>

Ergo.declare('Ergo.widgets.UploadBox', 'Ergo.widgets.Box', {

	defaults: {
		cls: 'e-upload-box',
		style: {'position': 'relative', 'display': 'inline-block'},
		events: {
			'mousedown': function(e, w) { w.content.states.set('clicked'); },
			'mouseup': function(e, w) { w.content.states.unset('clicked'); },
			'mouseenter': function(e, w) { w.content.states.set('hovered'); },
			'mouseleave': function(e, w) { w.content.states.unset('hovered'); }
		},

		transitions: {
			'> disabled': function() {
				this._uploader.content.el.attr('disabled', true);
			},
			'disabled >': function() {
				this._uploader.content.el.attr('disabled', false);
			}
		},

		components: {
			content: {
				weight: 10
			},
			_uploader: {
				opacity: 0,
				weight: 20,
				html: '<form name="file_uploader" method="POST" enctype="multipart/form-data"/>',
				style: {'overflow': 'hidden', 'position': 'absolute', 'left': 0, 'top': 0, 'right': 0, 'bottom': 0},
				content: {
					etype: 'file',
					html: '<input name="file" type="file" size="1">',
					style: {'font-size': 300, 'right': 0, 'top': 0, 'position': 'absolute', 'cursor': 'pointer'},
					opacity: 0,
					events: {
						'change': function(e, w) {
							var val = $(this).val();
							if(val)
//								w.events.bubble('action', {file: val}, e);
								w.events.bubble('fileSelect', {file: val}, e);
						}
					}
				}
			}/*,
			_target: {
				html: '<iframe name="uploader_target" frameborder="no" src="about:blank"/>',
				height: 0,
				width: 0,
				events: {
					'load': function(e, w) {
						//FIXME это работает не для всех браузеров
						var text = w.el[0].contentWindow.document.body.innerHTML;
						if(text) {
							var m = text.match(/^<pre.*>(.*)<\/pre>$/);
							text = m[1];
//							text = text.substring(5, text.length-6);
							w.events.bubble('upload', {textData: text});
						}
					}
				}
			}*/
		}
	},

	upload: function(path, data) {

		var target_name = '_target'+Ergo.timestamp();

		var result = $.Deferred();

		this.components.set(target_name, {
			etype: 'box',
			html: '<iframe name="upload'+target_name+'" frameborder="no" src="about:blank"/>',
			height: 0,
			width: 0,
			events: {
				'load': function(e, w) {
					//FIXME это работает не для всех браузеров
					var text = w.el[0].contentWindow.document.body.innerHTML;

					//FIXME проверка на text == null некорректна
					if(text) {
						var m = text.match(/^<pre.*>(.*)<\/pre>$/);
						var text2 = (m) ? m[1] : text;

//						w.events.bubble('upload', {textData: text, data: data});

						result.resolve({rawData: text, textData: text2});
//						w.destroy();
					}
				}
			}
		});

		this._uploader.el.attr('action', path);
		this._uploader.el.attr('target', 'upload'+target_name);

		if(data) {
			for(var name in data) {
				var val = data[name];
				var data_el = $('<input name="'+name+'"/>');
				data_el.val(val);
				this._uploader.el.append(data_el);
			}

			// var data_el = $('<input name="data"/>');
			// data_el.val(JSON.stringify(data));
			// this._uploader.el.append(data_el);
		}

		this._uploader.el.submit();

		return result;
	}

//	setDisabled: function(v) {
//	}

}, 'upload-box');
<|endoftext|>


<commit_before>// Create a Paper.js Path to draw a line into it:
var line = new Path();
line.style = {
    strokeColor: 'black',
    strokeWidth: 4
}

var start = new Point(300, 100);
// Move to start and draw a line from there
line.moveTo(start);
// Note the plus operator on Point objects.
line.lineTo(start + [200, -50]);

// if view is resized and then redrawn, pathCircle will recenter itself
var pathCircle = new Path.Circle({
    center: view.center,
    radius: 30,
    fillColor: new Color(0.9, 0.5, 0.5),
    strokeColor: 'red',
    strokeWidth: 10
});

// rounded rectangle
var rectOrigin = new Point(50, 140)
var rectHeight = 50
var rectWidth = 200
var rectEnd = new Point(rectOrigin.x + rectWidth, rectOrigin.y + rectHeight);
var rect = new Rectangle(rectOrigin, rectEnd);
var cornerSize = new Size(20, 20);
var roundRect = new Path.RoundRectangle(rect, cornerSize);
roundRect.style = {
    fillColor: 'orange',
    strokeColor: 'brown',
    strokeWidth: 6
};

// text
var text = new PointText({
    point: [rectOrigin.x + 20, (rectOrigin.y + rectHeight/2)],
    content: 'Hello text',
    fillColor: 'brown',
    fontSize: 25
});
<commit_msg>Create player object with a name, rounded rectangle and text showing name. Loop through array of players and draw them all.<commit_after>// Create a Paper.js Path to draw a line into it:
var line = new Path();
line.style = {
    strokeColor: 'black',
    strokeWidth: 4
}

var start = new Point(300, 100);
// Move to start and draw a line from there
line.moveTo(start);
// Note the plus operator on Point objects.
line.lineTo(start + [200, -50]);

// if view is resized and then redrawn, pathCircle will recenter itself
var pathCircle = new Path.Circle({
    center: view.center,
    radius: 30,
    fillColor: new Color(0.9, 0.5, 0.5),
    strokeColor: 'red',
    strokeWidth: 10
});

// Create player object with a name, rounded rectangle and text showing name.
function Player(name, origin, textColor)
{
    this.name = name;

    // rounded rectangle
    var rectSize = new Size(200, 50);
    var rect = new Rectangle(origin, rectSize);

    var cornerSize = new Size(20, 20);
    this.roundRect = new Path.RoundRectangle(rect, cornerSize);
    this.roundRect.style = {
        fillColor: 'orange',
        strokeColor: 'brown',
        strokeWidth: 6
    };

        //point: [this.position.x + 20, this.position.y + rectSize.height/2],
    this.text = new PointText({
        point: [origin.x + 20, origin.y + rectSize.height/2],
        content: this.name,
        fillColor: textColor,
        fontSize: 25
    });

    //return new Group([this.roundRect, this.text]);
}

// must use new Point, not [50, 140]
playerOrigin = new Point(50, 80);
//var playerA = Player(playerOrigin, 'blue');
//var playerA = new Player(playerOrigin, 'blue');
var playerA = new Player('bill', playerOrigin, 'blue');

// when playerA returns new Group and instantiate as = Player, set position works
// when playerA doesn't return group and instantiate as = new Player, set position doesn't work??
// for group or other 'item'?
//playerA.position = [300, 340];

// when playerA returns new Group and instantiate as = Player, set color doesn't work
// when playerA doesn't return new Group and instantiate as = new Player, set color works
playerA.text.fillColor = 'red';

// Loop through array of players and draw them all.
var playerNames = ['Bill', 'Joe', 'Fred', 'John'];
var offset = 60;
for(var i = 0; i < playerNames.length; i++) {
    var player = new Player(playerNames[i], playerOrigin, 'blue');
    // TODO: translate as a Group or using a function
    player.roundRect.translate(0, offset * i);
    player.text.translate(0, offset * i);
};
<|endoftext|>


<commit_before>/**
 * Define a simple addModule function. Each website that the changetip extension
 * supports will be a module - pass in a name and a function that returns a module
 *
 * @type {Object}
 */
 var modules = {},
 Utils = {},
 ChangeTip = {};

 function addModule(moduleID, defineModule) {
	var base = {
		moduleID: moduleID,
		moduleName: moduleID,
		category: 'General',
		options: {},
		description: '',
		// the string used to mention changetip on this medium
		ctMentionString: null,
		// given a tipAmount, returns the message to be placed into a comment box, etc.
		getTipMessage: function(tipAmount) {
			throw "This module, " + moduleID + ", needs its getTipMessage function defined";
		},
		// handles the placement of the getTipMessage text
		submit: function(tipAmount) {
			throw "This module, " + moduleID + ", needs its submit function defined";
		},
		isEnabled: function() {
			// TODO: if we hypothetically allowed enable/disable of modules, we would
			// check a setting here and return false if the user has disabled.
			return true;
		},
		/**
		 * URLs this module should be run on
		 *
		 * @type {Array}
		 */
		include: [
			'*'
		],
		/**
		 * URLs this module should not be run on
		 *
		 * @type {Array}
		 */
		exclude: [],
		beforeLoad: function() { },
		init: function() { }
	};

	var module = defineModule.call(base, base, moduleID) || base;
	modules[moduleID] = module;
 }

/**
 * Iterate through an array in chunks, executing a callback on each element.
 * Each chunk is handled asynchronously from the others with a delay betwen each batch.
 * If the provided callback returns false iteration will be halted.
 */
 Utils.forEachChunked = function(array, chunkSize, delay, call) {
	if (typeof array === 'undefined' || array === null) {
		return;
	}
	if (typeof chunkSize === 'undefined' || chunkSize === null || chunkSize < 1) {
		return;
	}
	if (typeof delay === 'undefined' || delay === null || delay < 0) {
		return;
	}
	if (typeof call === 'undefined' || call === null) {
		return;
	}
	var counter = 0,
	length = array.length;

	function doChunk() {
		for (var end = Math.min(length, counter + chunkSize); counter < end; counter++) {
			var ret = call(array[counter], counter, array);
			if (ret === false) {
				return;
			}
		}
		if (counter < length) {
			window.setTimeout(doChunk, delay);
		}
	}
	window.setTimeout(doChunk, delay);
};

Utils.createElement = function(elementType, id, classname, textContent) {
	var obj = document.createElement(elementType);
	if (id) {
		obj.setAttribute('id', id);
	}
	if ((typeof classname !== 'undefined') && classname) {
		obj.setAttribute('class', classname);
	}
	if (textContent) {
		obj.textContent = textContent;
	}
	return obj;
};

ChangeTip = {
	init: function() {
		// figure out which module to run, and fire its init function
		var me = this,
			bgImgURL = chrome.extension.getURL('images/changetip_round_icon.png');

		me.activeModuleName = me.getModuleFromDomain();
		if (modules[me.activeModuleName] && typeof modules[me.activeModuleName].init === 'function') {
			me.activeModule = modules[me.activeModuleName];
			modules[me.activeModuleName].init();
		} else {
			// no module to run.
			return;
		}

		// create the dialog DIV and its children...
		me.dialog = Utils.createElement('div', 'changeTipDialog', null, null);
		me.dialogHeader = Utils.createElement('div', 'changeTipDialog-header', null, null);
		me.dialogHeader.textContent = 'ChangeTip';
		me.dialogHeader.style.backgroundImage = 'url('+bgImgURL+')';

		me.dialogCloseButton = Utils.createElement('div', 'changeTipDialog-closeButton', null, null);
		me.dialogCloseButton.innerHTML = '✕';
		me.dialogCloseButton.addEventListener('click', me.closeDialog, false);
		me.dialogHeader.appendChild(me.dialogCloseButton);

		me.dialogBody = Utils.createElement('div', 'changeTipDialog-body', null, null);
		me.dialogForm = Utils.createElement('form');
		me.dialogForm.addEventListener('submit', me.submit, false);

		me.dialogInputLabel = Utils.createElement('label');
		me.dialogInputLabel.setAttribute('for','changeTip-amount');
		me.dialogInputLabel.textContent = 'Enter an amount:';

		me.dialogUsername = Utils.createElement('span', 'changeTipDialog-toUsername');

		me.tipAmountHelp = Utils.createElement('a','changeTipDialog-amount-help');
		me.tipAmountHelp.textContent = '?';
		me.tipAmountHelp.setAttribute('target','_blank');
		me.tipAmountHelp.setAttribute('href','https://www.changetip.com/tip-amounts');

		me.dialogInput = Utils.createElement('input','changeTip-amount');
		me.dialogInput.setAttribute('type','text');
		me.dialogInput.setAttribute('placeholder', 'Enter your tip amount...');

		me.submitButton = Utils.createElement('input', 'changeTipDialog-submit');
		me.submitButton.setAttribute('type','submit');
		me.submitButton.value = 'Send Tip';

		me.clearDiv = Utils.createElement('div', null, 'changetip-clear');

		me.dialogForm.appendChild(me.dialogInputLabel);
		me.dialogForm.appendChild(me.tipAmountHelp);
		me.dialogForm.appendChild(me.dialogInput);
		me.dialogForm.appendChild(me.dialogUsername);
		me.dialogForm.appendChild(me.submitButton);

		me.dialogBody.appendChild(me.dialogForm);
		me.dialogBody.appendChild(me.clearDiv);

		me.dialog.appendChild(me.dialogHeader);
		me.dialog.appendChild(me.dialogBody);

		document.body.appendChild(me.dialog);
	},
	getModuleFromDomain: function() {
		var secondLevelDomain = window.location.hostname.split('.').slice(-2).join('.');
		return this.domainModules[secondLevelDomain];
	},
	domainModules: {
		'reddit.com': 'reddit'
	},
	// TODO: remember last tip amount, default to that on new tips
	getSetting: function(key) {
		// TODO: make actual getters/setters here.
		// use monikers - link to a reference?
		if (key === 'defaultAmount') {
			return '$10';
		}
	},
	openDialog: function(config) {
		config = config || {
			x: 200,
			y: 200,
			username: 'username'
		};
		ChangeTip.dialog.style.top = parseInt(config.y, 10) + 'px';
		ChangeTip.dialog.style.left = parseInt(config.x, 10) + 'px';
		ChangeTip.dialog.classList.add('ct-visible');
		ChangeTip.dialogUsername.textContent = 'sending to: ' + config.username;

		BabelExt.storage.get('lastAmount', ChangeTip.populateLastAmount);

		window.addEventListener('keyup', ChangeTip.listenForEscape, false);
	},
	submit: function(e) {
		var tipString;
		e.preventDefault();

		ChangeTip.activeModule.submit(ChangeTip.dialogInput.value);
		BabelExt.storage.set('lastAmount', ChangeTip.dialogInput.value, ChangeTip.noop);
		ChangeTip.closeDialog();
	},
	populateLastAmount: function(returnData) {
		ChangeTip.dialogInput.value = returnData.value || '$5';
	},
	closeDialog: function() {
		ChangeTip.dialog.classList.remove('ct-visible');
		window.removeEventListener('keyup', ChangeTip.listenForEscape, false);
	},
	listenForEscape: function(e) {
		if (e.keyCode === 27) {
			ChangeTip.closeDialog();
		}
	},
	noop: function() {}
};<commit_msg>fix for input focus not functioning - seems to not play nice when called during CSS transition<commit_after>/**
 * Define a simple addModule function. Each website that the changetip extension
 * supports will be a module - pass in a name and a function that returns a module
 *
 * @type {Object}
 */
 var modules = {},
 Utils = {},
 ChangeTip = {};

 function addModule(moduleID, defineModule) {
	var base = {
		moduleID: moduleID,
		moduleName: moduleID,
		category: 'General',
		options: {},
		description: '',
		// the string used to mention changetip on this medium
		ctMentionString: null,
		// given a tipAmount, returns the message to be placed into a comment box, etc.
		getTipMessage: function(tipAmount) {
			throw "This module, " + moduleID + ", needs its getTipMessage function defined";
		},
		// handles the placement of the getTipMessage text
		submit: function(tipAmount) {
			throw "This module, " + moduleID + ", needs its submit function defined";
		},
		isEnabled: function() {
			// TODO: if we hypothetically allowed enable/disable of modules, we would
			// check a setting here and return false if the user has disabled.
			return true;
		},
		/**
		 * URLs this module should be run on
		 *
		 * @type {Array}
		 */
		include: [
			'*'
		],
		/**
		 * URLs this module should not be run on
		 *
		 * @type {Array}
		 */
		exclude: [],
		beforeLoad: function() { },
		init: function() { }
	};

	var module = defineModule.call(base, base, moduleID) || base;
	modules[moduleID] = module;
 }

/**
 * Iterate through an array in chunks, executing a callback on each element.
 * Each chunk is handled asynchronously from the others with a delay betwen each batch.
 * If the provided callback returns false iteration will be halted.
 */
 Utils.forEachChunked = function(array, chunkSize, delay, call) {
	if (typeof array === 'undefined' || array === null) {
		return;
	}
	if (typeof chunkSize === 'undefined' || chunkSize === null || chunkSize < 1) {
		return;
	}
	if (typeof delay === 'undefined' || delay === null || delay < 0) {
		return;
	}
	if (typeof call === 'undefined' || call === null) {
		return;
	}
	var counter = 0,
	length = array.length;

	function doChunk() {
		for (var end = Math.min(length, counter + chunkSize); counter < end; counter++) {
			var ret = call(array[counter], counter, array);
			if (ret === false) {
				return;
			}
		}
		if (counter < length) {
			window.setTimeout(doChunk, delay);
		}
	}
	window.setTimeout(doChunk, delay);
};

Utils.createElement = function(elementType, id, classname, textContent) {
	var obj = document.createElement(elementType);
	if (id) {
		obj.setAttribute('id', id);
	}
	if ((typeof classname !== 'undefined') && classname) {
		obj.setAttribute('class', classname);
	}
	if (textContent) {
		obj.textContent = textContent;
	}
	return obj;
};

ChangeTip = {
	init: function() {
		// figure out which module to run, and fire its init function
		var me = this,
			bgImgURL = chrome.extension.getURL('images/changetip_round_icon.png');

		me.activeModuleName = me.getModuleFromDomain();
		if (modules[me.activeModuleName] && typeof modules[me.activeModuleName].init === 'function') {
			me.activeModule = modules[me.activeModuleName];
			modules[me.activeModuleName].init();
		} else {
			// no module to run.
			return;
		}

		// create the dialog DIV and its children...
		me.dialog = Utils.createElement('div', 'changeTipDialog', null, null);

		// we can't focus the input until the css transition is complete, for
		// some reason it doesn't work if called during the transition.
		me.dialog.addEventListener('transitionend', function(e) {
			if ((e.propertyName === 'opacity') && (e.target.classList.contains('ct-visible'))) {
				me.dialogInput.focus();
			}
		}, false);

		me.dialogHeader = Utils.createElement('div', 'changeTipDialog-header', null, null);
		me.dialogHeader.textContent = 'ChangeTip';
		me.dialogHeader.style.backgroundImage = 'url('+bgImgURL+')';

		me.dialogCloseButton = Utils.createElement('div', 'changeTipDialog-closeButton', null, null);
		me.dialogCloseButton.innerHTML = '✕';
		me.dialogCloseButton.addEventListener('click', me.closeDialog, false);
		me.dialogHeader.appendChild(me.dialogCloseButton);

		me.dialogBody = Utils.createElement('div', 'changeTipDialog-body', null, null);
		me.dialogForm = Utils.createElement('form');
		me.dialogForm.addEventListener('submit', me.submit, false);

		me.dialogInputLabel = Utils.createElement('label');
		me.dialogInputLabel.setAttribute('for','changeTip-amount');
		me.dialogInputLabel.textContent = 'Enter an amount:';

		me.dialogUsername = Utils.createElement('span', 'changeTipDialog-toUsername');

		me.tipAmountHelp = Utils.createElement('a','changeTipDialog-amount-help');
		me.tipAmountHelp.textContent = '?';
		me.tipAmountHelp.setAttribute('target','_blank');
		me.tipAmountHelp.setAttribute('href','https://www.changetip.com/tip-amounts');

		me.dialogInput = Utils.createElement('input','changeTip-amount');
		me.dialogInput.setAttribute('type','text');
		me.dialogInput.setAttribute('placeholder', 'Enter your tip amount...');

		me.submitButton = Utils.createElement('input', 'changeTipDialog-submit');
		me.submitButton.setAttribute('type','submit');
		me.submitButton.value = 'Send Tip';

		me.clearDiv = Utils.createElement('div', null, 'changetip-clear');

		me.dialogForm.appendChild(me.dialogInputLabel);
		me.dialogForm.appendChild(me.tipAmountHelp);
		me.dialogForm.appendChild(me.dialogInput);
		me.dialogForm.appendChild(me.dialogUsername);
		me.dialogForm.appendChild(me.submitButton);

		me.dialogBody.appendChild(me.dialogForm);
		me.dialogBody.appendChild(me.clearDiv);

		me.dialog.appendChild(me.dialogHeader);
		me.dialog.appendChild(me.dialogBody);

		document.body.appendChild(me.dialog);
	},
	getModuleFromDomain: function() {
		var secondLevelDomain = window.location.hostname.split('.').slice(-2).join('.');
		return this.domainModules[secondLevelDomain];
	},
	domainModules: {
		'reddit.com': 'reddit'
	},
	// TODO: remember last tip amount, default to that on new tips
	getSetting: function(key) {
		// TODO: make actual getters/setters here.
		// use monikers - link to a reference?
		if (key === 'defaultAmount') {
			return '$10';
		}
	},
	openDialog: function(config) {
		config = config || {
			x: 200,
			y: 200,
			username: 'username'
		};
		ChangeTip.dialog.style.top = parseInt(config.y, 10) + 'px';
		ChangeTip.dialog.style.left = parseInt(config.x, 10) + 'px';
		ChangeTip.dialog.classList.add('ct-visible');
		ChangeTip.dialogUsername.textContent = 'sending to: ' + config.username;

		BabelExt.storage.get('lastAmount', ChangeTip.populateLastAmount);

		window.addEventListener('keyup', ChangeTip.listenForEscape, false);
	},
	submit: function(e) {
		e.preventDefault();

		ChangeTip.activeModule.submit(ChangeTip.dialogInput.value);
		BabelExt.storage.set('lastAmount', ChangeTip.dialogInput.value, ChangeTip.noop);
		ChangeTip.closeDialog();
	},
	populateLastAmount: function(returnData) {
		ChangeTip.dialogInput.value = returnData.value || '$5';
	},
	closeDialog: function() {
		ChangeTip.dialog.classList.remove('ct-visible');
		window.removeEventListener('keyup', ChangeTip.listenForEscape, false);
	},
	listenForEscape: function(e) {
		if (e.keyCode === 27) {
			ChangeTip.closeDialog();
		}
	},
	noop: function() {}
};<|endoftext|>


<commit_before>const stream_of = require('rillet').of;
const stream_from = require('rillet').from;
const tag_format = require('./tags.js');
const markdown = require('markdown').markdown;

function edition_or_artefact(artefact, edition_field, artefact_field) {
  if (artefact.edition && artefact.edition[edition_field])
    return artefact.edition[edition_field];
  return artefact[artefact_field];
} // edition_field

function minimal_artefact_format(artefact, url_helper) {
  return {
    'id': url_helper.artefact_url(artefact),
    'web_url': url_helper.artefact_web_url(artefact),
    'slug': artefact.slug,
    'title': edition_or_artefact(artefact, 'title', 'name'),
    'format': underscorify(edition_or_artefact(artefact, 'format', 'kind'))
  };
} // minimal_artefact_format

function basic_artefact_format(artefact, url_helper) {
  return merge(
    minimal_artefact_format(artefact, url_helper),
    {
      'updated_at': updated_date(artefact),
      'created_at': created_date(artefact),
      'tag_ids': artefact.tag_ids
    }
  );
} // basic_artefact_format

function format(artefact, url_helper) {
  const pretty = basic_artefact_format(artefact, url_helper);

  pretty.tags = tag_format(artefact.tags, url_helper);

  // populate the details
  pretty.details = {}

  merge_fields(pretty, BASE_FIELDS, artefact);
  merge_fields(pretty, OPTIONAL_FIELDS, artefact.edition);
  merge_fields(pretty, ODI_FIELDS, artefact.edition);

  pretty.related_external_links = stream_from(artefact.external_links).
    map(l => { return { 'title': l.title, 'url': l.url }; }).
    toArray();

  return pretty;
} // format

module.exports = format;

///////////////////////////////////////////////
function underscorify(str) {
  if (!str)
    return str;
  return str.replace(/ /g, '_');
} // underscorify

function merge(object1, object2) {
  for (const [k,v] of Object.entries(object2))
    object1[k] = v;
  return object1;
} // merge

function merge_fields(pretty, field_names, source) {
  if (!source)
    return;
  stream_of(field_names).flatten().
    filter(f => source[f] !== undefined).
    map(f => [f, source[f]]).
    map(fv => convertIfDate(...fv)).
    forEach(([f, v]) => pretty.details[f] = v);
} // merge_fields

function convertIfGovspeak(f, v) {
  if (GOVSPEAK.indexOf(f) == -1)
    return [f, v];

  return [f, markdown.toHTML(v)];
} // convertIfGovspeak

function convertIfDate(f, v) {
  if (!f.endsWith('date'))
    return [f, v];

  return [f, content_api_date(v)];
} // convertIfDate

function updated_date(artefact) {
  try {
    const ud = stream_of(artefact.updated_at, artefact.edition ? artefact.edition.updated_at : undefined).
  	filter(d => d).
 	max();
    return ud ? content_api_date(ud) : '';
  } catch(err) {
    return '';
  } // catch
} // updated_date

function created_date(artefact) {
  return artefact.created_at ? content_api_date(artefact.created_at) : '';
} // created_date

// if javascripts toISOString is ok, we can use that instead
function content_api_date(date) {
  return date.getUTCFullYear() +
        '-' + pad(date.getUTCMonth() + 1) +
        '-' + pad(date.getUTCDate()) +
        'T' + pad(date.getUTCHours()) +
        ':' + pad(date.getUTCMinutes()) +
        ':' + pad(date.getUTCSeconds()) +
        '+00:00';
} // content_api_date

function pad(n) {
  return (n < 10) ? `0${n}` : n;
} // pad

const BASE_FIELDS = [
  'need_id',
  'business_proposition',
  'description',
  'excerpt',
  'language',
  'need_extended_font'
];

const OPTIONAL_FIELDS = [
  'additional_information',
  'alternate_methods',
  'alternative_title',
  'body',
  'change_description',
  'introduction',
  'link',
  'more_information',
  'organiser',
  'place_type',
  'reviewed_at',
  'short_description',
  'summary',
  'video_summary',
  'video_url'
];

const ODI_FIELDS = [
  'honorific_prefix',
  'honorific_suffix',
  'role',
  'description',
  'affiliation',
  'url',
  'telephone',
  'twitter',
  'linkedin',
  'github',
  'email',
  'length',
  'outline',
  'outcomes',
  'audience',
  'prerequisites',
  'requirements',
  'materials',
  'subtitle',
  'content',
  'end_date',
  'media_enquiries_name',
  'media_enquiries_email',
  'media_enquiries_telephone',
  'location',
  'salary',
  'closing_date',
  'joined_at',
  'graduated',
  'tagline',
  'involvement',
  'want_to_meet',
  'case_study',
  'date_published',
  'course',
  'date',
  'price',
  'trainers',
  'start_date',
  'booking_url',
  'hashtag',
  'level',
  'region',
  'end_date',
  'beta',
  'join_date',
  'area',
  'host'
];

const GOVSPEAK = [
  'content',
  'description',
  'license_overview',
  'body'
];
<commit_msg>add markdown conversion back in - it had got lost :o<commit_after>const stream_of = require('rillet').of;
const stream_from = require('rillet').from;
const tag_format = require('./tags.js');
const markdown = require('markdown').markdown;

function edition_or_artefact(artefact, edition_field, artefact_field) {
  if (artefact.edition && artefact.edition[edition_field])
    return artefact.edition[edition_field];
  return artefact[artefact_field];
} // edition_field

function minimal_artefact_format(artefact, url_helper) {
  return {
    'id': url_helper.artefact_url(artefact),
    'web_url': url_helper.artefact_web_url(artefact),
    'slug': artefact.slug,
    'title': edition_or_artefact(artefact, 'title', 'name'),
    'format': underscorify(edition_or_artefact(artefact, 'format', 'kind'))
  };
} // minimal_artefact_format

function basic_artefact_format(artefact, url_helper) {
  return merge(
    minimal_artefact_format(artefact, url_helper),
    {
      'updated_at': updated_date(artefact),
      'created_at': created_date(artefact),
      'tag_ids': artefact.tag_ids
    }
  );
} // basic_artefact_format

function format(artefact, url_helper) {
  const pretty = basic_artefact_format(artefact, url_helper);

  pretty.tags = tag_format(artefact.tags, url_helper);

  // populate the details
  pretty.details = {}

  merge_fields(pretty, BASE_FIELDS, artefact);
  merge_fields(pretty, OPTIONAL_FIELDS, artefact.edition);
  merge_fields(pretty, ODI_FIELDS, artefact.edition);

  pretty.related_external_links = stream_from(artefact.external_links).
    map(l => { return { 'title': l.title, 'url': l.url }; }).
    toArray();

  return pretty;
} // format

module.exports = format;

///////////////////////////////////////////////
function underscorify(str) {
  if (!str)
    return str;
  return str.replace(/ /g, '_');
} // underscorify

function merge(object1, object2) {
  for (const [k,v] of Object.entries(object2))
    object1[k] = v;
  return object1;
} // merge

function merge_fields(pretty, field_names, source) {
  if (!source)
    return;
  stream_of(field_names).flatten().
    filter(f => source[f] !== undefined).
    map(f => [f, source[f]]).
    map(fv => convertIfGovspeak(...fv)).
    map(fv => convertIfDate(...fv)).
    forEach(([f, v]) => pretty.details[f] = v);
} // merge_fields

function convertIfGovspeak(f, v) {
  if (GOVSPEAK.indexOf(f) == -1)
    return [f, v];

  return [f, markdown.toHTML(v)];
} // convertIfGovspeak

function convertIfDate(f, v) {
  if (!f.endsWith('date'))
    return [f, v];

  return [f, content_api_date(v)];
} // convertIfDate

function updated_date(artefact) {
  try {
    const ud = stream_of(artefact.updated_at, artefact.edition ? artefact.edition.updated_at : undefined).
  	filter(d => d).
 	max();
    return ud ? content_api_date(ud) : '';
  } catch(err) {
    return '';
  } // catch
} // updated_date

function created_date(artefact) {
  return artefact.created_at ? content_api_date(artefact.created_at) : '';
} // created_date

// if javascripts toISOString is ok, we can use that instead
function content_api_date(date) {
  return date.getUTCFullYear() +
        '-' + pad(date.getUTCMonth() + 1) +
        '-' + pad(date.getUTCDate()) +
        'T' + pad(date.getUTCHours()) +
        ':' + pad(date.getUTCMinutes()) +
        ':' + pad(date.getUTCSeconds()) +
        '+00:00';
} // content_api_date

function pad(n) {
  return (n < 10) ? `0${n}` : n;
} // pad

const BASE_FIELDS = [
  'need_id',
  'business_proposition',
  'description',
  'excerpt',
  'language',
  'need_extended_font'
];

const OPTIONAL_FIELDS = [
  'additional_information',
  'alternate_methods',
  'alternative_title',
  'body',
  'change_description',
  'introduction',
  'link',
  'more_information',
  'organiser',
  'place_type',
  'reviewed_at',
  'short_description',
  'summary',
  'video_summary',
  'video_url'
];

const ODI_FIELDS = [
  'honorific_prefix',
  'honorific_suffix',
  'role',
  'description',
  'affiliation',
  'url',
  'telephone',
  'twitter',
  'linkedin',
  'github',
  'email',
  'length',
  'outline',
  'outcomes',
  'audience',
  'prerequisites',
  'requirements',
  'materials',
  'subtitle',
  'content',
  'end_date',
  'media_enquiries_name',
  'media_enquiries_email',
  'media_enquiries_telephone',
  'location',
  'salary',
  'closing_date',
  'joined_at',
  'graduated',
  'tagline',
  'involvement',
  'want_to_meet',
  'case_study',
  'date_published',
  'course',
  'date',
  'price',
  'trainers',
  'start_date',
  'booking_url',
  'hashtag',
  'level',
  'region',
  'end_date',
  'beta',
  'join_date',
  'area',
  'host'
];

const GOVSPEAK = [
  'content',
  'description',
  'license_overview',
  'body'
];
<|endoftext|>


<commit_before>// Constants
var leftMargin = 20;
var buttonWidth = 60;
var buttonHeight = 40;
var buttonSpacing = 20;
var smallMovement = 3;
var stepDelay = 500;

$(document).ready(function() {
    var ctx = $('#canvas').get(0).getContext('2d');
    ctx.textAlign = "center";

    // Scaling and panning
    var f = 30;
    var px = 0;
    var py = 0;

    // Mouse
    var mx = 0;
    var my = 0;
    var mdx = 0;
    var mdy = 0;
    var mouseDown = false;
    var selectedObjs = [];
    var movingGroup = false;

    // Keys
    var spaceDown = false;
    var shiftDown = false;

    // Button hover
    var leftIndex = -1;

    // Simulation
    var simulating = false;
    var intervalID = undefined;

    // Track IDs of switches and LEDs
    var idCounter = 0;

    var leftButtons = [
      {label: "GO", action: toggleSimulation},
      {label: "AND", action: newGate('and')},
      {label: "OR", action: newGate('or')},
      {label: "NOT", action: newGate('not')},
      {label: "SW", action: newNode('io')},
      {label: "LED", action: newNode('led')}
    ];

    function newGate(type) {
      return function() {
        circuit.gates.push({
          type: type,
          ins: [],
          outs: [],
          pos: [400 - px, 300 - py]
        })
      }
    }

    function newNode(type){
      return function() {
        circuit.nodes.push({
          id: idCounter++,
          type: type,
          pos: [400 - px, 300 - py],
          value: false
        })
      }
    }

    function draw_buttons() {
      ctx.font = "20px sans";
      var y = buttonSpacing;
      for (var i = 0; i < leftButtons.length; i++) {
        if (i === leftIndex) {
          ctx.fillStyle = "cyan";
          ctx.fillRect(leftMargin, y, buttonWidth, buttonHeight);
        }
        ctx.strokeRect(leftMargin, y, buttonWidth, buttonHeight);
        ctx.fillStyle = "black";
        ctx.fillText(leftButtons[i].label, leftMargin + buttonWidth / 2, y + 30);
        y += buttonHeight + buttonSpacing;
      }
    }

    // Helper function that finds the position of a node
    function draw_wires(){
      for (var i = 0; i < circuit.nodes.length; i++){

      }
    }

    // Drawing Gates
    function draw_and_gate(gate) {
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //draw the circle part of the and gate
      ctx.arc(x0 + f, y0 + f/2, f/2, -0.5 * Math.PI, 0.5 * Math.PI);
      ctx.stroke();

      //draw the rectangle part of the and gate
      ctx.moveTo(x0 + f, y0 + f)
      ctx.lineTo(x0, y0 + f);
      ctx.lineTo(x0, y0);
      ctx.lineTo(x0 + f, y0);
      ctx.stroke();

      //draw the leads
      ctx.moveTo(x0, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();

      // function to find the position of given node

    }

    function draw_or_gate(gate){
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //front part
      ctx.moveTo(x0, y0);
      ctx.quadraticCurveTo(x0 + 3 * f, y0 + 0.5 * f, x0, y0 + f);

      //back part
      ctx.quadraticCurveTo(x0 + 0.5*f, y0 + 0.5 * f, x0, y0);
      ctx.stroke();

      //draw the leads
      ctx.moveTo(x0 + 0.2 * f, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0 + 0.2 * f, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();
    }

    function draw_not_gate(gate){
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //triangle part
      ctx.moveTo(x0, y0);
      ctx.lineTo(x0 + 1.3 * f, y0 + 0.5 * f);
      ctx.lineTo(x0, y0 + f);
      ctx.closePath();

      //circle part
      var r = 0.1 * f;
      ctx.moveTo(x0 + 1.3 * f + 2 * r, y0 + 0.5 * f)
      ctx.arc(x0 + 1.3 * f + r, y0 + 0.5 * f, r, 0, Math.PI*2);
      ctx.stroke();

      //draw the leads whee
      ctx.moveTo(x0, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();
    }

    function draw_generic_gate(gate) {
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.font = Math.round(0.5 * f) + "px sans";
      ctx.strokeRect(x0, y0, 1.5 * f, f);
      ctx.fillText(gate.type, x0 + 0.75 * f, y0 + 0.8 * f);
    }

    function draw_gate(gate) {
      switch (gate.type) {
        case 'and':
          draw_and_gate(gate);
          break;
        case 'or':
          draw_or_gate(gate);
          break;
        case 'not':
          draw_not_gate(gate);
          break;
        default:
          draw_generic_gate(gate);
          break;
      }
    }

//Drawing Nodes
    function draw_switch(node){
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      ctx.fillStyle="#FF6600"; //orange
      ctx.fillRect(x0, y0, f, f);
      ctx.stroke();
    }

    function draw_led(node){
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      ctx.fillStyle="#00B8E6"; //blue
      ctx.arc(x0, y0, f/2, 0 * Math.PI, 2 * Math.PI);
      ctx.fill();
    }

    function draw_io(){
      switch (node.type) {
        case 'io':
          draw_switch(node);
          break;
        case 'led':
          draw_led(node);
          break;
        default:
          draw_node(node);
          break;
      }
    }

    function draw_node(node) {
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      ctx.fillStyle="#FF6600"; //orange
      ctx.fillRect(x0, y0, 0.3*f, 0.3*f);
    }

    function render() {
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      for (var i = 0; i < circuit.gates.length; i++) {
        if (selectedObjs.indexOf(circuit.gates[i]) > -1) {
          ctx.strokeStyle = "magenta";
        }
        draw_gate(circuit.gates[i]);
        ctx.strokeStyle = "black";
      }

      if (mouseDown && !spaceDown && !movingGroup) {
        ctx.fillStyle = "rgba(0, 1, 1, 0.2)";
        ctx.fillRect(mdx, mdy, mx - mdx, my - mdy);
      }

      draw_buttons();
    }

    function checkLeftButtons() {
      if (mx >= leftMargin && mx <= leftMargin + buttonWidth) {
        if (my % (buttonSpacing + buttonHeight) >= buttonSpacing) {
          var i = Math.floor(my / (buttonSpacing + buttonHeight));
          if (i < leftButtons.length) {
            leftIndex = i;
            return;
          }
        }
      }
      leftIndex = -1;
    }

    function objectsUnderCursor() {
      objs = [];
      for (var i = 0; i < circuit.gates.length; i++) {
        var x0 = px + circuit.gates[i].pos[0];
        var y0 = py + circuit.gates[i].pos[1];
        if (mx >= x0 && my >= y0 && mx <= x0 + 1.5 * f && my <= y0 + f) {
          objs.push(circuit.gates[i]);
        }
      }
      for (var i = 0; i < circuit.nodes.length; i++) {
        var x0 = px + circuit.nodes[i].pos[0];
        var y0 = px + circuit.nodes[i].pos[1];
        var size;
        if (circuit.nodes[i].type == undefined) {
          size = 0.2 * f;
        } else {
          size = 2 * f;
        }
        if (mx >= x0 && my >= y0 && mx <= x0 + nodeSize && my <= y0 + nodeSize) {
          objs.push(circuit.nodes[i]);
        }
      }
      return objs;
    }

    function objectsInMarquee() {
      objs = [];
      var xa = Math.min(mx, mdx);
      var xb = Math.max(mx, mdx);
      var ya = Math.min(my, mdy);
      var yb = Math.max(my, mdy);
      for (var i = 0; i < circuit.gates.length; i++) {
        var x0 = px + circuit.gates[i].pos[0];
        var y0 = py + circuit.gates[i].pos[1];
        if (x0 >= xa && y0 >= ya && x0 + 1.5 * f <= xb && y0 + f <= yb) {
          objs.push(circuit.gates[i]);
        }
      }
      for (var i = 0; i < circuit.nodes.length; i++) {
        var x0 = px + circuit.nodes[i].pos[0];
        var y0 = px + circuit.nodes[i].pos[1];
        var size;
        if (circuit.nodes[i].type == undefined) {
          size = 0.2 * f;
        } else {
          size = 2 * f;
        }
        if (x0 >= xa && y0 >= ya && x0 + size <= xb && y0 + size <= yb) {
          objs.push(circuit.nodes[i]);
        }
      }
      return objs;
    }

    function simulate() {
      updateAgenda();
      for (var i = 0; i < agenda.length; i++) {
        render();
        var tasks = agenda[i];
        for (var j = 0; j < tasks.length; j++) {
          apply(tasks[j]);
        }
      }
    }

    function step() {
      if (agenda.length === 0) {
        toggleSimulation();
      } else {
        for (var i = 0; i < agenda[0].length; i++) {
          apply(agenda[0][i]);
        }
        shift(agenda);
      }
    }

    function toggleSimulation() {
      simulating = !simulating;
      if (simulating) {
        leftButtons[0].label = "STOP";
        updateAgenda();
        intervalID = setInterval(step, stepDelay);
      } else {
        leftButtons[0].label = "GO";
        agenda = [];
        if (intervalID != undefined) {
          clearInterval(intervalID);
          intervalID = undefined;
        }
      }
      render();
    }

    $('#canvas').mousedown(function(e) {
      mouseDown = true;
      mdx = e.offsetX;
      mdy = e.offsetY;

      if (leftIndex !== -1) {
        if (!simulating || leftIndex == 0) {
          leftButtons[leftIndex].action();
          render();
        }
        return;
      }

      if (simulating) {
        return;
      }

      if (!spaceDown) {
        var objs = objectsUnderCursor();
        if (objs.length > 0) {
          movingGroup = true;
          var existing = false
          for (var i = 0; i < objs.length; i++) {
            for (var j = 0; j < selectedObjs.length; j++) {
              if (objs[i] == selectedObjs[j]) {
                existing = true;
                break;
              }
            }
          }
          if (!existing) {
            if (shiftDown) {
              selectedObjs.push(objs[0]);
            } else {
              selectedObjs = [objs[0]];
            }
          }
        }
      }

      render();
    });

    $('#canvas').mousemove(function(e) {
      if (mouseDown) {
        if (spaceDown) {
          px += e.offsetX - mx;
          py += e.offsetY - my;
        } else if (movingGroup) {
          for (var i = 0; i < selectedObjs.length; i++) {
            selectedObjs[i].pos[0] += e.offsetX - mx;
            selectedObjs[i].pos[1] += e.offsetY - my;
          }
        }
      }

      mx = e.offsetX;
      my = e.offsetY;

      var old = leftIndex;
      checkLeftButtons();
      if (old !== leftIndex || mouseDown) {
        render();
      }
    });

    $('#canvas').mouseup(function(e) {
      if (leftIndex === -1) {
        if (Math.abs(mx - mdx) <= smallMovement && Math.abs(my - mdy) <= smallMovement) {
          var objs = objectsUnderCursor();
          if (objs.length > 0) {
            if (shiftDown) {
              selectedObjs.push(objs[0]);
            } else {
              selectedObjs = [objs[0]];
            }
          } else {
            selectedObjs = [];
          }
        } else if (!spaceDown && !movingGroup) {
          selectedObjs = objectsInMarquee();
        }
      }
      mouseDown = false;
      movingGroup = false;
      render();
    });

    $(document).keydown(function(e) {
      if (e.which === 32) {
        e.preventDefault();
        spaceDown = true;
      } else if (e.which == 16) {
        shiftDown = true;
      }
    });

    $(document).keyup(function(e) {
      if (e.which === 32) {
        e.preventDefault();
        spaceDown = false;
      } else if (e.which == 16) {
        shiftDown = false;
      }
    });

    render();
});
<commit_msg>Add buttons for switch and LED<commit_after>// Constants
var leftMargin = 20;
var buttonWidth = 60;
var buttonHeight = 40;
var buttonSpacing = 20;
var smallMovement = 3;
var stepDelay = 500;

$(document).ready(function() {
    var ctx = $('#canvas').get(0).getContext('2d');
    ctx.textAlign = "center";

    // Scaling and panning
    var f = 30;
    var px = 0;
    var py = 0;

    // Mouse
    var mx = 0;
    var my = 0;
    var mdx = 0;
    var mdy = 0;
    var mouseDown = false;
    var selectedObjs = [];
    var movingGroup = false;

    // Keys
    var spaceDown = false;
    var shiftDown = false;

    // Button hover
    var leftIndex = -1;

    // Simulation
    var simulating = false;
    var intervalID = undefined;

    // Track IDs of switches and LEDs
    var idCounter = 0;

    var leftButtons = [
      {label: "GO", action: toggleSimulation},
      {label: "AND", action: newGate('and')},
      {label: "OR", action: newGate('or')},
      {label: "NOT", action: newGate('not')},
      {label: "SW", action: newNode('io')},
      {label: "LED", action: newNode('led')}
    ];

    function newGate(type) {
      return function() {
        circuit.gates.push({
          type: type,
          ins: [],
          outs: [],
          pos: [400 - px, 300 - py]
        })
      }
    }

    function newNode(type){
      return function() {
        circuit.nodes.push({
          id: idCounter++,
          type: type,
          pos: [400 - px, 300 - py],
          value: false
        })
      }
    }

    function draw_buttons() {
      ctx.font = "20px sans";
      var y = buttonSpacing;
      for (var i = 0; i < leftButtons.length; i++) {
        if (i === leftIndex) {
          ctx.fillStyle = "cyan";
          ctx.fillRect(leftMargin, y, buttonWidth, buttonHeight);
        }
        ctx.strokeRect(leftMargin, y, buttonWidth, buttonHeight);
        ctx.fillStyle = "black";
        ctx.fillText(leftButtons[i].label, leftMargin + buttonWidth / 2, y + 30);
        y += buttonHeight + buttonSpacing;
      }
    }

    // Helper function that finds the position of a node
    function draw_wires(){
      for (var i = 0; i < circuit.nodes.length; i++){

      }
    }

    // Drawing Gates
    function draw_and_gate(gate) {
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //draw the circle part of the and gate
      ctx.arc(x0 + f, y0 + f/2, f/2, -0.5 * Math.PI, 0.5 * Math.PI);
      ctx.stroke();

      //draw the rectangle part of the and gate
      ctx.moveTo(x0 + f, y0 + f)
      ctx.lineTo(x0, y0 + f);
      ctx.lineTo(x0, y0);
      ctx.lineTo(x0 + f, y0);
      ctx.stroke();

      //draw the leads
      ctx.moveTo(x0, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();

      // function to find the position of given node

    }

    function draw_or_gate(gate){
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //front part
      ctx.moveTo(x0, y0);
      ctx.quadraticCurveTo(x0 + 3 * f, y0 + 0.5 * f, x0, y0 + f);

      //back part
      ctx.quadraticCurveTo(x0 + 0.5*f, y0 + 0.5 * f, x0, y0);
      ctx.stroke();

      //draw the leads
      ctx.moveTo(x0 + 0.2 * f, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0 + 0.2 * f, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();
    }

    function draw_not_gate(gate){
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.beginPath();

      //triangle part
      ctx.moveTo(x0, y0);
      ctx.lineTo(x0 + 1.3 * f, y0 + 0.5 * f);
      ctx.lineTo(x0, y0 + f);
      ctx.closePath();

      //circle part
      var r = 0.1 * f;
      ctx.moveTo(x0 + 1.3 * f + 2 * r, y0 + 0.5 * f)
      ctx.arc(x0 + 1.3 * f + r, y0 + 0.5 * f, r, 0, Math.PI*2);
      ctx.stroke();

      //draw the leads whee
      ctx.moveTo(x0, y0 + f/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f/3);
      ctx.moveTo(x0, y0 + f * 2/3);
      ctx.lineTo(x0 - 0.5*f, y0 + f * 2/3);
      ctx.moveTo(x0 + 1.5 * f, y0 + 0.5 * f)
      ctx.lineTo(x0 + 2 * f,y0 + 0.5 * f )
      ctx.stroke();
    }

    function draw_generic_gate(gate) {
      var x0 = px + gate.pos[0];
      var y0 = py + gate.pos[1];

      ctx.font = Math.round(0.5 * f) + "px sans";
      ctx.strokeRect(x0, y0, 1.5 * f, f);
      ctx.fillText(gate.type, x0 + 0.75 * f, y0 + 0.8 * f);
    }

    function draw_gate(gate) {
      switch (gate.type) {
        case 'and':
          draw_and_gate(gate);
          break;
        case 'or':
          draw_or_gate(gate);
          break;
        case 'not':
          draw_not_gate(gate);
          break;
        default:
          draw_generic_gate(gate);
          break;
      }
    }

//Drawing Nodes
    function draw_switch(node){
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      if (node.value){
        ctx.fillStyle="#FF6600"; //orange for on
      }
      else {
        ctx.fillStyle="#000000"; //black for off
      }
      ctx.fillRect(x0, y0, f, f);
    }

    function draw_led(node){
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      if (node.value){
        ctx.fillStyle="#00B8E6"; //blue for on
      }
      else {
        ctx.fillStyle="#000000"; //black for off
      }
      ctx.arc(x0, y0, f/2, 0 * Math.PI, 2 * Math.PI);
      ctx.fill();
    }

    function draw_any_node(node) {
      switch (node.type) {
        case 'io':
          draw_switch(node);
          break;
        case 'led':
          draw_led(node);
          break;
        default:
          draw_node(node);
          break;
      }
    }

    function draw_node(node) {
      var x0 = px + node.pos[0];
      var y0 = py + node.pos[1];

      ctx.fillStyle="#FF6600"; //orange
      ctx.fillRect(x0, y0, 0.3*f, 0.3*f);
    }

    function render() {
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      for (var i = 0; i < circuit.gates.length; i++) {
        if (selectedObjs.indexOf(circuit.gates[i]) > -1) {
          ctx.strokeStyle = "magenta";
        }
        draw_gate(circuit.gates[i]);
        ctx.strokeStyle = "black";
      }

      for (var i = 0; i < circuit.nodes.length; i++) {
          if (selectedObjs.indexOf(circuit.nodes[i]) > -1) {
            ctx.strokeStyle = "magenta";
          }
          draw_any_node(circuit.nodes[i]);
          ctx.strokeStyle = "black";
      }

      if (mouseDown && !spaceDown && !movingGroup) {
        ctx.fillStyle = "rgba(0, 1, 1, 0.2)";
        ctx.fillRect(mdx, mdy, mx - mdx, my - mdy);
      }

      draw_buttons();
    }

    function checkLeftButtons() {
      if (mx >= leftMargin && mx <= leftMargin + buttonWidth) {
        if (my % (buttonSpacing + buttonHeight) >= buttonSpacing) {
          var i = Math.floor(my / (buttonSpacing + buttonHeight));
          if (i < leftButtons.length) {
            leftIndex = i;
            return;
          }
        }
      }
      leftIndex = -1;
    }

    function objectsUnderCursor() {
      objs = [];
      for (var i = 0; i < circuit.gates.length; i++) {
        var x0 = px + circuit.gates[i].pos[0];
        var y0 = py + circuit.gates[i].pos[1];
        if (mx >= x0 && my >= y0 && mx <= x0 + 1.5 * f && my <= y0 + f) {
          objs.push(circuit.gates[i]);
        }
      }
      for (var i = 0; i < circuit.nodes.length; i++) {
        var x0 = px + circuit.nodes[i].pos[0];
        var y0 = px + circuit.nodes[i].pos[1];
        var size;
        if (circuit.nodes[i].type == undefined) {
          size = 0.2 * f;
        } else {
          size = 2 * f;
        }
        if (mx >= x0 && my >= y0 && mx <= x0 + nodeSize && my <= y0 + nodeSize) {
          objs.push(circuit.nodes[i]);
        }
      }
      return objs;
    }

    function objectsInMarquee() {
      objs = [];
      var xa = Math.min(mx, mdx);
      var xb = Math.max(mx, mdx);
      var ya = Math.min(my, mdy);
      var yb = Math.max(my, mdy);
      for (var i = 0; i < circuit.gates.length; i++) {
        var x0 = px + circuit.gates[i].pos[0];
        var y0 = py + circuit.gates[i].pos[1];
        if (x0 >= xa && y0 >= ya && x0 + 1.5 * f <= xb && y0 + f <= yb) {
          objs.push(circuit.gates[i]);
        }
      }
      for (var i = 0; i < circuit.nodes.length; i++) {
        var x0 = px + circuit.nodes[i].pos[0];
        var y0 = px + circuit.nodes[i].pos[1];
        var size;
        if (circuit.nodes[i].type == undefined) {
          size = 0.2 * f;
        } else {
          size = 2 * f;
        }
        if (x0 >= xa && y0 >= ya && x0 + size <= xb && y0 + size <= yb) {
          objs.push(circuit.nodes[i]);
        }
      }
      return objs;
    }

    function simulate() {
      updateAgenda();
      for (var i = 0; i < agenda.length; i++) {
        render();
        var tasks = agenda[i];
        for (var j = 0; j < tasks.length; j++) {
          apply(tasks[j]);
        }
      }
    }

    function step() {
      if (agenda.length === 0) {
        toggleSimulation();
      } else {
        for (var i = 0; i < agenda[0].length; i++) {
          apply(agenda[0][i]);
        }
        shift(agenda);
      }
    }

    function toggleSimulation() {
      simulating = !simulating;
      if (simulating) {
        leftButtons[0].label = "STOP";
        updateAgenda();
        intervalID = setInterval(step, stepDelay);
      } else {
        leftButtons[0].label = "GO";
        agenda = [];
        if (intervalID != undefined) {
          clearInterval(intervalID);
          intervalID = undefined;
        }
      }
      render();
    }

    $('#canvas').mousedown(function(e) {
      mouseDown = true;
      mdx = e.offsetX;
      mdy = e.offsetY;

      if (leftIndex !== -1) {
        if (!simulating || leftIndex == 0) {
          leftButtons[leftIndex].action();
          render();
        }
        return;
      }

      if (simulating) {
        return;
      }

      if (!spaceDown) {
        var objs = objectsUnderCursor();
        if (objs.length > 0) {
          movingGroup = true;
          var existing = false
          for (var i = 0; i < objs.length; i++) {
            for (var j = 0; j < selectedObjs.length; j++) {
              if (objs[i] == selectedObjs[j]) {
                existing = true;
                break;
              }
            }
          }
          if (!existing) {
            if (shiftDown) {
              selectedObjs.push(objs[0]);
            } else {
              selectedObjs = [objs[0]];
            }
          }
        }
      }

      render();
    });

    $('#canvas').mousemove(function(e) {
      if (mouseDown) {
        if (spaceDown) {
          px += e.offsetX - mx;
          py += e.offsetY - my;
        } else if (movingGroup) {
          for (var i = 0; i < selectedObjs.length; i++) {
            selectedObjs[i].pos[0] += e.offsetX - mx;
            selectedObjs[i].pos[1] += e.offsetY - my;
          }
        }
      }

      mx = e.offsetX;
      my = e.offsetY;

      var old = leftIndex;
      checkLeftButtons();
      if (old !== leftIndex || mouseDown) {
        render();
      }
    });

    $('#canvas').mouseup(function(e) {
      if (leftIndex === -1) {
        if (Math.abs(mx - mdx) <= smallMovement && Math.abs(my - mdy) <= smallMovement) {
          var objs = objectsUnderCursor();
          if (objs.length > 0) {
            if (shiftDown) {
              selectedObjs.push(objs[0]);
            } else {
              selectedObjs = [objs[0]];
            }
          } else {
            selectedObjs = [];
          }
        } else if (!spaceDown && !movingGroup) {
          selectedObjs = objectsInMarquee();
        }
      }
      mouseDown = false;
      movingGroup = false;
      render();
    });

    $(document).keydown(function(e) {
      if (e.which === 32) {
        e.preventDefault();
        spaceDown = true;
      } else if (e.which == 16) {
        shiftDown = true;
      }
    });

    $(document).keyup(function(e) {
      if (e.which === 32) {
        e.preventDefault();
        spaceDown = false;
      } else if (e.which == 16) {
        shiftDown = false;
      }
    });

    render();
});
<|endoftext|>


<commit_before>/**
 * Created by sanjeevbudha on 6/30/16.
 */
function deleteFood(id){

    var mode ='delete';

    var n = noty({
        layout: 'center',
        text: "Are you sure you want delete? ",
        killer: true,
        buttons: [
            {
                addClass: 'btn btn-primary', text: 'Ok', onClick: function ($noty) {
                n.close();
                $.ajax({
                    type:"POST",
                    url:'../controller/foodHandler.php',
                    data:"mode="+mode+"&id="+id,
                    success:function(data){
                        var data = JSON.parse(data);

                        if(data.message=='success'){
                            displayMessage("Successfully Deleted","success");
                            customReloadWindow(2000)
                        }
                    },error: function (er) {
                        console.log(er);
                    }
                });
                return false;
            }
            },
            {
                addClass: 'btn btn-danger', text: 'Cancel', onClick: function ($noty) {
                n.close();
            }
            }
        ]
    })

}

function editFood(id){

    var mode ='edit';

    $.ajax({
        type:"POST",
        url:'../controller/foodHandler.php',
        data:"mode="+mode+"&id="+id,
        success:function(data){
            var data = JSON.parse(data);

            var f_id = data['id'];
            $("#feedName").val(data['title']);
            $("#description").val(data['description']);

            $('#insert-food').modal('show');
            $('#insert-food .modal-title').html("Edit Food");
            $('#insert-food button[type=submit]').html("Save Changes");
            $('#food-form').attr('action','../controller/foodHandler.php');
            $('#mode').attr('value','update');
            $('#food_id').attr('value',f_id);

            $('.modal').on('hidden.bs.modal', function(){
                $(this).find('form')[0].reset();
            });

        },error: function (er) {
            alert("Error while Creating" +er);
        }
    });

    return false;
}<commit_msg>updated<commit_after>/**
 * Created by sanjeevbudha on 6/30/16.
 */
function deleteFood(id){

    var mode ='delete';

    var n = noty({
        layout: 'center',
        text: "Are you sure you want delete? ",
        killer: true,
        buttons: [
            {
                addClass: 'btn btn-primary', text: 'Ok', onClick: function ($noty) {
                n.close();
                $.ajax({
                    type:"POST",
                    url:'../controller/foodHandler.php',
                    data:"mode="+mode+"&id="+id,
                    success:function(data){
                        var data = JSON.parse(data);

                        if(data.message=='success'){
                            displayMessage("Successfully Deleted","success");
                            customReloadWindow(2000)
                        }
                    },error: function (er) {
                        console.log(er);
                    }
                });
                return false;
            }
            },
            {
                addClass: 'btn btn-danger', text: 'Cancel', onClick: function ($noty) {
                n.close();
            }
            }
        ]
    })

}

function editFood(id){

    var mode ='edit';

    $.ajax({
        type:"POST",
        url:'../controller/foodHandler.php',
        data:"mode="+mode+"&id="+id,
        success:function(data){
            var data = JSON.parse(data);

            var f_id = data['id'];
            $("#feedName").val(data['title']);
            $("#description").val(data['description']);

            $('#insert-food').modal('show');
            $('#insert-food .modal-title').html("आहारा परिमार्जन गर्नुहोस्");
            $('#insert-food button[type=submit]').html("पेश गर्नुहोस्");
            $('#food-form').attr('action','../controller/foodHandler.php');
            $('#mode').attr('value','update');
            $('#food_id').attr('value',f_id);

            $('.modal').on('hidden.bs.modal', function(){
                $(this).find('form')[0].reset();
            });

        },error: function (er) {
            alert("Error while Creating" +er);
        }
    });

    return false;
}<|endoftext|>


<commit_before>// player prefs
var PLAYER_DATA = {};
PLAYER_DATA['UNLOCKED_INGREDIENTS'] = ['water'];
PLAYER_DATA['UNLOCKED_ACTIONS'] = [];
PLAYER_DATA['UNLOCKED_RESEARCH'] = [];

PLAYER_DATA['INGREDIENT_QUANTITIES'] = {};
function getIngredientQuantity(name) {
  if (name in PLAYER_DATA['INGREDIENT_QUANTITIES']) {
    return PLAYER_DATA['INGREDIENT_QUANTITIES'][name];
  } else {
    PLAYER_DATA['INGREDIENT_QUANTITIES'][name] = 0;
    return 0;
  }
}
PLAYER_DATA['EXPERIENCE'] = 0;
PLAYER_DATA['EXPERIENCE_BAR_SIZE'] = 5;
PLAYER_DATA['LEVEL'] = 1;
PLAYER_DATA['ENERGY'] = 0;
PLAYER_DATA['GOLD'] = 0;

PLAYER_DATA['LAST_SAVED'] = Math.round(new Date().getTime() / 1000);

PLAYER_DATA['RESEARCHED'] = {} //key: number owned, price to player

PLAYER_DATA['NUM_GOLEMS'] = 3;

PLAYER_DATA['DISCOVERED_RECIPES'] = [];

PLAYER_DATA['AUTOMATED_RECIPES'] = {};
PLAYER_DATA['AUTOMATED_ACTIONS'] = {};

PLAYER_DATA['UNLOCKED_PANES'] = ['info', 'recipes', 'golems', 'ingredients', 'research', 'tools', 'messages'];

PLAYER_DATA['CURRENT_ORDERS'] = []; // potion/ingredient, gold each, qty

unlockResearch('powerful_cranks'); unlockResearch('auto_cranker');
unlockAction('gather_water');

var GOLEMS_ARE_ENABLED = true;

//helper globals
var CURRENT_ACTIONS = []; //name, time total, time remaining

$(document).ready(function() {
  initCanvas();
  loadGame();
  displayIngredients();
  displayActions();
  refreshInfo();
  refreshIngredientCountDisplay();
  displayResearch();
  displayRecipes();
  displayGolems();
  refreshResearchInfo();
  displayClicker();
  logMessage('You open the door to your potion room. Inside, your crew of assistant golems lie dormant, waiting for your command.');
  updateXPBar();
  resume();
  showPanes();
  displayOrders();

  $('body').on('mouseenter', '.tooltip:not(.tooltipstered)', function(){
    $(this)
    .tooltipster()
    .tooltipster('open')
  });

  $('body').on('mouseenter', '.ing-tooltip:not(.tooltipstered)', function(){
    $(this)
    .tooltipster({theme: 'tooltipster-light', contentAsHTML: true, trackOrigin: true})
    .tooltipster('open')
  });

  if (PLAYER_DATA['UNLOCKED_PANES'].indexOf('orders') > -1) {
    setTimeout(newOrder, getRandomInt(20 * 1000, 600 * 1000)); // 20 and 600 seconds
  }

  $('.orders').droppable({
    classes: {
      "ui-droppable-hover": "ingredienthover",
    },
    drop: function(event, ui) {
      processDrop($(ui.draggable).data("type"));
    }
  });

  if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth < 800) {
    alert("This game does not work on mobile devices. Sorry! If you're not on a touch device, you can ignore this message.");
  }

  window.requestAnimationFrame(animation);

});

function resume() {
  var current_time = Math.round(new Date().getTime() / 1000);
  var delta = current_time - PLAYER_DATA['LAST_SAVED'];
  if (delta > 30) {
    var welcome_back_string = "
";
    delta = Math.ceil(delta/2);
    var energy_per_second = getEnergyPerSecond();
    PLAYER_DATA['ENERGY'] += energy_per_second * delta;
    welcome_back_string += '
Generated ' + energy_per_second * delta + ' energy
';

    for (var key in PLAYER_DATA['AUTOMATED_ACTIONS']) {
      var action = ALL_ACTIONS[key];
      if (PLAYER_DATA['AUTOMATED_ACTIONS'][key] > 0) {
        var output = Math.round((PLAYER_DATA['AUTOMATED_ACTIONS'][key] / ALL_ACTIONS[key].time) * delta);
        if (PLAYER_DATA['ENERGY'] > action.energycost * output) {
          PLAYER_DATA['ENERGY'] -= action.energycost * output;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][action.output] += action.quantity * output;
          welcome_back_string += '
Gathered ' + action.quantity * output + ' ' + ALL_INGREDIENTS[ALL_ACTIONS[key].output].name + '
';
        }
      }
    }

    for (var key in PLAYER_DATA['AUTOMATED_RECIPES']) {
      if (PLAYER_DATA['AUTOMATED_RECIPES'][key] > 0) {
        var ingredients = key.split(',');
        var capable_of = getCapableOf(key);
        capable_of = Math.min(delta, capable_of);
        switch (key) {
          case 'magic_ore,spark':
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][0][0]] -= ALL_RECIPES[key][0][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][1][0]] -= ALL_RECIPES[key][1][1] * capable_of;
          PLAYER_DATA['NUM_GOLEMS'] += 1 * capable_of;
          break;
          default:
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][0][0]] -= ALL_RECIPES[key][0][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][1][0]] -= ALL_RECIPES[key][1][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][2][0]] += ALL_RECIPES[key][2][1] * capable_of;
        }
        welcome_back_string += '
Crafted ' + capable_of + ' ' + ALL_INGREDIENTS[ALL_RECIPES[key][2][0]].name + '
';
      }
    }

    welcome_back_string += '
'
    $('#welcomeback').append(welcome_back_string);
    $('#welcomeback').show();
    refreshInfo();
    refreshIngredientCountDisplay();
  }
}

function refreshIngredientCountDisplay() {
  for (var i = 0; i < PLAYER_DATA['UNLOCKED_INGREDIENTS'].length; i++) {
    $('#ing-' + PLAYER_DATA['UNLOCKED_INGREDIENTS'][i]).find('.ing-qty').html(getIngredientQuantity(PLAYER_DATA['UNLOCKED_INGREDIENTS'][i]));
  }
}
function refreshInfo() {
  $('#energy-display').html(PLAYER_DATA['ENERGY']);
  $('#energy-per-second').html(getEnergyPerSecond() + ' energy/sec.');
  $('#energy-cost-per-second').html('Using ' + getEnergyCostPerSecond() + ' energy/sec.');
  $('#gold-display').html(PLAYER_DATA['GOLD']);
}

function logMessage(message) {
  var timestamp = new Date().toLocaleTimeString();
  $('#message-log').append(timestamp + ': ' + message + "
");
  document.getElementById('messages').scrollTop = document.getElementById('messages').scrollHeight;
}

function performAction(name) {
  $('#' + name + '-progressbar').show();

  if (PLAYER_DATA['ENERGY'] >= ALL_ACTIONS[name]['energycost']) {
    ACTION_QUEUE.push(name);
    PLAYER_DATA['ENERGY'] -= ALL_ACTIONS[name]['energycost'];
  } else {
    $.growl.error({title: "Golem says no.", message: "Not enough energy to perform that action."});
  }

  refreshInfo();
}
function actionComplete(name) {
  var output_name = ALL_ACTIONS[name].output;
  var this_quantity = getIngredientQuantity(output_name);
  PLAYER_DATA['INGREDIENT_QUANTITIES'][output_name] = this_quantity + ALL_ACTIONS[name].quantity;
  givexp(ALL_ACTIONS[name].xp);

  if (output_name in SPRITES) {
    createParticle(output_name);
  }

  updateXPBar();
  refreshIngredientCountDisplay();
}
<commit_msg>changed warning for mobile devices<commit_after>// player prefs
var PLAYER_DATA = {};
PLAYER_DATA['UNLOCKED_INGREDIENTS'] = ['water'];
PLAYER_DATA['UNLOCKED_ACTIONS'] = [];
PLAYER_DATA['UNLOCKED_RESEARCH'] = [];

PLAYER_DATA['INGREDIENT_QUANTITIES'] = {};
function getIngredientQuantity(name) {
  if (name in PLAYER_DATA['INGREDIENT_QUANTITIES']) {
    return PLAYER_DATA['INGREDIENT_QUANTITIES'][name];
  } else {
    PLAYER_DATA['INGREDIENT_QUANTITIES'][name] = 0;
    return 0;
  }
}
PLAYER_DATA['EXPERIENCE'] = 0;
PLAYER_DATA['EXPERIENCE_BAR_SIZE'] = 5;
PLAYER_DATA['LEVEL'] = 1;
PLAYER_DATA['ENERGY'] = 0;
PLAYER_DATA['GOLD'] = 0;

PLAYER_DATA['LAST_SAVED'] = Math.round(new Date().getTime() / 1000);

PLAYER_DATA['RESEARCHED'] = {} //key: number owned, price to player

PLAYER_DATA['NUM_GOLEMS'] = 3;

PLAYER_DATA['DISCOVERED_RECIPES'] = [];

PLAYER_DATA['AUTOMATED_RECIPES'] = {};
PLAYER_DATA['AUTOMATED_ACTIONS'] = {};

PLAYER_DATA['UNLOCKED_PANES'] = ['info', 'recipes', 'golems', 'ingredients', 'research', 'tools', 'messages'];

PLAYER_DATA['CURRENT_ORDERS'] = []; // potion/ingredient, gold each, qty

unlockResearch('powerful_cranks'); unlockResearch('auto_cranker');
unlockAction('gather_water');

var GOLEMS_ARE_ENABLED = true;

//helper globals
var CURRENT_ACTIONS = []; //name, time total, time remaining

$(document).ready(function() {
  initCanvas();
  loadGame();
  displayIngredients();
  displayActions();
  refreshInfo();
  refreshIngredientCountDisplay();
  displayResearch();
  displayRecipes();
  displayGolems();
  refreshResearchInfo();
  displayClicker();
  logMessage('You open the door to your potion room. Inside, your crew of assistant golems lie dormant, waiting for your command.');
  updateXPBar();
  resume();
  showPanes();
  displayOrders();

  $('body').on('mouseenter', '.tooltip:not(.tooltipstered)', function(){
    $(this)
    .tooltipster()
    .tooltipster('open')
  });

  $('body').on('mouseenter', '.ing-tooltip:not(.tooltipstered)', function(){
    $(this)
    .tooltipster({theme: 'tooltipster-light', contentAsHTML: true, trackOrigin: true})
    .tooltipster('open')
  });

  if (PLAYER_DATA['UNLOCKED_PANES'].indexOf('orders') > -1) {
    setTimeout(newOrder, getRandomInt(20 * 1000, 600 * 1000)); // 20 and 600 seconds
  }

  $('.orders').droppable({
    classes: {
      "ui-droppable-hover": "ingredienthover",
    },
    drop: function(event, ui) {
      processDrop($(ui.draggable).data("type"));
    }
  });

  if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth < 800) {
    alert("This game is not designed for mobile devices. Sorry! However, it works well for some people. Feel free to try.");
  }

  window.requestAnimationFrame(animation);

});

function resume() {
  var current_time = Math.round(new Date().getTime() / 1000);
  var delta = current_time - PLAYER_DATA['LAST_SAVED'];
  if (delta > 30) {
    var welcome_back_string = "
";
    delta = Math.ceil(delta/2);
    var energy_per_second = getEnergyPerSecond();
    PLAYER_DATA['ENERGY'] += energy_per_second * delta;
    welcome_back_string += '
Generated ' + energy_per_second * delta + ' energy
';

    for (var key in PLAYER_DATA['AUTOMATED_ACTIONS']) {
      var action = ALL_ACTIONS[key];
      if (PLAYER_DATA['AUTOMATED_ACTIONS'][key] > 0) {
        var output = Math.round((PLAYER_DATA['AUTOMATED_ACTIONS'][key] / ALL_ACTIONS[key].time) * delta);
        if (PLAYER_DATA['ENERGY'] > action.energycost * output) {
          PLAYER_DATA['ENERGY'] -= action.energycost * output;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][action.output] += action.quantity * output;
          welcome_back_string += '
Gathered ' + action.quantity * output + ' ' + ALL_INGREDIENTS[ALL_ACTIONS[key].output].name + '
';
        }
      }
    }

    for (var key in PLAYER_DATA['AUTOMATED_RECIPES']) {
      if (PLAYER_DATA['AUTOMATED_RECIPES'][key] > 0) {
        var ingredients = key.split(',');
        var capable_of = getCapableOf(key);
        capable_of = Math.min(delta, capable_of);
        switch (key) {
          case 'magic_ore,spark':
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][0][0]] -= ALL_RECIPES[key][0][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][1][0]] -= ALL_RECIPES[key][1][1] * capable_of;
          PLAYER_DATA['NUM_GOLEMS'] += 1 * capable_of;
          break;
          default:
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][0][0]] -= ALL_RECIPES[key][0][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][1][0]] -= ALL_RECIPES[key][1][1] * capable_of;
          PLAYER_DATA['INGREDIENT_QUANTITIES'][ALL_RECIPES[key][2][0]] += ALL_RECIPES[key][2][1] * capable_of;
        }
        welcome_back_string += '
Crafted ' + capable_of + ' ' + ALL_INGREDIENTS[ALL_RECIPES[key][2][0]].name + '
';
      }
    }

    welcome_back_string += '
'
    $('#welcomeback').append(welcome_back_string);
    $('#welcomeback').show();
    refreshInfo();
    refreshIngredientCountDisplay();
  }
}

function refreshIngredientCountDisplay() {
  for (var i = 0; i < PLAYER_DATA['UNLOCKED_INGREDIENTS'].length; i++) {
    $('#ing-' + PLAYER_DATA['UNLOCKED_INGREDIENTS'][i]).find('.ing-qty').html(getIngredientQuantity(PLAYER_DATA['UNLOCKED_INGREDIENTS'][i]));
  }
}
function refreshInfo() {
  $('#energy-display').html(PLAYER_DATA['ENERGY']);
  $('#energy-per-second').html(getEnergyPerSecond() + ' energy/sec.');
  $('#energy-cost-per-second').html('Using ' + getEnergyCostPerSecond() + ' energy/sec.');
  $('#gold-display').html(PLAYER_DATA['GOLD']);
}

function logMessage(message) {
  var timestamp = new Date().toLocaleTimeString();
  $('#message-log').append(timestamp + ': ' + message + "
");
  document.getElementById('messages').scrollTop = document.getElementById('messages').scrollHeight;
}

function performAction(name) {
  $('#' + name + '-progressbar').show();

  if (PLAYER_DATA['ENERGY'] >= ALL_ACTIONS[name]['energycost']) {
    ACTION_QUEUE.push(name);
    PLAYER_DATA['ENERGY'] -= ALL_ACTIONS[name]['energycost'];
  } else {
    $.growl.error({title: "Golem says no.", message: "Not enough energy to perform that action."});
  }

  refreshInfo();
}
function actionComplete(name) {
  var output_name = ALL_ACTIONS[name].output;
  var this_quantity = getIngredientQuantity(output_name);
  PLAYER_DATA['INGREDIENT_QUANTITIES'][output_name] = this_quantity + ALL_ACTIONS[name].quantity;
  givexp(ALL_ACTIONS[name].xp);

  if (output_name in SPRITES) {
    createParticle(output_name);
  }

  updateXPBar();
  refreshIngredientCountDisplay();
}
<|endoftext|>