<commit_before>//var program = process.argv[2];

var converter = new Showdown.converter();

var imports = [];

function binaryNumOp(args, env, f){
	var arg1 = parseFloat(executeExpression(args[0], env));
	var arg2 = parseFloat(executeExpression(args[1], env));
	return f(arg1, arg2);
}

var ops = {
	'-' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total -=  parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'+' : function(args, env){
		    var total = 0;
			for(var i in args){
				total +=  parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'pageName' : function(args, env){
			return pageName;
		},
	'=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a == b});
		},
	'<' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a < b});
		},
	'<=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a <= b});
		},
	'>' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a > b});
		},
	'>=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a >= b});
		},
	'length' : function(args, env){
		    return executeExpression(args[0], env).content.length;
		},
	'dotPath' : function(args, env){
			var dotPath = executeExpression(args[0], env)
			var json = executeExpression(args[1], env)
		    return json[dotPath];
		},
	'subseq' : function(args, env){
			var start = executeExpression(args[0], env);

			if(args.length == 2){
				var list = executeExpression(args[1], env);
				return list.slice(start);
			} else if(args.length == 3){
				var end = executeExpression(args[1], env);
				var list = executeExpression(args[2], env).content;
				return new List(list.slice(start, end));
			}
		},
	'nth' : function(args, env){
			var pos = executeExpression(args[0], env);
		    var list = executeExpression(args[1], env).content;

		    return list[pos];
		},
	'list' : function(args, env){
		    var list = [];
			for(var i in args){
				list.push(executeExpression(args[i], env));
			}
			return new List(list);
		},
	'sort' : function(args, env){
		    var list = executeExpression(args[0], env).content.slice();
		    var sortFn = executeExpression(args[1], env);

			var sort = function(a, b){
				var result = parseInt(sortFn(new Array(a, b), env));
				return result;
			}

			var sortedContent = list.sort(sort);
			var sortedList = new List(sortedContent);

			return sortedList;
		},
	'begin' : function(args, env){
			for(var i=0;i<args.length-1;i++){
				executeExpression(args[i], env);
			}
			return executeExpression(args[args.length-1], env);
		},
	'if' : function(args, env){
			var bool = executeExpression(args[0], env);

			var ret;
			if(bool == true){
				ret = executeExpression(args[1], env);
			} else {
				ret = executeExpression(args[2], env);
			}
			return ret;
		},
	'json' : function(args, env){
			var url = executeExpression(args[0], env);
			var fn = executeExpression(args[1], env);
			$.ajax({
			        async: true,
			        type: "GET",
			        contentType: "application/json; charset=utf-8",
			        dataType: "json",
			        url: url,
			        success: function(jsonData) {
			            fn(new Array(jsonData), env);
			        },
			        error: function(){
			        	//
			        }
			    });

		},
	'import' : function(args, env){
		    var str = "";
			for(var i in args){
				var importedPage = executeExpression(args[i], env);
				var url = './'+importedPage+'/code';

				if(url in imports){
					str += imports[url];
				} else {
					var jsonStringData;

					$.ajax({
				        async: false,
				        type: "GET",
				        contentType: "application/json; charset=utf-8",
				        dataType: "json",
				        url: url,
				        success: function(jsonData) {
				            jsonStringData = jsonData.data;
				        },
				        error: function(){
				        	jsonStringData = null;
				        }
				    });
					str += jsonStringData;
				}
			}

			if(jsonStringData){
				var newEnv = clone(env);
				newEnv.overrides = true;

				evalLispWithEnv(str, newEnv);
			}

			return null;
		},
	'concat' : function(args, env){
		    var str = "";
			for(i in args){
				str += executeExpression(args[i], env);
			}
			return str;
		},
	'defun' : function(args, env){
			var fnName = args.shift();

			if(! (env.overrides && (fnName in ops))){
				var fnArgs = args.shift();
				var fnBody = args.shift();
				var fn = function(params, env){
					for(var i in fnArgs){
						var arg = fnArgs[i];
						var value = executeExpression(params[i], env);
						env[arg] = value;
					}
					return executeExpression(fnBody.slice(), env);
				}
			    ops[fnName] = fn;
			}
		},
	'markdown' : function(args, env){
			return converter.makeHtml(ops['concat'](args, env));
		},
	'print' : function(args, env){
			if(args.length == 1){
				env.out(null, executeExpression(args[0], env));
			} else if(args.length == 2){
				env.out(
					executeExpression(args[0], env),
					executeExpression(args[1], env));
			}
		}
}

function Lambda(args, env){
	var fnArgs = args.shift();
	var fnBody = args.shift();
	return function(params, env){
		for(var i in fnArgs){
			var arg = fnArgs[i];
			var value = executeExpression(params[i], env);
			env[arg] = value;
		}
		return executeExpression(fnBody.slice(), env);
	}
}

function List(content) {
    this.content = content;
}

var trim = String.prototype.trim || function(){
	return (this + '').replace(/^\s+|\s+$/g, '');
};

function isBlank(str) {
    return (!str || /^\s*$/.test(str));
}

function evalLisp(program, callback){
	var env = {out:callback};
	return evalLispWithEnv(program, env);
}

function evalLispWithEnv(program, env){
	return execute(parseExpressions(program), env);
}

function execute(expressions, env){
	for(var i in expressions){
		env.out(null, executeExpression(expressions[i], env));
	}
}

function clone(obj){
	return jQuery.extend(true, {}, obj);
}

function executeExpression(stack, env){
	env = clone(env);
	if (stack instanceof List){
		return stack;
	}

	if (!Array.isArray(stack)){
		if(stack in env){
			return env[stack];
		} else {
			if(stack == 'Nil'){
				return null;
			} else {
				 return stack;
			}
		}
	}

	stack = stack.slice();
	if(env == null){
		throw new Error("Environment is NULL.");
	}

	var fn = null;
	var args = [];
	var operator = executeExpression(stack.shift(),env);

	if(operator == 'lambda'){
		return new Lambda(stack, env);
	}

	var fn;
	if (typeof(operator) == "function"){
		fn = operator;
	} else {
		fn = ops[operator];
	}

	if(env[operator]){
		fn = env[operator];
	}

	if(!fn){
		return function(f, env){
			return f(stack, env);
		}
	}

	for(var i=0;i<stack.length;i++){
		var arg = stack[i];
		if(arg in env){
			arg = env[arg];
		}
		args.push(arg);
	}

	return fn(args, env);
}

function getArgName(arg){
	if(arg.indexOf('.') === -1){
		return arg;
	} else {
		return arg.substr(0, arg.indexOf('.'));
	}
}

function parseExpressions(text){
	text = trim.call(text);

	var token = text.charAt(0);

	if (token != '(') {
		//throw new Error('unexepected token: ' + token);
	}

	var inQuotes = false;

	var stack = [];
	var parens = 0;
	var expression = "";

	while(text.length > 0){
		var token = text.charAt(0);
		text = text.substring(1);

		if (token == '"') {
			inQuotes = !inQuotes;
		}

		if(!inQuotes){
			if (token == '(') {
				parens++;
			} else if (token == ')'){
				parens--;
			}
		}

		expression += token;

		if (parens == '0'){
			if(!isBlank(expression)){
				stack.push(parseExpression(expression));
			}
			expression = "";
		}

	}

	return stack;
}

function parseExpression(text){
	text = trim.call(text);

	if (text.charAt(0) != '(') return text;

	var stack = [];
	var token;
	var tokens = '';
	var comment = false;
	var i = 0;
	var expr;

	while (i < text.length){
		token = text.charAt(i++);

		if (comment & token != '"'){
			tokens += token;
			continue;
		}

		if (token == '(' || token == ')' || (token == ' ' && !comment)){
			if (expr && tokens.length){
				var n = +tokens;
				var stripped = tokens.replace(/^\"|\"$/g, "");
				expr.push(isNaN(n) ? stripped : n);
			}
			tokens = '';
		} else {
			if (token == '"') comment = !comment;
			if (!/\s/.test(token) || comment) tokens += token;
		}

		if (token == '('){

			var previous = expr;
			expr = [];

			if (previous){
				// push the previous expresion to the stack
				stack.push(previous);
				// if expr is not top-level, append the expression
				previous.push(expr);
			}

		} else if (token == ')'){

			// pop one from stack
			var pop = stack.pop();
			// stack is empty, so expr is the top-level expression
			if (!pop) return expr;
			expr = pop;

		}

	}

	//throw new Error('unbalanced parentheses');

};

//execute(parseExpressions(program));<commit_msg>Adjusted import caching.<commit_after>//var program = process.argv[2];

var converter = new Showdown.converter();

var imports = {};

function binaryNumOp(args, env, f){
	var arg1 = parseFloat(executeExpression(args[0], env));
	var arg2 = parseFloat(executeExpression(args[1], env));
	return f(arg1, arg2);
}

var ops = {
	'-' : function(args, env){
		    var total = parseInt(executeExpression(args[0], env));
			for(var i=1;i<args.length;i++){
				total -=  parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'+' : function(args, env){
		    var total = 0;
			for(var i in args){
				total +=  parseInt(executeExpression(args[i], env));
			}
			return total;
		},
	'pageName' : function(args, env){
			return pageName;
		},
	'=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a == b});
		},
	'<' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a < b});
		},
	'<=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a <= b});
		},
	'>' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a > b});
		},
	'>=' : function(args, env){
			return binaryNumOp(args, env, function(a,b){return a >= b});
		},
	'length' : function(args, env){
		    return executeExpression(args[0], env).content.length;
		},
	'dotPath' : function(args, env){
			var dotPath = executeExpression(args[0], env)
			var json = executeExpression(args[1], env)
		    return json[dotPath];
		},
	'subseq' : function(args, env){
			var start = executeExpression(args[0], env);

			if(args.length == 2){
				var list = executeExpression(args[1], env);
				return list.slice(start);
			} else if(args.length == 3){
				var end = executeExpression(args[1], env);
				var list = executeExpression(args[2], env).content;
				return new List(list.slice(start, end));
			}
		},
	'nth' : function(args, env){
			var pos = executeExpression(args[0], env);
		    var list = executeExpression(args[1], env).content;

		    return list[pos];
		},
	'list' : function(args, env){
		    var list = [];
			for(var i in args){
				list.push(executeExpression(args[i], env));
			}
			return new List(list);
		},
	'sort' : function(args, env){
		    var list = executeExpression(args[0], env).content.slice();
		    var sortFn = executeExpression(args[1], env);

			var sort = function(a, b){
				var result = parseInt(sortFn(new Array(a, b), env));
				return result;
			}

			var sortedContent = list.sort(sort);
			var sortedList = new List(sortedContent);

			return sortedList;
		},
	'begin' : function(args, env){
			for(var i=0;i<args.length-1;i++){
				executeExpression(args[i], env);
			}
			return executeExpression(args[args.length-1], env);
		},
	'if' : function(args, env){
			var bool = executeExpression(args[0], env);

			var ret;
			if(bool == true){
				ret = executeExpression(args[1], env);
			} else {
				ret = executeExpression(args[2], env);
			}
			return ret;
		},
	'json' : function(args, env){
			var url = executeExpression(args[0], env);
			var fn = executeExpression(args[1], env);
			$.ajax({
			        async: true,
			        type: "GET",
			        contentType: "application/json; charset=utf-8",
			        dataType: "json",
			        url: url,
			        success: function(jsonData) {
			            fn(new Array(jsonData), env);
			        },
			        error: function(){
			        	//
			        }
			    });

		},
	'import' : function(args, env){
		    var str = "";
			for(var i in args){
				var importedPage = executeExpression(args[i], env);
				var url = './'+importedPage+'/code';

				if(url in imports){
					str += imports[url];
				} else {
					var jsonStringData;

					$.ajax({
				        async: false,
				        type: "GET",
				        contentType: "application/json; charset=utf-8",
				        dataType: "json",
				        url: url,
				        success: function(jsonData) {
				            jsonStringData = jsonData.data;
				        },
				        error: function(){
				        	jsonStringData = null;
				        }
				    });
				    imports[url] = jsonStringData;
					str += jsonStringData;
				}
			}

			if(jsonStringData){
				var newEnv = clone(env);
				newEnv.overrides = true;

				evalLispWithEnv(str, newEnv);
			}

			return null;
		},
	'concat' : function(args, env){
		    var str = "";
			for(i in args){
				str += executeExpression(args[i], env);
			}
			return str;
		},
	'defun' : function(args, env){
			var fnName = args.shift();

			if(! (env.overrides && (fnName in ops))){
				var fnArgs = args.shift();
				var fnBody = args.shift();
				var fn = function(params, env){
					for(var i in fnArgs){
						var arg = fnArgs[i];
						var value = executeExpression(params[i], env);
						env[arg] = value;
					}
					return executeExpression(fnBody.slice(), env);
				}
			    ops[fnName] = fn;
			}
		},
	'markdown' : function(args, env){
			return converter.makeHtml(ops['concat'](args, env));
		},
	'print' : function(args, env){
			if(args.length == 1){
				env.out(null, executeExpression(args[0], env));
			} else if(args.length == 2){
				env.out(
					executeExpression(args[0], env),
					executeExpression(args[1], env));
			}
		}
}

