<commit_before>/*
 * Script to obtain useful information from an Orange Your Account login in the UK.
 *
 * @todo Does from-scratch script now have problems?
 * @todo Move non-OO code into separate method
 * @todo Use regexps to seperate data out into parsable numbers
 * @todo Can we reduce reliance on full URLs?
 * @todo Can we get Orange working without SSL security disabled?
 */

var system = require('system');

// Get the parameters from the launch script
var jsonString = system.args[1];
var params = JSON.parse(jsonString);

// Check we have the necessary parameters
if (!params.username)
{
	console.log('[error] This script requires a username');
	phantom.exit();
}
if (!params.password)
{
	console.log('[error] This script requires a password');
	phantom.exit();
}

function LoadHandlerBase()
{
}

LoadHandlerBase.prototype.outputInfo = function(msg)
{
	console.log('[info] ' + msg);
};

LoadHandlerBase.prototype.outputDebug = function(msg)
{
	console.log('[debug] ' + msg);
};

LoadHandlerBase.prototype.outputData = function(msg)
{
	console.log('[data] ' + msg);
};

LoadHandlerBase.prototype.outputError = function(msg)
{
	console.log('[error] ' + msg);
};

LoadHandlerBase.prototype.outputWarning = function(msg)
{
	console.log('[warning] ' + msg);
};

LoadHandlerBase.prototype.outputRemote = function(msg)
{
	console.log('[remote] ' + msg);
};

LoadHandler.prototype = new LoadHandlerBase();

/**
 * This function is a class to hold the load handler methods
 */
function LoadHandler()
{
	this.constants = new Object();
	this.constants.PAGE_LOGIN = 'Login';
	this.constants.PAGE_LOGIN_FAILED = 'LoginFailed';
	// This is either the email request or the account home, don't care
	this.constants.PAGE_LOGIN_SUBMITTED = 'LoginSubmitted';
	this.constants.PAGE_EMAIL_REQUEST = 'Email';
	this.constants.PAGE_ACCOUNT_HOME = 'AccountHome';
	this.constants.PAGE_ALLOWANCE_PREP = 'AllowancePrep';
	this.constants.PAGE_ALLOWANCE_MAIN = 'AllowanceMain';
	this.constants.PAGE_USAGE = 'Usage';
}

/**
 * Handles the loading of the login screen
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadLogin = function(page, status)
{
	var pageId = page.evaluate(
		function(context)
		{
			var
				elementLoggedOut = document.querySelector('h1.PageTitleSignInEE'),
				titleLoggedOut = elementLoggedOut ? elementLoggedOut.innerText : '',

				elementAccount = document.querySelector('#header h1'),
				titleAccount = elementAccount ? elementAccount.innerText : '',

				pageId = null
			;

			// Determine whether we are logged out...
			if (titleLoggedOut.indexOf('SERVICES ON ORANGE.CO.UK') > -1)
			{
				pageId = context.constants.PAGE_LOGIN;
			}
			// ...or logged in from a previous run and found account home page
			else if (titleAccount.indexOf('YOUR ACCOUNT') > -1)
			{
				pageId = context.constants.PAGE_ACCOUNT_HOME;
			}

			return pageId;
		},
		{
			constants: this.constants
		}
	);

	// Only make an attempt to log on if this is the login page
	if (pageId === this.constants.PAGE_LOGIN)
	{
		this.outputInfo('Found login screen');
		page.watcherId = this.constants.PAGE_LOGIN_SUBMITTED;
		page.evaluate(
			function(params)
			{
				// Set up the credentials and submit the form
				document.querySelector('input[name=LOGIN]').value = params.username;
				document.querySelector('input[name=PASSWORD]').value = params.password;
				document.querySelector('div.inner_left_ee form').submit();
			},
			page.watcherParams
		);
	}
	else if (pageId === this.constants.PAGE_ACCOUNT_HOME)
	{
		this.outputInfo('Found account page, already logged in');

		// Emulates a finished event for the account page
		page.watcherId = this.constants.PAGE_ACCOUNT_HOME;
		page.onLoadFinished(status);
	}
	else
	{
		this.outputWarning('We received something unexpected in onLoadLogin');
	}
};

/**
 * Handles the screen after the creds have been submitted
 *
 * If the credentials are wrong this is sometimes called twice
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadLoginSubmitted = function(page, status)
{
	var pageId = page.evaluate(
		function(context)
		{
			var
				// Test for wrong credentials
				elementError = document.querySelector('div.inner_left_ee p.error'),
				textError = elementError ? elementError.innerText : '',

				elementEmail = document.querySelector('.login-flow h2'),
				titleEmail = elementEmail ? elementEmail.innerText : '',

				pageId = null
			;

			if (textError.indexOf('Please enter a valid username and password') > -1)
			{
				pageId = context.constants.PAGE_LOGIN_FAILED;
			}
			else if (titleEmail.indexOf("WE'D LIKE TO GET TO KNOW YOU BETTER") > -1)
			{
				pageId = context.constants.PAGE_EMAIL_REQUEST;
			}

			return pageId;
		},
		{
			constants: this.constants
		}
	);

	if (pageId === this.constants.PAGE_LOGIN_FAILED)
	{
		this.outputError('The username and password settings are incorrect');
		phantom.exit();
	}
	else if (pageId === this.constants.PAGE_EMAIL_REQUEST)
	{
		// Handle skip to next page here
		this.outputInfo('Found email request screen');

		// Point to the page we want to load
		page.watcherId = this.constants.PAGE_ACCOUNT_HOME;
		page.open('https://www.youraccount.orange.co.uk/sss/jfn?entry=true');
	}
	else
	{
		this.outputWarning('We received something unexpected in onLoadLoginSubmitted');
	}
};

LoadHandler.prototype.onLoadAccountHome = function(page, status)
{
	this.outputInfo('Now in account home screen');

	// This will cause a redirect, and we're interested in the second one (the first one says "processing")
	page.watcherId = this.constants.PAGE_ALLOWANCE_PREP;
	page.open('https://www.youraccount.orange.co.uk/sss/jfn?mfunc=877&cem=RMN0002_ViewRemMinAndText&jfnRC=1');
};

/**
 * This renders a "processing" screen on the remote side, and redirects after a few seconds
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadAllowancePrep = function(page, status)
{
	this.outputInfo('Now in allowance preparation screen');
	page.watcherId = this.constants.PAGE_ALLOWANCE_MAIN;
};

LoadHandler.prototype.onLoadAllowanceMain = function(page, status)
{
	this.outputInfo('Now in allowance main screen');

	var data = page.evaluate(
		function()
		{
			var
				elementBalance = document.querySelector('#paymBalanceIncVAT'),
				textBalance = elementBalance ? elementBalance.innerText : '',

				elementAllowance = document.querySelector('.bundleSummary .status'),
				textAllowance = elementAllowance ? elementAllowance.innerText : '',

				elementLastUpdated = document.querySelector('#viewRemMinsTextsSummaryForm .bundleUpdated'),
				textLastUpdated = elementLastUpdated ? elementLastUpdated.innerText : ''
			;

			return {
				balance: textBalance,
				allowance: textAllowance,
				lastUpdated: textLastUpdated
			};
		}
	);

	// Output the data
	this.outputData(JSON.stringify(data));

	// Finally pop over to the usage screen
	page.watcherId = this.constants.PAGE_USAGE;
	page.open('https://www.youraccount.orange.co.uk/sss/jfn?mfunc=1559&jfnRC=6');
};

LoadHandler.prototype.onLoadUsage = function(page, status)
{
	this.outputInfo('Now in data usage screen');

	var data = page.evaluate(
		function()
		{
			var
				elementUsage = document.querySelector('#viewUkDataAllowanceForm .dataUsageFont'),
				textUsage = elementUsage ? elementUsage.innerText : ''
			;

			return {
				usage: textUsage
			};
		}
	);

	// Output the data
	this.outputData(JSON.stringify(data));
};

function login(params)
{
	// Logon to the system
	var
		page = require('webpage').create(),
		loadHandler = new LoadHandler()
	;

	page.onLoadStarted = function() {
		page.watcherHandler.outputInfo('Page load started: ' + page.watcherId);
	};

	/**
	 * This is called, I think, when a redirect happens
	 *
	 * @param targetUrl
	 */
	page.onUrlChanged = function(targetUrl) {
		page.watcherHandler.outputDebug('URL changed: ' + targetUrl + ' on page: ' + page.watcherId);
	};

	// Thanks to https://www.princeton.edu/~crmarsh/phantomjs/
	page.onConsoleMessage = function(msg)
	{
		page.watcherHandler.outputRemote('Console log: ' + msg);
	};

	/**
	 * Handles all load finished events
	 *
	 * @param status
	 */
	page.onLoadFinished = function(status) {
		page.watcherHandler.outputInfo('Page load finished, page: ' + page.watcherId + ', status: ' + status);

		// Call the custom handler, passing in interesting params
		var method = loadHandler['onLoad' + page.watcherId];
		if (typeof method === 'function')
		{
			// Put in a small delay, so the server can breathe!
			setTimeout(
				function()
				{
					method.call(page.watcherHandler, page, status);
				},
				1500
			);
		}
		else
		{
			page.watcherHandler.outputError('Handler missing for load event: ' + page.watcherId);
		}
	};

	page.watcherId = loadHandler.constants.PAGE_LOGIN;
	page.watcherParams = params;
	page.watcherHandler = loadHandler;
	page.open('https://web.orange.co.uk/r/login/');
}

login(params);
<commit_msg>Exit when done<commit_after>/*
 * Script to obtain useful information from an Orange Your Account login in the UK.
 *
 * @todo Does from-scratch script now have problems?
 * @todo Move non-OO code into separate method
 * @todo Use regexps to seperate data out into parsable numbers
 * @todo Can we reduce reliance on full URLs?
 * @todo Can we get Orange working without SSL security disabled?
 */

var system = require('system');

// Get the parameters from the launch script
var jsonString = system.args[1];
var params = JSON.parse(jsonString);

// Check we have the necessary parameters
if (!params.username)
{
	console.log('[error] This script requires a username');
	phantom.exit();
}
if (!params.password)
{
	console.log('[error] This script requires a password');
	phantom.exit();
}

