<commit_before>'use strict';

console.log('Loading function');

const doc = require('dynamodb-doc');
const crypto = require('crypto');
const Q = require('q');
const Entities = require('html-entities').XmlEntities;

const entities = new Entities();
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {
	//console.log('Received event:', JSON.stringify(event, null, 2));
	if (process.env.ignoreSecurity || validate(event)) {

		var body = JSON.parse(event.body),
			bodyText = entities.decode(body.text),
			actionsRe = /<at>([^<]+)<\/at>\s{0,2}([+-]{2})|!(\w+)(?:\s+(\w+)="(.+?)")?/g,
			actions = [], action, reResult,
			resultPromisesArray = [];

		console.log('Parsed text:', bodyText);
		while((reResult = actionsRe.exec(bodyText)) !== null) {
            let action = { type: reResult[0] || '', teamid: body.channelData.teamsTeamId, caller: body.from };

			if (action.type.startsWith('<at>')) {
				let name = reResult[1];
				let op = reResult[2];
				let mention = body.entities.find(entity => { return entity.mentioned && entity.mentioned.name === name });

				if (mention) {
					action.type = op || action.type;
					action.userid = mention.mentioned.id;
					action.name = mention.mentioned.name;
				}
			} else if (action.type.startsWith('!set')) {
				action.type = 'set';
				action.key = reResult[4];
				action.value = reResult[5];
				if (!action.key || !action.value) {
					action.type = 'error'
				}
			} else if (action.type.startsWith('!')) {
				action.type = '!';
				action.key = reResult[3];
			}

			actions.push(action);
		}

		//console.log("Submitted actions:", actions);

		if (actions.length == 0) {
			sendHelp(context, callback);
			return;
		}

		actions.forEach(action => {
			logAction(action)
			switch (action.type) {
				case "set":
					resultPromisesArray.push(setBangAction(action));
					break;
				case "!":
					resultPromisesArray.push(bangAction(action));
					break;
				case "++":
					resultPromisesArray.push(increment(action));
					break;
				case "--":
					resultPromisesArray.push(increment(action));
			}
		}, this);

		Q.all(resultPromisesArray).fail(error => { console.error(error) }).done(results => {
			//console.log("final result: ", results);
			let response = results.join('
');

			callback(null, {
				statusCode: 200,
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ type: 'message', text: response })
			});
		});

	} else {
		callback(null, {
			statusCode: '401'
		});
	}

};

function bangAction(action) {
	let emoticon = '';

	switch(action.key) {
		case 'list':
			return getScoreList(action);
		case 'flip':
			emoticon = '(╯°Д°）╯︵ ┻━┻';
			break;
		case 'unflip':
			emoticon = '┬──┬ ノ( ゜-゜ノ)';
			break;
		case 'shrug':
			emoticon = '¯\\\\_(ツ)_/¯';
			break;
		case 'disapprove':
			emoticon = 'ಠ_ಠ';
			break;
		default:
			return getBangAction(action);
	}

	return Q(emoticon);
}

function getBangAction(action) {
	let params = {
		TableName: 'BangActions',
		Key: { "key": action.key, "teamid": action.teamid }
	};
	return Q.ninvoke(dynamo, "getItem", params)
		.then(data => {
			//console.log("Getting user for inc:", data);
			if (data.Item) {
				return data.Item.value;
			} else {
				return "Action not found.";
			}
		}).fail(error => {
			console.error('Error getting bang action:', error);
		});
}

function setBangAction(action) {
	let params = {
		TableName: 'BangActions',
		Item: {
			"creator": action.caller.id,
			"key": action.key,
			"value": action.value,
			"createtime": Date.now(),
			"teamid": action.teamid
		}
	};
	return Q.ninvoke(dynamo, "putItem", params)
		.then(data => {
			console.log("after put", data);
			return '!' + action.key + " is now \"" + action.value + "\"."
		}).fail(error => {
			console.error('Error setting bang action:', error);
		});
}

function getScoreList(action) {
	let params = {
		TableName: 'KarmaBot',
		KeyConditionExpression: "#t = :tid",
		ExpressionAttributeNames:{
			"#t": "teamid"
		},
		ExpressionAttributeValues: {
			":tid":action.teamid
		}
	}

    //console.log("scan params:",params)

	return Q.ninvoke(dynamo, "query", params)
		.then(data => {
			//console.log("scan data:",data)
			let res = '';

			if (data.Items.length) {
				res += "
";

				// sorting by score
				data.Items.sort((a, b) => b.score - a.score);

				res += data.Items.reduce((acc, user) => {
					return  acc += "
" + user.name + ": " + user.score + "
";
				}, '');

				res += "
";

			} else { res = "No one has karma :(" }
			//console.log("score list result:", res);
			return res;
		}).fail(error => {
			console.error('Error getting score list:', error);
		});
}

function increment(action) {
	let params = {
		TableName: 'KarmaBot',
		Key: { "userid": action.userid, "teamid": action.teamid }
	};

	return Q.ninvoke(dynamo, "getItem", params)
		.then(data => {
			//console.log("Getting user for inc:", data);
			if (data.Item) {
				let params = {
					TableName: 'KarmaBot',
					Key: { "userid": data.Item.userid, "teamid": data.Item.teamid },
					ExpressionAttributeNames: { "#S": "score", "#LS": "lastscore" },
					ExpressionAttributeValues: { ":s": action.type === "++" ? data.Item.score + 1 : data.Item.score - 1 , ":ls": Date.now() },
					ReturnValues: "ALL_NEW",
					UpdateExpression: "SET #S = :s, #LS = :ls"
				}

				//console.log("update params:", params);

				return Q.ninvoke(dynamo, "updateItem", params)
					.then(data => {
						//console.log("after update", data);
						return "<at>" + data.Attributes.name + "</at> has " + data.Attributes.score + " karma."
					});
			} else {
				let score = action.type === "++" ? 1 : -1;
				let friendlyName = action.name.split(', ').reverse().join(' ');
				let params = {
					TableName: 'KarmaBot',
					Item: {
						"userid": action.userid,
						"name": friendlyName,
						"score": score,
						"lastscore": Date.now(),
						"teamid": action.teamid
					}
				};
				return Q.ninvoke(dynamo, "putItem", params)
					.then(data => {
						console.log("after put", data);
						return "<at>" + friendlyName + "</at> has " + score + " karma."
					});
			}
		}).fail(error => {
			console.error('Error updating:', error);
		});
}

function logAction(action) {
	let params = {
		TableName: 'KarmaBotActions',
		Item: {
			'userid': action.caller.id,
			'actiontime': Date.now(),
			'action': JSON.stringify(action)
		}
	};
	dynamo.putItem(params).send();
}

function sendHelp(context, callback) {
	let response = ["You can use the following commands: ",
					"
@user++ : to add a point to a user
",
					"
@user-- : to remove a point from a user
",
					"
!list    : to list the current score board
"
				   ].join('');

	callback(null, {
		statusCode: 200,
		headers: { 'Content-Type': 'application/json' },
		body: JSON.stringify({ type: 'message', text: response })
	});
}