function Lambda(args, env){
	var fnArgs = args.shift();
	var fnBody = args.shift();
	return function(params, env){
		for(var i in fnArgs){
			var arg = fnArgs[i];
			var value = executeExpression(params[i], env);
			env[arg] = value;
		}
		return executeExpression(fnBody.slice(), env);
	}
}

function List(content) {
    this.content = content;
}

var trim = String.prototype.trim || function(){
	return (this + '').replace(/^\s+|\s+$/g, '');
};

function isBlank(str) {
    return (!str || /^\s*$/.test(str));
}

function evalLisp(program, callback){
	var env = {out:callback};
	return evalLispWithEnv(program, env);
}

function evalLispWithEnv(program, env){
	return execute(parseExpressions(program), env);
}

function execute(expressions, env){
	for(var i in expressions){
		env.out(null, executeExpression(expressions[i], env));
	}
}

function clone(obj){
	return jQuery.extend(true, {}, obj);
}

function executeExpression(stack, env){
	env = clone(env);
	if (stack instanceof List){
		return stack;
	}

	if (!Array.isArray(stack)){
		if(stack in env){
			return env[stack];
		} else {
			if(stack == 'Nil'){
				return null;
			} else {
				 return stack;
			}
		}
	}

	stack = stack.slice();
	if(env == null){
		throw new Error("Environment is NULL.");
	}

	var fn = null;
	var args = [];
	var operator = executeExpression(stack.shift(),env);

	if(operator == 'lambda'){
		return new Lambda(stack, env);
	}

	var fn;
	if (typeof(operator) == "function"){
		fn = operator;
	} else {
		fn = ops[operator];
	}

	if(env[operator]){
		fn = env[operator];
	}

	if(!fn){
		return function(f, env){
			return f(stack, env);
		}
	}

	for(var i=0;i<stack.length;i++){
		var arg = stack[i];
		if(arg in env){
			arg = env[arg];
		}
		args.push(arg);
	}

	return fn(args, env);
}

function getArgName(arg){
	if(arg.indexOf('.') === -1){
		return arg;
	} else {
		return arg.substr(0, arg.indexOf('.'));
	}
}

function parseExpressions(text){
	text = trim.call(text);

	var token = text.charAt(0);

	if (token != '(') {
		//throw new Error('unexepected token: ' + token);
	}

	var inQuotes = false;

	var stack = [];
	var parens = 0;
	var expression = "";

	while(text.length > 0){
		var token = text.charAt(0);
		text = text.substring(1);

		if (token == '"') {
			inQuotes = !inQuotes;
		}

		if(!inQuotes){
			if (token == '(') {
				parens++;
			} else if (token == ')'){
				parens--;
			}
		}

		expression += token;

		if (parens == '0'){
			if(!isBlank(expression)){
				stack.push(parseExpression(expression));
			}
			expression = "";
		}

	}

	return stack;
}

function parseExpression(text){
	text = trim.call(text);

	if (text.charAt(0) != '(') return text;

	var stack = [];
	var token;
	var tokens = '';
	var comment = false;
	var i = 0;
	var expr;

	while (i < text.length){
		token = text.charAt(i++);

		if (comment & token != '"'){
			tokens += token;
			continue;
		}

		if (token == '(' || token == ')' || (token == ' ' && !comment)){
			if (expr && tokens.length){
				var n = +tokens;
				var stripped = tokens.replace(/^\"|\"$/g, "");
				expr.push(isNaN(n) ? stripped : n);
			}
			tokens = '';
		} else {
			if (token == '"') comment = !comment;
			if (!/\s/.test(token) || comment) tokens += token;
		}

		if (token == '('){

			var previous = expr;
			expr = [];

			if (previous){
				// push the previous expresion to the stack
				stack.push(previous);
				// if expr is not top-level, append the expression
				previous.push(expr);
			}

		} else if (token == ')'){

			// pop one from stack
			var pop = stack.pop();
			// stack is empty, so expr is the top-level expression
			if (!pop) return expr;
			expr = pop;

		}

	}

	//throw new Error('unbalanced parentheses');

};

//execute(parseExpressions(program));<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles, IconButton } from '@material-ui/core';
import take from 'lodash/take';
import DeleteIcon from '@material-ui/icons/Delete';
import compose from 'recompose/compose';
import { withState } from 'recompose';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';
import DeleteWarningDialog from './DeleteWarningDialog';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
});

const deleteSubmitHandler = (deleteQuestion, question, setSubmitting) => () => {
  setSubmitting(true);
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      setSubmitting(false);
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

const openDeleteWarningDialog = setDeleteWarningOpen => () => setDeleteWarningOpen(true);

const onCancelDelete = (setDeleteWarningOpen, setSubmitting) => () => {
  setSubmitting(false);
  setDeleteWarningOpen(false);
};

/**
 * @param {string} str String to truncate
 */
const truncate = str =>
  take(str.split(' '), 7)
    .join(' ')
    .concat(' [...]');

function SafeDeleteIconButton({
  classes,
  deleteWarningOpen,
  question,
  setDeleteWarningOpen,
  setSubmitting,
  submitting,
  ...otherProps
}) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            disabled={submitting}
            onClick={openDeleteWarningDialog(setDeleteWarningOpen)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
          <DeleteWarningDialog
            title={`Excluir “${truncate(question.wording)}“?`}
            content={`A questão “${truncate(question.wording)}” será apagada permanentemente.`}
            isSubmitting={submitting}
            open={deleteWarningOpen}
            onCancel={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
            onSuccess={deleteSubmitHandler(deleteQuestion, question, setSubmitting)}
          />
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  deleteWarningOpen: PropTypes.bool.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
  setDeleteWarningOpen: PropTypes.func.isRequired,
  setSubmitting: PropTypes.func.isRequired,
  submitting: PropTypes.bool.isRequired,
};

export default compose(
  withState('deleteWarningOpen', 'setDeleteWarningOpen', false),
  withState('submitting', 'setSubmitting', false),
  withStyles(styles),
)(SafeDeleteIconButton);
<commit_msg>Rename functions in SafeDeleteIconButton<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles, IconButton } from '@material-ui/core';
import take from 'lodash/take';
import DeleteIcon from '@material-ui/icons/Delete';
import compose from 'recompose/compose';
import { withState } from 'recompose';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';
import DeleteWarningDialog from './DeleteWarningDialog';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
});