function LoadHandlerBase()
{
}

LoadHandlerBase.prototype.outputInfo = function(msg)
{
	console.log('[info] ' + msg);
};

LoadHandlerBase.prototype.outputDebug = function(msg)
{
	console.log('[debug] ' + msg);
};

LoadHandlerBase.prototype.outputData = function(msg)
{
	console.log('[data] ' + msg);
};

LoadHandlerBase.prototype.outputError = function(msg)
{
	console.log('[error] ' + msg);
};

LoadHandlerBase.prototype.outputWarning = function(msg)
{
	console.log('[warning] ' + msg);
};

LoadHandlerBase.prototype.outputRemote = function(msg)
{
	console.log('[remote] ' + msg);
};

LoadHandler.prototype = new LoadHandlerBase();

/**
 * This function is a class to hold the load handler methods
 */
function LoadHandler()
{
	this.constants = new Object();
	this.constants.PAGE_LOGIN = 'Login';
	this.constants.PAGE_LOGIN_FAILED = 'LoginFailed';
	// This is either the email request or the account home, don't care
	this.constants.PAGE_LOGIN_SUBMITTED = 'LoginSubmitted';
	this.constants.PAGE_EMAIL_REQUEST = 'Email';
	this.constants.PAGE_ACCOUNT_HOME = 'AccountHome';
	this.constants.PAGE_ALLOWANCE_PREP = 'AllowancePrep';
	this.constants.PAGE_ALLOWANCE_MAIN = 'AllowanceMain';
	this.constants.PAGE_USAGE = 'Usage';
}

/**
 * Handles the loading of the login screen
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadLogin = function(page, status)
{
	var pageId = page.evaluate(
		function(context)
		{
			var
				elementLoggedOut = document.querySelector('h1.PageTitleSignInEE'),
				titleLoggedOut = elementLoggedOut ? elementLoggedOut.innerText : '',

				elementAccount = document.querySelector('#header h1'),
				titleAccount = elementAccount ? elementAccount.innerText : '',

				pageId = null
			;

			// Determine whether we are logged out...
			if (titleLoggedOut.indexOf('SERVICES ON ORANGE.CO.UK') > -1)
			{
				pageId = context.constants.PAGE_LOGIN;
			}
			// ...or logged in from a previous run and found account home page
			else if (titleAccount.indexOf('YOUR ACCOUNT') > -1)
			{
				pageId = context.constants.PAGE_ACCOUNT_HOME;
			}

			return pageId;
		},
		{
			constants: this.constants
		}
	);

	// Only make an attempt to log on if this is the login page
	if (pageId === this.constants.PAGE_LOGIN)
	{
		this.outputInfo('Found login screen');
		page.watcherId = this.constants.PAGE_LOGIN_SUBMITTED;
		page.evaluate(
			function(params)
			{
				// Set up the credentials and submit the form
				document.querySelector('input[name=LOGIN]').value = params.username;
				document.querySelector('input[name=PASSWORD]').value = params.password;
				document.querySelector('div.inner_left_ee form').submit();
			},
			page.watcherParams
		);
	}
	else if (pageId === this.constants.PAGE_ACCOUNT_HOME)
	{
		this.outputInfo('Found account page, already logged in');

		// Emulates a finished event for the account page
		page.watcherId = this.constants.PAGE_ACCOUNT_HOME;
		page.onLoadFinished(status);
	}
	else
	{
		this.outputWarning('We received something unexpected in onLoadLogin');
	}
};

/**
 * Handles the screen after the creds have been submitted
 *
 * If the credentials are wrong this is sometimes called twice
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadLoginSubmitted = function(page, status)
{
	var pageId = page.evaluate(
		function(context)
		{
			var
				// Test for wrong credentials
				elementError = document.querySelector('div.inner_left_ee p.error'),
				textError = elementError ? elementError.innerText : '',

				elementEmail = document.querySelector('.login-flow h2'),
				titleEmail = elementEmail ? elementEmail.innerText : '',

				pageId = null
			;

			if (textError.indexOf('Please enter a valid username and password') > -1)
			{
				pageId = context.constants.PAGE_LOGIN_FAILED;
			}
			else if (titleEmail.indexOf("WE'D LIKE TO GET TO KNOW YOU BETTER") > -1)
			{
				pageId = context.constants.PAGE_EMAIL_REQUEST;
			}

			return pageId;
		},
		{
			constants: this.constants
		}
	);

	if (pageId === this.constants.PAGE_LOGIN_FAILED)
	{
		this.outputError('The username and password settings are incorrect');
		phantom.exit();
	}
	else if (pageId === this.constants.PAGE_EMAIL_REQUEST)
	{
		// Handle skip to next page here
		this.outputInfo('Found email request screen');

		// Point to the page we want to load
		page.watcherId = this.constants.PAGE_ACCOUNT_HOME;
		page.open('https://www.youraccount.orange.co.uk/sss/jfn?entry=true');
	}
	else
	{
		this.outputWarning('We received something unexpected in onLoadLoginSubmitted');
	}
};

LoadHandler.prototype.onLoadAccountHome = function(page, status)
{
	this.outputInfo('Now in account home screen');

	// This will cause a redirect, and we're interested in the second one (the first one says "processing")
	page.watcherId = this.constants.PAGE_ALLOWANCE_PREP;
	page.open('https://www.youraccount.orange.co.uk/sss/jfn?mfunc=877&cem=RMN0002_ViewRemMinAndText&jfnRC=1');
};

/**
 * This renders a "processing" screen on the remote side, and redirects after a few seconds
 *
 * @param page
 * @param status
 */
LoadHandler.prototype.onLoadAllowancePrep = function(page, status)
{
	this.outputInfo('Now in allowance preparation screen');
	page.watcherId = this.constants.PAGE_ALLOWANCE_MAIN;
};

LoadHandler.prototype.onLoadAllowanceMain = function(page, status)
{
	this.outputInfo('Now in allowance main screen');

	var data = page.evaluate(
		function()
		{
			var
				elementBalance = document.querySelector('#paymBalanceIncVAT'),
				textBalance = elementBalance ? elementBalance.innerText : '',

				elementAllowance = document.querySelector('.bundleSummary .status'),
				textAllowance = elementAllowance ? elementAllowance.innerText : '',

				elementLastUpdated = document.querySelector('#viewRemMinsTextsSummaryForm .bundleUpdated'),
				textLastUpdated = elementLastUpdated ? elementLastUpdated.innerText : ''
			;

			return {
				balance: textBalance,
				allowance: textAllowance,
				lastUpdated: textLastUpdated
			};
		}
	);

	// Output the data
	this.outputData(JSON.stringify(data));

	// Finally pop over to the usage screen
	page.watcherId = this.constants.PAGE_USAGE;
	page.open('https://www.youraccount.orange.co.uk/sss/jfn?mfunc=1559&jfnRC=6');
};

LoadHandler.prototype.onLoadUsage = function(page, status)
{
	this.outputInfo('Now in data usage screen');

	var data = page.evaluate(
		function()
		{
			var
				elementUsage = document.querySelector('#viewUkDataAllowanceForm .dataUsageFont'),
				textUsage = elementUsage ? elementUsage.innerText : ''
			;

			return {
				usage: textUsage
			};
		}
	);

	// Output the data
	this.outputData(JSON.stringify(data));

	// Exit before the log-out thingy reloads the page
	phantom.exit();
};

function login(params)
{
	// Logon to the system
	var
		page = require('webpage').create(),
		loadHandler = new LoadHandler()
	;

	page.onLoadStarted = function() {
		page.watcherHandler.outputInfo('Page load started: ' + page.watcherId);
	};

	/**
	 * This is called, I think, when a redirect happens
	 *
	 * @param targetUrl
	 */
	page.onUrlChanged = function(targetUrl) {
		page.watcherHandler.outputDebug('URL changed: ' + targetUrl + ' on page: ' + page.watcherId);
	};

	// Thanks to https://www.princeton.edu/~crmarsh/phantomjs/
	page.onConsoleMessage = function(msg)
	{
		page.watcherHandler.outputRemote('Console log: ' + msg);
	};

	/**
	 * Handles all load finished events
	 *
	 * @param status
	 */
	page.onLoadFinished = function(status) {
		page.watcherHandler.outputInfo('Page load finished, page: ' + page.watcherId + ', status: ' + status);

		// Call the custom handler, passing in interesting params
		var method = loadHandler['onLoad' + page.watcherId];
		if (typeof method === 'function')
		{
			// Put in a small delay, so the server can breathe!
			setTimeout(
				function()
				{
					method.call(page.watcherHandler, page, status);
				},
				1500
			);
		}
		else
		{
			page.watcherHandler.outputError('Handler missing for load event: ' + page.watcherId);
		}
	};

	page.watcherId = loadHandler.constants.PAGE_LOGIN;
	page.watcherParams = params;
	page.watcherHandler = loadHandler;
	page.open('https://web.orange.co.uk/r/login/');
}

login(params);
<|endoftext|>