function stringToUtf8ByteArray(str) {
	let out = [], p = 0;

	for (var i = 0; i < str.length; i++) {
		let c = str.charCodeAt(i);
		if (c < 128) {
			out[p++] = c;
		} else if (c < 2048) {
			out[p++] = (c >> 6) | 192;
			out[p++] = (c & 63) | 128;
		} else if (
			((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
			((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
			// Surrogate Pair
			c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
			out[p++] = (c >> 18) | 240;
			out[p++] = ((c >> 12) & 63) | 128;
			out[p++] = ((c >> 6) & 63) | 128;
			out[p++] = (c & 63) | 128;
		} else {
			out[p++] = (c >> 12) | 224;
			out[p++] = ((c >> 6) & 63) | 128;
			out[p++] = (c & 63) | 128;
		}
	}
	return out;
}

function validate(request) {
	let messageContent = request.body,
		authHeader = request.headers && request.headers.Authorization,
		claimedSenderId = request.queryStringParameters.id,
		signature, hash;

	if (!claimedSenderId) {
		console.log('Id not present on request', request);
		return false;
	}

	if (!authHeader) {
		console.log('Authentication header not provided', request);
		return false;
	}

	if (!authHeader.startsWith("HMAC ")) {
		console.log('Incorrect auth scheme', request);
		return false;
	}

	if (!messageContent) {
		console.log('Unable to validate authentication header for messages with empty body', request);
		return false;
	}

	signature = authHeader.substring(5);

	const secret = new Buffer(process.env[claimedSenderId], 'base64');
	const contentBytes = new Buffer(stringToUtf8ByteArray(messageContent));
	const hmac = crypto.createHmac('SHA256', secret);

	hmac.update(contentBytes);
	hash = hmac.digest('base64');

	if (hash == signature) {
		console.log("Authenticated!");
		return true;
	}

	console.log('AuthHeaderValueMismatch', "Expected:'" + hash + "' Provided:'" + signature + "'");
	return false;
}
<commit_msg>no more mixed tabs/spaces redux<commit_after>'use strict';

console.log('Loading function');

const doc = require('dynamodb-doc');
const crypto = require('crypto');
const Q = require('q');
const Entities = require('html-entities').XmlEntities;

const entities = new Entities();
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {
	//console.log('Received event:', JSON.stringify(event, null, 2));
	if (process.env.ignoreSecurity || validate(event)) {

		var body = JSON.parse(event.body),
			bodyText = entities.decode(body.text),
			actionsRe = /<at>([^<]+)<\/at>\s{0,2}([+-]{2})|!(\w+)(?:\s+(\w+)="(.+?)")?/g,
			actions = [], action, reResult,
			resultPromisesArray = [];

		console.log('Parsed text:', bodyText);
		while((reResult = actionsRe.exec(bodyText)) !== null) {
			let action = { type: reResult[0] || '', teamid: body.channelData.teamsTeamId, caller: body.from };

			if (action.type.startsWith('<at>')) {
				let name = reResult[1];
				let op = reResult[2];
				let mention = body.entities.find(entity => { return entity.mentioned && entity.mentioned.name === name });

				if (mention) {
					action.type = op || action.type;
					action.userid = mention.mentioned.id;
					action.name = mention.mentioned.name;
				}
			} else if (action.type.startsWith('!set')) {
				action.type = 'set';
				action.key = reResult[4];
				action.value = reResult[5];
				if (!action.key || !action.value) {
					action.type = 'error'
				}
			} else if (action.type.startsWith('!')) {
				action.type = '!';
				action.key = reResult[3];
			}

			actions.push(action);
		}

		//console.log("Submitted actions:", actions);

		if (actions.length == 0) {
			sendHelp(context, callback);
			return;
		}

		actions.forEach(action => {
			logAction(action)
			switch (action.type) {
				case "set":
					resultPromisesArray.push(setBangAction(action));
					break;
				case "!":
					resultPromisesArray.push(bangAction(action));
					break;
				case "++":
					resultPromisesArray.push(increment(action));
					break;
				case "--":
					resultPromisesArray.push(increment(action));
			}
		}, this);

		Q.all(resultPromisesArray).fail(error => { console.error(error) }).done(results => {
			//console.log("final result: ", results);
			let response = results.join('
');

			callback(null, {
				statusCode: 200,
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ type: 'message', text: response })
			});
		});

	} else {
		callback(null, {
			statusCode: '401'
		});
	}

};

function bangAction(action) {
	let emoticon = '';

	switch(action.key) {
		case 'list':
			return getScoreList(action);
		case 'flip':
			emoticon = '(╯°Д°）╯︵ ┻━┻';
			break;
		case 'unflip':
			emoticon = '┬──┬ ノ( ゜-゜ノ)';
			break;
		case 'shrug':
			emoticon = '¯\\\\_(ツ)_/¯';
			break;
		case 'disapprove':
			emoticon = 'ಠ_ಠ';
			break;
		default:
			return getBangAction(action);
	}

	return Q(emoticon);
}

function getBangAction(action) {
	let params = {
		TableName: 'BangActions',
		Key: { "key": action.key, "teamid": action.teamid }
	};
	return Q.ninvoke(dynamo, "getItem", params)
		.then(data => {
			//console.log("Getting user for inc:", data);
			if (data.Item) {
				return data.Item.value;
			} else {
				return "Action not found.";
			}
		}).fail(error => {
			console.error('Error getting bang action:', error);
		});
}

function setBangAction(action) {
	let params = {
		TableName: 'BangActions',
		Item: {
			"creator": action.caller.id,
			"key": action.key,
			"value": action.value,
			"createtime": Date.now(),
			"teamid": action.teamid
		}
	};
	return Q.ninvoke(dynamo, "putItem", params)
		.then(data => {
			console.log("after put", data);
			return '!' + action.key + " is now \"" + action.value + "\"."
		}).fail(error => {
			console.error('Error setting bang action:', error);
		});
}

function getScoreList(action) {
	let params = {
		TableName: 'KarmaBot',
		KeyConditionExpression: "#t = :tid",
		ExpressionAttributeNames:{
			"#t": "teamid"
		},
		ExpressionAttributeValues: {
			":tid":action.teamid
		}
	}

    //console.log("scan params:",params)

	return Q.ninvoke(dynamo, "query", params)
		.then(data => {
			//console.log("scan data:",data)
			let res = '';

			if (data.Items.length) {
				res += "
";

				// sorting by score
				data.Items.sort((a, b) => b.score - a.score);

				res += data.Items.reduce((acc, user) => {
					return  acc += "
" + user.name + ": " + user.score + "
";
				}, '');

				res += "
";

			} else { res = "No one has karma :(" }
			//console.log("score list result:", res);
			return res;
		}).fail(error => {
			console.error('Error getting score list:', error);
		});
}

function increment(action) {
	let params = {
		TableName: 'KarmaBot',
		Key: { "userid": action.userid, "teamid": action.teamid }
	};

	return Q.ninvoke(dynamo, "getItem", params)
		.then(data => {
			//console.log("Getting user for inc:", data);
			if (data.Item) {
				let params = {
					TableName: 'KarmaBot',
					Key: { "userid": data.Item.userid, "teamid": data.Item.teamid },
					ExpressionAttributeNames: { "#S": "score", "#LS": "lastscore" },
					ExpressionAttributeValues: { ":s": action.type === "++" ? data.Item.score + 1 : data.Item.score - 1 , ":ls": Date.now() },
					ReturnValues: "ALL_NEW",
					UpdateExpression: "SET #S = :s, #LS = :ls"
				}

				//console.log("update params:", params);

				return Q.ninvoke(dynamo, "updateItem", params)
					.then(data => {
						//console.log("after update", data);
						return "<at>" + data.Attributes.name + "</at> has " + data.Attributes.score + " karma."
					});
			} else {
				let score = action.type === "++" ? 1 : -1;
				let friendlyName = action.name.split(', ').reverse().join(' ');
				let params = {
					TableName: 'KarmaBot',
					Item: {
						"userid": action.userid,
						"name": friendlyName,
						"score": score,
						"lastscore": Date.now(),
						"teamid": action.teamid
					}
				};
				return Q.ninvoke(dynamo, "putItem", params)
					.then(data => {
						console.log("after put", data);
						return "<at>" + friendlyName + "</at> has " + score + " karma."
					});
			}
		}).fail(error => {
			console.error('Error updating:', error);
		});
}

function logAction(action) {
	let params = {
		TableName: 'KarmaBotActions',
		Item: {
			'userid': action.caller.id,
			'actiontime': Date.now(),
			'action': JSON.stringify(action)
		}
	};
	dynamo.putItem(params).send();
}

function sendHelp(context, callback) {
	let response = ["You can use the following commands: ",
					"
@user++ : to add a point to a user
",
					"
@user-- : to remove a point from a user
",
					"
!list    : to list the current score board
"
				   ].join('');

	callback(null, {
		statusCode: 200,
		headers: { 'Content-Type': 'application/json' },
		body: JSON.stringify({ type: 'message', text: response })
	});
}

function stringToUtf8ByteArray(str) {
	let out = [], p = 0;

	for (var i = 0; i < str.length; i++) {
		let c = str.charCodeAt(i);
		if (c < 128) {
			out[p++] = c;
		} else if (c < 2048) {
			out[p++] = (c >> 6) | 192;
			out[p++] = (c & 63) | 128;
		} else if (
			((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
			((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
			// Surrogate Pair
			c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
			out[p++] = (c >> 18) | 240;
			out[p++] = ((c >> 12) & 63) | 128;
			out[p++] = ((c >> 6) & 63) | 128;
			out[p++] = (c & 63) | 128;
		} else {
			out[p++] = (c >> 12) | 224;
			out[p++] = ((c >> 6) & 63) | 128;
			out[p++] = (c & 63) | 128;
		}
	}
	return out;
}

function validate(request) {
	let messageContent = request.body,
		authHeader = request.headers && request.headers.Authorization,
		claimedSenderId = request.queryStringParameters.id,
		signature, hash;

	if (!claimedSenderId) {
		console.log('Id not present on request', request);
		return false;
	}

	if (!authHeader) {
		console.log('Authentication header not provided', request);
		return false;
	}

	if (!authHeader.startsWith("HMAC ")) {
		console.log('Incorrect auth scheme', request);
		return false;
	}

	if (!messageContent) {
		console.log('Unable to validate authentication header for messages with empty body', request);
		return false;
	}

	signature = authHeader.substring(5);

	const secret = new Buffer(process.env[claimedSenderId], 'base64');
	const contentBytes = new Buffer(stringToUtf8ByteArray(messageContent));
	const hmac = crypto.createHmac('SHA256', secret);

	hmac.update(contentBytes);
	hash = hmac.digest('base64');

	if (hash == signature) {
		console.log("Authenticated!");
		return true;
	}

	console.log('AuthHeaderValueMismatch', "Expected:'" + hash + "' Provided:'" + signature + "'");
	return false;
}
<|endoftext|>


<commit_before>var utils = require( './utils' );
var config = require( './config' ).Config;
var fabric = require( './fabric').MessageFabric;
var encoder = require( './encoder').Encoder;
var userinfo = require( './userinfo').UserInfo;
var client = require( './client').Client;

exports.utils = utils;
exports.Config = config;
exports.MessageFabric = fabric;
exports.Encoder = encoder;
exports.UserInfo = userinfo;
exports.Client = client;

//console.log( 'index.js> tbox is loaded...' );<commit_msg>reference of config.js removed from index.js<commit_after>var utils = require( './utils' );
var fabric = require( './fabric').MessageFabric;
var encoder = require( './encoder').Encoder;
var userinfo = require( './userinfo').UserInfo;
var client = require( './client').Client;

exports.utils = utils;
exports.MessageFabric = fabric;
exports.Encoder = encoder;
exports.UserInfo = userinfo;
exports.Client = client;

//console.log( 'index.js> tbox is loaded...' );<|endoftext|>


<commit_before>var postcss = require('postcss');

module.exports = postcss.plugin('postcss-javascript-output', function (opts) {
    opts = opts || {};

    // Work with options here

    return function (css, result) {
        result.js =

        // Transform CSS AST here

    };
});
<commit_msg>added js<commit_after>var postcss = require('postcss');

function JS() {
   this.fragments = [];
}

JS.prototype.toString = function() {
    return this.fragments.join("\n");
};

JS.prototype.append = function(f) {
    this.fragments.push(f);
    return this;
};

JS.prototype.prepend = function(f) {
    this.fragments.unshift(f);
    return this;
};

module.exports = postcss.plugin('postcss-javascript-output', function (opts) {
    opts = opts || {};

    // Work with options here

    return function (css, result) {
        result.js = new JS;
    };
});
<|endoftext|>


<commit_before>// Dependencies
var Url = require ("url")
  , Fs  = require ("fs")
  , Path = require("path")
  , Events = require("events")
  ;

// MIME types
const MIME_TYPES = {
    "html": "text/html"
  , "jpeg": "image/jpeg"
  , "jpg":  "image/jpeg"
  , "png":  "image/png"
  , "js":   "text/javascript"
  , "css":  "text/css"
};

/**
 * Le Statique
 * -----------
 * A node-static minimalist alternative.
 * Licensed under the MIT license. See the LICENSE file.
 *
 *
 * Documentation can be found in README and on GitHub:
 * http://github.com/IonicaBizau/node-statique
 */
var Statique = module.exports = {};

/**
 * Sets the root of the public folder.
 *
 * @param {Object} options an object containing the following fields:
 *  - root: string representing the absolute path to the public folder.
 *  - cache: the number of seconds of cache
 * @return {Object} Statique object
 */
Statique.server = function (options) {
    if (typeof options === "string") {
        options = {
            root: options
        }
    }
    if (options.root.slice (-1) !== "/") {
        options.root += "/";
    }

    Statique._root = options.root;
    Statique._cache = options.cache || 3600;

    return Statique;
};

/**
 * Sets the routes of the website.
 *
 * @param {Object} routes an object containing fields and values in the
 * following format:
 *  {
 *      "/":       "/html/index.html"
 *    , "/foo/":   { url: "/html/foo.html" }
 *    , "/another-foo": "/html/myfoo.html"
 *    , "/some/api": function (req, res) {
 *          res.end("Hello World!");
 *      }
 *  }
 *
 *  See test file for more examples.
 * @return {Object} Statique object
 */
Statique.setRoutes = function (routes) {
    Statique._routes = routes;
    return Statique;
};

/**
 * Gets the route by providing an @url
 *
 * @param {String} url a string representing the url of the page that
 * must be served
 * @return {Object} the route object that contains the following fields:
 *  - url
 *  - handler
 */
Statique.getRoute = function (url) {

    var route = {};

    // remove slash at the end of the string
    if (url.slice (-1) === "/") {
        url = url.substring (0, url.length - 1);
    }

    // get the route that was set in the configuration
    var routeObj = Statique._routes[url] || Statique._routes[url + "/"] || null;
    route.url = (routeObj || {}).url || routeObj;
    route.reqUrl = route.url || url;

    // handle url as function
    if (typeof route.url === "function") {
        route.handler = route.url;
        delete route.url;
    }

    if (routeObj && typeof routeObj.handler === "function") {
        routeObj.handler = routeObj.handler;
    }

    return route;
};

/**
 * Checks if a route exists.
 *
 * @param {Object} req the request object
 * @return {Boolean} true, if the route was found, else false
 */
Statique.exists = function (req) {
    return Boolean (Statique.getRoute(Url.parse(req.url).pathname));
};

/**
 * Reads the file and callbacks the content.
 *
 * @param {String} file the relative path to the file
 * @param {Function} callback the callback function that will be called with an
 * err (first argument) and the content of the file (second argument)
 * @return {Buffer} the raw buffer
 */
Statique.readFile = function (file, callback) {
    return Fs.readFile (Statique._root + file, function (err, buffer) {
        if (err) { return callback (err); }
        callback (null, buffer.toString())
    });
};

/**
 * Serves the HTML file according by providing the @req and @res parameters
 *
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @return {Object} the Statique instance
 */
Statique.serve = function (req, res) {
    return Statique.serveRoute(undefined, req, res);
};

/**
 * This function is used for sending custom status messages and content
 * If the @content parameter is not provided or is not a string, the response
 * will not be ended. The status code and the headers will be set
 *
 * @param {Object} res the response object
 * @param {Number} statusCode the response status code
 * @param {String} mimeType the response mime type
 * @param {String} content the content that you want to send via response
 * @param {Object} otherHeaders Aditional headers that will be merged with
 * the basic ones. They have greater priority than basic headers.
 * @return {Object} the Statique instance
 */
Statique.sendRes = function (res, statusCode, mimeType, content, otherHeaders) {

    var headers = {
        "Content-Type": mimeType || "plain/text"
      , "Server": "Statique Server"
    };

    for (var h in otherHeaders) {
        headers[h] = otherHeaders[h] || headers[h];
    }

    res.writeHead(statusCode, headers);

    if (typeof content === "string") {
        res.end (content);
    }

    return Statique;
};

/**
 * serveRoute
 * Serves a provided route.
 *
 * @name serveRoute
 * @function
 * @param {String} route The route that should be served
 * @param {Object} req The request object
 * @param {Object} res The response object
 * @return {Object} The Statique instance
 */
Statique.serveRoute = function (route, req, res) {

    var parsedUrl = Url.parse (req.url)
      , routeToServe = Statique.getRoute(
            route || parsedUrl.pathname
        ) || parsedUrl.pathname
      , stats = null
      , fileName = Statique._root + (routeToServe.url || routeToServe.reqUrl)
      , method = req.method.toLowerCase()
      , form = {
            data: ""
          , error: ""
          , _emitter: new Events.EventEmitter()
        }
      ;

    req.on("data", function (chunk) {
        form.data += chunk;
    });

    req.on("error", function (err) {
        form.error += err;
    });

    req.on("end", function () {
        form._emitter.emit("done", form);
    });

    if (routeToServe.url && typeof routeToServe.url[method] === "function") {
        routeToServe.url[method](req, res, form._emitter);
        return Statique;
    }

    if (typeof routeToServe.handler === "function") {
        routeToServe.handler(req, res, form._emitter);
        return Statique;
    }

    try {
        stats = Fs.lstatSync (fileName);
    } catch (e) {
        Statique.sendRes (res, 404, "html", "404 - Not found");
        return Statique;
    }

    // no file, no fun
    if (!stats.isFile()) { return Statique; }

    // cache stuff
    var mtime = Date.parse(stats.mtime)
      , clientETag = req.headers['if-none-match']
      , clientMTime = Date.parse(req.headers['if-modified-since'])
      , contentType = MIME_TYPES[
            Path.extname(routeToServe.reqUrl).substring(1)
        ]
      , headers = {
            "Etag": JSON.stringify([stats.ino, stats.size, mtime].join('-'))
          , "Date": (new Date()).toUTCString()
          , "Last-Modified": (new Date(stats.mtime)).toUTCString()
          , "Content-Type": contentType
          , "Content-Length": stats.size
        }
      ;

    // Conditional GET
    // If the "If-Modified-Since" or "If-None-Match" headers
    // match the conditions, send a 304 Not Modified.
    // Thanks! https://github.com/cloudhead/node-static/blob/4858a8212c580fa831b9614825275f38791df579/lib/node-static.js#L250
    if ((clientMTime  || clientETag) &&
        (!clientETag  || clientETag === headers['Etag']) &&
        (!clientMTime || clientMTime >= mtime)) {
        // 304 response should not contain entity headers
        ['Content-Encoding',
         'Content-Language',
         'Content-Length',
         'Content-Location',
         'Content-MD5',
         'Content-Range',
         'Content-Type',
         'Expires',
         'Last-Modified'].forEach(function(entityHeader) {
            delete headers[entityHeader];
        });
        Statique.sendRes(res, 304, contentType, null, headers);
        res.end();
        return Statique;
    }

    // Set cache-control  header
    headers["cache-control"] = "max-age=" + Statique._cache;

    // file should cached
    Statique.sendRes(res, 200, contentType, null, headers)

    var fileStream = Fs.createReadStream(fileName);
    fileStream.pipe(res);

    return Statique;
};
<commit_msg>Minor changes<commit_after>// Dependencies
var Url = require ("url")
  , Fs  = require ("fs")
  , Path = require("path")
  , Events = require("events")
  ;

// MIME types
const MIME_TYPES = {
    "html": "text/html"
  , "jpeg": "image/jpeg"
  , "jpg":  "image/jpeg"
  , "png":  "image/png"
  , "js":   "text/javascript"
  , "css":  "text/css"
};

/**
 * Le Statique
 * -----------
 * A node-static minimalist alternative.
 * Licensed under the MIT license. See the LICENSE file.
 *
 * Documentation can be found in README and on GitHub:
 * http://github.com/IonicaBizau/node-statique
 */
var Statique = module.exports = {};

/**
 * Sets the root of the public folder.
 *
 * @param {Object} options an object containing the following fields:
 *  - root: string representing the absolute path to the public folder.
 *  - cache: the number of seconds of cache
 * @return {Object} Statique object
 */
Statique.server = function (options) {
    if (typeof options === "string") {
        options = {
            root: options
        }
    }
    if (options.root.slice (-1) !== "/") {
        options.root += "/";
    }

    Statique._root = options.root;
    Statique._cache = options.cache || 3600;

    return Statique;
};

/**
 * Sets the routes of the website.
 *
 * @param {Object} routes an object containing fields and values in the
 * following format:
 *  {
 *      "/":       "/html/index.html"
 *    , "/foo/":   { url: "/html/foo.html" }
 *    , "/another-foo": "/html/myfoo.html"
 *    , "/some/api": function (req, res) {
 *          res.end("Hello World!");
 *      }
 *  }
 *
 *  See test file for more examples.
 * @return {Object} Statique object
 */
Statique.setRoutes = function (routes) {
    Statique._routes = routes;
    return Statique;
};

/**
 * Gets the route by providing an @url
 *
 * @param {String} url a string representing the url of the page that
 * must be served
 * @return {Object} the route object that contains the following fields:
 *  - url
 *  - handler
 */
Statique.getRoute = function (url) {

    var route = {};

    // remove slash at the end of the string
    if (url.slice (-1) === "/") {
        url = url.substring (0, url.length - 1);
    }

    // get the route that was set in the configuration
    var routeObj = Statique._routes[url] || Statique._routes[url + "/"] || null;
    route.url = (routeObj || {}).url || routeObj;
    route.reqUrl = route.url || url;

    // handle url as function
    if (typeof route.url === "function") {
        route.handler = route.url;
        delete route.url;
    }

    if (routeObj && typeof routeObj.handler === "function") {
        routeObj.handler = routeObj.handler;
    }

    return route;
};

/**
 * Checks if a route exists.
 *
 * @param {Object} req the request object
 * @return {Boolean} true, if the route was found, else false
 */
Statique.exists = function (req) {
    return Boolean (Statique.getRoute(Url.parse(req.url).pathname));
};

/**
 * Reads the file and callbacks the content.
 *
 * @param {String} file the relative path to the file
 * @param {Function} callback the callback function that will be called with an
 * err (first argument) and the content of the file (second argument)
 * @return {Buffer} the raw buffer
 */
Statique.readFile = function (file, callback) {
    return Fs.readFile (Statique._root + file, function (err, buffer) {
        if (err) { return callback (err); }
        callback (null, buffer.toString())
    });
};

/**
 * Serves the HTML file according by providing the @req and @res parameters
 *
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @return {Object} the Statique instance
 */
Statique.serve = function (req, res) {
    return Statique.serveRoute(undefined, req, res);
};

/**
 * This function is used for sending custom status messages and content
 * If the @content parameter is not provided or is not a string, the response
 * will not be ended. The status code and the headers will be set
 *
 * @param {Object} res the response object
 * @param {Number} statusCode the response status code
 * @param {String} mimeType the response mime type
 * @param {String} content the content that you want to send via response
 * @param {Object} otherHeaders Aditional headers that will be merged with
 * the basic ones. They have greater priority than basic headers.
 * @return {Object} the Statique instance
 */
Statique.sendRes = function (res, statusCode, mimeType, content, otherHeaders) {

    var headers = {
        "Content-Type": mimeType || "plain/text"
      , "Server": "Statique Server"
    };

    for (var h in otherHeaders) {
        headers[h] = otherHeaders[h] || headers[h];
    }

    res.writeHead(statusCode, headers);

    if (typeof content === "string") {
        res.end (content);
    }

    return Statique;
};

/**
 * serveRoute
 * Serves a provided route.
 *
 * @name serveRoute
 * @function
 * @param {String} route The route that should be served
 * @param {Object} req The request object
 * @param {Object} res The response object
 * @return {Object} The Statique instance
 */
Statique.serveRoute = function (route, req, res) {

    var parsedUrl = Url.parse (req.url)
      , routeToServe = Statique.getRoute(
            route || parsedUrl.pathname
        ) || parsedUrl.pathname
      , stats = null
      , fileName = Statique._root + (routeToServe.url || routeToServe.reqUrl)
      , method = req.method.toLowerCase()
      , form = {
            data: ""
          , error: ""
          , _emitter: new Events.EventEmitter()
        }
      ;

    req.on("data", function (chunk) {
        form.data += chunk;
    });

    req.on("error", function (err) {
        form.error += err;
    });

    req.on("end", function () {
        form._emitter.emit("done", form);
    });

    if (routeToServe.url && typeof routeToServe.url[method] === "function") {
        routeToServe.url[method](req, res, form._emitter);
        return Statique;
    }

    if (typeof routeToServe.handler === "function") {
        routeToServe.handler(req, res, form._emitter);
        return Statique;
    }

    try {
        stats = Fs.lstatSync (fileName);
    } catch (e) {
        Statique.sendRes (res, 404, "html", "404 - Not found");
        return Statique;
    }

    // no file, no fun
    if (!stats.isFile()) { return Statique; }

    // cache stuff
    var mtime = Date.parse(stats.mtime)
      , clientETag = req.headers['if-none-match']
      , clientMTime = Date.parse(req.headers['if-modified-since'])
      , contentType = MIME_TYPES[
            Path.extname(routeToServe.reqUrl).substring(1)
        ]
      , headers = {
            "Etag": JSON.stringify([stats.ino, stats.size, mtime].join('-'))
          , "Date": (new Date()).toUTCString()
          , "Last-Modified": (new Date(stats.mtime)).toUTCString()
          , "Content-Type": contentType
          , "Content-Length": stats.size
        }
      ;

    // file is cached
    if ((clientMTime  || clientETag) &&
        (!clientETag  || clientETag === headers['Etag']) &&
        (!clientMTime || clientMTime >= mtime)) {
        // 304 response should not contain entity headers
        ['Content-Encoding',
         'Content-Language',
         'Content-Length',
         'Content-Location',
         'Content-MD5',
         'Content-Range',
         'Content-Type',
         'Expires',
         'Last-Modified'].forEach(function(entityHeader) {
            delete headers[entityHeader];
        });
        Statique.sendRes(res, 304, contentType, null, headers);
        res.end();
        return Statique;
    }

    // Set cache-control  header
    headers["cache-control"] = "max-age=" + Statique._cache;

    // file should cached
    Statique.sendRes(res, 200, contentType, null, headers)

    var fileStream = Fs.createReadStream(fileName);
    fileStream.pipe(res);

    return Statique;
};
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash')
const chrono = require('chrono-node')
const humanname = require('humanname')
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance()

let parseData = function (data, regex) {
	let result = data
	if (regex) {
		try {
			let rgx = regex
			if (_.isString(regex)) {
				rgx = new RegExp(regex, 'gim')
			}
			result = data.match(rgx)[0]
		} catch (error) {
			// console.log("Regex error: ", error);
		}
	}

	return result
}

let filterData = function (data, filter) {
	let result = data
	if (["raw"].includes(filter)) {
		// let the raw data
	} else if (["trim"].includes(filter)) {
		result = result.trim()
	} else if (["lowercase", "lcase"].includes(filter)) {
		result = result.toLowerCase()
	} else if (["uppercase", "ucase"].includes(filter)) {
		result = result.toUpperCase()
	} else if (["capitalize", "cap"].includes(filter)) {
		result = _.startCase(result)
	} else if (["numbers"].includes(filter)) {
		result = result.replace(/\D/g, "")
	} else {
		// Default trim and set one spaces
		result = result.replace(/\s+/gm, " ").trim()
	}
	return result
}

let extractByExtractor = function (data, extractor, plural = false) {
	let result = data
	let emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gmi
	let phoneRegex = /\+?\(?\d*\)? ?\(?\d+\)?\d*([\s./-]\d{2,})+/gmi

	if (["phone", "telephone"].includes(extractor)) {
		if (plural) {
			result = data.match(phoneRegex) || data
		} else {
			result = data.match(phoneRegex) !== null ? data.match(phoneRegex)[0] : data
		}
		// let countryCode = result.match(/([A-Z])+/)[0]
		// console.log("countryCode", countryCode);
		// if (countryCode) {
		// 	try {
		// 		result = phoneUtil.parse(result, "US") // with option, the country code number
		// 	} catch (e) {
		// 		//
		// 	}
		// }
	} else if (["email", "mail", "@"].includes(extractor)) {
		if (plural) {
			result = data.match(emailRegex) || data
		} else {
			result = data.match(emailRegex) !== null ? data.match(emailRegex)[0] : data
		}
	} else if (["date", "d"].includes(extractor)) {
		result = chrono.casual.parseDate(data).toString()
	} else if (["fullName", "firstName", "lastName", "initials", "suffix", "salutation"].includes(extractor)) {
		result = humanname.parse(data)
		if ("fullName".includes(extractor)) {
			// return the object
		} else if ("firstName".includes(extractor)) {
			result = result.firstName
		} else if ("lastName".includes(extractor)) {
			result = result.lastName
		} else if ("initials".includes(extractor)) {
			result = result.initials
		} else if ("suffix".includes(extractor)) {
			result = result.suffix
		} else if ("salutation".includes(extractor)) {
			result = result.salutation
		}
	}

	return result
}

let getPropertyFromObj = function (obj, propertyName) {
	let properties = {
		'selector': ['selector', '_s', '_selector'],
		'attribute': ['attr', 'attribute', '_attr', '_a'],
		'filter': ['filter', '_filter', '_f'],
		'extractor': ['extractor', '_e', 'type', '_t'], //keep temporary old types
		'data': ['data', '_d', '_data'],
		'parserr': ['parser', '_parser', '_p'],
		'group': ['_g', '_group']
	}
	let ob = this
	let res = null
	if (properties[propertyName]) {
		properties[propertyName].forEach(function (property, i) {
			if (obj[property]) {
				res = obj[property]
				return
			}
		})
	}
	return res
}

let getNodeFromSmartSelector = function (node, selector) {
	if (selector === "_parent_") {
		return node
	} else {
		return node.find(selector)
	}
}

let timeSpent = function (lastTime) {
	return new Date().getTime() - lastTime
}

String.prototype.oneSplitFromEnd = function (char) {
	let arr = this.split(char),
		res = []

	res[1] = arr[arr.length - 1]
	arr.pop()
	res[0] = arr.join(char)
	return res
}

let extractSmartSelector = function ({
	selector,
	attribute = null,
	filter = null,
	extractor = null,
	parser = null
}) {
	let res = {
		"selector": selector,
		"attribute": attribute,
		"filter": filter,
		"extractor": extractor,
		"parser": parser
	}

	if (res.selector.includes('||')) {
		res.parser = res.selector.oneSplitFromEnd('||')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('||')[0].trim()
	}

	if (res.selector.includes('|')) {
		res.filter = res.selector.oneSplitFromEnd('|')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('|')[0].trim()
	}

	if (res.selector.includes('<')) {
		res.extractor = res.selector.oneSplitFromEnd('<')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('<')[0].trim()
	}

	if (res.selector.includes('@')) {
		res.attribute = res.selector.oneSplitFromEnd('@')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('@')[0].trim()
	}

	return res
}

module.exports = function ($) {

	let getTheRightData = function (node, {
		attr = null,
		extractor = null,
		filter = null,
		parser = null,
		multiple = false
	} = {}) {

		let results = []
		let localNodes = []

		for (var index = 0; index < node.length; index++) {
			localNodes.push(node[index])
		}

		if (multiple && localNodes.length > 1) {
			// Do a looop and stuff
		} else if (localNodes.length > 1) {
			// reset to the only first child
			let tempNode = localNodes[0]
			localNodes = []
			localNodes.push(tempNode)
		}

		localNodes.forEach(function (localNode, index) {

			if (attr) {
				results[index] = $(localNode).attr(attr)
			} else if (extractor === "html") {
				results[index] = $(localNode).html()
			} else {
				results[index] = $(localNode).text()
			}

			if (extractor && extractor !== "html") {
				results[index] = extractByExtractor(results[index], extractor)
			}

			if (_.isObject(results[index])) {
				_.forOwn(results[index], function (value, key) {
					results[index][key] = filterData(results[index][key], filter)
				})
			} else {
				results[index] = filterData(results[index], filter)
			}

			if (parser) {
				results[index] = parseData(results[index], parser)
			}

		})

		if (!multiple) {
			return results[0]
		} else {
			return results
		}

	}

	// real prototype
	$.prototype.scrape = function (frame, {
		debug = false,
		timestats = false
	} = {}) {

		let output = {}
		let mainNode = $(this)

		let iterateThrough = function (obj, elem, node) {

			let gTime = new Date().getTime()

			Object.keys(obj).forEach(function (key) {

				// Security for jsonpath in "_to" > "_frame"
				if (key === "_frame" || key === "_from") {
					elem[key] = obj[key]
				} else {

					try {

						let gSelector, gAttribute, gExtractor, gData, gParser, gGroup, gFilter, gINFO

						if (_.isObject(obj[key]) && !_.isArray(obj[key])) {
							gSelector = getPropertyFromObj(obj[key], 'selector')
							gAttribute = getPropertyFromObj(obj[key], 'attribute')
							gFilter = getPropertyFromObj(obj[key], 'filter')
							gExtractor = getPropertyFromObj(obj[key], 'extractor')
							gData = getPropertyFromObj(obj[key], 'data')
							gParser = getPropertyFromObj(obj[key], 'parserr')
							gGroup = getPropertyFromObj(obj, 'group')
							// console.log("gSelector", gSelector);
							// console.log("gData", gData);

							// console.log("gParser", gParser);

							if (gSelector && gData && _.isObject(gGroup)) {

								let n = getNodeFromSmartSelector($(node), gSelector)
								iterateThrough(gData, elem, $(n))

							} else if (gSelector && _.isString(gSelector)) {

								gINFO = extractSmartSelector({
									selector: gSelector
								})

								gSelector = gINFO.selector
								gParser = gParser ? gParser : gINFO.parser
								gFilter = gFilter ? gFilter : gINFO.filter
								gAttribute = gAttribute ? gAttribute : gINFO.attribute
								gExtractor = gExtractor ? gExtractor : gINFO.extractor

								if (gData && _.isObject(gData)) {

									if (_.isArray(gData)) {

										// Check if object in array
										if (_.isObject(gData[0]) && _.size(gData[0]) > 0) {

											elem[key] = [];

											$(node).find(gSelector).each(function (i, n) {
												elem[key][i] = {};
												iterateThrough(gData[0], elem[key][i], $(n));
											});

											// If no object, taking the single string
										} else if (_.isString(gData[0])) {
											elem[key] = []

											let n = getNodeFromSmartSelector($(node), gSelector)

											if (timestats) {
												elem[key] = {}
												elem[key]['_value'] = []
												n.each(function (i, n) {
													elem[key]['_value'][i] = getTheRightData($(n), {
														extractor: gExtractor,
														filter: gFilter,
														attr: gAttribute,
														parser: gParser
													})
												});
												elem[key]['_timestat'] = timeSpent(gTime)
											} else {
												n.each(function (i, n) {
													elem[key][i] = getTheRightData($(n), {
														extractor: gExtractor,
														filter: gFilter,
														attr: gAttribute,
														parser: gParser
													})
												});
											}

										}

										// Simple data object to use parent selector as base
									} else {

										if (_.size(gData) > 0) {
											elem[key] = {};
											let n = $(node).find(gSelector).first();
											iterateThrough(gData, elem[key], $(n));
										}

									}

								} else {

									let n = getNodeFromSmartSelector($(node), gSelector)

									if (n.length > 0) {

										if (!gAttribute && n.get(0).tagName === "img") {
											gAttribute = "src"
										}

										if (timestats) {
											elem[key] = {}
											elem[key]['_value'] = getTheRightData($(n), {
												extractor: gExtractor,
												filter: gFilter,
												attr: gAttribute,
												parser: gParser
											});
											elem[key]['_timestat'] = timeSpent(gTime)
										} else {
											elem[key] = getTheRightData($(n), {
												extractor: gExtractor,
												filter: gFilter,
												attr: gAttribute,
												parser: gParser
											});
										}

									} else {
										elem[key] = null;
									}
								}
							}

							// There is no Selector but still an Object for organization
							else {
								elem[key] = {};
								iterateThrough(obj[key], elem[key], node);
							}
						} else if (_.isArray(obj[key])) {

							if (_.isString(obj[key][0])) {

								gINFO = extractSmartSelector({
									selector: obj[key][0]
								})

								gSelector = gINFO.selector
								gParser = gParser ? gParser : gINFO.parser
								gFilter = gFilter ? gFilter : gINFO.filter
								gAttribute = gAttribute ? gAttribute : gINFO.attribute
								gExtractor = gExtractor ? gExtractor : gINFO.extractor

								elem[key] = []
								let n = getNodeFromSmartSelector($(node), gSelector)

								if (timestats) {
									elem[key] = {}
									elem[key]['_value'] = []
									n.each(function (i, n) {
										elem[key]['_value'][i] = getTheRightData($(n), {
											extractor: gExtractor,
											filter: gFilter,
											attr: gAttribute,
											parser: gParser
										})
									});
									elem[key]['_timestat'] = timeSpent(gTime)
								} else {
									n.each(function (i, n) {
										elem[key][i] = getTheRightData($(n), {
											extractor: gExtractor,
											filter: gFilter,
											attr: gAttribute,
											parser: gParser
										})
									});
								}

							}
						}
						// The Parameter is a single string === selector > directly scraped
						else {

							gINFO = extractSmartSelector({
								selector: obj[key]
							})

							gSelector = gINFO.selector
							gParser = gParser ? gParser : gINFO.parser
							gFilter = gFilter ? gFilter : gINFO.filter
							gAttribute = gAttribute ? gAttribute : gINFO.attribute
							gExtractor = gExtractor ? gExtractor : gINFO.extractor

							let n = getNodeFromSmartSelector($(node), gSelector)

							if (n.length > 0) {

								if (!gAttribute && n.get(0).tagName === "img") {
									gAttribute = "src"
								}

								if (timestats) {
									elem[key] = {}
									elem[key]['_value'] = getTheRightData(n, {
										extractor: gExtractor,
										filter: gFilter,
										attr: gAttribute,
										parser: gParser
									})
									elem[key]['_timestat'] = timeSpent(gTime)
								} else {
									elem[key] = getTheRightData(n, {
										extractor: gExtractor,
										filter: gFilter,
										attr: gAttribute,
										parser: gParser
									})
								}

							} else {
								elem[key] = null
							}
						}

					} catch (error) {
						console.log(error)
					}

				}

			})
		}

		iterateThrough(frame, output, mainNode)

		return output
	};

};<commit_msg>Adding String option to output a stringified version of the object<commit_after>'use strict';

const _ = require('lodash')
const chrono = require('chrono-node')
const humanname = require('humanname')
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance()

let parseData = function (data, regex) {
	let result = data
	if (regex) {
		try {
			let rgx = regex
			if (_.isString(regex)) {
				rgx = new RegExp(regex, 'gim')
			}
			result = data.match(rgx)[0]
		} catch (error) {
			// console.log("Regex error: ", error);
		}
	}

	return result
}

let filterData = function (data, filter) {
	let result = data
	if (["raw"].includes(filter)) {
		// let the raw data
	} else if (["trim"].includes(filter)) {
		result = result.trim()
	} else if (["lowercase", "lcase"].includes(filter)) {
		result = result.toLowerCase()
	} else if (["uppercase", "ucase"].includes(filter)) {
		result = result.toUpperCase()
	} else if (["capitalize", "cap"].includes(filter)) {
		result = _.startCase(result)
	} else if (["numbers"].includes(filter)) {
		result = result.replace(/\D/g, "")
	} else {
		// Default trim and set one spaces
		result = result.replace(/\s+/gm, " ").trim()
	}
	return result
}

let extractByExtractor = function (data, extractor, plural = false) {
	let result = data
	let emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gmi
	let phoneRegex = /\+?\(?\d*\)? ?\(?\d+\)?\d*([\s./-]\d{2,})+/gmi

	if (["phone", "telephone"].includes(extractor)) {
		if (plural) {
			result = data.match(phoneRegex) || data
		} else {
			result = data.match(phoneRegex) !== null ? data.match(phoneRegex)[0] : data
		}
		// let countryCode = result.match(/([A-Z])+/)[0]
		// console.log("countryCode", countryCode);
		// if (countryCode) {
		// 	try {
		// 		result = phoneUtil.parse(result, "US") // with option, the country code number
		// 	} catch (e) {
		// 		//
		// 	}
		// }
	} else if (["email", "mail", "@"].includes(extractor)) {
		if (plural) {
			result = data.match(emailRegex) || data
		} else {
			result = data.match(emailRegex) !== null ? data.match(emailRegex)[0] : data
		}
	} else if (["date", "d"].includes(extractor)) {
		result = chrono.casual.parseDate(data).toString()
	} else if (["fullName", "firstName", "lastName", "initials", "suffix", "salutation"].includes(extractor)) {
		result = humanname.parse(data)
		if ("fullName".includes(extractor)) {
			// return the object
		} else if ("firstName".includes(extractor)) {
			result = result.firstName
		} else if ("lastName".includes(extractor)) {
			result = result.lastName
		} else if ("initials".includes(extractor)) {
			result = result.initials
		} else if ("suffix".includes(extractor)) {
			result = result.suffix
		} else if ("salutation".includes(extractor)) {
			result = result.salutation
		}
	}

	return result
}

let getPropertyFromObj = function (obj, propertyName) {
	let properties = {
		'selector': ['selector', '_s', '_selector'],
		'attribute': ['attr', 'attribute', '_attr', '_a'],
		'filter': ['filter', '_filter', '_f'],
		'extractor': ['extractor', '_e', 'type', '_t'], //keep temporary old types
		'data': ['data', '_d', '_data'],
		'parserr': ['parser', '_parser', '_p'],
		'group': ['_g', '_group']
	}
	let ob = this
	let res = null
	if (properties[propertyName]) {
		properties[propertyName].forEach(function (property, i) {
			if (obj[property]) {
				res = obj[property]
				return
			}
		})
	}
	return res
}

let getNodeFromSmartSelector = function (node, selector) {
	if (selector === "_parent_") {
		return node
	} else {
		return node.find(selector)
	}
}

let timeSpent = function (lastTime) {
	return new Date().getTime() - lastTime
}

String.prototype.oneSplitFromEnd = function (char) {
	let arr = this.split(char),
		res = []

	res[1] = arr[arr.length - 1]
	arr.pop()
	res[0] = arr.join(char)
	return res
}

let extractSmartSelector = function ({
	selector,
	attribute = null,
	filter = null,
	extractor = null,
	parser = null
}) {
	let res = {
		"selector": selector,
		"attribute": attribute,
		"filter": filter,
		"extractor": extractor,
		"parser": parser
	}

	if (res.selector.includes('||')) {
		res.parser = res.selector.oneSplitFromEnd('||')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('||')[0].trim()
	}

	if (res.selector.includes('|')) {
		res.filter = res.selector.oneSplitFromEnd('|')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('|')[0].trim()
	}

	if (res.selector.includes('<')) {
		res.extractor = res.selector.oneSplitFromEnd('<')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('<')[0].trim()
	}

	if (res.selector.includes('@')) {
		res.attribute = res.selector.oneSplitFromEnd('@')[1].trim()
		res.selector = res.selector.oneSplitFromEnd('@')[0].trim()
	}

	return res
}

module.exports = function ($) {

	let getTheRightData = function (node, {
		attr = null,
		extractor = null,
		filter = null,
		parser = null,
		multiple = false
	} = {}) {

		let results = []
		let localNodes = []

		for (var index = 0; index < node.length; index++) {
			localNodes.push(node[index])
		}

		if (multiple && localNodes.length > 1) {
			// Do a looop and stuff
		} else if (localNodes.length > 1) {
			// reset to the only first child
			let tempNode = localNodes[0]
			localNodes = []
			localNodes.push(tempNode)
		}

		localNodes.forEach(function (localNode, index) {

			if (attr) {
				results[index] = $(localNode).attr(attr)
			} else if (extractor === "html") {
				results[index] = $(localNode).html()
			} else {
				results[index] = $(localNode).text()
			}

			if (extractor && extractor !== "html") {
				results[index] = extractByExtractor(results[index], extractor)
			}

			if (_.isObject(results[index])) {
				_.forOwn(results[index], function (value, key) {
					results[index][key] = filterData(results[index][key], filter)
				})
			} else {
				results[index] = filterData(results[index], filter)
			}

			if (parser) {
				results[index] = parseData(results[index], parser)
			}

		})

		if (!multiple) {
			return results[0]
		} else {
			return results
		}

	}

	// real prototype
	$.prototype.scrape = function (frame, {
		debug = false,
		timestats = false,
		string = false
	} = {}) {

		let output = {}
		let mainNode = $(this)

		let iterateThrough = function (obj, elem, node) {

			let gTime = new Date().getTime()

			Object.keys(obj).forEach(function (key) {

				// Security for jsonpath in "_to" > "_frame"
				if (key === "_frame" || key === "_from") {
					elem[key] = obj[key]
				} else {

					try {

						let gSelector, gAttribute, gExtractor, gData, gParser, gGroup, gFilter, gINFO

						if (_.isObject(obj[key]) && !_.isArray(obj[key])) {
							gSelector = getPropertyFromObj(obj[key], 'selector')
							gAttribute = getPropertyFromObj(obj[key], 'attribute')
							gFilter = getPropertyFromObj(obj[key], 'filter')
							gExtractor = getPropertyFromObj(obj[key], 'extractor')
							gData = getPropertyFromObj(obj[key], 'data')
							gParser = getPropertyFromObj(obj[key], 'parserr')
							gGroup = getPropertyFromObj(obj, 'group')
							// console.log("gSelector", gSelector);
							// console.log("gData", gData);

							// console.log("gParser", gParser);

							if (gSelector && gData && _.isObject(gGroup)) {

								let n = getNodeFromSmartSelector($(node), gSelector)
								iterateThrough(gData, elem, $(n))

							} else if (gSelector && _.isString(gSelector)) {

								gINFO = extractSmartSelector({
									selector: gSelector
								})

								gSelector = gINFO.selector
								gParser = gParser ? gParser : gINFO.parser
								gFilter = gFilter ? gFilter : gINFO.filter
								gAttribute = gAttribute ? gAttribute : gINFO.attribute
								gExtractor = gExtractor ? gExtractor : gINFO.extractor

								if (gData && _.isObject(gData)) {

									if (_.isArray(gData)) {

										// Check if object in array
										if (_.isObject(gData[0]) && _.size(gData[0]) > 0) {

											elem[key] = [];

											$(node).find(gSelector).each(function (i, n) {
												elem[key][i] = {};
												iterateThrough(gData[0], elem[key][i], $(n));
											});

											// If no object, taking the single string
										} else if (_.isString(gData[0])) {
											elem[key] = []

											let n = getNodeFromSmartSelector($(node), gSelector)

											if (timestats) {
												elem[key] = {}
												elem[key]['_value'] = []
												n.each(function (i, n) {
													elem[key]['_value'][i] = getTheRightData($(n), {
														extractor: gExtractor,
														filter: gFilter,
														attr: gAttribute,
														parser: gParser
													})
												});
												elem[key]['_timestat'] = timeSpent(gTime)
											} else {
												n.each(function (i, n) {
													elem[key][i] = getTheRightData($(n), {
														extractor: gExtractor,
														filter: gFilter,
														attr: gAttribute,
														parser: gParser
													})
												});
											}

										}

										// Simple data object to use parent selector as base
									} else {

										if (_.size(gData) > 0) {
											elem[key] = {};
											let n = $(node).find(gSelector).first();
											iterateThrough(gData, elem[key], $(n));
										}

									}

								} else {

									let n = getNodeFromSmartSelector($(node), gSelector)

									if (n.length > 0) {

										if (!gAttribute && n.get(0).tagName === "img") {
											gAttribute = "src"
										}

										if (timestats) {
											elem[key] = {}
											elem[key]['_value'] = getTheRightData($(n), {
												extractor: gExtractor,
												filter: gFilter,
												attr: gAttribute,
												parser: gParser
											});
											elem[key]['_timestat'] = timeSpent(gTime)
										} else {
											elem[key] = getTheRightData($(n), {
												extractor: gExtractor,
												filter: gFilter,
												attr: gAttribute,
												parser: gParser
											});
										}

									} else {
										elem[key] = null;
									}
								}
							}

							// There is no Selector but still an Object for organization
							else {
								elem[key] = {};
								iterateThrough(obj[key], elem[key], node);
							}
						} else if (_.isArray(obj[key])) {

							if (_.isString(obj[key][0])) {

								gINFO = extractSmartSelector({
									selector: obj[key][0]
								})

								gSelector = gINFO.selector
								gParser = gParser ? gParser : gINFO.parser
								gFilter = gFilter ? gFilter : gINFO.filter
								gAttribute = gAttribute ? gAttribute : gINFO.attribute
								gExtractor = gExtractor ? gExtractor : gINFO.extractor

								elem[key] = []
								let n = getNodeFromSmartSelector($(node), gSelector)

								if (timestats) {
									elem[key] = {}
									elem[key]['_value'] = []
									n.each(function (i, n) {
										elem[key]['_value'][i] = getTheRightData($(n), {
											extractor: gExtractor,
											filter: gFilter,
											attr: gAttribute,
											parser: gParser
										})
									});
									elem[key]['_timestat'] = timeSpent(gTime)
								} else {
									n.each(function (i, n) {
										elem[key][i] = getTheRightData($(n), {
											extractor: gExtractor,
											filter: gFilter,
											attr: gAttribute,
											parser: gParser
										})
									});
								}

							}
						}
						// The Parameter is a single string === selector > directly scraped
						else {

							gINFO = extractSmartSelector({
								selector: obj[key]
							})

							gSelector = gINFO.selector
							gParser = gParser ? gParser : gINFO.parser
							gFilter = gFilter ? gFilter : gINFO.filter
							gAttribute = gAttribute ? gAttribute : gINFO.attribute
							gExtractor = gExtractor ? gExtractor : gINFO.extractor

							let n = getNodeFromSmartSelector($(node), gSelector)

							if (n.length > 0) {

								if (!gAttribute && n.get(0).tagName === "img") {
									gAttribute = "src"
								}

								if (timestats) {
									elem[key] = {}
									elem[key]['_value'] = getTheRightData(n, {
										extractor: gExtractor,
										filter: gFilter,
										attr: gAttribute,
										parser: gParser
									})
									elem[key]['_timestat'] = timeSpent(gTime)
								} else {
									elem[key] = getTheRightData(n, {
										extractor: gExtractor,
										filter: gFilter,
										attr: gAttribute,
										parser: gParser
									})
								}

							} else {
								elem[key] = null
							}
						}

					} catch (error) {
						console.log(error)
					}

				}

			})
		}

		iterateThrough(frame, output, mainNode)

		if(string) {
			output = JSON.stringify(output, null, 2)
		}

		return output
	};

};<|endoftext|>


<commit_before>/**
 * @todo: recursively send requests until all contacts are fetched
 *
 * @see https://developers.google.com/google-apps/contacts/v3/reference#ContactsFeed
 *
 * To API test requests:
 *
 * @see https://developers.google.com/oauthplayground/
 *
 * To format JSON nicely:
 *
 * @see http://jsonviewer.stack.hu/
 *
 * Note: The Contacts API has a hard limit to the number of results it can return at a
 * time even if you explicitly request all possible results. If the requested feed has
 * more fields than can be returned in a single response, the API truncates the feed and adds
 * a "Next" link that allows you to request the rest of the response.
 */
var EventEmitter = require('events').EventEmitter,
    _ = require('lodash'),
    qs = require('querystring'),
    util = require('util'),
    url = require('url'),
    https = require('https'),
    debug = require('debug')('google-contacts');

var GoogleContacts = function (params) {
    if (typeof params === 'string') {
        params = {token: params}
    }
    if (!params) {
        params = {};
    }

    this.contacts = [];
    this.consumerKey = params.consumerKey ? params.consumerKey : null;
    this.consumerSecret = params.consumerSecret ? params.consumerSecret : null;
    this.token = params.token ? params.token : null;
    this.refreshToken = params.refreshToken ? params.refreshToken : null;

    this.params = _.defaults(params, {thin: true});
};

GoogleContacts.prototype = {};

util.inherits(GoogleContacts, EventEmitter);

GoogleContacts.prototype._get = function (params, cb) {
    if (typeof params === 'function') {
        cb = params;
        params = {};
    }

    var req = {
        host: 'www.google.com',
        port: 443,
        path: this._buildPath(params),
        method: 'GET',
        headers: {
            'Authorization': 'OAuth ' + this.token,
            'GData-Version': 3
        }
    };

    debug(req);

    https.request(req, function (res) {
            var data = '';

            res.on('data', function (chunk) {
                debug('got ' + chunk.length + ' bytes');
                data += chunk.toString('utf-8');
            });

            res.on('error', function (err) {
                cb(err);
            });

            res.on('end', function () {
                if (res.statusCode < 200 || res.statusCode >= 300) {
                    var error = new Error('Bad client request status: ' + res.statusCode);
                    return cb(error);
                }
                try {
                    debug(data);
                    cb(null, JSON.parse(data));
                }
                catch (err) {
                    cb(err);
                }
            });
        })
        .on('error', cb)
        .end();
};

GoogleContacts.prototype.getContacts = function (cb, params) {
    var self = this;

    this._get(_.extend({type: 'contacts'}, params, this.params), receivedContacts);
    function receivedContacts(err, data) {
        if (err) return cb(err);

        var feed = _.get(data, 'feed', []);
        var entry = _.get(data, 'feed.entry', []);
        if (!entry.length) {
            return cb(null, entry);
        }

        self._saveContactsFromFeed(feed);

        var next = false;
        _.each(feed.link, function (link) {
            if (link.rel === 'next') {
                next = true;
                var path = url.parse(link.href).path;
                self._get({path: path}, receivedContacts);
            }
        });
        if (!next) {
            cb(null, self.contacts);
        }
    }
};

GoogleContacts.prototype.getContact = function (cb, params) {
    var self = this;

    if(!_.has(params, 'id')){
        return cb("No id found in params");
    }

    this._get(_.extend({type: 'contacts'}, this.params, params), receivedContact);

    function receivedContact(err, contact) {
        if (err) return cb(err);

        cb(null, contact);
    }

};

GoogleContacts.prototype._saveContactsFromFeed = function (feed) {
    var self = this;
    _.each(feed.entry, function (entry) {
        var el, url;
        if (self.params.thin) {
            url = _.get(entry, 'id.$t', '');
            el = {
                name: _.get(entry, 'title.$t'),
                email: _.get(entry, 'gd$email.0.address'), // only save first email
                phoneNumber: _.get(entry, 'gd$phoneNumber.0.uri', '').replace('tel:', ''),
                id: url.substring(_.lastIndexOf(url, '/') + 1)
            };
        } else {
            el = entry;
        }
        self.contacts.push(el);
    });
};

GoogleContacts.prototype._buildPath = function (params) {
    if (params.path) return params.path;

    params = _.extend({}, params, this.params);
    params.type = params.type || 'contacts';
    params.alt = params.alt || 'json';
    params.projection = params.projection || (params.thin ? 'thin' : 'full');
    params.email = params.email || 'default';
    params['max-results'] = params['max-results'] || 10000;

    var query = {
        alt: params.alt
    };

    if(!params.id) query['max-results'] = params['max-results'];

    if (params['updated-min'])
        query['updated-min'] = params['updated-min'];

    var path = '/m8/feeds/';
    path += params.type + '/';
    path += params.email + '/';
    path += params.projection;
    if(params.id) path +=  '/'+ params.id;
    path += '?' + qs.stringify(query);

    return path;
};

GoogleContacts.prototype.refreshAccessToken = function (refreshToken, params, cb) {
    if (typeof params === 'function') {
        cb = params;
        params = {};
    }

    var data = {
        refresh_token: refreshToken,
        client_id: this.consumerKey,
        client_secret: this.consumerSecret,
        grant_type: 'refresh_token'

    };

    var body = qs.stringify(data);

    var opts = {
        host: 'accounts.google.com',
        port: 443,
        path: '/o/oauth2/token',
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': body.length
        }
    };

    var req = https.request(opts, function (res) {
        var data = '';
        res.on('end', function () {
            if (res.statusCode < 200 || res.statusCode >= 300) {
                var error = new Error('Bad client request status: ' + res.statusCode);
                return cb(error);
            }
            try {
                data = JSON.parse(data);
                cb(null, data.access_token);
            }
            catch (err) {
                cb(err);
            }
        });

        res.on('data', function (chunk) {
            data += chunk;
        });

        res.on('error', cb);

    }).on('error', cb);

    req.write(body);
    req.end();
};

exports.GoogleContacts = GoogleContacts;
<commit_msg>Feature: getContacts should filter results if we pass params.q or params.query<commit_after>/**
 * @todo: recursively send requests until all contacts are fetched
 *
 * @see https://developers.google.com/google-apps/contacts/v3/reference#ContactsFeed
 *
 * To API test requests:
 *
 * @see https://developers.google.com/oauthplayground/
 *
 * To format JSON nicely:
 *
 * @see http://jsonviewer.stack.hu/
 *
 * Note: The Contacts API has a hard limit to the number of results it can return at a
 * time even if you explicitly request all possible results. If the requested feed has
 * more fields than can be returned in a single response, the API truncates the feed and adds
 * a "Next" link that allows you to request the rest of the response.
 */
var EventEmitter = require('events').EventEmitter,
    _ = require('lodash'),
    qs = require('querystring'),
    util = require('util'),
    url = require('url'),
    https = require('https'),
    debug = require('debug')('google-contacts');

var GoogleContacts = function (params) {
    if (typeof params === 'string') {
        params = {token: params}
    }
    if (!params) {
        params = {};
    }

    this.contacts = [];
    this.consumerKey = params.consumerKey ? params.consumerKey : null;
    this.consumerSecret = params.consumerSecret ? params.consumerSecret : null;
    this.token = params.token ? params.token : null;
    this.refreshToken = params.refreshToken ? params.refreshToken : null;

    this.params = _.defaults(params, {thin: true});
};

GoogleContacts.prototype = {};

util.inherits(GoogleContacts, EventEmitter);

GoogleContacts.prototype._get = function (params, cb) {
    if (typeof params === 'function') {
        cb = params;
        params = {};
    }

    var req = {
        host: 'www.google.com',
        port: 443,
        path: this._buildPath(params),
        method: 'GET',
        headers: {
            'Authorization': 'OAuth ' + this.token,
            'GData-Version': 3
        }
    };

    debug(req);

    https.request(req, function (res) {
            var data = '';

            res.on('data', function (chunk) {
                debug('got ' + chunk.length + ' bytes');
                data += chunk.toString('utf-8');
            });

            res.on('error', function (err) {
                cb(err);
            });

            res.on('end', function () {
                if (res.statusCode < 200 || res.statusCode >= 300) {
                    var error = new Error('Bad client request status: ' + res.statusCode);
                    return cb(error);
                }
                try {
                    debug(data);
                    cb(null, JSON.parse(data));
                }
                catch (err) {
                    cb(err);
                }
            });
        })
        .on('error', cb)
        .end();
};

GoogleContacts.prototype.getContacts = function (cb, params) {
    var self = this;

    this._get(_.extend({type: 'contacts'}, params, this.params), receivedContacts);
    function receivedContacts(err, data) {
        if (err) return cb(err);

        var feed = _.get(data, 'feed', []);
        var entry = _.get(data, 'feed.entry', []);
        if (!entry.length) {
            return cb(null, entry);
        }

        self._saveContactsFromFeed(feed);

        var next = false;
        _.each(feed.link, function (link) {
            if (link.rel === 'next') {
                next = true;
                var path = url.parse(link.href).path;
                self._get({path: path}, receivedContacts);
            }
        });
        if (!next) {
            cb(null, self.contacts);
        }
    }
};

GoogleContacts.prototype.getContact = function (cb, params) {
    var self = this;

    if(!_.has(params, 'id')){
        return cb("No id found in params");
    }

    this._get(_.extend({type: 'contacts'}, this.params, params), receivedContact);

    function receivedContact(err, contact) {
        if (err) return cb(err);

        cb(null, contact);
    }

};

GoogleContacts.prototype._saveContactsFromFeed = function (feed) {
    var self = this;
    _.each(feed.entry, function (entry) {
        var el, url;
        if (self.params.thin) {
            url = _.get(entry, 'id.$t', '');
            el = {
                name: _.get(entry, 'title.$t'),
                email: _.get(entry, 'gd$email.0.address'), // only save first email
                phoneNumber: _.get(entry, 'gd$phoneNumber.0.uri', '').replace('tel:', ''),
                id: url.substring(_.lastIndexOf(url, '/') + 1)
            };
        } else {
            el = entry;
        }
        self.contacts.push(el);
    });
};

GoogleContacts.prototype._buildPath = function (params) {
    if (params.path) return params.path;

    params = _.extend({}, params, this.params);
    params.type = params.type || 'contacts';
    params.alt = params.alt || 'json';
    params.projection = params.projection || (params.thin ? 'thin' : 'full');
    params.email = params.email || 'default';
    params['max-results'] = params['max-results'] || 10000;

    var query = {
        alt: params.alt
    };

    if(!params.id) query['max-results'] = params['max-results'];

    if (params['updated-min'])
        query['updated-min'] = params['updated-min'];

    if (params.q || params.query)
        query.q = params.q || params.query;

    var path = '/m8/feeds/';
    path += params.type + '/';
    path += params.email + '/';
    path += params.projection;
    if(params.id) path +=  '/'+ params.id;
    path += '?' + qs.stringify(query);

    return path;
};

GoogleContacts.prototype.refreshAccessToken = function (refreshToken, params, cb) {
    if (typeof params === 'function') {
        cb = params;
        params = {};
    }

    var data = {
        refresh_token: refreshToken,
        client_id: this.consumerKey,
        client_secret: this.consumerSecret,
        grant_type: 'refresh_token'

    };

    var body = qs.stringify(data);

    var opts = {
        host: 'accounts.google.com',
        port: 443,
        path: '/o/oauth2/token',
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': body.length
        }
    };

    var req = https.request(opts, function (res) {
        var data = '';
        res.on('end', function () {
            if (res.statusCode < 200 || res.statusCode >= 300) {
                var error = new Error('Bad client request status: ' + res.statusCode);
                return cb(error);
            }
            try {
                data = JSON.parse(data);
                cb(null, data.access_token);
            }
            catch (err) {
                cb(err);
            }
        });

        res.on('data', function (chunk) {
            data += chunk;
        });

        res.on('error', cb);

    }).on('error', cb);

    req.write(body);
    req.end();
};

exports.GoogleContacts = GoogleContacts;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {
  NativeModules,
  Platform,
  StyleSheet,
  requireNativeComponent,
  View,
} from 'react-native';

const CameraManager = NativeModules.ALPRCameraManager;
const CAMERA_REF = 'camera';

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  // delete this prop because we are going to replace it with our own
  delete newProps.onPlateRecognized;
  return newProps;
}

export default class Camera extends Component {

  static constants = {
    Aspect: CameraManager.Aspect,
    CaptureQuality: CameraManager.CaptureQuality,
    TorchMode: CameraManager.TorchMode
  };

  static propTypes = {
    ...View.propTypes,
    aspect: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureQuality: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    country: PropTypes.string,
    onPlateRecognized: PropTypes.func,
    plateOutlineColor: PropTypes.string,
    showPlateOutline: PropTypes.bool,
    torchMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    touchToFocus: PropTypes.bool,
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    captureQuality: CameraManager.CaptureQuality.medium,
    country: 'us',
    plateOutlineColor: '#0028ff',
    showPlateOutline: true,
    torchMode: CameraManager.TorchMode.off,
    touchToFocus: true,
  };

  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;

  setNativeProps(props) {
    this.refs[CAMERA_REF].setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false
    };
  }

  onPlateRecognized = (event) => {
      if(this.props.onPlateRecognized) {
        this.props.onPlateRecognized(event.nativeEvent);
      }
  }

  async componentWillMount() {
    let check = Camera.checkVideoAuthorizationStatus;

    if (check) {
      const isAuthorized = await check();
      this.setState({ isAuthorized });
    }
  }

  render() {
    const nativeProps = convertNativeProps(this.props);

    return <ALPRCamera ref={CAMERA_REF} onPlateRecognized={this.onPlateRecognized} {...nativeProps} />;
  }

}

export const constants = Camera.constants;

const ALPRCamera = requireNativeComponent(
  'ALPRCamera',
   Camera,
   {
     nativeOnly: {
       'rotateMode': true,
       'mounted': true
     }
   }
);
<commit_msg>Use prop-types from separate package<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
  NativeModules,
  Platform,
  StyleSheet,
  requireNativeComponent,
  View,
} from 'react-native';

const CameraManager = NativeModules.ALPRCameraManager;
const CAMERA_REF = 'camera';

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  // delete this prop because we are going to replace it with our own
  delete newProps.onPlateRecognized;
  return newProps;
}

export default class Camera extends Component {

  static constants = {
    Aspect: CameraManager.Aspect,
    CaptureQuality: CameraManager.CaptureQuality,
    TorchMode: CameraManager.TorchMode
  };

  static propTypes = {
    ...View.propTypes,
    aspect: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    captureQuality: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    country: PropTypes.string,
    onPlateRecognized: PropTypes.func,
    plateOutlineColor: PropTypes.string,
    showPlateOutline: PropTypes.bool,
    torchMode: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number
    ]),
    touchToFocus: PropTypes.bool,
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    captureQuality: CameraManager.CaptureQuality.medium,
    country: 'us',
    plateOutlineColor: '#0028ff',
    showPlateOutline: true,
    torchMode: CameraManager.TorchMode.off,
    touchToFocus: true,
  };

  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;

  setNativeProps(props) {
    this.refs[CAMERA_REF].setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false
    };
  }

  onPlateRecognized = (event) => {
    if (this.props.onPlateRecognized) {
      this.props.onPlateRecognized(event.nativeEvent);
    }
  }

  async componentWillMount() {
    let check = Camera.checkVideoAuthorizationStatus;

    if (check) {
      const isAuthorized = await check();
      this.setState({ isAuthorized });
    }
  }

  render() {
    const nativeProps = convertNativeProps(this.props);

    return <ALPRCamera ref={CAMERA_REF} onPlateRecognized={this.onPlateRecognized} {...nativeProps} />;
  }

}