const deleteHandler = (deleteQuestion, question, setSubmitting) => () => {
  setSubmitting(true);
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      setSubmitting(false);
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

const onCancelDelete = (setDeleteWarningOpen, setSubmitting) => () => {
  setSubmitting(false);
  setDeleteWarningOpen(false);
};

/**
 * @param {string} str String to truncate
 */
const truncate = str =>
  take(str.split(' '), 7)
    .join(' ')
    .concat(' [...]');

function SafeDeleteIconButton({
  classes,
  deleteWarningOpen,
  question,
  setDeleteWarningOpen,
  setSubmitting,
  submitting,
  ...otherProps
}) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            disabled={submitting}
            onClick={() => setDeleteWarningOpen(true)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
          <DeleteWarningDialog
            title={`Excluir “${truncate(question.wording)}“?`}
            content={`A questão “${truncate(question.wording)}” será apagada permanentemente.`}
            isSubmitting={submitting}
            open={deleteWarningOpen}
            onCancel={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
            onSuccess={deleteHandler(deleteQuestion, question, setSubmitting)}
          />
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  deleteWarningOpen: PropTypes.bool.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
  setDeleteWarningOpen: PropTypes.func.isRequired,
  setSubmitting: PropTypes.func.isRequired,
  submitting: PropTypes.bool.isRequired,
};

export default compose(
  withState('deleteWarningOpen', 'setDeleteWarningOpen', false),
  withState('submitting', 'setSubmitting', false),
  withStyles(styles),
)(SafeDeleteIconButton);
<|endoftext|>


<commit_before>//Import dependencies
var fs = require('fs');

//Read a JSON file
module.exports.read = function(file, opt, cb)
{
  //Parse the callback method
  var cb = (typeof opt === 'function') ? opt : cb;

  //Parse the options
  var opt = (typeof opt === 'function') ? {} : opt;

  //Check the encoding value
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'utf8'; }

  //Read the file
  return fs.readFile(file, opt, function(error, data)
  {
    //Check the error
    if(error){ return cb(error, null); }

    //Output json object
    var obj = null;

    //Convert the data to json
    try
    {
      //Convert to a json object
      obj = JSON.parse(data);
    }
    catch(e)
    {
      //Do the callback with the parse error
      return cb(e, null);
    }

    //Do the callback with the parsed JSON
    return cb(null, obj);
  });
};

//Write a JSON file
module.exports.write = function(file, content, opt, cb)
{
  //Parse the callback method
  var cb = (typeof opt === 'function') ? opt : cb;

  //Parse the options
  var opt = (typeof opt === 'function') ? {} : opt;

  //Check for string options
  if(typeof opt === 'string'){ opt = { encoding: opt }; }

  //Check the encoding value
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'utf8'; }

  //Check the space option
  if(typeof opt.space !== 'string'){ opt.space = '  '; }

  //Content in string format
  var data = null;

  //Convert the content to string
  try
  {
    data = JSON.stringify(content, null, opt.space);
  }
  catch(error)
  {
    //Do the callback with the error
    return cb(error);
  }

  //Write to the file
  return fs.writeFile(file, data, opt, function(error)
  {
    //Do the callback with the error
    return cb(error);
  });
};
<commit_msg>lib/json.js: minor changes. Added json.storage method<commit_after>//Import dependencies
var fs = require('fs');
var path = require('path');

//Import utily methods
var utily_fs = require('./fs.js');
var utily_queue = require('./queue.js');

//Initialize the json object
var json = {};

//Read a JSON file
json.read = function(file, opt, cb)
{
  //Parse the callback method
  var cb = (typeof opt === 'function') ? opt : cb;

  //Parse the options
  var opt = (typeof opt === 'function') ? {} : opt;

  //Check the encoding value
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'utf8'; }

  //Read the file
  return fs.readFile(file, opt, function(error, data)
  {
    //Check the error
    if(error){ return cb(error, null); }

    //Output json object
    var obj = null;

    //Convert the data to json
    try
    {
      //Convert to a json object
      obj = JSON.parse(data);
    }
    catch(e)
    {
      //Do the callback with the parse error
      return cb(e, null);
    }

    //Do the callback with the parsed JSON
    return cb(null, obj);
  });
};

//Write a JSON file
json.write = function(file, content, opt, cb)
{
  //Parse the callback method
  var cb = (typeof opt === 'function') ? opt : cb;

  //Parse the options
  var opt = (typeof opt === 'function') ? {} : opt;

  //Check for string options
  if(typeof opt === 'string'){ opt = { encoding: opt }; }

  //Check the encoding value
  if(typeof opt.encoding !== 'string'){ opt.encoding = 'utf8'; }

  //Check the space option
  if(typeof opt.space !== 'string'){ opt.space = '  '; }

  //Content in string format
  var data = null;

  //Convert the content to string
  try
  {
    data = JSON.stringify(content, null, opt.space);
  }
  catch(error)
  {
    //Do the callback with the error
    return cb(error);
  }

  //Write to the file
  return fs.writeFile(file, data, opt, function(error)
  {
    //Do the callback with the error
    return cb(error);
  });
};

//Json storage
json.storage = function(opt, cb)
{
  //Check the options object
  if(typeof opt !== 'object'){ throw new Error('No options object provided'); }

  //Check the storage path option
  if(typeof opt.path !== 'string'){ throw new Error('No storage path provided'); }

  //Save the database path
  this.path = path.resolve(process.cwd(), opt.path);

  //Save the default encoding
  this.encoding = (typeof opt.encoding === 'string') ? opt.encoding : 'utf8';

  //Create the database directory
  utily_fs.mkdir(this.path, function(error)
  {
    //Check the callback method
    if(typeof cb !== 'function'){ return; }

    //Call the callback method
    return cb(error);
  });

  //Return this
  return this;
};

//Get a document file path
json.storage.prototype.file = function(id)
{
  //Return the document path
  return path.join(this.path, id + '.json');
};

//Get the list of documents available
json.storage.prototype.documents = function(cb)
{
  //Read the directory
  return utily_fs.readdir(this.path, function(error, files)
  {
    //Check the error
    if(error){ return cb(error, null);}

    //Output files list
    var list = {};

    //For each file path
    files.forEach(function(file)
    {
      //Check the file extension
      if(path.extname(file) !== '.json'){ return; }

      //Get the file id
      var id = path.basename(file, '.json');

      //Add the json file path
      list[id] = { id: id, path: file };
    });

    //Call the callback with the list of documents
    return cb(null, list);
  });
};

//Get a document
json.storage.prototype.get = function(id, cb)
{
  //Get the file path
  var file = this.file(id);

  //Register the task queue
  return utily_queue.add(file, function(next)
  {
    //Read the content of the document
    return json.read(file, function(error, data)
    {
      //Next task on the queue
      next();

      //Check the error
      if(error){ return cb(error, null); }

      //Return the content of the document
      return cb(null, data);
    });
  });
};

//Set a document content
json.storage.prototype.set = function(id, obj, cb)
{
  //Get the document id
  var file_id = (typeof id !== 'string') ? utily.string.unique() : id.trim();

  //Get the file content
  var file_content = (typeof id === 'object') ? id : obj;

  //Get the document path
  var file_path = this.file(file_id);

  //Register the task in the queue
  return utily_queue.add(file_path, function(next)
  {
    //Read the file path
    return json.read(file_path, function(error, data)
    {
      //Check the error
      if(error)
      {
        //Check for not found error
        if(error.code === 'ENOENT')
        {
          //File does not exists, initialize the data object
          data = {};
        }
        else
        {
          //Next task
          next();

          //Another error -> call the callback with the error
          return cb(error, null);
        }
      }

      //Assign the new values
      data = Object.assign(data, file_content);

      //Save to the file
      return json.write(file_path, data, function(error)
      {
        //Next task
        next();

        //Call the callback
        return cb(error, data);
      });
    });
  });
};

//Remove a document
json.storage.prototype.remove = function(id, cb)
{
  //Get the file path
  var file = this.file(id);

  //Register the task queue
  return utily_queue.add(file, function(next)
  {
    //Delete the file
    return utily_fs.unlink(file, function(error)
    {
      //Next task in the queue
      next();

      //Call the callback method
      return cb(error)
    });
  });
};

//Exports the json object
module.exports = json;
<|endoftext|>


<commit_before>/**
 * Parted JSON Parser
 * Copyright (c) 2011, Christopher Jeffrey (MIT License)
 */

var EventEmitter = require('events').EventEmitter
  , StringDecoder = require('string_decoder').StringDecoder
  , FreeList = require('freelist').FreeList;

/**
 * Parser
 */

var Parser = function(options) {
  if (!(this instanceof Parser)) {
    return new Parser(options);
  }

  EventEmitter.call(this);

  this.writable = true;
  this.readable = true;

  this.options = options || {};

  this._reset();
};

Parser.prototype.__proto__ = EventEmitter.prototype;

/**
 * Parsing
 */

Parser.prototype.write = function(data) {
  if (!this.writable) return;

  try {
    this._parse(data);
    this.written += data.length;
    this.emit('data', data.length);
  } catch(e) {
    this._error(e);
  }

  return true;
};

Parser.prototype.end = function(data) {
  if (!this.writable) return;

  if (data) this.write(data);

  this.writable = false;
  this.readable = false;

  if (this.value) {
    switch (this.state) {
      case 'number':
        this.emit('number', +this.value);
        break;
      case 'value':
        this.emit('string', this.value);
        break;
      default:
        return this._error('Unexpected EOF.');
    }
  }

  this.emit('end', this.data);

  this._reset();

  return true;
};

Parser.prototype._expect = function(ch, ex) {
  if (ch !== ex) {
    throw new
      Error('Unexpected `' + ch + '`.'
        + (ex ? ' Expected: `' + ex + '`.' : ''));
  }
};

Parser.prototype._parse = function(data) {
  var data = this.decode.write(data)
    , i = 0
    , l = data.length
    , ch;

  for (; i < l; i++) {
    ch = data[i];
    switch (this.state) {
      case 'value': {
        switch (ch) {
          case '{':
            this.emit('object start');
            break;
          case '}':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            this.emit('object end');
            break;
          case '[':
            this.emit('array start');
            break;
          case ']':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            this.emit('array end');
            break;
          case '"':
            this.state = 'string';
            break;
          case ',':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            break;
          case ':':
            this.emit('object key', this.value);
            this.value = '';
            break;
          case '-':
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            this.state = 'number';
            this.value += ch;
            break;
          case 'f':
          case 'n':
          case 't':
            if (this.value) {
              return this._error(this.value + ' in buffer before literal.');
            }
            this.state = ch;
            break;
          default:
            if (ch > ' ') {
              this._expect(ch);
            }
            break;
        }
        break;
      }
      case 'number': {
        switch (ch) {
          case '}':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            this.emit('object end');
            break;
          case ']':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            this.emit('array end');
            break;
          case ',':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            break;
          case 'e':
          case 'E':
            if (!~this.value.indexOf('.')) return this._expect(ch);
            this.value += ch;
            break;
          case '-':
          case '+':
            if (!/e$/i.test(this.value)) return this._expect(ch);
            this.value += ch;
            break;
          case '.':
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            this.value += ch;
            break;
          default:
            if (ch <= ' ') {
              this.state = 'value';
              this.emit('number', +this.value);
              this.value = '';
            } else {
              return this._expect(ch);
            }
            break;
        }
        break;
      }
      case 'string': {
        switch (ch) {
          case '"':
            this.state = 'value';
            // hack for empty strings
            if (!this.value) this.value = ' ';
            break;
          case '\\':
            this.state = 'escape';
            break;
          default:
            this.value += ch;
            break;
        }
        break;
      }
      case 'escape': {
        switch (ch) {
          case 'u':
            this.unicode = '';
            break;
          case 'b':
            this.value += '\b';
            break;
          case 'f':
            this.value += '\f';
            break;
          case 'n':
            this.value += '\n';
            break;
          case 'r':
            this.value += '\r';
            break;
          case 't':
            this.value += '\t';
            break;
          case '"':
            this.value += ch;
            break;
          case '\\':
            this.value += ch;
            break;
          default:
            // json is supposed to throw
            // if there's a backslash
            // in the wrong spot
            this._expect(ch);
        }
        if (ch === 'u') {
          this.state = 'unicode';
        } else {
          this.state = 'string';
        }
        break;
      }
      case 'unicode': {
        switch (ch) {
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            this.unicode += ch;
            if (this.unicode.length === 4) {
              this.unicode = parseInt(this.unicode, 16);
              this.value += String.fromCharCode(this.unicode);
              this.unicode = '';
              this.state = 'string';
            }
            break;
          default:
            return this._expect(ch);
        }
        break;
      }
      case 'n': {
        this._expect(ch, 'u');
        this.state = 'nu';
        break;
      }
      case 'nu': {
        this._expect(ch, 'l');
        this.state = 'nul';
        break;
      }
      case 'nul': {
        this._expect(ch, 'l');
        this.emit('null', null);
        this.state = 'value';
        break;
      }
      case 'f': {
        this._expect(ch, 'a');
        this.state = 'fa';
        break;
      }
      case 'fa': {
        this._expect(ch, 'l');
        this.state = 'fal';
        break;
      }
      case 'fal': {
        this._expect(ch, 's');
        this.state = 'fals';
        break;
      }
      case 'fals': {
        this._expect(ch, 'e');
        this.emit('boolean', false);
        this.state = 'value';
        break;
      }
      case 't': {
        this._expect(ch, 'r');
        this.state = 'tr';
        break;
      }
      case 'tr': {
        this._expect(ch, 'u');
        this.state = 'tru';
        break;
      }
      case 'tru': {
        this._expect(ch, 'e');
        this.emit('boolean', true);
        this.state = 'value';
        break;
      }
    }
  }
};