<commit_before>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "Bot Typing",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "Bot Client Control",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function(data) {
		const names = ['Same Channel', 'Mentioned Channel', 'Default Channel', 'Temp Variable', 'Server Variable', 'Global Variable'];
		const names2 = ['Starts Typing', 'Stops Typing']
		const index2 = parseInt(data.EliteArtzIsPro);
		const index = parseInt(data.storage);
		return index < 3 ? `${names[index]} - ${names2[index2]}` : `${names[index]} - ${data.varName} - ${names2[index2]}`;
	},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: ["storage", "varName", "EliteArtzIsPro"],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function(isEvent, data) {
		return `

				Mod Info:

				Created by Lasse! (Merged by EliteArtz)

			Typing Option:

			<select id="EliteArtzIsPro" class="round">
				<option value="0" selected>Start Typing</option>
				<option value="1">Stop Typing</option>
			</select>

			Channel to start typing in:

			<select id="storage" class="round" onchange="glob.channelChange(this, 'varNameContainer')">
				${data.channels[isEvent ? 1 : 0]}
			</select>

			Variable Name:

			<input id="varName" class="round" type="text" list="variableList">

			You can stop the typing with Stop Typing

`
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function() {
		const {glob, document} = this;

		glob.channelChange(document.getElementById('storage'), 'varNameContainer');
	},

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function(cache) {
		const data = cache.actions[cache.index];
		const storage = parseInt(data.storage);
		const varName = this.evalMessage(data.VarName, cache);
		const time = parseInt(this.evalMessage(data.time, cache));
		const channel = this.getChannel(storage, varName, cache);

		try { //This "Try and Catch" Function is really useful for when it's coming up an error, it will log it in your logs.
			if (data.EliteArtzIsPro === "0") { //"If and else" Function is for looking if the result of them equals what you wan't.
				channel.startTyping(); //Starts the Typing
			} else {
				channel.stopTyping(true); //Stops the Typing
			}
		} catch (e) {
			console.error("ERROR!" + e + e.stack); // Here it's gonna log if an error occured.
		}

		this.callNextAction(cache);
	},

	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function(DBM) {
	}

	}; // End of module
	<commit_msg>beautified + added mod info "typing_MOD"<commit_after>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "Bot Typing",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "Bot Client Control",

	//---------------------------------------------------------------------
	// DBM Mods Manager Variables (Optional but nice to have!)
	//
	// These are variables that DBM Mods Manager uses to show information
	// about the mods for people to see in the list.
	//---------------------------------------------------------------------

	// Who made the mod (If not set, defaults to "DBM Mods")
	author: "Lasse & EliteArtz",

	// The version of the mod (Defaults to 1.0.0)
	version: "1.8.7", // Added in 1.8.7

	// A short description to show on the mod line for this mod (Must be on a single line)
	short_description: "Allows the bot to get the *is typing* status",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function(data) {
		const names = ['Same Channel', 'Mentioned Channel', 'Default Channel', 'Temp Variable', 'Server Variable', 'Global Variable'];
		const names2 = ['Starts Typing', 'Stops Typing']
		const index2 = parseInt(data.EliteArtzIsPro);
		const index = parseInt(data.storage);
		return index < 3 ? `${names[index]} - ${names2[index2]}` : `${names[index]} - ${data.varName} - ${names2[index2]}`;
	},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: ["storage", "varName", "EliteArtzIsPro"],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function(isEvent, data) {
		return `

				Mod Info:

				Created by Lasse! (Merged by EliteArtz)

			Typing Option:

			<select id="EliteArtzIsPro" class="round">
				<option value="0" selected>Start Typing</option>
				<option value="1">Stop Typing</option>
			</select>

			Channel to start typing in:

			<select id="storage" class="round" onchange="glob.channelChange(this, 'varNameContainer')">
				${data.channels[isEvent ? 1 : 0]}
			</select>

			Variable Name:

			<input id="varName" class="round" type="text" list="variableList">

			You can stop the typing with Stop Typing

`
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function() {
		const {glob, document} = this;

		glob.channelChange(document.getElementById('storage'), 'varNameContainer');
	},

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function(cache) {
		const data = cache.actions[cache.index];
		const storage = parseInt(data.storage);
		const varName = this.evalMessage(data.VarName, cache);
		const time = parseInt(this.evalMessage(data.time, cache));
		const channel = this.getChannel(storage, varName, cache);

		try { //This "Try and Catch" Function is really useful for when it's coming up an error, it will log it in your logs.
			if (data.EliteArtzIsPro === "0") { //"If and else" Function is for looking if the result of them equals what you wan't.
				channel.startTyping(); //Starts the Typing
			} else {
				channel.stopTyping(true); //Stops the Typing
			}
		} catch (e) {
			console.error("ERROR! " + e + e.stack); // Here it's gonna log if an error occured.
		}

		this.callNextAction(cache);
	},

	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function(DBM) {
	}

	}; // End of module
<|endoftext|>


<commit_before>'use strict';

const rethinkDB = require('rethinkdb');

const protoDB = require('./protodb');
const common = require('./common');

class CartographerDB extends protoDB.ProtoDB {
  /**
   *
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   * @returns {Object} where startY and startX - start point of the line
   */
  static getLineParams(height, width, max) {
    const ret = {};

    ret.startY = common.getRandomInt(0, height - max);
    ret.startX = common.getRandomInt(0, width - max);
    ret.length = common.getRandomInt(3, max);

    return ret;
  }

  /**
   * draw horizontal line on the Map
   * @param locationMap - array for location's map
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   */
  static createHorizontalLine(locationMap, height, width, max) {
    const params = CartographerDB.getLineParams(height, width, max);

    for (let i = 0; i < params.length; i++) {
      locationMap[params.startY][params.startX + i] = 1;
    }
  }

  /**
   * draw vertical line on the Map
   * @param locationMap - array for location's map
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   */
  static createVerticalLine(locationMap, height, width, max) {
    const params = CartographerDB.getLineParams(height, width, max);

    for (let i = 0; i < params.length; i++) {
      locationMap[params.startY + i][params.startX] = 1;
    }
  }

  /**
   *
   * @param height Y
   * @param width X
   * @returns {Array} new map of the Labyrinth's location
   */
  static generateLocationMap(height, width) {
    let locationMap = [];

    for (let i = 0; i < height; i++) {
      locationMap.push(Array.apply(null, Array(width)).map(function (_, i) {
        return 0;
      }));
    }

    for (let i = 0; i < 300; i++) {
      if (i % 2 === 0) {
        CartographerDB.createHorizontalLine(locationMap, height, width, 10);
      }
      if (i % 2 === 1) {
        CartographerDB.createVerticalLine(locationMap, height, width, 10);
      }
    }

    return locationMap;
  }

  createTable (tableName) {
    const _this = this;

    rethinkDB.tableCreate(tableName).run(this.conn, function (err, res) {
      if (err) throw err;

      if (tableName === 'startLocation') {
        common.log('Map generator started.');
        _this.writeNewLocationMap(tableName, CartographerDB.generateLocationMap(100, 100));
        common.log('Map generator ended.');
      }
    });
  }

  writeNewLocationMap(tableName, worldMapArray) {
    let buffer = [];

    for (let y = 0; y < worldMapArray.length; y++) {
      let mapRow = worldMapArray[y];

      for (let x = 0; x < mapRow.length; x++) {
        let elem = {};
        elem['x'] = x;
        elem['y'] = y;
        elem['type'] = mapRow[x];
        buffer.push(elem);
      }
    }

    const _this = this;

    rethinkDB
      .table(tableName)
      .insert(buffer)
      .run(this.conn, function (err, res) {
        if (err) throw err;

        common.log(`Location map done. We inserted ${res['inserted']} elements to ${tableName} for you!`);
        common.log('Let\'s create the index!');

        rethinkDB
          .table(tableName)
          .indexCreate('coord', [rethinkDB.row('x'), rethinkDB.row('y')])
          .run(_this.conn, function(err, res) {
            if (err) throw err;

            rethinkDB
              .table(tableName)
              .indexWait('coord')
              .run(_this.conn, function(err, res) {
                if (err) throw err;

                common.log(`Index for ${tableName} created!`);
                _this.runDB();
              });
          });
      });
  }

  runDB () {
    const _this = this;

    setInterval(function () {
      common.log('Change the Map!');

      const params = CartographerDB.getLineParams(100, 100, 20);
      const elementId = common.getRandomInt(0, 1);

      for (let i = 0; i < params.length; i++) {
        if (elementId === 0) {
          params.startX += 1;
        } else {
          params.startY += 1;
        }

        common.log(`${JSON.stringify(params)}, ${elementId}`);

        rethinkDB
          .table('startLocation')
          .getAll([params.startX, params.startY], {index: 'coord'})
          .update({type: elementId})
          .run(_this.conn, function (err, result) {
            if (err) throw err;
            common.log(JSON.stringify(result));
          });
      }
    }, 5000);
  }

}

if (require.main === module) {
  rethinkDB.connect( {host: 'localhost', port: 28015}, function(err, conn) {
    if (err) throw err;

    const cdb = new CartographerDB(conn, 'labyrinth', ['userPosition', 'startLocation']);
    cdb.initDB();
  });
}<commit_msg>Use arrow functions in Cartographer<commit_after>'use strict';

const rethinkDB = require('rethinkdb');

const protoDB = require('./protodb');
const common = require('./common');

class CartographerDB extends protoDB.ProtoDB {
  /**
   *
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   * @returns {Object} where startY and startX - start point of the line
   */
  static getLineParams(height, width, max) {
    const ret = {};

    ret.startY = common.getRandomInt(0, height - max);
    ret.startX = common.getRandomInt(0, width - max);
    ret.length = common.getRandomInt(3, max);

    return ret;
  }

  /**
   * draw horizontal line on the Map
   * @param locationMap - array for location's map
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   */
  static createHorizontalLine(locationMap, height, width, max) {
    const params = CartographerDB.getLineParams(height, width, max);

    for (let i = 0; i < params.length; i++) {
      locationMap[params.startY][params.startX + i] = 1;
    }
  }

  /**
   * draw vertical line on the Map
   * @param locationMap - array for location's map
   * @param height - height of the game Map
   * @param width - width of the game Map
   * @param max - maximum line's length
   */
  static createVerticalLine(locationMap, height, width, max) {
    const params = CartographerDB.getLineParams(height, width, max);

    for (let i = 0; i < params.length; i++) {
      locationMap[params.startY + i][params.startX] = 1;
    }
  }

  /**
   *
   * @param height Y
   * @param width X
   * @returns {Array} new map of the Labyrinth's location
   */
  static generateLocationMap(height, width) {
    let locationMap = [];

    for (let i = 0; i < height; i++) {
      locationMap.push(Array.apply(null, Array(width)).map(function (_, i) {
        return 0;
      }));
    }

    for (let i = 0; i < 300; i++) {
      if (i % 2 === 0) {
        CartographerDB.createHorizontalLine(locationMap, height, width, 10);
      }
      if (i % 2 === 1) {
        CartographerDB.createVerticalLine(locationMap, height, width, 10);
      }
    }

    return locationMap;
  }