export const constants = Camera.constants;

const ALPRCamera = requireNativeComponent(
  'ALPRCamera',
  Camera,
  {
    nativeOnly: {
      'rotateMode': true,
      'mounted': true
    }
  }
);
<|endoftext|>


<commit_before>var events = require('events');
var wormhole = function (socket) {
	events.EventEmitter.call(this);
	this.isWormhole = null;
	this.setupListeners();
	this.setSocket(socket);

	this._availablerpc = {};
	this.rpc = {};

	this.__hashes__ = [];

	this.__hash__ = "";
};
wormhole.prototype.__proto__ = events.EventEmitter.prototype;
wormhole.prototype.setSocket = function(socket) {
	this.socket && this.socket.removeAllListeners();
	this.socket = socket;
	this.setupSocketListeners();
};
wormhole.prototype.isWormhole = function(cb) {
	if (this.isWormhole === null) {
		this.socket.emit("isWormhole", function (err, isWormhole) {
			if (!err) {
				this.isWormhole = isWormhole;
			} else {
				this.isWormhole = !!isWormhole;
			}
		});
	} else {
		cb(null, isWormhole);
	}
};
wormhole.prototype.setupListeners = function() {
	var self = this;
	this.on("outofsync", self.syncFunctions);
	this.on("newListener", function (event, func) {
		if (event != "removeListener" && event != "newListener") {
			// Oh, this is an RPC, Add the fucker!
			self.addFunction(event, func);
		}
	});
};
wormhole.prototype.setupSocketListeners = function() {
	var self = this;
	//Original func
	this.socket.on("isWormhole", function (cb) {
		cb(null, true);
		self.syncFunctions();
	});
	this.socket.on("disconnect", function () {
		self.removeAllListeners();
	});
	this.socket.on("rpc", function (data) {
		if (data.__hash__ != self.__hash__) {
			self.emit("outofsync", data.__hash__);
		}
	});
};
wormhole.prototype.addFunction = function(func, cb) {
	this._availablerpc[func] = cb;
	var str = Object.keys(this._availablerpc).join("");
	// Simple RPC versioning.
	this.__hash__ = new Buffer(str).toString('base64');
	this.__hashes__.push({hash: this.__hash__, name: func});
};
wormhole.prototype.syncFunctions = function(oldhash) {
	if (oldhash) {
		var changes = this.__changes__(oldhash);
		this.socket.emit("functions", changes);
	} else {
		this.socket.emit("functions", Object.keys(this._availablerpc));
	}
};
wormhole.prototype.addClientFunction = function(func) {
	var self = this;
	this.rpc[func] = function () {
		var args = ["rpc", func].concat([].slice.call(arguments));
		self.socket.emit.apply(self, args);
	};
};
wormhole.prototype.__changes__ = function(hash) {
	var out = [];
	var keys = Object.keys(this.__hashes__);
	for (var i = keys.length; i >= 0; i--) {
		// Reverse traverse, most likely they'll have a more-or-less up to date stash.
		if (keys[i].hash === hash) {
			out.push(keys[i].name)
			break;
		}
	}
	return out;
};
module.exports = wormhole;<commit_msg>woops<commit_after>var events = require('events');
var wormhole = function (socket) {
	events.EventEmitter.call(this);
	this.isWormhole = null;
	this.setupListeners();
	this.setSocket(socket);

	this._availablerpc = {};
	this.rpc = {};

	this.__hashes__ = [];

	this.__hash__ = "";
};
wormhole.prototype.__proto__ = events.EventEmitter.prototype;
wormhole.prototype.setSocket = function(socket) {
	this.socket && this.socket.removeAllListeners();
	this.socket = socket;
	this.setupSocketListeners();
};
wormhole.prototype.isWormhole = function(cb) {
	if (this.isWormhole === null) {
		this.socket.emit("isWormhole", function (err, isWormhole) {
			if (!err) {
				this.isWormhole = isWormhole;
			} else {
				this.isWormhole = !!isWormhole;
			}
		});
	} else {
		cb(null, isWormhole);
	}
};
wormhole.prototype.setupListeners = function() {
	var self = this;
	this.on("outofsync", self.syncFunctions);
	this.on("newListener", function (event, func) {
		if (event != "removeListener" && event != "newListener") {
			// Oh, this is an RPC, Add the fucker!
			self.addFunction(event, func);
		}
	});
};
wormhole.prototype.setupSocketListeners = function() {
	var self = this;
	//Original func
	this.socket.on("isWormhole", function (cb) {
		cb(null, true);
		self.syncFunctions();
	});
	this.socket.on("disconnect", function () {
		self.removeAllListeners();
	});
	this.socket.on("rpc", function (data) {
		if (data.__hash__ != self.__hash__) {
			self.emit("outofsync", data.__hash__);
		}
	});
};
wormhole.prototype.addFunction = function(func, cb) {
	this._availablerpc[func] = cb;
	var str = Object.keys(this._availablerpc).join("");
	// Simple RPC versioning.
	this.__hash__ = new Buffer(str).toString('base64');
	this.__hashes__.push({hash: this.__hash__, name: func});
};
wormhole.prototype.syncFunctions = function(oldhash) {
	if (oldhash) {
		var changes = this.__changes__(oldhash);
		this.socket.emit("functions", changes);
	} else {
		this.socket.emit("functions", Object.keys(this._availablerpc));
	}
};
wormhole.prototype.addClientFunction = function(func) {
	var self = this;
	this.rpc[func] = function () {
		var args = ["rpc", func].concat([].slice.call(arguments));
		self.socket.emit.apply(self, args);
	};
};
wormhole.prototype.__changes__ = function(hash) {
	var out = [];
	var keys = Object.keys(this.__hashes__);
	for (var i = keys.length; i >= 0; i--) {
		// Reverse traverse, most likely they'll have a more-or-less up to date stash.
		if (keys[i].hash === hash) {
			break;
		}
		out.push(keys[i].name);
	}
	return out;
};
module.exports = wormhole;<|endoftext|>