Parser.prototype._reset = function() {
  this.state = 'value';
  this.value = '';
  this.unicode = '';
  this.written = 0;
  this.decode = new StringDecoder('utf8');
  this.data = null;
  this._events = {};
  this._escapeNext = 0;
};

Parser.prototype._error = function(err) {
  this.destroy();
  this.emit('error', typeof err === 'string'
    ? new Error(err + '')
    : err);
};

Parser.prototype.destroy = function(err) {
  this.writable = false;
  this.readable = false;
  this._reset();
};

/**
 * Object Assembler
 */

Parser.create = function(parser) {
  var parser = parser || new Parser()
    , stack = []
    , key;

  parser.on('object start', function() {
    var object = {};
    this.emit('.value', object);
    stack.push(object);
  });

  parser.on('object key', function(val) {
    key = val;
  });

  parser.on('object end', function() {
    this.emit('object', stack.pop());
  });

  parser.on('array start', function() {
    var array = [];
    this.emit('.value', array);
    stack.push(array);
  });

  parser.on('array end', function() {
    this.emit('array', stack.pop());
  });

  parser.on('number', function(val) {
    this.emit('.value', val); // , key
  });

  parser.on('string', function(val) {
    this.emit('.value', val);
  });

  parser.on('boolean', function(val) {
    this.emit('.value', val);
  });

  parser.on('.value', function(val) {
    var top = stack[stack.length-1];
    if (!top) {
      if (key) {
        return this._error('Unexpected key.');
      }
      this.data = val;
      stack.push(val);
      return;
    }
    if (!key) {
      if (!Array.isArray(top)) {
        return this._error('Expected key.');
      }
      top.push(val);
    } else {
      if (Array.isArray(top)) {
        return this._error('Unexpected key.');
      }
      top[key] = val;
      key = null;
    }
  });

  return parser;
};

/**
 * Pool
 */

var parsers = new FreeList('parsers', 20, function() {
  return Parser.create();
});

/**
 * Expose
 */

module.exports = exports = Parser.create;
exports.Parser = Parser;

exports.middleware = function(options) {
  return function(req, res, next) {
    if (req.method === 'GET'
        || req.method === 'HEAD'
        || req._json) return next();

    req._json = true;

    var type = req.headers['content-type'];

    if (type) type = type.split(';')[0].trim().toLowerCase();

    if (type === 'application/json') {
      exports.handle(req, res, next, options);
    } else {
      if (options.ensureBody) {
        req.body = {};
      }
      next();
    }
  };
};

exports.handle = function(req, res, next, options) {
  var parser = parsers.alloc()
    , limit = options.jsonLimit || options.limit;

  parser.on('error', function(err) {
    req.socket.destroy();
    next(err);
  });

  parser.on('end', function(data) {
    parsers.free(parser);
    req.body = data;
    next();
  });

  if (limit) {
    parser.on('data', function() {
      if (this.written > limit) {
        this.emit('error', new Error('Overflow.'));
        this.destroy();
      }
    });
  }
};

/**
 * Crude Test
 */

if (!module.parent) (function() {
  var assert = require('assert');
  var TEST_JSON = '{"a":{"b":100,"c":[2,3]},"d":["e"],"f":true}';

  var parser = Parser.create();

  parser.on('end', function(obj) {
    console.log(obj);
    assert.deepEqual(obj, JSON.parse(TEST_JSON), 'Not deep equal.');
    assert.equal(JSON.stringify(obj), TEST_JSON, 'Not equal.');
    console.log('Completed.');
  });

  var emit = parser.emit;
  parser.emit = function(type, val) {
    console.log(type, val);
    return emit.apply(this, arguments);
  };

  parser.write(TEST_JSON.slice(0, 25));
  parser.write(TEST_JSON.slice(25));
  parser.end();

  /*
  (function emit(a, b) {
    parser.emit(a, b);
    return emit;
  })
  ('object start')
  ('object key', 'hello')
  ('object start')
  ('object key', 'world')
  ('number', 100)
  ('object key', 'test')
  ('array start')
  ('number', 2)
  ('number', 3)
  ('array end')
  ('object end')
  ('object key', 'hi')
  ('array start')
  ('string', 'an array!')
  ('array end')
  ('object end')
  ('end', parser.data);
  */
})();

<commit_msg>error messages<commit_after>/**
 * Parted JSON Parser
 * Copyright (c) 2011, Christopher Jeffrey (MIT License)
 */

var EventEmitter = require('events').EventEmitter
  , StringDecoder = require('string_decoder').StringDecoder
  , FreeList = require('freelist').FreeList;

/**
 * Parser
 */

var Parser = function(options) {
  if (!(this instanceof Parser)) {
    return new Parser(options);
  }

  EventEmitter.call(this);

  this.writable = true;
  this.readable = true;

  this.options = options || {};

  this._reset();
};

Parser.prototype.__proto__ = EventEmitter.prototype;

/**
 * Parsing
 */

Parser.prototype.write = function(data) {
  if (!this.writable) return;

  try {
    this._parse(data);
    this.written += data.length;
    this.emit('data', data.length);
  } catch(e) {
    this._error(e);
  }

  return true;
};

Parser.prototype.end = function(data) {
  if (!this.writable) return;

  if (data) this.write(data);

  this.writable = false;
  this.readable = false;

  if (this.value) {
    switch (this.state) {
      case 'number':
        this.emit('number', +this.value);
        break;
      case 'value':
        this.emit('string', this.value);
        break;
      default:
        return this._error('Unexpected EOF.');
    }
  }

  this.emit('end', this.data);

  this._reset();

  return true;
};

Parser.prototype._expect = function(ch, ex) {
  if (ch !== ex) {
    throw new
      Error('Unexpected `' + ch + '`.'
        + (ex ? ' Expected: `' + ex + '`.' : ''));
  }
};

Parser.prototype._parse = function(data) {
  var data = this.decode.write(data)
    , i = 0
    , l = data.length
    , ch;

  for (; i < l; i++) {
    ch = data[i];
    switch (this.state) {
      case 'value': {
        switch (ch) {
          case '{':
            this.emit('object start');
            break;
          case '}':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            this.emit('object end');
            break;
          case '[':
            this.emit('array start');
            break;
          case ']':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            this.emit('array end');
            break;
          case '"':
            this.state = 'string';
            break;
          case ',':
            if (this.value) {
              this.emit('string', this.value);
              this.value = '';
            }
            break;
          case ':':
            this.emit('object key', this.value);
            this.value = '';
            break;
          case '-':
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            if (this.value) {
              return this._error(this.value
                + ' in buffer before literal.'
              );
            }
            this.state = 'number';
            this.value += ch;
            break;
          case 'f':
          case 'n':
          case 't':
            if (this.value) {
              return this._error(this.value
                + ' in buffer before literal.'
              );
            }
            this.state = ch;
            break;
          default:
            if (ch > ' ') {
              this._expect(ch);
            }
            break;
        }
        break;
      }
      case 'number': {
        switch (ch) {
          case '}':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            this.emit('object end');
            break;
          case ']':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            this.emit('array end');
            break;
          case ',':
            this.state = 'value';
            this.emit('number', +this.value);
            this.value = '';
            break;
          case 'e':
          case 'E':
            if (!~this.value.indexOf('.')) {
              return this._expect(ch);
            }
            this.value += ch;
            break;
          case '-':
          case '+':
            if (!/e$/i.test(this.value)) {
              return this._expect(ch);
            }
            this.value += ch;
            break;
          case '.':
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            this.value += ch;
            break;
          default:
            if (ch <= ' ') {
              this.state = 'value';
              this.emit('number', +this.value);
              this.value = '';
            } else {
              return this._expect(ch);
            }
            break;
        }
        break;
      }
      case 'string': {
        switch (ch) {
          case '"':
            this.state = 'value';
            // hack for empty strings
            if (!this.value) this.value = ' ';
            break;
          case '\\':
            this.state = 'escape';
            break;
          default:
            this.value += ch;
            break;
        }
        break;
      }
      case 'escape': {
        switch (ch) {
          case 'u':
            this.unicode = '';
            break;
          case 'b':
            this.value += '\b';
            break;
          case 'f':
            this.value += '\f';
            break;
          case 'n':
            this.value += '\n';
            break;
          case 'r':
            this.value += '\r';
            break;
          case 't':
            this.value += '\t';
            break;
          case '"':
            this.value += ch;
            break;
          case '\\':
            this.value += ch;
            break;
          default:
            // json is supposed to throw
            // if there's a backslash
            // in the wrong spot
            return this._expect(ch);
        }
        if (ch === 'u') {
          this.state = 'unicode';
        } else {
          this.state = 'string';
        }
        break;
      }
      case 'unicode': {
        switch (ch) {
          case '0':
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
          case '6':
          case '7':
          case '8':
          case '9':
            this.unicode += ch;
            if (this.unicode.length === 4) {
              this.unicode = parseInt(this.unicode, 16);
              this.value += String.fromCharCode(this.unicode);
              this.unicode = '';
              this.state = 'string';
            }
            break;
          default:
            return this._expect(ch);
        }
        break;
      }
      case 'n': {
        this._expect(ch, 'u');
        this.state = 'nu';
        break;
      }
      case 'nu': {
        this._expect(ch, 'l');
        this.state = 'nul';
        break;
      }
      case 'nul': {
        this._expect(ch, 'l');
        this.emit('null', null);
        this.state = 'value';
        break;
      }
      case 'f': {
        this._expect(ch, 'a');
        this.state = 'fa';
        break;
      }
      case 'fa': {
        this._expect(ch, 'l');
        this.state = 'fal';
        break;
      }
      case 'fal': {
        this._expect(ch, 's');
        this.state = 'fals';
        break;
      }
      case 'fals': {
        this._expect(ch, 'e');
        this.emit('boolean', false);
        this.state = 'value';
        break;
      }
      case 't': {
        this._expect(ch, 'r');
        this.state = 'tr';
        break;
      }
      case 'tr': {
        this._expect(ch, 'u');
        this.state = 'tru';
        break;
      }
      case 'tru': {
        this._expect(ch, 'e');
        this.emit('boolean', true);
        this.state = 'value';
        break;
      }
    }
  }
};