  createTable (tableName) {
    rethinkDB
      .tableCreate(tableName)
      .run(this.conn, (err, res) => {
        if (err) throw err;

        if (tableName === 'startLocation') {
          common.log('Map generator started.');
          this.writeNewLocationMap(tableName, CartographerDB.generateLocationMap(100, 100));
          common.log('Map generator ended.');
        }
      });
  }

  writeNewLocationMap(tableName, worldMapArray) {
    let buffer = [];

    for (let y = 0; y < worldMapArray.length; y++) {
      let mapRow = worldMapArray[y];

      for (let x = 0; x < mapRow.length; x++) {
        let elem = {};
        elem['x'] = x;
        elem['y'] = y;
        elem['type'] = mapRow[x];
        buffer.push(elem);
      }
    }

    rethinkDB
      .table(tableName)
      .insert(buffer)
      .run(this.conn, (err, res) => {
        if (err) throw err;

        common.log(`Location map done. We inserted ${res['inserted']} elements to ${tableName} for you!`);
        common.log('Let\'s create the index!');

        rethinkDB
          .table(tableName)
          .indexCreate('coord', [rethinkDB.row('x'), rethinkDB.row('y')])
          .run(this.conn, (err, res) => {
            if (err) throw err;

            rethinkDB
              .table(tableName)
              .indexWait('coord')
              .run(this.conn, (err, res) => {
                if (err) throw err;

                common.log(`Index for ${tableName} created!`);
                this.runDB();
              });
          });
      });
  }

  runDB () {
    setInterval( () => {
      common.log('Change the Map!');

      const params = CartographerDB.getLineParams(100, 100, 20);
      const elementId = common.getRandomInt(0, 1);

      for (let i = 0; i < params.length; i++) {
        if (elementId === 0) {
          params.startX += 1;
        } else {
          params.startY += 1;
        }

        common.log(`${JSON.stringify(params)}, ${elementId}`);

        rethinkDB
          .table('startLocation')
          .getAll([params.startX, params.startY], {index: 'coord'})
          .update({type: elementId})
          .run(this.conn, (err, result) => {
            if (err) throw err;
            common.log(JSON.stringify(result));
          });
      }
    }, 5000);
  }

}

if (require.main === module) {
  rethinkDB.connect( {host: 'localhost', port: 28015}, function(err, conn) {
    if (err) throw err;

    const cdb = new CartographerDB(conn, 'labyrinth', ['userPosition', 'startLocation']);
    cdb.initDB();
  });
}<|endoftext|>


<commit_before>const _ = require('underscore');

const Effects = {
    all: function(effects) {
        return {
            apply: function(card, context) {
                _.each(effects, effect => effect.apply(card, context));
            },
            unapply: function(card, context) {
                _.each(effects, effect => effect.unapply(card, context));
            },
            isStateDependent: _.any(effects, effect => !!effect.isStateDependent)
        };
    },
    modifyStrength: function(value) {
        return {
            apply: function(card) {
                card.strengthModifier += value;
            },
            unapply: function(card) {
                card.strengthModifier -= value;
            }
        };
    },
    dynamicStrength: function(calculate) {
        return {
            apply: function(card, context) {
                context.dynamicStrength = context.dynamicStrength || {};
                context.dynamicStrength[card] = calculate(card, context);
                card.strengthModifier += context.dynamicStrength[card];
            },
            unapply: function(card, context) {
                card.strengthModifier -= context.dynamicStrength[card];
                delete context.dynamicStrength[card];
            },
            isStateDependent: true
        };
    },
    addIcon: function(icon) {
        return {
            apply: function(card) {
                card.addIcon(icon);
            },
            unapply: function(card) {
                card.removeIcon(icon);
            }
        };
    },
    removeIcon: function(icon) {
        return {
            apply: function(card) {
                card.removeIcon(icon);
            },
            unapply: function(card) {
                card.addIcon(icon);
            }
        };
    },
    addKeyword: function(keyword) {
        return {
            apply: function(card) {
                card.addKeyword(keyword);
            },
            unapply: function(card) {
                card.removeKeyword(keyword);
            }
        };
    },
    addTrait: function(trait) {
        return {
            apply: function(card) {
                card.addTrait(trait);
            },
            unapply: function(card) {
                card.removeTrait(trait);
            }
        };
    },
    killByStrength: {
        apply: function(card, context) {
            if(card.getStrength() <= 0) {
                card.controller.killCharacter(card);
                context.game.addMessage('{0} is killed as its STR is 0', card);
            }
        },
        unapply: function() {
            // nothing happens when this effect expires.
        },
        isStateDependent: true
    },
    blank: {
        apply: function(card) {
            card.setBlank();
        },
        unapply: function(card) {
            card.clearBlank();
        }
    },
    poison: {
        apply: function(card, context) {
            card.addToken('poison', 1);
            context.game.addMessage('{0} uses {1} to place 1 poison token on {2}', context.source.controller, context.source, card);
        },
        unapply: function(card, context) {
            if(card.location === 'play area' && card.hasToken('poison')) {
                card.removeToken('poison', 1);
                card.controller.killCharacter(card);
                context.game.addMessage('{0} uses {1} to kill {2} at the end of the phase', context.source.controller, context.source, card);
            }
        }
    },
    discardIfStillInPlay: function(allowSave = false) {
        return {
            apply: function(card, context) {
                context.discardIfStillInPlay = context.discardIfStillInPlay || [];
                context.discardIfStillInPlay.push(card);
            },
            unapply: function(card, context) {
                if(card.location === 'play area' && context.discardIfStillInPlay.includes(card)) {
                    context.discardIfStillInPlay = _.reject(context.discardIfStillInPlay, c => c === card);
                    card.controller.discardCard(card, allowSave);
                    context.game.addMessage('{0} discards {1} at the end of the phase because of {2}', context.source.controller, card, context.source);
                }
            }
        };
    },
    takeControl: function(newController) {
        return {
            apply: function(card, context) {
                context.takeControl = context.takeControl || {};
                context.takeControl[card] = { originalController: card.controller };
                context.game.takeControl(newController, card);
                context.game.addMessage('{0} uses {1} to take control of {2}', context.source.controller, context.source, card);
            },
            unapply: function(card, context) {
                context.game.takeControl(context.takeControl[card].originalController, card);
                delete context.takeControl[card];
            }
        };
    }
};

module.exports = Effects;
<commit_msg>killing by strength must force the kill and not allow saves<commit_after>const _ = require('underscore');

const Effects = {
    all: function(effects) {
        return {
            apply: function(card, context) {
                _.each(effects, effect => effect.apply(card, context));
            },
            unapply: function(card, context) {
                _.each(effects, effect => effect.unapply(card, context));
            },
            isStateDependent: _.any(effects, effect => !!effect.isStateDependent)
        };
    },
    modifyStrength: function(value) {
        return {
            apply: function(card) {
                card.strengthModifier += value;
            },
            unapply: function(card) {
                card.strengthModifier -= value;
            }
        };
    },
    dynamicStrength: function(calculate) {
        return {
            apply: function(card, context) {
                context.dynamicStrength = context.dynamicStrength || {};
                context.dynamicStrength[card] = calculate(card, context);
                card.strengthModifier += context.dynamicStrength[card];
            },
            unapply: function(card, context) {
                card.strengthModifier -= context.dynamicStrength[card];
                delete context.dynamicStrength[card];
            },
            isStateDependent: true
        };
    },
    addIcon: function(icon) {
        return {
            apply: function(card) {
                card.addIcon(icon);
            },
            unapply: function(card) {
                card.removeIcon(icon);
            }
        };
    },
    removeIcon: function(icon) {
        return {
            apply: function(card) {
                card.removeIcon(icon);
            },
            unapply: function(card) {
                card.addIcon(icon);
            }
        };
    },
    addKeyword: function(keyword) {
        return {
            apply: function(card) {
                card.addKeyword(keyword);
            },
            unapply: function(card) {
                card.removeKeyword(keyword);
            }
        };
    },
    addTrait: function(trait) {
        return {
            apply: function(card) {
                card.addTrait(trait);
            },
            unapply: function(card) {
                card.removeTrait(trait);
            }
        };
    },
    killByStrength: {
        apply: function(card, context) {
            if(card.getStrength() <= 0) {
                card.controller.killCharacter(card, true);
                context.game.addMessage('{0} is killed as its STR is 0', card);
            }
        },
        unapply: function() {
            // nothing happens when this effect expires.
        },
        isStateDependent: true
    },
    blank: {
        apply: function(card) {
            card.setBlank();
        },
        unapply: function(card) {
            card.clearBlank();
        }
    },
    poison: {
        apply: function(card, context) {
            card.addToken('poison', 1);
            context.game.addMessage('{0} uses {1} to place 1 poison token on {2}', context.source.controller, context.source, card);
        },
        unapply: function(card, context) {
            if(card.location === 'play area' && card.hasToken('poison')) {
                card.removeToken('poison', 1);
                card.controller.killCharacter(card);
                context.game.addMessage('{0} uses {1} to kill {2} at the end of the phase', context.source.controller, context.source, card);
            }
        }
    },
    discardIfStillInPlay: function(allowSave = false) {
        return {
            apply: function(card, context) {
                context.discardIfStillInPlay = context.discardIfStillInPlay || [];
                context.discardIfStillInPlay.push(card);
            },
            unapply: function(card, context) {
                if(card.location === 'play area' && context.discardIfStillInPlay.includes(card)) {
                    context.discardIfStillInPlay = _.reject(context.discardIfStillInPlay, c => c === card);
                    card.controller.discardCard(card, allowSave);
                    context.game.addMessage('{0} discards {1} at the end of the phase because of {2}', context.source.controller, card, context.source);
                }
            }
        };
    },
    takeControl: function(newController) {
        return {
            apply: function(card, context) {
                context.takeControl = context.takeControl || {};
                context.takeControl[card] = { originalController: card.controller };
                context.game.takeControl(newController, card);
                context.game.addMessage('{0} uses {1} to take control of {2}', context.source.controller, context.source, card);
            },
            unapply: function(card, context) {
                context.game.takeControl(context.takeControl[card].originalController, card);
                delete context.takeControl[card];
            }
        };
    }
};

module.exports = Effects;
<|endoftext|>


<commit_before>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Blockly blocks for Espruino
 ------------------------------------------------------------------
**/

// --------------------------------- Blockly init code - see /js/core/editorBlockly.js
window.onload = function() {
  Blockly.inject(document.body,{path: '', toolbox: document.getElementById('toolbox')});
  Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, document.getElementById('blocklyInitial'));
  window.parent.blocklyLoaded(Blockly); // see core/editorBlockly.js
};
// ---------------------------------

var ESPRUINO_COL = 190;

var PORTS = ["A","B","C"];
var PINS = [
      ["LED1", 'LED1'],
      ["LED2", 'LED2'],
      ["LED3", 'LED3'],
      ["BTN1", 'BTN1']];
for (var p in PORTS)
  for (var i=0;i<16;i++) {
    var pinname = PORTS[p]+i;
    PINS.push([pinname,pinname]);
  }

Blockly.Language.espruino_timeout = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('SECONDS')
          .setCheck('Number')
          .appendTitle('wait');
      this.appendDummyInput()
          .appendTitle("seconds");
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Waits for a certain period before running code');
  }
};
Blockly.Language.espruino_interval = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('SECONDS')
          .setCheck('Number')
          .appendTitle('every');
      this.appendDummyInput()
          .appendTitle("seconds");
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Runs code repeatedly, every so many seconds');
  }
};
Blockly.Language.espruino_pin = {
//      category: 'Espruino',
  init: function() {
    this.setColour(ESPRUINO_COL);
    this.setOutput(true, 'Pin');
    this.appendDummyInput()
         .appendTitle(new Blockly.FieldDropdown(this.PINS), 'PIN');
    this.setTooltip('The Name of a Pin');
  },
  PINS: PINS,
};

Blockly.Language.espruino_watch = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('watch');
      this.appendDummyInput()
           .appendTitle(new Blockly.FieldDropdown(this.EDGES), 'EDGE').appendTitle('edge');;
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Runs code when an input changes');
  },
EDGES: [
["both", 'both'],
["rising", 'rising'],
["falling", 'falling']]
};

Blockly.Language.espruino_getTime = {
    category: 'Espruino',
    init: function() {
      this.appendDummyInput().appendTitle('Time');
      this.setOutput(true, 'Number');
      this.setColour(230/*Number*/);
      this.setInputsInline(true);
      this.setTooltip('Read the current time in seconds');
    }
  };

Blockly.Language.espruino_digitalWrite = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('digitalWrite Pin');
      this.appendValueInput('VAL')
          .setCheck(['Number','Boolean'])
          .appendTitle('Value');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Writes a Digital Value to a Pin');
  }
};
Blockly.Language.espruino_digitalPulse = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('digitalPulse Pin');
        this.appendValueInput('VAL')
            .setCheck(['Boolean']);
        this.appendValueInput('TIME')
            .setCheck(['Number'])
            .appendTitle('Milliseconds');

      this.setPreviousStatement(true);
      this.setNextStatement(true);
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Pulses a pin for the given number of milliseconds');
    }
  };
Blockly.Language.espruino_digitalRead = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('digitalRead Pin');

    this.setOutput(true, 'Boolean');
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Read a Digital Value from a Pin');
  }
};

Blockly.Language.espruino_analogWrite = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('analogWrite Pin');
        this.appendValueInput('VAL')
            .setCheck(['Number','Boolean'])
            .appendTitle('Value');

      this.setPreviousStatement(true);
      this.setNextStatement(true);
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Writes an Analog Value to a Pin');
    }
  };
Blockly.Language.espruino_analogRead = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('analogRead Pin');

      this.setOutput(true, 'Number');
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Read an Analog Value from a Pin');
    }
  };
// -----------------------------------------------------------------------------------

Blockly.JavaScript.text_print = function() {
  var argument0 = Blockly.JavaScript.valueToCode(this, 'TEXT',
      Blockly.JavaScript.ORDER_NONE) || '\'\'';
  return 'print(' + argument0 + ');\n';
};
Blockly.JavaScript.espruino_timeout = function() {
  var seconds = Blockly.JavaScript.valueToCode(this, 'SECONDS',
      Blockly.JavaScript.ORDER_ASSIGNMENT) || '1';
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  return "setTimeout(function() {\n"+branch+" }, "+seconds+"*1000.0);\n";
};
Blockly.JavaScript.espruino_getTime = function() {
  return ["getTime()\n", Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_interval = function() {
  var seconds = Blockly.JavaScript.valueToCode(this, 'SECONDS',
      Blockly.JavaScript.ORDER_ASSIGNMENT) || '1';
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  return "setInterval(function() {\n"+branch+" }, "+seconds+"*1000.0);\n";
};
Blockly.JavaScript.espruino_pin = function() {
  var code = this.getTitleValue('PIN');
  return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_watch = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var edge = this.getTitleValue('EDGE');
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  var json = { repeat : true, edge : edge };
  if (pin=="BTN1") json.debounce = 10;
  return "setWatch(function() {\n"+branch+" }, "+pin+", "+JSON.stringify(json)+");\n";
};
Blockly.JavaScript.espruino_digitalWrite = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "digitalWrite("+pin+", "+val+");\n";
};
Blockly.JavaScript.espruino_digitalPulse = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var tim = Blockly.JavaScript.valueToCode(this, 'TIME', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "digitalPulse("+pin+", "+val+", "+tim+");\n";
};
Blockly.JavaScript.espruino_digitalRead = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return ["digitalRead("+pin+")\n", Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_analogWrite = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "analogWrite("+pin+", "+val+");\n";
};
Blockly.JavaScript.espruino_analogRead = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return ["analogRead("+pin+")\n", Blockly.JavaScript.ORDER_ATOMIC];
};
<commit_msg>Fix scroll for blockly pins (fix #75)<commit_after>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Blockly blocks for Espruino
 ------------------------------------------------------------------
**/

// --------------------------------- Blockly init code - see /js/core/editorBlockly.js
window.onload = function() {
  Blockly.inject(document.body,{path: '', toolbox: document.getElementById('toolbox')});
  Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, document.getElementById('blocklyInitial'));
  window.parent.blocklyLoaded(Blockly); // see core/editorBlockly.js
};
// ---------------------------------

var ESPRUINO_COL = 190;

var PORTS = ["A","B","C"];
var PINS = [
      ["LED1", 'LED1'],
      ["LED2", 'LED2'],
      ["LED3", 'LED3'],
      ["BTN1", 'BTN1']];
for (var p in PORTS)
  for (var i=0;i<16;i++) {
    var pinname = PORTS[p]+i;
    PINS.push([pinname,pinname]);
  }

Blockly.Language.espruino_timeout = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('SECONDS')
          .setCheck('Number')
          .appendTitle('wait');
      this.appendDummyInput()
          .appendTitle("seconds");
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Waits for a certain period before running code');
  }
};
Blockly.Language.espruino_interval = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('SECONDS')
          .setCheck('Number')
          .appendTitle('every');
      this.appendDummyInput()
          .appendTitle("seconds");
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Runs code repeatedly, every so many seconds');
  }
};

Blockly.Language.espruino_pin = {
//      category: 'Espruino',
  init: function() {

    var start = 0;
    var incrementStep = 10;
    var originalPin = undefined;
    var listGen = function() {
      originalPin = this.value_;
      var list = PINS.slice(start, start+incrementStep);
      console.log(start, incrementStep, list);
      if (start>0) list.unshift(['Back...', 'Back']);
      if (start+incrementStep<PINS.length) list.push(['More...', 'More']);
      return list;
    };

    var pinSelector = new Blockly.FieldDropdown(listGen, function(selection){
      var ret = undefined;

      if (selection == "More" || selection == "Back") {
        if (selection == "More")
          start += incrementStep;
        else
          start -= incrementStep;

        var t = this;
        setTimeout(function(){t.showEditor_();},1);

        return originalPin;
      }
    });

    this.setColour(ESPRUINO_COL);
    this.setOutput(true, 'Pin');
    this.appendDummyInput().appendTitle(pinSelector, 'PIN');
    this.setTooltip('The Name of a Pin');
  },
};

Blockly.Language.espruino_watch = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('watch');
      this.appendDummyInput()
           .appendTitle(new Blockly.FieldDropdown(this.EDGES), 'EDGE').appendTitle('edge');;
      this.appendStatementInput('DO')
           .appendTitle('do');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Runs code when an input changes');
  },
EDGES: [
["both", 'both'],
["rising", 'rising'],
["falling", 'falling']]
};

Blockly.Language.espruino_getTime = {
    category: 'Espruino',
    init: function() {
      this.appendDummyInput().appendTitle('Time');
      this.setOutput(true, 'Number');
      this.setColour(230/*Number*/);
      this.setInputsInline(true);
      this.setTooltip('Read the current time in seconds');
    }
  };

Blockly.Language.espruino_digitalWrite = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('digitalWrite Pin');
      this.appendValueInput('VAL')
          .setCheck(['Number','Boolean'])
          .appendTitle('Value');

    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Writes a Digital Value to a Pin');
  }
};
Blockly.Language.espruino_digitalPulse = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('digitalPulse Pin');
        this.appendValueInput('VAL')
            .setCheck(['Boolean']);
        this.appendValueInput('TIME')
            .setCheck(['Number'])
            .appendTitle('Milliseconds');

      this.setPreviousStatement(true);
      this.setNextStatement(true);
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Pulses a pin for the given number of milliseconds');
    }
  };
Blockly.Language.espruino_digitalRead = {
  category: 'Espruino',
  init: function() {
      this.appendValueInput('PIN')
          .setCheck('Pin')
          .appendTitle('digitalRead Pin');

    this.setOutput(true, 'Boolean');
    this.setColour(ESPRUINO_COL);
    this.setInputsInline(true);
    this.setTooltip('Read a Digital Value from a Pin');
  }
};

Blockly.Language.espruino_analogWrite = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('analogWrite Pin');
        this.appendValueInput('VAL')
            .setCheck(['Number','Boolean'])
            .appendTitle('Value');

      this.setPreviousStatement(true);
      this.setNextStatement(true);
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Writes an Analog Value to a Pin');
    }
  };