Parser.prototype._reset = function() {
  this.state = 'value';
  this.value = '';
  this.unicode = '';
  this.written = 0;
  this.decode = new StringDecoder('utf8');
  this.data = null;
  this._events = {};
  this._escapeNext = 0;
};

Parser.prototype._error = function(err) {
  this.destroy();
  this.emit('error', typeof err === 'string'
    ? new Error(err + '')
    : err);
};

Parser.prototype.destroy = function(err) {
  this.writable = false;
  this.readable = false;
  this._reset();
};

/**
 * Object Assembler
 */

Parser.create = function(parser) {
  var parser = parser || new Parser()
    , stack = []
    , key;

  parser.on('object start', function() {
    var object = {};
    this.emit('.value', object);
    stack.push(object);
  });

  parser.on('object key', function(val) {
    key = val;
  });

  parser.on('object end', function() {
    this.emit('object', stack.pop());
  });

  parser.on('array start', function() {
    var array = [];
    this.emit('.value', array);
    stack.push(array);
  });

  parser.on('array end', function() {
    this.emit('array', stack.pop());
  });

  parser.on('number', function(val) {
    this.emit('.value', val); // , key
  });

  parser.on('string', function(val) {
    this.emit('.value', val);
  });

  parser.on('boolean', function(val) {
    this.emit('.value', val);
  });

  parser.on('.value', function(val) {
    var top = stack[stack.length-1];
    if (!top) {
      if (key) {
        return this._error('Unexpected key.');
      }
      this.data = val;
      stack.push(val);
      return;
    }
    if (!key) {
      if (!Array.isArray(top)) {
        return this._error('Expected key.');
      }
      top.push(val);
    } else {
      if (Array.isArray(top)) {
        return this._error('Unexpected key.');
      }
      top[key] = val;
      key = null;
    }
  });

  return parser;
};

/**
 * Pool
 */

var parsers = new FreeList('parsers', 20, function() {
  return Parser.create();
});

/**
 * Expose
 */

module.exports = exports = Parser.create;
exports.Parser = Parser;

exports.middleware = function(options) {
  return function(req, res, next) {
    if (req.method === 'GET'
        || req.method === 'HEAD'
        || req._json) return next();

    req._json = true;

    var type = req.headers['content-type'];

    if (type) type = type.split(';')[0].trim().toLowerCase();

    if (type === 'application/json') {
      exports.handle(req, res, next, options);
    } else {
      if (options.ensureBody) {
        req.body = {};
      }
      next();
    }
  };
};

exports.handle = function(req, res, next, options) {
  var parser = parsers.alloc()
    , limit = options.jsonLimit || options.limit;

  parser.on('error', function(err) {
    req.socket.destroy();
    next(err);
  });

  parser.on('end', function(data) {
    parsers.free(parser);
    req.body = data;
    next();
  });

  if (limit) {
    parser.on('data', function() {
      if (this.written > limit) {
        this.emit('error', new Error('Overflow.'));
        this.destroy();
      }
    });
  }
};

/**
 * Crude Test
 */

if (!module.parent) (function() {
  var assert = require('assert');
  var TEST_JSON = '{"a":{"b":100,"c":[2,3]},"d":["e"],"f":true}';

  var parser = Parser.create();

  parser.on('end', function(obj) {
    console.log(obj);
    assert.deepEqual(obj, JSON.parse(TEST_JSON), 'Not deep equal.');
    assert.equal(JSON.stringify(obj), TEST_JSON, 'Not equal.');
    console.log('Completed.');
  });

  var emit = parser.emit;
  parser.emit = function(type, val) {
    console.log(type, val);
    return emit.apply(this, arguments);
  };

  parser.write(TEST_JSON.slice(0, 25));
  parser.write(TEST_JSON.slice(25));
  parser.end();

  /*
  (function emit(a, b) {
    parser.emit(a, b);
    return emit;
  })
  ('object start')
  ('object key', 'hello')
  ('object start')
  ('object key', 'world')
  ('number', 100)
  ('object key', 'test')
  ('array start')
  ('number', 2)
  ('number', 3)
  ('array end')
  ('object end')
  ('object key', 'hi')
  ('array start')
  ('string', 'an array!')
  ('array end')
  ('object end')
  ('end', parser.data);
  */
})();

<|endoftext|>


<commit_before>'use strict'

const TelegramRoute = require('./TelegramRoute')

/**
 * Routing class, helps to route updates to controllers
 */
class TelegramRouter {
    constructor() {
        this._routes = []
        this._otherwiseController = null
        this._callbackQueryController = null
        this._inlineQueryController = null
        this._anyController = null
    }

    /**
     * You can pass your command pattern or array of patterns
     * and some child of TelegramBaseController
     *
     * After that any update that satisfies your command
     * will be passed to your controller
     *
     * @param {string[]|string|RegExp|RegExp[]} commands
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    when(commands, controller) {
        this._routes.push(new TelegramRoute(commands, controller))

        return this
    }

    /**
     * This child of TelegramBaseController will be called for all updates
     *
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    any(controller) {
        this._anyController = controller
        return this
    }

    /**
     * This child of TelegramBaseController will be called
     * if there is no controller for that update (except controller passed to 'any' method)
     *
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    otherwise(controller) {
        this._otherwiseController = controller
        return this
    }

    /**
     * This child of TelegramBaseCallbackQueryController will be called for all callback queries
     *
     * @param {TelegramBaseCallbackQueryController} controller
     */
    callbackQuery(controller) {
        this._callbackQueryController = controller
        return this
    }

    /**
     * This child of TelegramBaseCallbackQueryController will be called for all inline queries
     *
     * @param {TelegramBaseInlineQueryController} controller
     * @returns {TelegramRouter}
     */
    inlineQuery(controller) {
        this._inlineQueryController = controller
        return this
    }

    /**
     *
     * @returns {TelegramBaseCallbackQueryController|null}
     */
    get callbackQueryController() {
        return this._callbackQueryController
    }

    /**
     *
     * @returns {TelegramBaseInlineQueryController|null}
     */
    get inlineQueryController() {
        return this._inlineQueryController
    }

    /**
     *
     * @param {Update} update
     * @returns {TelegramBaseController[]}
     */
    controllersForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        let controllers = []

        if (this._anyController) controllers.push(this._anyController)

        let haveControllerForCommand = false

        for (const route of this._routes) {
            for (const command of route.commands) {
                let test = this._testCommand(command, update.message || update.editedMessage)

                if (test !== false) {
                    if (test === 'otherwise') {
                        break
                    }

                    controllers.push(route.controller)
                    haveControllerForCommand = true

                    break
                }
            }
        }

        if (!haveControllerForCommand) controllers.push(this._otherwiseController)

        return controllers
    }

    /**
     *
     * @param {Update} update
     * @returns {string}
     */
    commandNameForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        for (const route of this._routes) {
            for (const command of route.commands) {
                if (this._testCommand(command, update.message || update.editedMessage) !== false) {
                    return command.name || command
                }
            }
        }
    }

    /**
     *
     * @param {Update} update
     * @returns {string}
     */
    commandForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        for (const route of this._routes) {
            for (const command of route.commands) {
                if (this._testCommand(command, update.message || update.editedMessage) !== false) {
                    return command
                }
            }
        }

        if (this._otherwiseController) return 'otherwise'
    }

    /**
     *
     * @param {Update} update
     * @returns {string[]}
     */
    queryForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        const command = this.commandForUpdate(update)

        const args = this._testCommand(command, update.message || update.editedMessage)

        if (args) return args

        return []
    }

    /**
     * If test fails = returns false,
     * if test passed returns array of command arguments.
     *
     * @param {string|RegExp|Function} command
     * @param {Message} message
     * @returns {boolean|string[]|Object}
     * @private
     */
    _testCommand(command, message) {
        if (typeof command === 'string' && message.text) {
            let haveQuery = true

            const mask = command.split(' ')
            const query = message.text.split(' ')

            let result = {}

            if (mask.length === query.length) {
                for (var i = 0; i < query.length; i++) {
                    switch (mask[i][0]) {
                        case '/':
                            if (mask[i] !== query[i]) haveQuery = false
                            result.command = query[i]
                            break
                        case ':':
                            result[mask[i].replace(':', '')] = query[i]
                    }
                }
            }

            if (!result.command) haveQuery = false

            if (result && haveQuery) return result

            if (message.text.indexOf(command) > -1 && !haveQuery) return message.text.replace(command, '')

            return false
        }

        if (command instanceof RegExp && message.text) {
            if (command.test(message.text)) {
                let query = []
                var arg

                command.lastIndex = 0 //reset regexp
                while (arg = command.exec(message.text)) {
                    query.push(arg[1] || arg[0])
                }

                return query
            }

            return false
        }

        if (command.name && command.test) {
            return command.test(message)
        }

        if (this._otherwiseController) return 'otherwise'
    }
}