Blockly.Language.espruino_analogRead = {
    category: 'Espruino',
    init: function() {
        this.appendValueInput('PIN')
            .setCheck('Pin')
            .appendTitle('analogRead Pin');

      this.setOutput(true, 'Number');
      this.setColour(ESPRUINO_COL);
      this.setInputsInline(true);
      this.setTooltip('Read an Analog Value from a Pin');
    }
  };
// -----------------------------------------------------------------------------------

Blockly.JavaScript.text_print = function() {
  var argument0 = Blockly.JavaScript.valueToCode(this, 'TEXT',
      Blockly.JavaScript.ORDER_NONE) || '\'\'';
  return 'print(' + argument0 + ');\n';
};
Blockly.JavaScript.espruino_timeout = function() {
  var seconds = Blockly.JavaScript.valueToCode(this, 'SECONDS',
      Blockly.JavaScript.ORDER_ASSIGNMENT) || '1';
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  return "setTimeout(function() {\n"+branch+" }, "+seconds+"*1000.0);\n";
};
Blockly.JavaScript.espruino_getTime = function() {
  return ["getTime()\n", Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_interval = function() {
  var seconds = Blockly.JavaScript.valueToCode(this, 'SECONDS',
      Blockly.JavaScript.ORDER_ASSIGNMENT) || '1';
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  return "setInterval(function() {\n"+branch+" }, "+seconds+"*1000.0);\n";
};
Blockly.JavaScript.espruino_pin = function() {
  var code = this.getTitleValue('PIN');
  return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_watch = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var edge = this.getTitleValue('EDGE');
  var branch = Blockly.JavaScript.statementToCode(this, 'DO');
  var json = { repeat : true, edge : edge };
  if (pin=="BTN1") json.debounce = 10;
  return "setWatch(function() {\n"+branch+" }, "+pin+", "+JSON.stringify(json)+");\n";
};
Blockly.JavaScript.espruino_digitalWrite = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "digitalWrite("+pin+", "+val+");\n";
};
Blockly.JavaScript.espruino_digitalPulse = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var tim = Blockly.JavaScript.valueToCode(this, 'TIME', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "digitalPulse("+pin+", "+val+", "+tim+");\n";
};
Blockly.JavaScript.espruino_digitalRead = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return ["digitalRead("+pin+")\n", Blockly.JavaScript.ORDER_ATOMIC];
};
Blockly.JavaScript.espruino_analogWrite = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  var val = Blockly.JavaScript.valueToCode(this, 'VAL', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return "analogWrite("+pin+", "+val+");\n";
};
Blockly.JavaScript.espruino_analogRead = function() {
  var pin = Blockly.JavaScript.valueToCode(this, 'PIN', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0';
  return ["analogRead("+pin+")\n", Blockly.JavaScript.ORDER_ATOMIC];
};
<|endoftext|>


<commit_before>const passport = require('passport');
const SlackStrategy = require('passport-slack').Strategy;
const config = require('../config').slack;
const slack = require('./slack');

module.exports = (User) => {
    passport.serializeUser((user, done) => {
        done(null, user._id);
    });

    // Get user by ID
    passport.deserializeUser((id, done) => {
        User.findById(id)
        .exec()
        .then(user => {
            done(null, user);
        })
        .catch(done);
    });

    passport.use(new SlackStrategy(config,
        (req, token, refreshToken, profile, done) => {
            console.log(profile);

            // Make sure user is in Kids Tales Slack team
            if (profile.team.id !== config.teamID) return done(null, false, { message: 'You must be on the Kids Tales Slack team!' });

            const email = profile.user.email;

            // Find user
            User.findOne({ slackId: profile.slackId })
            .exec()
            .then(user => {
                if (!user) {
                    console.log(`Creating user with email ${email}...`);
                    user = new User({
                        slackId: profile.id,
                        email,
                        name: {
                            full: profile.user.name,
                            first: profile.user.name.split(' ')[0],
                            last: profile.user.name.split(' ')[1],
                        },
                        profileImageName: profile.user.image_192,
                        verified: false,
                        admin: false
                    });

                    user.save();
                    sendEmail(user.email, 'Welcome to Kids Tales', 'newUser', { firstName: user.name.first });
                }
                console.log(`Logging in ${email}...`);

                const u = user.sendSlackMessage('Welcome!')
                    .then(data => {
                        return done(null, user);
                    })
                    .catch(err => {
                        return done(err, false);
                    });
            })
            .catch(err => {
                console.log(`Failed to login user with email ${email}.`)
                return done(err, false, { message: 'There was an error logging you in, please try again later.' });
            });
        }
    ));

    return passport;
};
<commit_msg>Login doesn't always create new user<commit_after>const passport = require('passport');
const SlackStrategy = require('passport-slack').Strategy;
const config = require('../config').slack;
const slack = require('./slack');

module.exports = (User) => {
    passport.serializeUser((user, done) => {
        done(null, user._id);
    });

    // Get user by ID
    passport.deserializeUser((id, done) => {
        User.findById(id)
        .exec()
        .then(user => {
            done(null, user);
        })
        .catch(done);
    });

    passport.use(new SlackStrategy(config,
        (req, token, refreshToken, profile, done) => {
            console.log(profile);

            // Make sure user is in Kids Tales Slack team
            if (profile.team.id !== config.teamID) return done(null, false, { message: 'You must be on the Kids Tales Slack team!' });

            const email = profile.user.email;

            // Find user
            User.findOne({ slackId: profile.id })
            .exec()
            .then(user => {
                if (!user) {
                    console.log(`Creating user with email ${email}...`);
                    user = new User({
                        slackId: profile.id,
                        email,
                        name: {
                            full: profile.user.name,
                            first: profile.user.name.split(' ')[0],
                            last: profile.user.name.split(' ')[1],
                        },
                        profileImageName: profile.user.image_192,
                        verified: false,
                        admin: false
                    });

                    user.save()
                        .then(u => {
                            u.sendSlackMessage('Welcome to Kids Tales!');
                        });
                    sendEmail(user.email, 'Welcome to Kids Tales', 'newUser', { firstName: user.name.first });
                }
                console.log(`Logging in ${email}...`);

                return done(null, user);
            })
            .catch(err => {
                console.log(`Failed to login user with email ${email}.`)
                return done(err, false, { message: 'There was an error logging you in, please try again later.' });
            });
        }
    ));

    return passport;
};
<|endoftext|>


<commit_before>steal(function(){

	var table = document.createElement('table'),
    	tableRow = document.createElement('tr'),
		containers = {
		  'tr': document.createElement('tbody'),
		  'tbody': table, 'thead': table, 'tfoot': table,
		  'td': tableRow, 'th': tableRow,
		  '*': document.createElement('div')
		},
   		fragmentRE = /^\s*<(\w+)[^>]*>/,
   		fragment  = function(html, name) {
		    if (name === undefined) {
		    	name = fragmentRE.test(html) && RegExp.$1;
		    }
		    if (!(name in containers)) name = '*';
		    var container = containers[name];
		     /*
			    IE's parser will strip any
 tags when innerHTML
			    is called on a tbody. To get around this, we construct a
			    valid table with a tbody that has the innerHTML we want.
			    Then the container is the firstChild of the tbody
			    http://www.ericvasilik.com/2006/07/code-karma.html
		    */
		    if(name === "tr") {
		    	var temp = document.createElement('div');
		    	temp.innerHTML = "

" + html + "

";
		    	container = temp.firstChild.firstChild;
		    } else {
		    	container.innerHTML = '' + html;
		    }
		    return [].slice.call(container.childNodes);
		}

	can.buildFragment = function(htmls, nodes){
		var parts = fragment(htmls[0]),
			frag = document.createDocumentFragment();
		parts.forEach(function(part){
			frag.appendChild(part);
		})
		return {
			fragment: frag
		}
	};

})
<commit_msg>fixing fragment for IE8<commit_after>steal(function(){

	var table = document.createElement('table'),
    	tableRow = document.createElement('tr'),
		containers = {
		  'tr': document.createElement('tbody'),
		  'tbody': table, 'thead': table, 'tfoot': table,
		  'td': tableRow, 'th': tableRow,
		  '*': document.createElement('div')
		},
   		fragmentRE = /^\s*<(\w+)[^>]*>/,
   		fragment  = function(html, name) {
		    if (name === undefined) {
		    	name = fragmentRE.test(html) && RegExp.$1;
		    }
		    if (!(name in containers)) name = '*';
		    var container = containers[name];
		     /*
			    IE's parser will strip any
 tags when innerHTML
			    is called on a tbody. To get around this, we construct a
			    valid table with a tbody that has the innerHTML we want.
			    Then the container is the firstChild of the tbody
			    http://www.ericvasilik.com/2006/07/code-karma.html
		    */
		    if(name === "tr") {
		    	var temp = document.createElement('div');
		    	temp.innerHTML = "

" + html + "

";
		    	container = temp.firstChild.firstChild;
		    } else {
		    	container.innerHTML = '' + html;
		    }
		    // IE8 barfs if you pass slice a childNodes object, so make a copy
		    var tmp = {},
		    	children = container.childNodes;
		    tmp.length = children.length;
		    for(var i=0; i<children.length; i++){
		    	tmp[i] = children[i];
		    }
		    return [].slice.call(tmp);
		}

	can.buildFragment = function(htmls, nodes){
		var parts = fragment(htmls[0]),
			frag = document.createDocumentFragment();
		parts.forEach(function(part){
			frag.appendChild(part);
		})
		return {
			fragment: frag
		}
	};

})
<|endoftext|>


<commit_before>'use strict';
const MongoClient = require('mongodb').MongoClient;
let ObjectID = require('mongodb').ObjectID;
const DBURI = process.env.MONGODB_URI;

const MongoC = require('./mongodb');

let fetchUserById = userId => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').findOne({ _id: ObjectID(userId) }, (error, item) => {
        if (error) {
          reject(error);
        }
        resolve(item);
      });
    });
  });
};

let fetchUserByEmail = email => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').findOne({ email: email }, (error, item) => {
        if (error) {
          reject(error);
        }
        resolve(item);
      });
    });
  });
};