module.exports = TelegramRouter<commit_msg>Fix router<commit_after>'use strict'

const TelegramRoute = require('./TelegramRoute')

/**
 * Routing class, helps to route updates to controllers
 */
class TelegramRouter {
    constructor() {
        this._routes = []
        this._otherwiseController = null
        this._callbackQueryController = null
        this._inlineQueryController = null
        this._anyController = null
    }

    /**
     * You can pass your command pattern or array of patterns
     * and some child of TelegramBaseController
     *
     * After that any update that satisfies your command
     * will be passed to your controller
     *
     * @param {string[]|string|RegExp|RegExp[]} commands
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    when(commands, controller) {
        this._routes.push(new TelegramRoute(commands, controller))

        return this
    }

    /**
     * This child of TelegramBaseController will be called for all updates
     *
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    any(controller) {
        this._anyController = controller
        return this
    }

    /**
     * This child of TelegramBaseController will be called
     * if there is no controller for that update (except controller passed to 'any' method)
     *
     * @param {TelegramBaseController} controller
     * @returns {TelegramRouter}
     */
    otherwise(controller) {
        this._otherwiseController = controller
        return this
    }

    /**
     * This child of TelegramBaseCallbackQueryController will be called for all callback queries
     *
     * @param {TelegramBaseCallbackQueryController} controller
     */
    callbackQuery(controller) {
        this._callbackQueryController = controller
        return this
    }

    /**
     * This child of TelegramBaseCallbackQueryController will be called for all inline queries
     *
     * @param {TelegramBaseInlineQueryController} controller
     * @returns {TelegramRouter}
     */
    inlineQuery(controller) {
        this._inlineQueryController = controller
        return this
    }

    /**
     *
     * @returns {TelegramBaseCallbackQueryController|null}
     */
    get callbackQueryController() {
        return this._callbackQueryController
    }

    /**
     *
     * @returns {TelegramBaseInlineQueryController|null}
     */
    get inlineQueryController() {
        return this._inlineQueryController
    }

    /**
     *
     * @param {Update} update
     * @returns {TelegramBaseController[]}
     */
    controllersForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        let controllers = []

        if (this._anyController) controllers.push(this._anyController)

        let haveControllerForCommand = false

        for (const route of this._routes) {
            for (const command of route.commands) {
                let test = this._testCommand(command, update.message || update.editedMessage)

                if (test !== false) {
                    if (test === 'otherwise') {
                        break
                    }

                    controllers.push(route.controller)
                    haveControllerForCommand = true

                    break
                }
            }
        }

        if (!haveControllerForCommand && this._otherwiseController) controllers.push(this._otherwiseController)

        return controllers
    }

    /**
     *
     * @param {Update} update
     * @returns {string}
     */
    commandNameForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        for (const route of this._routes) {
            for (const command of route.commands) {
                if (this._testCommand(command, update.message || update.editedMessage) !== false) {
                    return command.name || command
                }
            }
        }
    }

    /**
     *
     * @param {Update} update
     * @returns {string}
     */
    commandForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        for (const route of this._routes) {
            for (const command of route.commands) {
                if (this._testCommand(command, update.message || update.editedMessage) !== false) {
                    return command
                }
            }
        }

        if (this._otherwiseController) return 'otherwise'
    }

    /**
     *
     * @param {Update} update
     * @returns {string[]}
     */
    queryForUpdate(update) {
        if (!update.message && !update.editedMessage) return null

        const command = this.commandForUpdate(update)

        if (!command) return null

        const args = this._testCommand(command, update.message || update.editedMessage)

        if (args) return args

        return []
    }

    /**
     * If test fails = returns false,
     * if test passed returns array of command arguments.
     *
     * @param {string|RegExp|Function} command
     * @param {Message} message
     * @returns {boolean|string[]|Object}
     * @private
     */
    _testCommand(command, message) {
        if (typeof command === 'string' && message.text) {
            let haveQuery = true

            const mask = command.split(' ')
            const query = message.text.split(' ')

            let result = {}

            if (mask.length === query.length) {
                for (var i = 0; i < query.length; i++) {
                    switch (mask[i][0]) {
                        case '/':
                            if (mask[i] !== query[i]) haveQuery = false
                            result.command = query[i]
                            break
                        case ':':
                            result[mask[i].replace(':', '')] = query[i]
                    }
                }
            }

            if (!result.command) haveQuery = false

            if (result && haveQuery) return result

            if (message.text.indexOf(command) > -1 && !haveQuery) return message.text.replace(command, '')

            return false
        }

        if (command instanceof RegExp && message.text) {
            if (command.test(message.text)) {
                let query = []
                var arg

                command.lastIndex = 0 //reset regexp
                while (arg = command.exec(message.text)) {
                    query.push(arg[1] || arg[0])
                }

                return query
            }

            return false
        }

        if (command.name && command.test) {
            return command.test(message)
        }

        if (this._otherwiseController) return 'otherwise'
    }
}

module.exports = TelegramRouter<|endoftext|>


<commit_before>import { extend } from 'marbles/utils';
import Store from '../store';
import Config from '../config';
import Dispatcher from '../dispatcher';

var App = Store.createClass({
	displayName: "Stores.App",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = this.id;

		this.__formationLock = Promise.resolve();
		this.__releaseLock = Promise.resolve();
	},

	getInitialState: function () {
		return {
			app: null,
			release: null,
			formation: null,
			serviceUnavailable: false,
			notFound: false
		};
	},

	didBecomeActive: function () {
		this.__fetchApp();
		Dispatcher.dispatch({
			name: 'GET_APP_RELEASE',
			appID: this.props.appId,
		});
	},

	didBecomeInactive: function () {
		this.constructor.discardInstance(this);
	},

	handleEvent: function (event) {
		switch (event.name) {
			case 'APP':
				if (event.app === this.props.appId) {
					this.setState({
						app: event.data
					});
				}
			break;

			case 'APP_RELEASE':
				if (event.app === this.props.appId) {
					this.setState({
						formation: this.state.formation === null ? null : extend({}, this.state.formation, {
							release: event.object_id
						}),
						app: extend({}, this.state.app, {
							release_id: event.object_id
						}),
						release: event.data.release
					});
					if ((this.state.formation || {}).release !== event.object_id) {
						Dispatcher.dispatch({
							name: 'GET_APP_FORMATION',
							appID: this.props.appId,
							releaseID: event.object_id
						});
					}
				}
			break;

			case 'APP_FORMATION':
				if (event.app === this.props.appId && event.data.release === this.state.release.id) {
					this.setState({
						formation: event.data
					});
				}
			break;

			case 'SCALE':
				if (event.app === this.props.appId && event.data.processes !== null) {
					this.setState({
						formation: extend({}, this.state.formation, {
							release: event.data.release,
							processes: event.data.processes || {}
						})
					});
				}
			break;

			case 'DEPLOYMENT':
				if ((this.release || {}).id === event.data.release && event.data.status === 'failed') {
					Dispatcher.dispatch({
						name: 'GET_APP_RELEASE',
						appID: this.props.appId,
					});
				}
			break;

			case "APP_PROCESSES:CREATE_FORMATION":
				this.__createAppFormation(event.formation);
			break;

			case "APP_DELETE:DELETE_APP":
				this.__deleteApp();
			break;
		}
	},

	__withoutChangeEvents: function (fn) {
		var handleChange = this.handleChange;
		this.handleChange = function(){};
		return fn().then(function () {
			this.handleChange = handleChange;
		}.bind(this));
	},

	__getApp: function () {
		if (this.state.app) {
			return Promise.resolve(this.state.app);
		} else {
			return this.__fetchApp();
		}
	},

	__fetchApp: function () {
		return App.getClient.call(this).getApp(this.props.appId).then(function (args) {
			var res = args[0];
			if (res.name === 'dashboard') {
				Config.setDashboardAppID(res.id);
			}
			this.setState({
				app: res
			});
		}.bind(this)).catch(function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			} else {
				var xhr = args[1];
				if (xhr.status === 503) {
					this.setState({
						serviceUnavailable: true
					});
				} else if (xhr.status === 404) {
					this.setState({
						notFound: true
					});
				} else {
					return Promise.reject(args);
				}
			}
		}.bind(this));
	},

	__createAppFormation: function (formation) {
		return this.__formationLock.then(function () {
			return App.getClient.call(this).createAppFormation(formation.app, formation).then(function (args) {
				var res = args[0];
				this.setState({
					formation: res
				});
			}.bind(this));
		}.bind(this));
	},

	__deleteApp: function () {
		var __appId = this.id.appId;
		return App.getClient.call(this).deleteApp(this.props.appId).then(function (args) {
			Dispatcher.handleStoreEvent({
				name: "APP:DELETED",
				appId: __appId
			});
			return args;
		});
	}
});

App.getClient = function () {
	return Config.client;
};

App.isValidId = function (id) {
	return !!id.appId;
};

App.dispatcherIndex = App.registerWithDispatcher(Dispatcher);

App.isSystemApp = function (app) {
	return app.meta && app.meta["flynn-system-app"] === "true";
};

export default App;
<commit_msg>dashboard: Fix scale app<commit_after>import { extend } from 'marbles/utils';
import Store from '../store';
import Config from '../config';
import Dispatcher from '../dispatcher';

var App = Store.createClass({
	displayName: "Stores.App",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = this.id;

		this.__formationLock = Promise.resolve();
		this.__releaseLock = Promise.resolve();
	},

	getInitialState: function () {
		return {
			app: null,
			release: null,
			formation: null,
			serviceUnavailable: false,
			notFound: false
		};
	},

	didBecomeActive: function () {
		this.__fetchApp();
		Dispatcher.dispatch({
			name: 'GET_APP_RELEASE',
			appID: this.props.appId,
		});
	},

	didBecomeInactive: function () {
		this.constructor.discardInstance(this);
	},

	handleEvent: function (event) {
		switch (event.name) {
			case 'APP':
				if (event.app === this.props.appId) {
					this.setState({
						app: event.data
					});
				}
			break;

			case 'APP_RELEASE':
				if (event.app === this.props.appId) {
					this.setState({
						formation: this.state.formation === null ? null : extend({}, this.state.formation, {
							release: event.object_id
						}),
						app: extend({}, this.state.app, {
							release: event.object_id
						}),
						release: event.data.release
					});
					if ((this.state.formation || {}).release !== event.object_id) {
						Dispatcher.dispatch({
							name: 'GET_APP_FORMATION',
							appID: this.props.appId,
							releaseID: event.object_id
						});
					}
				}
			break;

			case 'APP_FORMATION':
				if (event.app === this.props.appId && event.data.release === this.state.release.id) {
					this.setState({
						formation: event.data
					});
				}
			break;

			case 'SCALE':
				if (event.app === this.props.appId && event.data.processes !== null) {
					this.setState({
						formation: extend({}, this.state.formation, {
							release: event.data.release,
							processes: event.data.processes || {}
						})
					});
				}
			break;

			case 'DEPLOYMENT':
				if ((this.release || {}).id === event.data.release && event.data.status === 'failed') {
					Dispatcher.dispatch({
						name: 'GET_APP_RELEASE',
						appID: this.props.appId,
					});
				}
			break;

			case "APP_PROCESSES:CREATE_FORMATION":
				this.__createAppFormation(event.formation);
			break;

			case "APP_DELETE:DELETE_APP":
				this.__deleteApp();
			break;
		}
	},

	__withoutChangeEvents: function (fn) {
		var handleChange = this.handleChange;
		this.handleChange = function(){};
		return fn().then(function () {
			this.handleChange = handleChange;
		}.bind(this));
	},

	__getApp: function () {
		if (this.state.app) {
			return Promise.resolve(this.state.app);
		} else {
			return this.__fetchApp();
		}
	},

	__fetchApp: function () {
		return App.getClient.call(this).getApp(this.props.appId).then(function (args) {
			var res = args[0];
			if (res.name === 'dashboard') {
				Config.setDashboardAppID(res.id);
			}
			this.setState({
				app: res
			});
		}.bind(this)).catch(function (args) {
			if (args instanceof Error) {
				return Promise.reject(args);
			} else {
				var xhr = args[1];
				if (xhr.status === 503) {
					this.setState({
						serviceUnavailable: true
					});
				} else if (xhr.status === 404) {
					this.setState({
						notFound: true
					});
				} else {
					return Promise.reject(args);
				}
			}
		}.bind(this));
	},

	__createAppFormation: function (formation) {
		return this.__formationLock.then(function () {
			return App.getClient.call(this).createAppFormation(formation.app, formation).then(function (args) {
				var res = args[0];
				this.setState({
					formation: res
				});
			}.bind(this));
		}.bind(this));
	},

	__deleteApp: function () {
		var __appId = this.id.appId;
		return App.getClient.call(this).deleteApp(this.props.appId).then(function (args) {
			Dispatcher.handleStoreEvent({
				name: "APP:DELETED",
				appId: __appId
			});
			return args;
		});
	}
});

App.getClient = function () {
	return Config.client;
};

App.isValidId = function (id) {
	return !!id.appId;
};

App.dispatcherIndex = App.registerWithDispatcher(Dispatcher);

App.isSystemApp = function (app) {
	return app.meta && app.meta["flynn-system-app"] === "true";
};

export default App;
<|endoftext|>


<commit_before>/**
 * Created by Baptiste Gouby on 2014-07-29.
 */
Backbone.EspressoLogic = (function(Backbone, _) {

    var EspressoLogic = {};
    EspressoLogic.Model = Backbone.Model.extend({
        /**
         * Using Espresso Logic, we can provide SQL-like filters to the requested URL
         * We just have to set a filter in the options when creating a model
         */
        initialize: function(attr, opts) {
            if (opts && opts.apiFilter) {
                this.apiFilter = opts.apiFilter;
            }
        },
        /**
         * The URL used to make the request is created.
         * Append the filter to the URL
         */
        url: function() {
            var url = this.urlRoot;
            if (this.apiFilter) {
                url += this.apiFilter;
            }
            return url;
        },
        parse: function(response) {
            // If the response has a status code 201 (Created), the Model data object will be the only item in the 'txsummary' array
            if (response.statusCode && response.statusCode === 201) {
                return response.txsummary[0];
            // Espresso Logic returns an array even if we GET a single entity like '[...]/user/1
            // If the array length is only 1, it returns object
            } else if (response.length === 1) {
                return response[0];
            } else {
                return response;
            }
        }
    });

    EspressoLogic.Collection = Backbone.Collection.extend({
        initialize: function(attr, opts) {
            if (opts && opts.apiFilter) {
                this.apiFilter = opts.apiFilter;
            }
        },
        url: function() {
            var url = this.urlRoot;
            if (this.apiFilter) {
                url += this.apiFilter;
            }
            return url;
        }
    });

    return EspressoLogic;

})
(Backbone, _);<commit_msg>Added HTTP 200 support<commit_after>/**
 * Created by Baptiste Gouby on 2014-07-29.
 */
Backbone.EspressoLogic = (function(Backbone, _) {

    var EspressoLogic = {};
    EspressoLogic.Model = Backbone.Model.extend({
        /**
         * Using Espresso Logic, we can provide SQL-like filters to the requested URL
         * We just have to set a filter in the options when creating a model
         */
        initialize: function(attr, opts) {
            if (opts && opts.apiFilter) {
                this.apiFilter = opts.apiFilter;
            }
        },
        /**
         * The URL used to make the request is created.
         * Append the filter to the URL
         */
        url: function() {
            var url = this.urlRoot;
            if (this.apiFilter) {
                url += this.apiFilter;
            }
            return url;
        },
        parse: function(response) {
            // If the response has a status code 201 (Created) or 200 (OK), the Model data object will be the only item in the 'txsummary' array
            if (response.statusCode && (response.statusCode === 201 || response.statusCode === 200)) {
                return response.txsummary[0];
            // Espresso Logic returns an array even if we GET a single entity like '[...]/user/1
            // If the array length is only 1, it returns object
            } else if (response.length === 1) {
                return response[0];
            } else {
                return response;
            }
        }
    });

    EspressoLogic.Collection = Backbone.Collection.extend({
        initialize: function(attr, opts) {
            if (opts && opts.apiFilter) {
                this.apiFilter = opts.apiFilter;
            }
        },
        url: function() {
            var url = this.urlRoot;
            if (this.apiFilter) {
                url += this.apiFilter;
            }
            return url;
        }
    });

    return EspressoLogic;

})
(Backbone, _);<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react'

import _ from 'lodash'
import uuid from 'node-uuid'

import ResizeContainer, {ResizeBottom} from 'src/shared/components/ResizeContainer'
import QueryBuilder from 'src/data_explorer/components/QueryBuilder'
import Visualization from 'src/data_explorer/components/Visualization'
import OverlayControls from 'src/dashboards/components/OverlayControls'
import * as queryModifiers from 'src/utils/queryTransitions'

import defaultQueryConfig from 'src/utils/defaultQueryConfig'
import buildInfluxQLQuery from 'utils/influxql'
import {getQueryConfig} from 'shared/apis'

class CellEditorOverlay extends Component {
  constructor(props) {
    super(props)

    this.queryStateReducer = ::this.queryStateReducer

    this.handleAddQuery = ::this.handleAddQuery
    this.handleDeleteQuery = ::this.handleDeleteQuery

    this.handleSaveCell = ::this.handleSaveCell

    this.handleSelectGraphType = ::this.handleSelectGraphType
    this.handleSetActiveQueryIndex = ::this.handleSetActiveQueryIndex
    this.handleEditRawText = ::this.handleEditRawText

    const {cell: {name, type, queries}} = props

    const queriesWorkingDraft = _.cloneDeep(queries.map(({queryConfig}) => ({...queryConfig, id: uuid.v4()})))

    this.state = {
      cellWorkingName: name,
      cellWorkingType: type,
      queriesWorkingDraft,
      activeQueryIndex: 0,
    }
  }

  componentWillReceiveProps(nextProps) {
    const {status, queryID} = this.props.queryStatus
    const nextStatus = nextProps.queryStatus
    if (nextStatus.status && nextStatus.queryID) {
      if (nextStatus.queryID !== queryID || nextStatus.status !== status) {
        const nextQueries = this.state.queriesWorkingDraft.map((q) => q.id === queryID ? ({...q, status: nextStatus.status}) : q)
        this.setState({queriesWorkingDraft: nextQueries})
      }
    }
  }

  queryStateReducer(queryModifier) {
    return (queryID, payload) => {
      const {queriesWorkingDraft} = this.state
      const query = queriesWorkingDraft.find((q) => q.id === queryID)

      const nextQuery = queryModifier(query, payload)

      const nextQueries = queriesWorkingDraft.map((q) => q.id === query.id ? nextQuery : q)
      this.setState({queriesWorkingDraft: nextQueries})
    }
  }

  handleAddQuery(options) {
    const newQuery = Object.assign({}, defaultQueryConfig(uuid.v4()), options)
    const nextQueries = this.state.queriesWorkingDraft.concat(newQuery)
    this.setState({queriesWorkingDraft: nextQueries})
  }

  handleDeleteQuery(index) {
    const nextQueries = this.state.queriesWorkingDraft.filter((__, i) => i !== index)
    this.setState({queriesWorkingDraft: nextQueries})
  }

  handleSaveCell() {
    const {queriesWorkingDraft, cellWorkingType, cellWorkingName} = this.state
    const {cell, timeRange} = this.props

    const newCell = _.cloneDeep(cell)
    newCell.name = cellWorkingName
    newCell.type = cellWorkingType
    newCell.queries = queriesWorkingDraft.map((q) => {
      const query = q.rawText || buildInfluxQLQuery(timeRange, q)
      const label = q.rawText ?
        "" :
        `${q.measurement}.${q.fields[0].field}`

      return {
        queryConfig: q,
        query,
        label,
      }
    })

    this.props.onSave(newCell)
  }

  handleSelectGraphType(graphType) {
    this.setState({cellWorkingType: graphType})
  }

  handleSetActiveQueryIndex(activeQueryIndex) {
    this.setState({activeQueryIndex})
  }

  async handleEditRawText(url, id, text) {
    // use this as the handler passed into fetchTimeSeries to update a query status
    try {
      const {data} = await getQueryConfig(url, [{query: text, id}])
      const config = data.queries.find(q => q.id === id)
      const nextQueries = this.state.queriesWorkingDraft.map((q) => q.id === id ? config.queryConfig : q)
      this.setState({queriesWorkingDraft: nextQueries})
    } catch (error) {
      console.error(error)
    }
  }