let fetchUserFeed = user => {
  let today = Math.round(new Date().getTime() / 1000);
  let twentyFoursAgo = (today - 24 * 3600) * 1000;
  let userInterests = user.interests.map(i => i.name);
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db
        .collection('feeditems')
        .find(
          {
            $and: [
              { status: 'classified' },
              { category: { $in: userInterests } },
              { pubDate: { $gte: twentyFoursAgo } }
            ]
          },
          {
            url: 1,
            title: 1,
            description: 1,
            keywords: 1,
            author: 1,
            pubDate: 1,
            provider: 1,
            category: 1
          }
        )
        .limit(50)
        .toArray((error, docs) => {
          if (error) {
            reject(error);
          }
          resolve(docs);
        });
    });
  });
};

let fetchAnonymousFeed = () => {
  let today = Math.round(new Date().getTime() / 1000);
  let twentyFoursAgo = (today - 24 * 3600) * 1000;
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db
        .collection('feeditems')
        .find(
          { $and: [{ status: 'classified' }, { pubDate: { $gte: twentyFoursAgo } }] },
          {
            url: 1,
            title: 1,
            description: 1,
            keywords: 1,
            author: 1,
            pubDate: 1,
            provider: 1,
            category: 1
          }
        )
        .limit(50)
        .toArray((error, docs) => {
          if (error) {
            reject(error);
          }
          resolve(docs);
        });
    });
  });
};

let newUser = user => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').insertOne(
        {
          nickname: user.nickname,
          name: user.name,
          email: user.email,
          picture: user.picture,
          updated_at: user.updated_at,
          role: user.role ? user.role : 'member'
        },
        (error, result) => {
          if (error) {
            reject(error);
          }
          resolve(result);
        }
      );
    });
  });
};

let updateUser = (userId, reqBody) => {
  let { op, attr, value } = reqBody;
  let query = null;
  switch (attr) {
  case 'interest':
    query = { [op === 'add' ? '$addToSet' : '$pull']: { interests: value } };
    break;
  case 'user':
    query = { $set: { value } };
    break;
  default:
    break;
  }

  return new Promise((resolve, reject) => {
    MongoC.updateDocument('users', userId, query)
      .then(result => resolve(result))
      .catch(err => reject(err));
  });
  // return new Promise((resolve, reject) => {
  //   MongoClient.connect(DBURI, (err, db) => {
  //     db.collection('users').updateOne({
  //       email: user.email
  //     },
  //     { $set: user },
  //     { new: true },
  //     (error, result) => {
  //       if (error) {
  //         reject(err);
  //       }
  //       resolve(result);
  //     });
  //   });
  // });
};

module.exports = {
  fetchUserById,
  fetchUserByEmail,
  fetchUserFeed,
  newUser,
  updateUser,
  fetchAnonymousFeed
};
<commit_msg>adding parent and subcategory attributes to be returned as part of feed<commit_after>'use strict';
const MongoClient = require('mongodb').MongoClient;
let ObjectID = require('mongodb').ObjectID;
const DBURI = process.env.MONGODB_URI;

const MongoC = require('./mongodb');

let fetchUserById = userId => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').findOne({ _id: ObjectID(userId) }, (error, item) => {
        if (error) {
          reject(error);
        }
        resolve(item);
      });
    });
  });
};

let fetchUserByEmail = email => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').findOne({ email: email }, (error, item) => {
        if (error) {
          reject(error);
        }
        resolve(item);
      });
    });
  });
};

let fetchUserFeed = user => {
  let today = Math.round(new Date().getTime() / 1000);
  let twentyFoursAgo = (today - 24 * 3600) * 1000;
  let userInterests = user.interests.map(i => i.name);
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db
        .collection('feeditems')
        .find(
          {
            $and: [
              { status: 'classified' },
              { category: { $in: userInterests } },
              { pubDate: { $gte: twentyFoursAgo } }
            ]
          },
          {
            url: 1,
            title: 1,
            description: 1,
            keywords: 1,
            author: 1,
            pubDate: 1,
            provider: 1,
            category: 1,
            parentcat: 1,
            subcategory: 1
          }
        )
        .limit(50)
        .toArray((error, docs) => {
          if (error) {
            reject(error);
          }
          resolve(docs);
        });
    });
  });
};

let fetchAnonymousFeed = () => {
  let today = Math.round(new Date().getTime() / 1000);
  let twentyFoursAgo = (today - 24 * 3600) * 1000;
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db
        .collection('feeditems')
        .find(
          { $and: [{ status: 'classified' }, { pubDate: { $gte: twentyFoursAgo } }] },
          {
            url: 1,
            title: 1,
            description: 1,
            keywords: 1,
            author: 1,
            pubDate: 1,
            provider: 1,
            category: 1
          }
        )
        .limit(50)
        .toArray((error, docs) => {
          if (error) {
            reject(error);
          }
          resolve(docs);
        });
    });
  });
};

let newUser = user => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(DBURI, (err, db) => {
      db.collection('users').insertOne(
        {
          nickname: user.nickname,
          name: user.name,
          email: user.email,
          picture: user.picture,
          updated_at: user.updated_at,
          role: user.role ? user.role : 'member'
        },
        (error, result) => {
          if (error) {
            reject(error);
          }
          resolve(result);
        }
      );
    });
  });
};

let updateUser = (userId, reqBody) => {
  let { op, attr, value } = reqBody;
  let query = null;
  switch (attr) {
  case 'interest':
    query = { [op === 'add' ? '$addToSet' : '$pull']: { interests: value } };
    break;
  case 'user':
    query = { $set: { value } };
    break;
  default:
    break;
  }

  return new Promise((resolve, reject) => {
    MongoC.updateDocument('users', userId, query)
      .then(result => resolve(result))
      .catch(err => reject(err));
  });
  // return new Promise((resolve, reject) => {
  //   MongoClient.connect(DBURI, (err, db) => {
  //     db.collection('users').updateOne({
  //       email: user.email
  //     },
  //     { $set: user },
  //     { new: true },
  //     (error, result) => {
  //       if (error) {
  //         reject(err);
  //       }
  //       resolve(result);
  //     });
  //   });
  // });
};

module.exports = {
  fetchUserById,
  fetchUserByEmail,
  fetchUserFeed,
  newUser,
  updateUser,
  fetchAnonymousFeed
};
<|endoftext|>


<commit_before>const getJSON = require('get-json');
const unique = require('array-unique');

/** URL of the Overpass API being used */
const overpass = 'http://overpass-api.de/api/interpreter?data=';

/**
 *
 *
 * @param {any} query
 * @param {any} callback
 */
function getRoads(query, callback) {
  getJSON(`${overpass}${query}`, (err, result) => {
    if (err) return callback(err, null);

    let roads = [];

    result.elements.forEach((element) => {
      if (element.tags.name !== undefined) {
        roads.push(element.tags.name);
      }
    });

    roads = unique(roads);

    return callback(null, roads);
  });
}

module.exports = { getRoads };
<commit_msg>Add missing JSDoc to getRoads<commit_after>const getJSON = require('get-json');
const unique = require('array-unique');

/** URL of the Overpass API being used */
const overpass = 'http://overpass-api.de/api/interpreter?data=';

/**
 * Retrieve and process roads from the the Overpass API
 *
 * @param {String} query The Overpass query describing the request.
 * @param {Function} callback (err, roads)
 * @returns {Array} Array of road names matching query.
 */
function getRoads(query, callback) {
  getJSON(`${overpass}${query}`, (err, result) => {
    if (err) return callback(err, null);

    let roads = [];

    result.elements.forEach((element) => {
      if (element.tags.name !== undefined) {
        roads.push(element.tags.name);
      }
    });

    roads = unique(roads);

    return callback(null, roads);
  });
}

module.exports = { getRoads };
<|endoftext|>


<commit_before>const url         = require('url');

send404 = res => {
    res.status(404);
    return res.render('404');

}

module.exports = {
  handleNotFound: function(req, res, next) {
    var parts = url.parse(req.url);
    let urlParts = req.path.split('/');

    // we don't need to worry about non-docs pages, just 404 it
    if (urlParts[1] === 'docs') {
      // native links might erroneosly contain capital letters
      if (req.path.includes('/native/') && /[A-Z]/.test(req.path)) {
        return res.redirect(301, req.path.toLowerCase() ) || true;

      // native links might erroneosly contain dashes
      } else if (req.path.includes('/native/') && req.path.includes('%20')) {
        return res.redirect(301, req.path.replace('%20', '-') ) || true;

        // remove erroneous double slashes
        } else if (req.path.includes('//')) {
          return res.redirect(301, req.path.replace('//', '/') ) || true;

      } else if (urlParts[2].charAt(0) === '1') {
        // if v1 version is pruned, redirect to v1 latest
        urlParts[2] = '1.3.2';
        return res.redirect(301, urlParts.join('/')) || true;
      } else if (urlParts[2] === 'v2') {
        // update to new v2 location
        return res.redirect(301, req.path.replace('/docs/v2', '/docs')) || true;
      } else if (urlParts[2].charAt(0) === '2') {
        // if version is pruned, redirect to latest release
        urlParts[2] = '';
        return res.redirect(301, urlParts.join('/').replace('//', '/')) || true;
      } else if (urlParts[2] == 'resources') {
        // resources is now developer-resources
        return res.redirect(301,
          req.path.replace('/resources', '/developer-resources')) || true;
      }
    }

    console.error(`404 on request: ${req.path}`);
    send404(res);
  }
}
<commit_msg>Log referer on 404<commit_after>const url         = require('url');

send404 = res => {
    res.status(404);
    return res.render('404');

}