  render() {
    const {
      source,
      onCancel,
      timeRange,
      autoRefresh,
      editQueryStatus,
    } = this.props

    const {
      activeQueryIndex,
      cellWorkingName,
      cellWorkingType,
      queriesWorkingDraft,
    } = this.state

    const queryActions = {
      addQuery: this.handleAddQuery,
      editRawTextAsync: this.handleEditRawText,
      ..._.mapValues(queryModifiers, (qm) => this.queryStateReducer(qm)),
    }

    return (

        <ResizeContainer>
          <Visualization
            autoRefresh={autoRefresh}
            timeRange={timeRange}
            queryConfigs={queriesWorkingDraft}
            activeQueryIndex={0}
            cellType={cellWorkingType}
            cellName={cellWorkingName}
            editQueryStatus={editQueryStatus}
          />
          <ResizeBottom>

              <OverlayControls
                selectedGraphType={cellWorkingType}
                onSelectGraphType={this.handleSelectGraphType}
                onCancel={onCancel}
                onSave={this.handleSaveCell}
              />
              <QueryBuilder
                source={source}
                queries={queriesWorkingDraft}
                actions={queryActions}
                autoRefresh={autoRefresh}
                timeRange={timeRange}
                setActiveQueryIndex={this.handleSetActiveQueryIndex}
                onDeleteQuery={this.handleDeleteQuery}
                activeQueryIndex={activeQueryIndex}
              />

          </ResizeBottom>
        </ResizeContainer>

    )
  }
}

const {
  func,
  number,
  shape,
  string,
} = PropTypes

CellEditorOverlay.propTypes = {
  onCancel: func.isRequired,
  onSave: func.isRequired,
  cell: shape({}).isRequired,
  timeRange: shape({
    upper: string,
    lower: string,
  }).isRequired,
  autoRefresh: number.isRequired,
  source: shape({
    links: shape({
      queries: string.isRequired,
    }),
  }),
  editQueryStatus: func.isRequired,
  queryStatus: shape({
    queryID: string,
    status: shape({}),
  }).isRequired,
}

export default CellEditorOverlay
<commit_msg>Add required proxy link prop to CEO<commit_after>import React, {Component, PropTypes} from 'react'

import _ from 'lodash'
import uuid from 'node-uuid'

import ResizeContainer, {ResizeBottom} from 'src/shared/components/ResizeContainer'
import QueryBuilder from 'src/data_explorer/components/QueryBuilder'
import Visualization from 'src/data_explorer/components/Visualization'
import OverlayControls from 'src/dashboards/components/OverlayControls'
import * as queryModifiers from 'src/utils/queryTransitions'

import defaultQueryConfig from 'src/utils/defaultQueryConfig'
import buildInfluxQLQuery from 'utils/influxql'
import {getQueryConfig} from 'shared/apis'

class CellEditorOverlay extends Component {
  constructor(props) {
    super(props)

    this.queryStateReducer = ::this.queryStateReducer

    this.handleAddQuery = ::this.handleAddQuery
    this.handleDeleteQuery = ::this.handleDeleteQuery

    this.handleSaveCell = ::this.handleSaveCell

    this.handleSelectGraphType = ::this.handleSelectGraphType
    this.handleSetActiveQueryIndex = ::this.handleSetActiveQueryIndex
    this.handleEditRawText = ::this.handleEditRawText

    const {cell: {name, type, queries}} = props

    const queriesWorkingDraft = _.cloneDeep(queries.map(({queryConfig}) => ({...queryConfig, id: uuid.v4()})))

    this.state = {
      cellWorkingName: name,
      cellWorkingType: type,
      queriesWorkingDraft,
      activeQueryIndex: 0,
    }
  }

  componentWillReceiveProps(nextProps) {
    const {status, queryID} = this.props.queryStatus
    const nextStatus = nextProps.queryStatus
    if (nextStatus.status && nextStatus.queryID) {
      if (nextStatus.queryID !== queryID || nextStatus.status !== status) {
        const nextQueries = this.state.queriesWorkingDraft.map((q) => q.id === queryID ? ({...q, status: nextStatus.status}) : q)
        this.setState({queriesWorkingDraft: nextQueries})
      }
    }
  }

  queryStateReducer(queryModifier) {
    return (queryID, payload) => {
      const {queriesWorkingDraft} = this.state
      const query = queriesWorkingDraft.find((q) => q.id === queryID)

      const nextQuery = queryModifier(query, payload)

      const nextQueries = queriesWorkingDraft.map((q) => q.id === query.id ? nextQuery : q)
      this.setState({queriesWorkingDraft: nextQueries})
    }
  }

  handleAddQuery(options) {
    const newQuery = Object.assign({}, defaultQueryConfig(uuid.v4()), options)
    const nextQueries = this.state.queriesWorkingDraft.concat(newQuery)
    this.setState({queriesWorkingDraft: nextQueries})
  }

  handleDeleteQuery(index) {
    const nextQueries = this.state.queriesWorkingDraft.filter((__, i) => i !== index)
    this.setState({queriesWorkingDraft: nextQueries})
  }

  handleSaveCell() {
    const {queriesWorkingDraft, cellWorkingType, cellWorkingName} = this.state
    const {cell, timeRange} = this.props

    const newCell = _.cloneDeep(cell)
    newCell.name = cellWorkingName
    newCell.type = cellWorkingType
    newCell.queries = queriesWorkingDraft.map((q) => {
      const query = q.rawText || buildInfluxQLQuery(timeRange, q)
      const label = q.rawText ?
        "" :
        `${q.measurement}.${q.fields[0].field}`

      return {
        queryConfig: q,
        query,
        label,
      }
    })

    this.props.onSave(newCell)
  }

  handleSelectGraphType(graphType) {
    this.setState({cellWorkingType: graphType})
  }

  handleSetActiveQueryIndex(activeQueryIndex) {
    this.setState({activeQueryIndex})
  }

  async handleEditRawText(url, id, text) {
    // use this as the handler passed into fetchTimeSeries to update a query status
    try {
      const {data} = await getQueryConfig(url, [{query: text, id}])
      const config = data.queries.find(q => q.id === id)
      const nextQueries = this.state.queriesWorkingDraft.map((q) => q.id === id ? config.queryConfig : q)
      this.setState({queriesWorkingDraft: nextQueries})
    } catch (error) {
      console.error(error)
    }
  }

  render() {
    const {
      source,
      onCancel,
      timeRange,
      autoRefresh,
      editQueryStatus,
    } = this.props

    const {
      activeQueryIndex,
      cellWorkingName,
      cellWorkingType,
      queriesWorkingDraft,
    } = this.state

    const queryActions = {
      addQuery: this.handleAddQuery,
      editRawTextAsync: this.handleEditRawText,
      ..._.mapValues(queryModifiers, (qm) => this.queryStateReducer(qm)),
    }

    return (

        <ResizeContainer>
          <Visualization
            autoRefresh={autoRefresh}
            timeRange={timeRange}
            queryConfigs={queriesWorkingDraft}
            activeQueryIndex={0}
            cellType={cellWorkingType}
            cellName={cellWorkingName}
            editQueryStatus={editQueryStatus}
          />
          <ResizeBottom>

              <OverlayControls
                selectedGraphType={cellWorkingType}
                onSelectGraphType={this.handleSelectGraphType}
                onCancel={onCancel}
                onSave={this.handleSaveCell}
              />
              <QueryBuilder
                source={source}
                queries={queriesWorkingDraft}
                actions={queryActions}
                autoRefresh={autoRefresh}
                timeRange={timeRange}
                setActiveQueryIndex={this.handleSetActiveQueryIndex}
                onDeleteQuery={this.handleDeleteQuery}
                activeQueryIndex={activeQueryIndex}
              />

          </ResizeBottom>
        </ResizeContainer>

    )
  }
}

const {
  func,
  number,
  shape,
  string,
} = PropTypes

CellEditorOverlay.propTypes = {
  onCancel: func.isRequired,
  onSave: func.isRequired,
  cell: shape({}).isRequired,
  timeRange: shape({
    upper: string,
    lower: string,
  }).isRequired,
  autoRefresh: number.isRequired,
  source: shape({
    links: shape({
      proxy: string.isRequired,
      queries: string.isRequired,
    }).isRequired,
  }).isRequired,
  editQueryStatus: func.isRequired,
  queryStatus: shape({
    queryID: string,
    status: shape({}),
  }).isRequired,
}

export default CellEditorOverlay
<|endoftext|>


<commit_before>'use strict';
angular.module('genie.eventsMap')
.directive('chipmap', ['StylesService', 'mapService', 'ZoomLevel',
  function(StylesService, mapService, ZoomLevel) {

  function link(scope, elem, attrs) {
    var mapOptions = {
      zoom: +attrs.zoom || 5,
      styles: StylesService.dark
    };

    scope.map = new google.maps.Map(elem[0], mapOptions);
    scope.features = {heatmap: true};

    var zoomLevelObj = new ZoomLevel();
    zoomLevelObj.clusters = [];
    scope.zoomLevelObj = zoomLevelObj;

    mapService
    .getZoomLevel({zoom_level: 18, minutes_ago: 1440})
    .then(function(doc) {
      if (doc && doc.id) { // found a matching doc
        scope.zoomLevelObj = doc;
        scope.map.setCenter({lat: doc.center_lat,
          lng: doc.center_lng});
      } else {
        scope.map.setCenter({lat: 30.25, lng: -97.75}); // default Austin
      }
    });
  }

  return {
    restrict: 'E',
    replace: true,
    link: link,
    template: '
'
  };
}]);
<commit_msg>fix chipmap<commit_after>'use strict';
angular.module('genie.eventsMap')
.directive('chipmap', ['StylesService', 'mapService', 'ZoomLevel',
  function(StylesService, mapService, ZoomLevel) {

  function link(scope, elem, attrs) {
    var mapOptions = {
      zoom: +attrs.zoom || 5,
      styles: StylesService.dark
    };

    scope.map = new google.maps.Map(elem[0], mapOptions);
    scope.features = {heatmap: true};
    scope.clusters = [];

    mapService
    .getZoomLevel({zoom_level: 18, minutes_ago: 1440})
    .then(function(doc) {
      if (doc && doc.id) { // found a matching doc
        scope.clusters = doc.clusters;
        scope.map.setCenter({lat: doc.center_lat,
          lng: doc.center_lng});
      } else {
        scope.map.setCenter({lat: 30.25, lng: -97.75}); // default Austin
      }
    });
  }

  return {
    restrict: 'E',
    replace: true,
    link: link,
    template: '
'
  };
}]);
<|endoftext|>