module.exports = {
  handleNotFound: function(req, res, next) {
    var parts = url.parse(req.url);
    let urlParts = req.path.split('/');

    // we don't need to worry about non-docs pages, just 404 it
    if (urlParts[1] === 'docs') {
      // native links might erroneosly contain capital letters
      if (req.path.includes('/native/') && /[A-Z]/.test(req.path)) {
        return res.redirect(301, req.path.toLowerCase() ) || true;

      // native links might erroneosly contain dashes
      } else if (req.path.includes('/native/') && req.path.includes('%20')) {
        return res.redirect(301, req.path.replace('%20', '-') ) || true;

        // remove erroneous double slashes
        } else if (req.path.includes('//')) {
          return res.redirect(301, req.path.replace('//', '/') ) || true;

      } else if (urlParts[2].charAt(0) === '1') {
        // if v1 version is pruned, redirect to v1 latest
        urlParts[2] = '1.3.2';
        return res.redirect(301, urlParts.join('/')) || true;
      } else if (urlParts[2] === 'v2') {
        // update to new v2 location
        return res.redirect(301, req.path.replace('/docs/v2', '/docs')) || true;
      } else if (urlParts[2].charAt(0) === '2') {
        // if version is pruned, redirect to latest release
        urlParts[2] = '';
        return res.redirect(301, urlParts.join('/').replace('//', '/')) || true;
      } else if (urlParts[2] == 'resources') {
        // resources is now developer-resources
        return res.redirect(301,
          req.path.replace('/resources', '/developer-resources')) || true;
      }
    }

    console.error(`404 on request: path=${req.path} referer=${req.headers.referer}`);
    send404(res);
  }
}
<|endoftext|>


<commit_before>/**
 * Routes for the RESTful API
 */

var express = require('express');
var router = express.Router();

var VPNModel = require("../model/vpn.js");
var BBXModel = require("../model/bbx.js");

/* TODO: de-bogosify */
router.get('/vpn', function(req, res, next) {
    var vpn_data =  [
        {title: "Foo", detail: "Foofoo", bbxs:["bboo", "bbar"]},
        {title: "Bar", detail: "Foobar", bbxs:["bbar2"]},
        {title: "Baz", detail: "Foobaz", bbxs:["bbaz"]}
    ];
    res.json(VPNModel.sort(vpn_data, req.query._sortField, req.query._sortDir));
});

router.get('/vpn/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    VPNModel.validName(stem);
    res.json({title: stem, detail: "Foo" + stem});
});

router.get('/bbx', function(req, res, next) {
    var bbx_data = [
        {title: "bboo", vpn: "Foo", detail: "Booboo"},
        {title: "bbar", vpn: "Foo", detail: "Boobar"},
        {title: "bbar2", vpn: "Bar", detail: "Boobar2"},
        {title: "bbaz", vpn: "Bazz", detail: "Boobaz"}
    ];
    res.json(BBXModel.sort(bbx_data, req.query._sortField, req.query._sortDir));
});

router.get('/bbx/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    BBXModel.validName(stem);
    res.json({title: stem, vpn: "Bazz", detail: "Foo" + stem});
});

module.exports = router;
<commit_msg>user and vnc added, fake data are now outside of function to be define once<commit_after>/**
 * Routes for the RESTful API
 */
// @todo: check the http://expressjs.com/api.html#app.param to regexp the route without validator
var express = require('express');
var router = express.Router();

var VPNModel = require("../model/vpn.js");
var BBXModel = require("../model/bbx.js");
var VNCModel = require("../model/vnc.js");
var USERModel = require("../model/user.js");

/* TODO: de-bogosify */

// fake vpn data
var vpn_data =  [
    {title: "Foo", detail: "Foofoo", bbxs:["bboo", "bbar"]},
    {title: "Bar", detail: "Foobar", bbxs:["bbar2"]},
    {title: "Baz", detail: "Foobaz", bbxs:["bbaz"]},
    {title: "Bax", detail: "Foobax", bbxs:["bboo", "bbaz"]}
];
router.get('/vpn', function(req, res, next) {
    res.json(VPNModel.sort(vpn_data, req.query._sortField, req.query._sortDir));
});

router.get('/vpn/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    VPNModel.validName(stem);
    vpn_data.forEach(function (value, index) {
        if (vpn_data[index].title == stem) {
            return res.json(vpn_data[index]);
        }
    });
});

// fake bbx data
var bbx_data = [
    {title: "bboo", vpn: "Foo", detail: "Booboo"},
    {title: "bbar", vpn: "Foo", detail: "Boobar"},
    {title: "bbar2", vpn: "Bar", detail: "Boobar2"},
    {title: "bbaz", vpn: "Baz", detail: "Boobaz"}
];
router.get('/bbx', function(req, res, next) {
    res.json(BBXModel.sort(bbx_data, req.query._sortField, req.query._sortDir));
});

router.get('/bbx/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    BBXModel.validName(stem);
    bbx_data.forEach(function (value, index) {
        if (bbx_data[index].title == stem) {
            return res.json(bbx_data[index]);
        }
    });
});

// fake vnc data
var vnc_data = [
    {title: "vnc1", ip:"192.168.10.10", port:"5900", vpn: "Foo", detail: "detail of my first vnc"},
    {title: "vnc1", ip:"192.168.20.20", port:"5900", vpn: "Bar", detail: "detail of my second vnc"},
    {title: "vnc3", ip:"192.168.30.30", port:"5900", vpn: "Bar", detail: "detail of my third vnc"},
    {title: "vnc4", ip:"192.168.40.40", port:"5901", vpn: "Baz", detail: "detail of my fourth vnc"},
    {title: "vnc5", ip:"192.168.50.50", port:"5901", vpn: "Bax", detail: "detail of my fifth vnc"}
];
router.get('/vnc', function(req, res, next) {
    res.json(VNCModel.sort(vnc_data, req.query._sortField, req.query._sortDir));
});

router.get('/vnc/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    VNCModel.validName(stem);
    vnc_data.forEach(function (value, index) {
        if (vnc_data[index].title == stem) {
            return res.json(vnc_data[index]);
        }
    });
});

// fake users data
var users_data = [
    //{username: "user1", sciper:"100100", email:"foo.bar@epfl.ch", group: ["Foo", "Bar", "Baz"], detail: "detail of my first users"},
    // @todo check map function to get group in an array (https://github.com/marmelab/ng-admin/)
    {username: "user1", sciper:"100100", email:"foo.bar@epfl.ch", group: "Foo", detail: "detail of my first users"},
    {username: "user2", sciper:"200200", email:"james.kilroy@epfl.ch", group: "Bar", detail: "detail of my second users"},
    {username: "user3", sciper:"300300", email:"andre.roussimoff@epfl.ch", group: "Foo", detail: "detail of my third users"}
];

router.get('/user', function(req, res, next) {
    res.json(USERModel.sort(users_data, req.query._sortField, req.query._sortDir));
});

router.get('/user/*', function(req, res, next) {
    var urlparts = req.url.split("/");
    var stem = urlparts.pop();
    users_data.forEach(function (value, index) {
        if (users_data[index].username == stem) {
            return res.json(users_data[index]);
        }
    });
});

module.exports = router;
<|endoftext|>


<commit_before>Meteor.publish('posts', function () {
    return Posts.find();
});

Meteor.publish('comments', function (postId) {
    check(postId, String);
    return Comments.find({ postId: postId });
});

Meteor.publish('notifications', function () {
    return Notifications.find();
});<commit_msg>publish notifications for user only<commit_after>Meteor.publish('posts', function () {
    return Posts.find();
});

Meteor.publish('comments', function (postId) {
    check(postId, String);
    return Comments.find({ postId: postId });
});

Meteor.publish('notifications', function () {
    return Notifications.find({userId: this.userId, read: false});
});<|endoftext|>


<commit_before>var redis = require("redis")
var cacheMan = function(options){
	if (this instanceof cacheMan){
		this.options = options;
		this.clientLimit = this.options.clientLimit || 20;
		this.currentConnections = {
			bits: []
		};
		this.connections = 0;
	} else {
		return new cacheMan(options);
	}

}
cacheMan.prototype.getClient = function() {
	if (this.currentConnections.bits.length >this.clientLimit){
		return this.lowBound();
	} else {
		this.connections = ++this.connections;
		var client = redis.createClient();
		client.select(this.options.db||1);
		this.currentConnections.bits[this.currentConnections.bits.length] = 1;
		client.__id = this.currentConnections.bits.length-1;
		var self = this;
		client.release = function(id){
			self.release(id);
		};
		this.currentConnections[this.currentConnections.bits.length-1] = client;
		return client;
	}
};
cacheMan.prototype.lowBound = function() {
	var small=Math.min.apply(null, this.currentConnections.bits);
	for (var i=0;i<this.currentConnections.bits.length;i++){
		if (this.currentConnections.bits[i] == small){
			var value = this.currentConnections.bits[i]+1;
			this.currentConnections.bits[i] = value;
			++this.connections;
			return this.currentConnections[i];
		}
	}
};
cacheMan.prototype.release = function(id) {
	--this.connections;
	var value = this.currentConnections.bits[id]-1;
	value = value == -1?0:value;
	this.currentConnections.bits[id] = value;
};
module.exports = cacheMan;<commit_msg>Fixes<commit_after>var redis = require("redis")
var cacheMan = function(options){
	if (this instanceof cacheMan){
		this.options = options;
		this.clientLimit = this.options.clientLimit || 20;
		this.currentConnections = {
			bits: []
		};
		this.connections = 0;
	} else {
		return new cacheMan(options);
	}

}
cacheMan.prototype.getClient = function() {
	if (this.currentConnections.bits.length >this.clientLimit){
		return this.lowBound();
	} else {
		this.connections = ++this.connections;
		var client = redis.createClient(this.options.redis);
		client.select(this.options.redis.db||1);
		this.currentConnections.bits[this.currentConnections.bits.length] = 1;
		client.__id = this.currentConnections.bits.length-1;
		var self = this;
		client.release = function(id){
			self.release(id);
		};
		this.currentConnections[this.currentConnections.bits.length-1] = client;
		return client;
	}
};
cacheMan.prototype.lowBound = function() {
	var small=Math.min.apply(null, this.currentConnections.bits);
	for (var i=0;i<this.currentConnections.bits.length;i++){
		if (this.currentConnections.bits[i] == small){
			var value = this.currentConnections.bits[i]+1;
			this.currentConnections.bits[i] = value;
			++this.connections;
			return this.currentConnections[i];
		}
	}
};
cacheMan.prototype.release = function(id) {
	--this.connections;
	var value = this.currentConnections.bits[id]-1;
	value = value == -1?0:value;
	this.currentConnections.bits[id] = value;
};
module.exports = cacheMan;
<|endoftext|>