<commit_before>'use strict';

const debug = require('debug')('enquirer');
const Emitter = require('component-emitter');
const utils = require('./lib/utils');

/**
 * Create an instance of `Enquirer` with the given `options`.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 * ```
 * @param {Object} `options`
 * @api public
 */

function Enquirer(options) {
  debug('initializing from <%s>', __filename);
  this.session = false;
  this.options = options || {};
  this.questions = {};
  this.prompts = {};
  this.answers = {};
  this.queue = [];
}

/**
 * Initialize Enquirer defaults
 */

Enquirer.prototype.init = function() {
  if (!this.prompts.hasOwnProperty('input')) {
    this.register('input', require('enquirer-prompt-input'));
  }

  this.UI = this.options.UI || utils.UI;
  this.ui = this.UI.create(this.options);
  this.ui.once('finish', function() {
    this.session = false;
    this.close = null;
    this.queue = [];
    this.emit('finish');
  }.bind(this));

  this.rl = this.ui.rl;
  this.finish = this.ui.finish.bind(this.ui);
  this.close = this.ui.close.bind(this.ui);
  this.emit('init', this);
};

/**
 * Lazily initialize Enquirer defaults
 */

Enquirer.prototype.lazyInit = function() {
  if (this.initialized) return;
  this.initialized = true;
  this.init();
};

/**
 * Register a new prompt `type` with the given `fn`.
 *
 * ```js
 * enquirer.register('confirm', require('enquirer-prompt-confirm'));
 * ```
 * @param {String} `type` The name of the prompt type
 * @param {Function} `fn` Prompt function that inherits from [prompt-base][].
 * @return {Object} Returns the Enquirer instance for chaining.
 * @api public
 */

Enquirer.prototype.register = function(type, PromptType) {
  if (utils.isObject(type)) {
    return this.visit('register', type);
  }
  this.prompts[type] = PromptType;
  return this;
};

/**
 * Invoke a plugin `fn`
 *
 * ```js
 * enquirer.use(require('some-enquirer-plugin'));
 * ```
 * @param {Function} `fn` Function that takes an instance of `Enquirer`
 * @return {Object} Returns the instance for chaining.
 * @api public
 */

Enquirer.prototype.use = function(fn) {
  fn.call(this, this);
  return this;
};

/**
 * Create question `name` with the given `message` and `options`.
 * Uses [enquirer-question][], visit that library for additional details.
 *
 * ```js
 * enquirer.question('color', 'What is your favorite color?');
 * enquirer.question('color', 'What is your favorite color?', {
 *   default: 'blue'
 * });
 * enquirer.question('color', {
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * enquirer.question({
 *   name: 'color',
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * enquirer.question({
 *   name: 'color',
 *   type: 'input', // "input" is the default prompt type and doesn't need to be specified
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * ```
 * @emits `question`
 * @param {String|Object} `name` Name or options object
 * @param {String|Object} `message` Message or options object
 * @param {Object} `options`
 * @return {Object} Returns the created question object
 * @api public
 */

Enquirer.prototype.question = function(name, message, options) {
  if (arguments.length === 1 && typeof name === 'string') {
    name = this.questions[name] || name;
  }

  var opts = utils.extend({}, this.options, options);
  var question = new utils.Question(name, message, opts);
  this.questions[question.name] = question;
  this.emit('question', question);
  return question;
};

/**
 * Enqueue one or more questions.
 *
 * @param {Object|Array|String} `questions`
 * @return {Array} Returns an array of question names
 */

Enquirer.prototype.enqueue = function(questions) {
  if (typeof questions === 'string') {
    questions = this.question(questions);
  }
  if (utils.isObject(questions)) {
    questions = [questions];
  }
  if (Array.isArray(questions)) {
    return (this.queue = questions);
  }
  this.queue = Object.keys(this.questions);
  return this.queue;
};

/**
 * Initialize a prompt session for one or more questions.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 *
 * enquirer.question('first', 'First name?');
 * enquirer.question('last', 'Last name?');
 *
 * enquirer.ask('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   });
 *
 * // errors
 * enquirer.ask('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   })
 *   .catch(function(err) {
 *     console.log(err)
 *   });
 * ```
 * @emits `ask` With the array of `questions` to be asked
 * @return {Array|Object} `questions` One or more question objects or names of registered questions.
 * @api public
 */

Enquirer.prototype.ask = function(questions) {
  this.lazyInit();
  var queue = this.enqueue(questions);
  var prompt = this.prompt.bind(this);
  var finish = this.finish.bind(this);
  this.session = true;

  // disable `finish` to prevent successive calls
  this.finish = utils.identity;
  function ask(acc, question) {
    return prompt(question);
  }

  this.emit('ask', queue);
  return Promise.resolve(queue)
    .then(utils.reduce(ask, this.answers))
    .then(finish());
};

/**
 * Initialize a prompt session for a single question. Used by the [ask](#ask) method.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 *
 * enquirer.question('first', 'First name?');
 * enquirer.prompt('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   });
 * ```
 * @emits `prompt` with the `default` value, `key`, `question` object, and `answers` object
 * @emits `answer` with the `answer` value, `key`, `question` object, and `answers` object
 * @param {String} `name`
 * @api public
 */

Enquirer.prototype.prompt = function(name) {
  if (Array.isArray(name)) {
    return this.ask.apply(this, arguments);
  }

  this.lazyInit();
  this.queue = this.queue || [name];
  var answers = this.answers;
  var self = this;

  try {
    var question = this.question(name).clone();
    var PromptType = this.prompts[question.type];
    var key = question.name;

    if (typeof PromptType !== 'function') {
      throw new Error(`prompt type "${question.type}" is not registered`);
    }

    var prompt = new PromptType(question, answers, this.ui);
    if (this.session) prompt.session = true;
    this.emit('prompt', question.default, question, answers, prompt);

    return prompt.run()
      .then(function(answer) {
        answers[key] = question.answer = answer;
        self.emit('answer', answer, key, question, answers);
        return answers;
      });

  } catch (err) {
    this.close();
    throw err;
  }
};

/**
 * Create a new `Separator` to use in a choices array.
 * @api public
 */

Enquirer.prototype.separator = function(options) {
  return new utils.Separator(options);
};

/**
 * Visit `method` over the properties in the given object, or map
 * visit over the object-elements in an array.
 *
 * @param {String} `method` The name of the `base` method to call.
 * @param {Object|Array} `val` The object or array to iterate over.
 * @return {Object} Returns the instance for chaining.
 */

Enquirer.prototype.visit = function(method, val) {
  utils.visit(this, method, val);
  return this;
};

/**
 * Create a new `Separator` to use in a choices array.
 * @api public
 */

Enquirer.Separator = utils.Separator;

/**
 * Decorate `Emitter` methods onto the Enquirer prototype
 */

Emitter(Enquirer.prototype);

/**
 * Expose `Enquirer`
 */

module.exports = Enquirer;
<commit_msg>don't automatically close the readline interface after asking a series of questions<commit_after>'use strict';

const debug = require('debug')('enquirer');
const Emitter = require('component-emitter');
const utils = require('./lib/utils');

/**
 * Create an instance of `Enquirer` with the given `options`.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 * ```
 * @param {Object} `options`
 * @api public
 */

function Enquirer(options) {
  debug('initializing from <%s>', __filename);
  this.session = false;
  this.options = options || {};
  this.questions = {};
  this.prompts = {};
  this.answers = {};
  this.queue = [];
}

/**
 * Initialize Enquirer defaults
 */

Enquirer.prototype.init = function() {
  if (!this.prompts.hasOwnProperty('input')) {
    this.register('input', require('enquirer-prompt-input'));
  }

  this.UI = this.options.UI || utils.UI;
  this.ui = this.UI.create(this.options);
  this.ui.once('finish', function() {
    this.session = false;
    this.close = null;
    this.queue = [];
    this.emit('finish');
  }.bind(this));

  this.rl = this.ui.rl;
  this.finish = this.ui.finish.bind(this.ui);
  this.close = this.ui.close.bind(this.ui);
  this.emit('init', this);
};

/**
 * Lazily initialize Enquirer defaults
 */

Enquirer.prototype.lazyInit = function() {
  if (this.initialized) return;
  this.initialized = true;
  this.init();
};

/**
 * Register a new prompt `type` with the given `fn`.
 *
 * ```js
 * enquirer.register('confirm', require('enquirer-prompt-confirm'));
 * ```
 * @param {String} `type` The name of the prompt type
 * @param {Function} `fn` Prompt function that inherits from [prompt-base][].
 * @return {Object} Returns the Enquirer instance for chaining.
 * @api public
 */

Enquirer.prototype.register = function(type, PromptType) {
  if (utils.isObject(type)) {
    return this.visit('register', type);
  }
  this.prompts[type] = PromptType;
  return this;
};

/**
 * Invoke a plugin `fn`
 *
 * ```js
 * enquirer.use(require('some-enquirer-plugin'));
 * ```
 * @param {Function} `fn` Function that takes an instance of `Enquirer`
 * @return {Object} Returns the instance for chaining.
 * @api public
 */

Enquirer.prototype.use = function(fn) {
  fn.call(this, this);
  return this;
};

/**
 * Create question `name` with the given `message` and `options`.
 * Uses [enquirer-question][], visit that library for additional details.
 *
 * ```js
 * enquirer.question('color', 'What is your favorite color?');
 * enquirer.question('color', 'What is your favorite color?', {
 *   default: 'blue'
 * });
 * enquirer.question('color', {
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * enquirer.question({
 *   name: 'color',
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * enquirer.question({
 *   name: 'color',
 *   type: 'input', // "input" is the default prompt type and doesn't need to be specified
 *   message: 'What is your favorite color?',
 *   default: 'blue'
 * });
 * ```
 * @emits `question`
 * @param {String|Object} `name` Name or options object
 * @param {String|Object} `message` Message or options object
 * @param {Object} `options`
 * @return {Object} Returns the created question object
 * @api public
 */

Enquirer.prototype.question = function(name, message, options) {
  if (arguments.length === 1 && typeof name === 'string') {
    name = this.questions[name] || name;
  }

  var opts = utils.extend({}, this.options, options);
  var question = new utils.Question(name, message, opts);
  this.questions[question.name] = question;
  this.emit('question', question);
  return question;
};

/**
 * Enqueue one or more questions.
 *
 * @param {Object|Array|String} `questions`
 * @return {Array} Returns an array of question names
 */

Enquirer.prototype.enqueue = function(questions) {
  if (typeof questions === 'string') {
    questions = this.question(questions);
  }
  if (utils.isObject(questions)) {
    questions = [questions];
  }
  if (Array.isArray(questions)) {
    return (this.queue = questions);
  }
  this.queue = Object.keys(this.questions);
  return this.queue;
};

/**
 * Initialize a prompt session for one or more questions.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 *
 * enquirer.question('first', 'First name?');
 * enquirer.question('last', 'Last name?');
 *
 * enquirer.ask('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   });
 *
 * // errors
 * enquirer.ask('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   })
 *   .catch(function(err) {
 *     console.log(err)
 *   });
 * ```
 * @emits `ask` With the array of `questions` to be asked
 * @return {Array|Object} `questions` One or more question objects or names of registered questions.
 * @api public
 */

Enquirer.prototype.ask = function(questions) {
  this.lazyInit();
  var queue = this.enqueue(questions);
  var prompt = this.prompt.bind(this);
  this.session = true;

  function ask(acc, question) {
    return prompt(question);
  }

  this.emit('ask', queue);
  return Promise.resolve(queue)
    .then(utils.reduce(ask, this.answers));
};

/**
 * Initialize a prompt session for a single question. Used by the [ask](#ask) method.
 *
 * ```js
 * var Enquirer = require('enquirer');
 * var enquirer = new Enquirer();
 *
 * enquirer.question('first', 'First name?');
 * enquirer.prompt('first')
 *   .then(function(answers) {
 *     console.log(answers)
 *   });
 * ```
 * @emits `prompt` with the `default` value, `key`, `question` object, and `answers` object
 * @emits `answer` with the `answer` value, `key`, `question` object, and `answers` object
 * @param {String} `name`
 * @api public
 */

Enquirer.prototype.prompt = function(name) {
  if (Array.isArray(name)) {
    return this.ask.apply(this, arguments);
  }

  this.lazyInit();
  this.queue = this.queue || [name];
  var answers = this.answers;
  var self = this;

  try {
    var question = this.question(name).clone();
    var PromptType = this.prompts[question.type];
    var key = question.name;

    if (typeof PromptType !== 'function') {
      throw new Error(`prompt type "${question.type}" is not registered`);
    }

    var prompt = new PromptType(question, answers, this.ui);
    if (this.session) prompt.session = true;
    this.emit('prompt', question.default, question, answers, prompt);

    return prompt.run()
      .then(function(answer) {
        answers[key] = question.answer = answer;
        self.emit('answer', answer, key, question, answers);
        return answers;
      });

  } catch (err) {
    this.close();
    throw err;
  }
};

/**
 * Create a new `Separator` to use in a choices array.
 * @api public
 */

Enquirer.prototype.separator = function(options) {
  return new utils.Separator(options);
};

/**
 * Visit `method` over the properties in the given object, or map
 * visit over the object-elements in an array.
 *
 * @param {String} `method` The name of the `base` method to call.
 * @param {Object|Array} `val` The object or array to iterate over.
 * @return {Object} Returns the instance for chaining.
 */

Enquirer.prototype.visit = function(method, val) {
  utils.visit(this, method, val);
  return this;
};

/**
 * Create a new `Separator` to use in a choices array.
 * @api public
 */

Enquirer.Separator = utils.Separator;

/**
 * Decorate `Emitter` methods onto the Enquirer prototype
 */

Emitter(Enquirer.prototype);

/**
 * Expose `Enquirer`
 */

module.exports = Enquirer;
<|endoftext|>


<commit_before>#!/usr/bin/env node
var login = require("facebook-chat-api"),
    fs = require('fs'),
    exec = require('child_process').exec;

var loginInfo = {appState: JSON.parse(fs.readFileSync("appstate.json"))};
var cds = [];
var lastDate = Date.now();
var lastMessage = "";

var directory = __dirname;
console.log(__dirname);
login(loginInfo,{logLevel: "silent"},function callback (err, api) {

    if(err) return console.error(err);
    console.log("Logged in.");
    // fs.writeFileSync('appstate.json', JSON.stringify(api.getAppState())); // save app state for future launches

    api.changeNickname("fbterm", api.getCurrentUserID(), api.getCurrentUserID(), function(err){});   // set user's message-to-self nickname to 'fbterm'
    api.sendMessage("@fbterm connected", api.getCurrentUserID());
    api.setOptions({selfListen: true});

    api.listen(function callback(err, message) {
    	if(message.senderID != message.threadID) // do not accept messages from group chats unless preceded by '/fbterm'
    	    if(message.body.startsWith("/fbterm"))
                message.body = message.body.substring(7);
            else
                return;

        if(message.senderID != api.getCurrentUserID()) // do not accept messages from other people
    	    return;

        if(message.body.startsWith("@fbterm"))	// do not accept messages that were sent by the bot
    	    return;

    	if(Date.now()-lastDate < 300 && lastMessage == message.body)	// prevent duplicate calls
	    return;
    	lastDate = Date.now();
	   lastMessage = message.body;
    	console.log("\nexecuting command @ "+Date.now());

        if(message.body.trim() == "cls" || message.body.trim() == "clear"){     // deletes thread (clears messages)
            api.sendMessage("@fbterm\nReload page to finish clearing thread.", message.threadID, function(err, messageInfo){
                api.deleteThread(message.threadID);
                api.sendMessage("@fbterm :)", message.threadID);
            });
            return;
        }

         if(message.body.toLowerCase().startsWith("sendfile ")){
            var filename = message.body.substring(9).trim();
            console.log("Attempting to send file: "+filename);
            fs.stat(directory+"/"+filename, function(err, stat) { //check if file exists
                if(err == null) {
                    api.sendMessage({body: "@fbterm "+filename, attachment: fs.createReadStream(directory+"/"+filename)}, message.threadID);
                    console.log('File exists');
                } else if(err.code == 'ENOENT') {
                    api.sendMessage("@fbterm ERR:\nFile "+filename+" not found.", message.threadID);
                } else {
                    console.log('Some other error: ', err.code);
                }
            });
            return;
        }

    	if(message.body.trim().startsWith("cd")){
            var success = true;
            var relativeDir = message.body.trim().substring(2).trim();
            if(relativeDir == ".."){
                directory = directory.substring(0, directory.lastIndexOf("\\"));
            }
            else if(relativeDir != "."){
                try{
                    var stat = fs.statSync(directory+"\\"+relativeDir);
                    if(stat.isDirectory()){
                        directory+="\\"+relativeDir;
                    }else{
                        success = false;
                    }
                }catch(e){
                    success = false;
                }
            }
            if(success){
                api.sendMessage("@fbterm\n"+directory, message.threadID);
                console.log("cwd: "+directory);
            }else{
                api.sendMessage("@fbterm\nThe system could not find the path specified.", message.threadID);
            }
            return;
    		/*console.log(message.body);
    		cds.push(message.body+" && ");
            var command = "";
            for(var i = 0; i < cds.length; i++)
                command+=cds[i];
            command+="pwd";
            exec(command, function(error, stdout, stderr){
                api.sendMessage("@fbterm\n"+stdout, message.threadID);
            });
            return;*/
    	}

    	var command = "";
    	for(var i = 0; i < cds.length; i++)
    		command+=cds[i];
    	command+=message.body;
    	console.log(command);

    	exec(command, {
            cwd: directory
        }, function(error, stdout, stderr){
            // stdout = stdout.replace(/\./g, ",");     // replaces periods with commas to prevent fb bot detection
    		if(error)
    			api.sendMessage("@fbterm ERR:\n"+error, message.threadID);
    		else{
	    		api.sendMessage("@fbterm\n"+stdout+"\n"+stderr, message.threadID);

	    		console.log("\nexecuted command: "+command+"\n"+stdout+"\n\n");
	    	}
    	});

    });
});
<commit_msg>Improved cd handling using 'path' module<commit_after>#!/usr/bin/env node
var login = require("facebook-chat-api"),
    fs = require('fs'),
    exec = require('child_process').exec,
    path = require('path');

var loginInfo = {appState: JSON.parse(fs.readFileSync("appstate.json"))};
var cds = [];
var lastDate = Date.now();
var lastMessage = "";

var directory = __dirname;
console.log(__dirname);
login(loginInfo,{logLevel: "silent"},function callback (err, api) {

    if(err) return console.error(err);
    console.log("Logged in.");
    // fs.writeFileSync('appstate.json', JSON.stringify(api.getAppState())); // save app state for future launches

    api.changeNickname("fbterm", api.getCurrentUserID(), api.getCurrentUserID(), function(err){});   // set user's message-to-self nickname to 'fbterm'
    api.sendMessage("@fbterm connected", api.getCurrentUserID());
    api.setOptions({selfListen: true});

    api.listen(function callback(err, message) {
    	if(message.senderID != message.threadID) // do not accept messages from group chats unless preceded by '/fbterm'
    	    if(message.body.startsWith("/fbterm"))
                message.body = message.body.substring(7);
            else
                return;

        if(message.senderID != api.getCurrentUserID()) // do not accept messages from other people
    	    return;

        if(message.body.startsWith("@fbterm"))	// do not accept messages that were sent by the bot
    	    return;

    	if(lastMessage == message.body){	// prevent duplicate calls
            lastMessage = "";
	       return;
       }
    	lastDate = Date.now();
	   lastMessage = message.body;
    	console.log("\nexecuting command @ "+Date.now());

        if(message.body.trim() == "cls" || message.body.trim() == "clear"){     // deletes thread (clears messages)
            api.sendMessage("@fbterm\nReload page to finish clearing thread.", message.threadID, function(err, messageInfo){
                api.deleteThread(message.threadID);
                api.sendMessage("@fbterm :)", message.threadID);
            });
            return;
        }

         if(message.body.toLowerCase().startsWith("sendfile ")){
            var filename = message.body.substring(9).trim();
            console.log("Attempting to send file: "+filename);
            fs.stat(directory+"/"+filename, function(err, stat) { //check if file exists
                if(err == null) {
                    api.sendMessage({body: "@fbterm "+filename, attachment: fs.createReadStream(directory+"/"+filename)}, message.threadID);
                    console.log('File exists');
                } else if(err.code == 'ENOENT') {
                    api.sendMessage("@fbterm ERR:\nFile "+filename+" not found.", message.threadID);
                } else {
                    console.log('Some other error: ', err.code);
                }
            });
            return;
        }

    	if(message.body.trim().startsWith("cd")){
            var success = false;
            var relativeDir = message.body.trim().substring(2).trim();
            try{
                var stat = fs.statSync(path.join(directory, relativeDir));
                if(stat.isDirectory()){
                    directory = path.join(directory, relativeDir);
                    success = true;
                }
            }catch(e){}
            if(success){
                api.sendMessage("@fbterm\n"+directory, message.threadID);
                console.log("cwd: "+directory);
            }else{
                api.sendMessage("@fbterm\nThe system could not find the path specified.", message.threadID);
            }
            return;
    		/*console.log(message.body);
    		cds.push(message.body+" && ");
            var command = "";
            for(var i = 0; i < cds.length; i++)
                command+=cds[i];
            command+="pwd";
            exec(command, function(error, stdout, stderr){
                api.sendMessage("@fbterm\n"+stdout, message.threadID);
            });
            return;*/
    	}

    	var command = "";
    	for(var i = 0; i < cds.length; i++)
    		command+=cds[i];
    	command+=message.body;
    	console.log(command);

    	exec(command, {
            cwd: directory
        }, function(error, stdout, stderr){
            // stdout = stdout.replace(/\./g, ",");     // replaces periods with commas to prevent fb bot detection
    		if(error)
    			api.sendMessage("@fbterm ERR:\n"+error, message.threadID);
    		else{
	    		api.sendMessage("@fbterm\n"+stdout+"\n"+stderr, message.threadID);

	    		console.log("\nexecuted command: "+command+"\n"+stdout+"\n\n");
	    	}
    	});

    });
});
<|endoftext|>


<commit_before>module.exports = {
  "parser": "babel-eslint",
  "extends": [
    "airbnb",
    "plugin:flowtype/recommended"
  ],
  "env": {
    "node": true,
    "es6": true,
    "commonjs": true,
    "mocha": true
  },
  "rules": {
    "arrow-body-style": 0,
    "padded-blocks": 0,
    "comma-dangle": 0,
    "react/jsx-boolean-value": 0,
    "max-len": [2, 200],
    "no-underscore-dangle": ["error", { "allow": ["_id", "__v"] }],
    "flowtype",
  },
  parserOptions: {
    ecmaFeatures: {
      experimentalObjectRestSpread: true,
      "arrow-body-style": 0,
      "padded-blocks": 0,
      "comma-dangle": 0,
      "react/jsx-boolean-value": 0,
      "max-len": [2, 200],
      "no-use-before-define": 0,
      "react/sort-comp": 0,
      "no-shadow": 0,
      "dot-notation": 0,
      "no-underscore-dangle": 0,
      "import/no-unresolved": 0,
      "flowtype/boolean-style": [ 2, "boolean" ],
      "flowtype/define-flow-type": 1,
      "flowtype/delimiter-dangle": [ 2, "never" ],
      "flowtype/generic-spacing": [ 2, "never" ],
      "flowtype/no-primitive-constructor-types": 2,
      "flowtype/no-weak-types": 2,
      "flowtype/object-type-delimiter": [ 2,  "comma" ],
      "flowtype/require-parameter-type": 2,
      "flowtype/require-return-type": [ 2,  "always", { "annotateUndefined": "never" } ],
      "flowtype/require-valid-file-annotation": [ 2, "always", { "annotationStyle": "line" }],
      "flowtype/semi": [ 2,  "always" ],
      "flowtype/space-after-type-colon": [ 2,  "always" ],
      "flowtype/space-before-generic-bracket": [ 2, "never" ],
      "flowtype/space-before-type-colon": [ 2, "never" ],
      "flowtype/type-id-match": [ 2, "^([A-Z][a-z0-9]+)+Type$" ],
      "flowtype/union-intersection-spacing": [ 2, "always" ],
      "flowtype/use-flow-type": 1,
      "flowtype/valid-syntax": 1
    }
  },
  "settings": {
    "flowtype": {
      "onlyFilesWithFlowAnnotation": false
    }
  }
}
<commit_msg>added plugins<commit_after>module.exports = {
  "parser": "babel-eslint",
  "extends": [
    "airbnb",
    "plugin:flowtype/recommended"
  ],
  "env": {
    "node": true,
    "es6": true,
    "commonjs": true,
    "mocha": true
  },
  "plugins": [
    "flowtype"
    "jsx-a11y",
    "flowtype"
  ],
  "rules": {
    "arrow-body-style": 0,
    "padded-blocks": 0,
    "comma-dangle": 0,
    "react/jsx-boolean-value": 0,
    "max-len": [2, 200],
    "no-underscore-dangle": ["error", { "allow": ["_id", "__v"] }],
  },
  parserOptions: {
    ecmaFeatures: {
      experimentalObjectRestSpread: true,
      "arrow-body-style": 0,
      "padded-blocks": 0,
      "comma-dangle": 0,
      "react/jsx-boolean-value": 0,
      "max-len": [2, 200],
      "no-use-before-define": 0,
      "react/sort-comp": 0,
      "no-shadow": 0,
      "dot-notation": 0,
      "no-underscore-dangle": 0,
      "import/no-unresolved": 0,
      "flowtype/boolean-style": [ 2, "boolean" ],
      "flowtype/define-flow-type": 1,
      "flowtype/delimiter-dangle": [ 2, "never" ],
      "flowtype/generic-spacing": [ 2, "never" ],
      "flowtype/no-primitive-constructor-types": 2,
      "flowtype/no-weak-types": 2,
      "flowtype/object-type-delimiter": [ 2,  "comma" ],
      "flowtype/require-parameter-type": 2,
      "flowtype/require-return-type": [ 2,  "always", { "annotateUndefined": "never" } ],
      "flowtype/require-valid-file-annotation": [ 2, "always", { "annotationStyle": "line" }],
      "flowtype/semi": [ 2,  "always" ],
      "flowtype/space-after-type-colon": [ 2,  "always" ],
      "flowtype/space-before-generic-bracket": [ 2, "never" ],
      "flowtype/space-before-type-colon": [ 2, "never" ],
      "flowtype/type-id-match": [ 2, "^([A-Z][a-z0-9]+)+Type$" ],
      "flowtype/union-intersection-spacing": [ 2, "always" ],
      "flowtype/use-flow-type": 1,
      "flowtype/valid-syntax": 1
    }
  },
  "settings": {
    "flowtype": {
      "onlyFilesWithFlowAnnotation": false
    }
  }
}
<|endoftext|>


<commit_before>
var newUid = require("./lib/uniqueid.js")

var on = require("./lib/events/on.js")
// var off = require("./lib/events/on.js")
var trigger = require("./lib/events/trigger.js")

var Pjax = function(options) {
    this.firstrun = true

    var parseOptions = require("./lib/proto/parse-options.js");
    parseOptions.apply(this,[options])
    this.log("Pjax options", this.options)

    this.maxUid = this.lastUid = newUid()

    this.parseDOM(document)

    on(window, "popstate", function(st) {
      if (st.state) {
        var opt = Pjax.clone(this.options)
        opt.url = st.state.url
        opt.title = st.state.title
        opt.history = false

        if (st.state.uid < this.lastUid) {
          opt.backward = true
        }
        else {
          opt.forward = true
        }
        this.lastUid = st.state.uid

        // @todo implement history cache here, based on uid
        this.loadUrl(st.state.url, opt)
      }
    }.bind(this))
  }

Pjax.prototype = {
  log: require("./lib/proto/log.js"),

  getElements: require("./lib/proto/get-elements.js"),

  parseDOM: require("./lib/proto/parse-dom.js"),

  refresh: require("./lib/proto/refresh.js"),

  attachLink: require("./lib/proto/attach-link.js"),

  forEachSelectors: function(cb, context, DOMcontext) {
    return require("./lib/foreach-selectors.js")(this.options.selectors, cb, context, DOMcontext)
  },

  switchSelectors: function(selectors, fromEl, toEl, options) {
    return require("./lib/switches-selectors.js")(this.options.switches, this.options.switchesOptions, selectors, fromEl, toEl, options)
  },

  // too much problem with the code below
  // + it’s too dangerous
//   switchFallback: function(fromEl, toEl) {
//     this.switchSelectors(["head", "body"], fromEl, toEl)
//     // execute script when DOM is like it should be
//     Pjax.executeScripts(document.querySelector("head"))
//     Pjax.executeScripts(document.querySelector("body"))
//   }

  latestChance: function(href) {
    window.location = href
  },

  onSwitch: function() {
    trigger(window, "resize scroll")
  },

  loadContent: function(html, options) {
    var tmpEl = document.implementation.createHTMLDocument()

    // parse HTML attributes to copy them
    // since we are forced to use documentElement.innerHTML (outerHTML can't be used for <html>)
    var htmlRegex = /<html[^>]+>/gi
    var htmlAttribsRegex = /\s?[a-z:]+(?:\=(?:\'|\")[^\'\">]+(?:\'|\"))*/gi
    var matches = html.match(htmlRegex)
    if (matches && matches.length) {
      matches = matches[0].match(htmlAttribsRegex)
      if (matches.length) {
        matches.shift()
        matches.forEach(function(htmlAttrib) {
          var attr = htmlAttrib.trim().split("=")
          tmpEl.documentElement.setAttribute(attr[0], attr[1].slice(1, -1))
        })
      }
    }

    tmpEl.documentElement.innerHTML = html
    this.log("load content", tmpEl.documentElement.attributes, tmpEl.documentElement.innerHTML.length)

    // Clear out any focused controls before inserting new page contents.
    // we clear focus on non form elements
    if (document.activeElement && !document.activeElement.value) {
      try {
        document.activeElement.blur()
      } catch (e) { }
    }

    // try {
    this.switchSelectors(this.options.selectors, tmpEl, document, options)

    // FF bug: Won’t autofocus fields that are inserted via JS.
    // This behavior is incorrect. So if theres no current focus, autofocus
    // the last field.
    //
    // http://www.w3.org/html/wg/drafts/html/master/forms.html
    var autofocusEl = Array.prototype.slice.call(document.querySelectorAll("[autofocus]")).pop()
    if (autofocusEl && document.activeElement !== autofocusEl) {
      autofocusEl.focus();
    }

    // execute scripts when DOM have been completely updated
    this.options.selectors.forEach(function(selector) {
      Pjax.forEachEls(document.querySelectorAll(selector), function(el) {
        Pjax.executeScripts(el)
      })
    })
    // }
    // catch(e) {
    //   if (this.options.debug) {
    //     this.log("Pjax switch fail: ", e)
    //   }
    //   this.switchFallback(tmpEl, document)
    // }
  },

  doRequest: require("./lib/request.js"),

  loadUrl: function(href, options) {
    this.log("load href", href, options)

    trigger(document, "pjax:send", options);

    // Do the request
    this.doRequest(href, function(html) {
      // Fail if unable to load HTML via AJAX
      if (html === false) {
        trigger(document,"pjax:complete pjax:error", options)

        return
      }

      // Clear out any focused controls before inserting new page contents.
      document.activeElement.blur()

      try {
        this.loadContent(html, options)
      }
      catch (e) {
        if (!this.options.debug) {
          if (console && console.error) {
            console.error("Pjax switch fail: ", e)
          }
          this.latestChance(href)
          return
        }
        else {
          throw e
        }
      }

      if (options.history) {
        if (this.firstrun) {
          this.lastUid = this.maxUid = newUid()
          this.firstrun = false
          window.history.replaceState({
            url: window.location.href,
            title: document.title,
            uid: this.maxUid
          },
          document.title)
        }

        // Update browser history
        this.lastUid = this.maxUid = newUid()
        window.history.pushState({
          url: href,
          title: options.title,
          uid: this.maxUid
        },
          options.title,
          href)
      }

      this.forEachSelectors(function(el) {
        this.parseDOM(el)
      }, this)

      // Fire Events
      trigger(document,"pjax:complete pjax:success", options)

      options.analytics()

      // Scroll page to top on new page load
      if (options.scrollTo !== false) {
        if (options.scrollTo.length > 1) {
          window.scrollTo(options.scrollTo[0], options.scrollTo[1])
        }
        else {
          window.scrollTo(0, options.scrollTo)
        }
      }
    }.bind(this))
  }
}

Pjax.isSupported = require("./lib/is-supported.js");

//arguably could do `if( require("./lib/is-supported.js")()) {` but that might be a little to simple
if (Pjax.isSupported()) {
  module.exports = Pjax
}
// if there isn’t required browser functions, returning stupid api
else {
  var stupidPjax = function() {}
  for (var key in Pjax.prototype) {
    if (Pjax.prototype.hasOwnProperty(key) && typeof Pjax.prototype[key] === "function") {
      stupidPjax[key] = stupidPjax
    }
  }

  module.exports = stupidPjax
}
<commit_msg>Bind required functions to pjax<commit_after>
var newUid = require("./lib/uniqueid.js")

var on = require("./lib/events/on.js")
// var off = require("./lib/events/on.js")
var trigger = require("./lib/events/trigger.js")

var Pjax = function(options) {
    this.firstrun = true

    var parseOptions = require("./lib/proto/parse-options.js");
    parseOptions.apply(this,[options])
    this.log("Pjax options", this.options)

    this.maxUid = this.lastUid = newUid()

    this.parseDOM(document)

    on(window, "popstate", function(st) {
      if (st.state) {
        var opt = Pjax.clone(this.options)
        opt.url = st.state.url
        opt.title = st.state.title
        opt.history = false

        if (st.state.uid < this.lastUid) {
          opt.backward = true
        }
        else {
          opt.forward = true
        }
        this.lastUid = st.state.uid

        // @todo implement history cache here, based on uid
        this.loadUrl(st.state.url, opt)
      }
    }.bind(this))
  }

Pjax.prototype = {
  log: require("./lib/proto/log.js"),

  getElements: require("./lib/proto/get-elements.js"),

  parseDOM: require("./lib/proto/parse-dom.js"),

  refresh: require("./lib/proto/refresh.js"),

  attachLink: require("./lib/proto/attach-link.js"),

  forEachSelectors: function(cb, context, DOMcontext) {
    return require("./lib/foreach-selectors.js").bind(this)(this.options.selectors, cb, context, DOMcontext)
  },

  switchSelectors: function(selectors, fromEl, toEl, options) {
    return require("./lib/switches-selectors.js").bind(this)(this.options.switches, this.options.switchesOptions, selectors, fromEl, toEl, options)
  },

  // too much problem with the code below
  // + it’s too dangerous
//   switchFallback: function(fromEl, toEl) {
//     this.switchSelectors(["head", "body"], fromEl, toEl)
//     // execute script when DOM is like it should be
//     Pjax.executeScripts(document.querySelector("head"))
//     Pjax.executeScripts(document.querySelector("body"))
//   }

  latestChance: function(href) {
    window.location = href
  },

  onSwitch: function() {
    trigger(window, "resize scroll")
  },

  loadContent: function(html, options) {
    var tmpEl = document.implementation.createHTMLDocument()

    // parse HTML attributes to copy them
    // since we are forced to use documentElement.innerHTML (outerHTML can't be used for <html>)
    var htmlRegex = /<html[^>]+>/gi
    var htmlAttribsRegex = /\s?[a-z:]+(?:\=(?:\'|\")[^\'\">]+(?:\'|\"))*/gi
    var matches = html.match(htmlRegex)
    if (matches && matches.length) {
      matches = matches[0].match(htmlAttribsRegex)
      if (matches.length) {
        matches.shift()
        matches.forEach(function(htmlAttrib) {
          var attr = htmlAttrib.trim().split("=")
          tmpEl.documentElement.setAttribute(attr[0], attr[1].slice(1, -1))
        })
      }
    }

    tmpEl.documentElement.innerHTML = html
    this.log("load content", tmpEl.documentElement.attributes, tmpEl.documentElement.innerHTML.length)

    // Clear out any focused controls before inserting new page contents.
    // we clear focus on non form elements
    if (document.activeElement && !document.activeElement.value) {
      try {
        document.activeElement.blur()
      } catch (e) { }
    }

    // try {
    this.switchSelectors(this.options.selectors, tmpEl, document, options)

    // FF bug: Won’t autofocus fields that are inserted via JS.
    // This behavior is incorrect. So if theres no current focus, autofocus
    // the last field.
    //
    // http://www.w3.org/html/wg/drafts/html/master/forms.html
    var autofocusEl = Array.prototype.slice.call(document.querySelectorAll("[autofocus]")).pop()
    if (autofocusEl && document.activeElement !== autofocusEl) {
      autofocusEl.focus();
    }

    // execute scripts when DOM have been completely updated
    this.options.selectors.forEach(function(selector) {
      Pjax.forEachEls(document.querySelectorAll(selector), function(el) {
        Pjax.executeScripts(el)
      })
    })
    // }
    // catch(e) {
    //   if (this.options.debug) {
    //     this.log("Pjax switch fail: ", e)
    //   }
    //   this.switchFallback(tmpEl, document)
    // }
  },

  doRequest: require("./lib/request.js"),

  loadUrl: function(href, options) {
    this.log("load href", href, options)

    trigger(document, "pjax:send", options);

    // Do the request
    this.doRequest(href, function(html) {
      // Fail if unable to load HTML via AJAX
      if (html === false) {
        trigger(document,"pjax:complete pjax:error", options)

        return
      }

      // Clear out any focused controls before inserting new page contents.
      document.activeElement.blur()

      try {
        this.loadContent(html, options)
      }
      catch (e) {
        if (!this.options.debug) {
          if (console && console.error) {
            console.error("Pjax switch fail: ", e)
          }
          this.latestChance(href)
          return
        }
        else {
          throw e
        }
      }

      if (options.history) {
        if (this.firstrun) {
          this.lastUid = this.maxUid = newUid()
          this.firstrun = false
          window.history.replaceState({
            url: window.location.href,
            title: document.title,
            uid: this.maxUid
          },
          document.title)
        }

        // Update browser history
        this.lastUid = this.maxUid = newUid()
        window.history.pushState({
          url: href,
          title: options.title,
          uid: this.maxUid
        },
          options.title,
          href)
      }

      this.forEachSelectors(function(el) {
        this.parseDOM(el)
      }, this)

      // Fire Events
      trigger(document,"pjax:complete pjax:success", options)

      options.analytics()

      // Scroll page to top on new page load
      if (options.scrollTo !== false) {
        if (options.scrollTo.length > 1) {
          window.scrollTo(options.scrollTo[0], options.scrollTo[1])
        }
        else {
          window.scrollTo(0, options.scrollTo)
        }
      }
    }.bind(this))
  }
}

Pjax.isSupported = require("./lib/is-supported.js");

//arguably could do `if( require("./lib/is-supported.js")()) {` but that might be a little to simple
if (Pjax.isSupported()) {
  module.exports = Pjax
}
// if there isn’t required browser functions, returning stupid api
else {
  var stupidPjax = function() {}
  for (var key in Pjax.prototype) {
    if (Pjax.prototype.hasOwnProperty(key) && typeof Pjax.prototype[key] === "function") {
      stupidPjax[key] = stupidPjax
    }
  }

  module.exports = stupidPjax
}
<|endoftext|>


<commit_before>'use strict'

const strToStream = require('string-to-stream')
const spawn = require('child_process').spawn
const through = require('through2')
const fse = require('fs-extra')
const temp = require('temp')
const path = require('path')
const fs = require('fs')

/**
 * Generates a PDF stream from a LaTeX document.
 *
 * @param {String} src - The LaTeX document.
 * @param {Object} options - Optional compilation specifications.
 *
 * @return {DestroyableTransform}
 */
function latex(src, options) {
  const outputStream = through()

  /**
   * Emits the given error to the returned output stream.
   */
  const handleErrors = (err) => {
    outputStream.emit('error', err)
    outputStream.destroy()
  }

  /**
   * Emits errors from logs to output stream, and also gives full log to user if requested.
   */
  const printErrors = (tempPath, userLogPath) => {
    const errorLogPath = path.join(tempPath, 'texput.log')
    const errorLogStream = fs.createReadStream(errorLogPath)

    if (userLogPath) {
      const userLogStream = fs.createWriteStream(userLogPath)
      errorLogStream.pipe(userLogStream)
    }

    const errors = []

    errorLogStream.on('data', (data) => {
      const lines = data.toString().split('\n')

      lines.forEach((line, i) => {
        if (line.startsWith('! Undefined control sequence.')) {
          errors.push(lines[i - 1])
          errors.push(lines[i])
          errors.push(lines[i + 1])
        } else if (line.startsWith('!')) {
          errors.push(line)
        }
      })
    })

    errorLogStream.on('end', () => {
      const errMessage = `LaTeX Syntax Error\n${errors.join('\n')}`
      const error = new Error(errMessage)

      outputStream.emit('error', error)
    })
  }

  temp.mkdir('node-latex', (err, tempPath) => {
    if (err) {
      handleErrors(err)
    }

    let inputStream

    if (!src) {
      handleErrors(new Error('Error: No TeX document provided.'))
    }

    if (typeof src === 'string') {
      inputStream = strToStream(src)
    } else if (src.pipe) {
      inputStream = src
    } else {
      handleErrors(new Error('Error: Invalid TeX document.'))
    }

    options = options || {}

    // The path(s) to your TEXINPUTS.
    const inputs = options.inputs || tempPath

    // The path(s) to your font inputs for fontspec.
    const fonts = options.fonts || tempPath

    // The binary command to run (`pdflatex`, `xetex`, etc).
    const cmd = options.cmd || 'pdflatex'

    // The number of times to run LaTeX.
    const passes = options.passes || 1

    // The path to where the user wants to save the error log file to.
    const userLogPath = options.errorLogs

    // The current amount of times LaTeX has run so far.
    let completedPasses = 0

    if (passes > 1 && typeof src !== 'string') {
      const msg = 'Error: You can\'t process a stream twice. Pass a string to use multiple passes.'
      handleErrors(new Error(msg))

      return
    }

    /**
     * Combines all paths into a single PATH to be added to process.env.
     */
    const joinPaths = inputs =>
      Array.isArray(inputs)
        ? `${inputs.join(':')}:`
        : `${inputs}:`

    const args = [
      '-halt-on-error'
    ]

    const opts = {
      cwd: tempPath,
      env: Object.assign({}, process.env, {
        TEXINPUTS: joinPaths(inputs),
        TTFONTS: joinPaths(fonts),
        OPENTYPEFONTS: joinPaths(fonts)
      })
    }

    /**
     * Runs a LaTeX child process on the document stream
     * and then decides whether it needs to do it again.
     */
    const runLatex = (inputStream) => {
      const tex = spawn(cmd, args, opts)

      inputStream.pipe(tex.stdin)

      // Prevent Node from crashing on compilation error.
      tex.stdin.on('error', handleErrors)

      tex.on('error', () => {
        handleErrors(new Error(`Error: Unable to run ${cmd} command.`))
      })

      tex.on('exit', (code) => {
        if (code !== 0) {
          printErrors(tempPath, userLogPath)
          return
        }

        completedPasses++

        // Schedule another run if necessary.
        completedPasses >= passes
          ? returnDocument()
          : runLatex(strToStream(src))
      })
    }

    /**
     * Returns the PDF stream after the final run.
     */
    const returnDocument = () => {
      const pdfPath = path.join(tempPath, 'texput.pdf')
      const pdfStream = fs.createReadStream(pdfPath)

      pdfStream.pipe(outputStream)
      pdfStream.on('close', () => fse.removeSync(tempPath))
    }

    // Start the first run.
    runLatex(inputStream)
  })

  return outputStream
}

module.exports = latex
<commit_msg>handle errors when trying to read pdf stream<commit_after>'use strict'

const strToStream = require('string-to-stream')
const spawn = require('child_process').spawn
const through = require('through2')
const fse = require('fs-extra')
const temp = require('temp')
const path = require('path')
const fs = require('fs')

/**
 * Generates a PDF stream from a LaTeX document.
 *
 * @param {String} src - The LaTeX document.
 * @param {Object} options - Optional compilation specifications.
 *
 * @return {DestroyableTransform}
 */
function latex(src, options) {
  const outputStream = through()

  /**
   * Emits the given error to the returned output stream.
   */
  const handleErrors = (err) => {
    outputStream.emit('error', err)
    outputStream.destroy()
  }

  /**
   * Emits errors from logs to output stream, and also gives full log to user if requested.
   */
  const printErrors = (tempPath, userLogPath) => {
    const errorLogPath = path.join(tempPath, 'texput.log')
    const errorLogStream = fs.createReadStream(errorLogPath)

    if (userLogPath) {
      const userLogStream = fs.createWriteStream(userLogPath)
      errorLogStream.pipe(userLogStream)
    }

    const errors = []

    errorLogStream.on('data', (data) => {
      const lines = data.toString().split('\n')

      lines.forEach((line, i) => {
        if (line.startsWith('! Undefined control sequence.')) {
          errors.push(lines[i - 1])
          errors.push(lines[i])
          errors.push(lines[i + 1])
        } else if (line.startsWith('!')) {
          errors.push(line)
        }
      })
    })

    errorLogStream.on('end', () => {
      const errMessage = `LaTeX Syntax Error\n${errors.join('\n')}`
      const error = new Error(errMessage)

      outputStream.emit('error', error)
    })
  }

  temp.mkdir('node-latex', (err, tempPath) => {
    if (err) {
      handleErrors(err)
    }

    let inputStream

    if (!src) {
      handleErrors(new Error('Error: No TeX document provided.'))
    }

    if (typeof src === 'string') {
      inputStream = strToStream(src)
    } else if (src.pipe) {
      inputStream = src
    } else {
      handleErrors(new Error('Error: Invalid TeX document.'))
    }

    options = options || {}

    // The path(s) to your TEXINPUTS.
    const inputs = options.inputs || tempPath

    // The path(s) to your font inputs for fontspec.
    const fonts = options.fonts || tempPath

    // The binary command to run (`pdflatex`, `xetex`, etc).
    const cmd = options.cmd || 'pdflatex'

    // The number of times to run LaTeX.
    const passes = options.passes || 1

    // The path to where the user wants to save the error log file to.
    const userLogPath = options.errorLogs

    // The current amount of times LaTeX has run so far.
    let completedPasses = 0

    if (passes > 1 && typeof src !== 'string') {
      const msg = 'Error: You can\'t process a stream twice. Pass a string to use multiple passes.'
      handleErrors(new Error(msg))

      return
    }

    /**
     * Combines all paths into a single PATH to be added to process.env.
     */
    const joinPaths = inputs =>
      Array.isArray(inputs)
        ? `${inputs.join(':')}:`
        : `${inputs}:`

    const args = [
      '-halt-on-error'
    ]

    const opts = {
      cwd: tempPath,
      env: Object.assign({}, process.env, {
        TEXINPUTS: joinPaths(inputs),
        TTFONTS: joinPaths(fonts),
        OPENTYPEFONTS: joinPaths(fonts)
      })
    }

    /**
     * Runs a LaTeX child process on the document stream
     * and then decides whether it needs to do it again.
     */
    const runLatex = (inputStream) => {
      const tex = spawn(cmd, args, opts)

      inputStream.pipe(tex.stdin)

      // Prevent Node from crashing on compilation error.
      tex.stdin.on('error', handleErrors)

      tex.on('error', () => {
        handleErrors(new Error(`Error: Unable to run ${cmd} command.`))
      })

      tex.on('exit', (code) => {
        if (code !== 0) {
          printErrors(tempPath, userLogPath)
          return
        }

        completedPasses++

        // Schedule another run if necessary.
        completedPasses >= passes
          ? returnDocument()
          : runLatex(strToStream(src))
      })
    }

    /**
     * Returns the PDF stream after the final run.
     */
    const returnDocument = () => {
      const pdfPath = path.join(tempPath, 'texput.pdf')
      const pdfStream = fs.createReadStream(pdfPath)

      pdfStream.pipe(outputStream)
      pdfStream.on('close', () => fse.removeSync(tempPath))
      pdfStream.on('error', handleErrors)
    }

    // Start the first run.
    runLatex(inputStream)
  })

  return outputStream
}

module.exports = latex
<|endoftext|>


<commit_before>'use strict';

var cp = require('child_process');
var path = require('path');
var fs = require('fs');
var os = require('os');

module.exports = function(input, output, cb) {
  var suffix = '-new';
  var pngdefryBinPath;

  // Darwin
  // Linux
  // Windows_NT
  if (os.type() === 'Darwin') {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'osx', 'pngdefry');
  } else if (os.type() === 'Linux') {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'linux', 'pngdefry');
  } else {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'windows', 'pngdefry');
  }

  var newOutput = getNewOutput(output);
  var outputFileName = getOutputFileName(input, newOutput);

  convert(input, newOutput, outputFileName, function(err) {
    if (err) {
      cb(err);
    }

    cb(null);
  });

  // /////////////////////////////
  function getNewOutput(output) {
    var arr = output.split(path.sep);
    arr.pop();
    return arr.join(path.sep);
  }

  function getOutputFileName(input, newOutput) {
    var inputArr = input.split(path.sep);
    var originFileName = inputArr[inputArr.length - 1];
    var outputFileName = path.join(newOutput, originFileName.replace(/\.png$/, suffix + '.png'));
    return outputFileName;
  }

  function convert(input, newOutput, outputFileName, cb) {
    var pd = cp.spawn(pngdefryBinPath, ['-s', suffix, '-o', newOutput, input]);

    pd.stdout.on('data', function(data) {
      console.log(data.toString());
    });

    pd.on('exit', function(code) {
      if (code !== 0) {
        return cb('convert fail');
      }

      fs.renameSync(outputFileName, output);
      cb(null);
    });

  }

};
<commit_msg>change suffix<commit_after>'use strict';

var cp = require('child_process');
var path = require('path');
var fs = require('fs');
var os = require('os');

module.exports = function(input, output, cb) {
  var suffix = '-' + Date.now() + '-pngdefry';
  var pngdefryBinPath;

  // Darwin
  // Linux
  // Windows_NT
  if (os.type() === 'Darwin') {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'osx', 'pngdefry');
  } else if (os.type() === 'Linux') {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'linux', 'pngdefry');
  } else {
    pngdefryBinPath = path.join(__dirname, 'pngdefry', 'bin', 'windows', 'pngdefry');
  }

  var newOutput = getNewOutput(output);
  var outputFilePath = getOutputFilePath(input, newOutput);

  convert(input, newOutput, outputFilePath, function(err) {
    if (err) {
      cb(err);
    }

    cb(null);
  });

  // /////////////////////////////
  function getNewOutput(output) {
    var arr = output.split(path.sep);
    arr.pop();
    return arr.join(path.sep);
  }

  function getOutputFilePath(input, newOutput) {
    var inputArr = input.split(path.sep);
    var originFileName = inputArr[inputArr.length - 1];
    var outputFilePath = path.join(newOutput, originFileName.replace(/\.png$/, suffix + '.png'));
    return outputFilePath;
  }

  function convert(input, newOutput, outputFilePath, cb) {
    var pd = cp.spawn(pngdefryBinPath, ['-s', suffix, '-o', newOutput, input]);

    pd.stdout.on('data', function(data) {
      console.log(data.toString());
    });

    pd.on('exit', function(code) {
      if (code !== 0) {
        return cb('convert fail');
      }

      fs.renameSync(outputFilePath, output);
      cb(null);
    });

  }

};
<|endoftext|>


<commit_before>/**
 * Dependencies.
 */
var bcrypt = require('bcrypt')
  , jwt    = require('jsonwebtoken')
  , errors = require('../lib/errors')
  , config = require('config')
  ;

/**
 * Constants.
 */
var SALT_WORK_FACTOR = 10;

/**
 * Model.
 */
module.exports = function(Sequelize, DataTypes) {

  var User = Sequelize.define('User', {

    _access: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },

    first_name: DataTypes.STRING,
    last_name: DataTypes.STRING,

    username: {
      type: DataTypes.STRING,
      unique: true
    },

    avatar: DataTypes.STRING,

    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true, // need that? http://stackoverflow.com/questions/16356856/sequelize-js-custom-validator-check-for-unique-username-password
      validate: {
        len: {
          args: [6, 128],
          msg: "Email must be between 6 and 128 characters in length"
        },
        isEmail: {
          msg: "Email must be valid"
        }
      }
    },

    _salt: {
      type: DataTypes.STRING,
      defaultValue: bcrypt.genSaltSync(SALT_WORK_FACTOR)
    },
    refresh_token: {
      type: DataTypes.STRING,
      defaultValue: bcrypt.genSaltSync(SALT_WORK_FACTOR)
    },
    password_hash: DataTypes.STRING,
    password: {
      type: DataTypes.VIRTUAL,
      set: function (val) {
        this.setDataValue('password', val);
        this.setDataValue('password_hash', bcrypt.hashSync(val, this._salt));
       },
       validate: {
        len: {
          args: [6, 128],
          msg: 'Password must be between 6 and 128 characters in length'
        }
      }
    },

    createdAt: {
      type: DataTypes.DATE,
      defaultValue: Sequelize.NOW
    },
    updatedAt: {
      type: DataTypes.DATE,
      defaultValue: Sequelize.NOW
    },
    seenAt: DataTypes.DATE,

  }, {
    paranoid: true,

    getterMethods: {
      // Full name.
      fullName: function() {
        return this.first_name + ' ' + this.last_name;
      },
      // Info (private).
      info: function() {
        return {
            id: this.id
          , first_name: this.first_name
          , last_name: this.last_name
          , name: this.fullName
          , username: this.username
          , email: this.email
          , createdAt: this.createdAt
          , updatedAt: this.updatedAt
        };
      },
      // Show (to any other user).
      show: function() {
        return {
            id: this.id
          , first_name: this.first_name
          , last_name: this.last_name
          , name: this.fullName
          , username: this.username
          , createdAt: this.createdAt
          , updatedAt: this.updatedAt
        };
      },
      // Minimal (used to feed the jwt token)
      minimal: function() {
        return {
            id: this.id
          , username: this.username
          , avatar: this.avatar
          , name: this.fullName
          , email: this.email
        };
      },
      // JWT token.
      jwt: function() {
        var secret = config.keys.unionsq.secret;
        var payload = this.minimal;
        return jwt.sign(payload, secret, {
            expiresInMinutes: 60*24*30 // 1 month
          , subject: this.id // user
          , issuer: config.host.api
          , audience: config.application.id // only 1 application for now
        });
      }
    },

    classMethods: {
      auth: function(usernameOrEmail, password, fn) {
        var msg = 'Invalid username/email or password.';

        User
          .find({ where: ["username = ? OR email = ?", usernameOrEmail, usernameOrEmail] })
          .then(function(user) {
            if (!user) return fn(new errors.BadRequest(msg));

            bcrypt.compare(password, user.password_hash, function(err, matched) {
              if (!err && matched) {
                user.updateAttributes({
                  seenAt: new Date
                }).done(fn);
              } else {
                fn(new errors.BadRequest(msg));
              }
            });
          })
          .catch(fn);
      }
    },

  });

  return User;
};
<commit_msg>add avatar to return information for a user<commit_after>/**
 * Dependencies.
 */
var bcrypt = require('bcrypt')
  , jwt    = require('jsonwebtoken')
  , errors = require('../lib/errors')
  , config = require('config')
  ;

/**
 * Constants.
 */
var SALT_WORK_FACTOR = 10;

/**
 * Model.
 */
module.exports = function(Sequelize, DataTypes) {

  var User = Sequelize.define('User', {

    _access: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },

    first_name: DataTypes.STRING,
    last_name: DataTypes.STRING,

    username: {
      type: DataTypes.STRING,
      unique: true
    },

    avatar: DataTypes.STRING,

    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true, // need that? http://stackoverflow.com/questions/16356856/sequelize-js-custom-validator-check-for-unique-username-password
      validate: {
        len: {
          args: [6, 128],
          msg: "Email must be between 6 and 128 characters in length"
        },
        isEmail: {
          msg: "Email must be valid"
        }
      }
    },

    _salt: {
      type: DataTypes.STRING,
      defaultValue: bcrypt.genSaltSync(SALT_WORK_FACTOR)
    },
    refresh_token: {
      type: DataTypes.STRING,
      defaultValue: bcrypt.genSaltSync(SALT_WORK_FACTOR)
    },
    password_hash: DataTypes.STRING,
    password: {
      type: DataTypes.VIRTUAL,
      set: function (val) {
        this.setDataValue('password', val);
        this.setDataValue('password_hash', bcrypt.hashSync(val, this._salt));
       },
       validate: {
        len: {
          args: [6, 128],
          msg: 'Password must be between 6 and 128 characters in length'
        }
      }
    },

    createdAt: {
      type: DataTypes.DATE,
      defaultValue: Sequelize.NOW
    },
    updatedAt: {
      type: DataTypes.DATE,
      defaultValue: Sequelize.NOW
    },
    seenAt: DataTypes.DATE,

  }, {
    paranoid: true,

    getterMethods: {
      // Full name.
      fullName: function() {
        return this.first_name + ' ' + this.last_name;
      },
      // Info (private).
      info: function() {
        return {
            id: this.id
          , first_name: this.first_name
          , last_name: this.last_name
          , name: this.fullName
          , username: this.username
          , email: this.email
          , avatar: this.avatar
          , createdAt: this.createdAt
          , updatedAt: this.updatedAt
        };
      },
      // Show (to any other user).
      show: function() {
        return {
            id: this.id
          , first_name: this.first_name
          , last_name: this.last_name
          , name: this.fullName
          , username: this.username
          , avatar: this.avatar
          , createdAt: this.createdAt
          , updatedAt: this.updatedAt
        };
      },
      // Minimal (used to feed the jwt token)
      minimal: function() {
        return {
            id: this.id
          , username: this.username
          , avatar: this.avatar
          , name: this.fullName
          , email: this.email
        };
      },
      // JWT token.
      jwt: function() {
        var secret = config.keys.unionsq.secret;
        var payload = this.minimal;
        return jwt.sign(payload, secret, {
            expiresInMinutes: 60*24*30 // 1 month
          , subject: this.id // user
          , issuer: config.host.api
          , audience: config.application.id // only 1 application for now
        });
      }
    },

    classMethods: {
      auth: function(usernameOrEmail, password, fn) {
        var msg = 'Invalid username/email or password.';

        User
          .find({ where: ["username = ? OR email = ?", usernameOrEmail, usernameOrEmail] })
          .then(function(user) {
            if (!user) return fn(new errors.BadRequest(msg));

            bcrypt.compare(password, user.password_hash, function(err, matched) {
              if (!err && matched) {
                user.updateAttributes({
                  seenAt: new Date
                }).done(fn);
              } else {
                fn(new errors.BadRequest(msg));
              }
            });
          })
          .catch(fn);
      }
    },

  });

  return User;
};
<|endoftext|>


<commit_before>const {Users, Groups} = require('../models/users')
const mongoose = require('mongoose')

module.exports = function(router) {
  router.post('/group-invite/accept/:id', (req, res) => {
    Groups.findOne({_id: req.params.id})
    .then(group => {
      //Check if the user is already in the group
      let isUserAlreadyInGroup = group.users.find(id => id.equals(req.user._id))
      let userContainsGroup = req.user.groups.find(id => id.equals(group._id))
      if(!group) throw 'Group does not exist'
      if(userContainsGroup && !isUserAlreadyInGroup) throw new databaseException('User contains group, but group does not contain the user')
      if(isUserAlreadyInGroup && !userContainsGroup) throw new databaseException('Group contains the user, but the user does not contain the group')
      if(isUserAlreadyInGroup && userContainsGroup) throw 'User is already inside the group'
      group.users.push(req.user._id)
      group.save()
      //remove invite
      req.user.invites.remove(req.params.id)
      req.user.groups.push(group._id)
      return req.user.save()
    })
    .then(() => res.redirect(`/group/${req.params.id}`))
    .catch(err => {
      if(err == 'User is already inside the group') {
        req.user.invites.remove(req.params.id)
        req.user.save()
        return res.redirect('/dashboard')
      }else if(err.msg == 'Group contains the user, but the user does not contain the group') {
        //Group has user use doesn't have the group
        //save the group to the user
        req.user.groups.push(req.params.id)
        req.user.save()
        res.redirect(`/group/${req.params.id}`)
      }else if(err.msg == 'User contains group, but group does not contain the user') {
        //The user contains the group, but the group does not have the user
        //save the user to the group then redirect to the group
        Groups.update({_id: req.params.id}, {$push: {users: req.user._id}})
        .then(data => {
          req.user.invites.remove(req.params.id)
          req.user.save()
          res.redirect(`/group/${req.params.id}`)
        })
      }else if(err == 'Group does not exist'){
        req.user.invites.remove(req.params.id)
        req.user.save()
        res.redirect('/dashboard')
      }else {
        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/group-invite/decline/:id', (req, res) => {
    //Remove the invite
    req.user.invites.remove(req.params.id)
    req.user.save()
    res.redirect('/dashboard')
  })

  router.post('/borrow-request/accept/:bookId/:requestId/:borrowerId', (req, res) => {
    let findBorrower = Users.findOne({_id: req.params.borrowerId})
    //Remove the request
    let updateOwner = Users.findOneAndUpdate({_id: req.user._id}, {$pull: {borrowRequests: {_id: req.params.requestId}}},{safe: true, multi:true}).exec()
    .then(user => user)
    Promise.all([findBorrower, updateOwner])
    .then( data => {
      let borrower = data[0]
      let book = data[1].books.id(req.params.bookId)
      if(!book) throw 'Book does not exist'
      if(!borrower) throw 'Borrower does not exist'
      if(book.borrower) throw 'Book is already being borrowed'
      //Update book
      book.borrower = borrower.username
      data[1].save()
      //Add book to borrower
      borrower.borrowedBooks.push(book)
      borrower.save()
      res.redirect('/dashboard')
    })
    .catch(err => {
      if(err == 'Book does not exist' || err == 'Borrower does not exist' || err == 'Book is already being borrowed') {
        res.redirect('/dashboard')
      }else {
        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/borrow-request/decline/:requestId', (req, res) => {
    //Find and remove the reques
    Users.findOneAndUpdate({_id: req.user._id}, {$pull: {borrowRequests: {_id: req.params.requestId}}},{safe: true, multi:true}).exec()
    .then(user => {
      res.redirect('/dashboard')
    })
    .catch(err => {
      console.log(err)
      req.render('error')
    })
  })

  router.post('/return-request/approve/:bookId/:borrowerId/:returnId', (req, res) => {
    let findOwner = Users.findOne({_id: req.user._id})
    let findBorrower = Users.findOne({_id: req.params.borrowerId})
    let removeReturn = Users.findOneAndUpdate({_id: req.user._id}, {$pull: {bookReturns: {_id: req.params.returnId}}},{safe:true,multi:true})

    Promise.all([findOwner, findBorrower, removeReturn])
    .then(data => {
      let owner = data[0]
      let borrower = data[1]
      let book = owner.books.id(req.params.bookId)

      if(!book) throw 'Book does not exist'

      //Remove book borrower
      book.borrower = null
      //Remove book from borrower
      if(borrower) {
        borrower.borrowedBooks.remove(book._id)
        borrower.save()
      }
      return owner.save()
    })
    .then(() => res.redirect('/dashboard'))
    .catch(err => {
      if(err == 'Book does not exist') {
        res.redirect('/dashboard')
      }else {

        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/return-request/reject/:returnId', (req, res) => {
    Users.findOneAndUpdate({_id: req.user._id}, {$pull: {bookReturns: {_id: req.params.returnId}}}, {safe:true,multi:true})
    .then(() => {
      res.redirect('/dashboard')
    })
    .catch(err => {
      console.log(err)
      res.render('error')
    })
  })
}

function databaseException(msg) {
  this.name = 'Database inconsistency'
  this.msg = msg
}
<commit_msg>bug fix<commit_after>const {Users, Groups} = require('../models/users')
const mongoose = require('mongoose')

module.exports = function(router) {
  router.post('/group-invite/accept/:id', (req, res) => {
    Groups.findOne({_id: req.params.id})
    .then(group => {
      //Check if the user is already in the group
      let isUserAlreadyInGroup = group.users.find(id => id.equals(req.user._id))
      let userContainsGroup = req.user.groups.find(id => id.equals(group._id))
      if(!group) throw 'Group does not exist'
      if(userContainsGroup && !isUserAlreadyInGroup) throw new databaseException('User contains group, but group does not contain the user')
      if(isUserAlreadyInGroup && !userContainsGroup) throw new databaseException('Group contains the user, but the user does not contain the group')
      if(isUserAlreadyInGroup && userContainsGroup) throw 'User is already inside the group'
      group.users.push(req.user._id)
      group.save()
      //remove invite
      req.user.invites.remove(req.params.id)
      req.user.groups.push(group._id)
      return req.user.save()
    })
    .then(() => res.redirect(`/group/${req.params.id}`))
    .catch(err => {
      if(err == 'User is already inside the group') {
        req.user.invites.remove(req.params.id)
        req.user.save()
        return res.redirect('/dashboard')
      }else if(err.msg == 'Group contains the user, but the user does not contain the group') {
        //Group has user use doesn't have the group
        //save the group to the user
        req.user.groups.push(req.params.id)
        req.user.save()
        res.redirect(`/group/${req.params.id}`)
      }else if(err.msg == 'User contains group, but group does not contain the user') {
        //The user contains the group, but the group does not have the user
        //save the user to the group then redirect to the group
        Groups.update({_id: req.params.id}, {$push: {users: req.user._id}})
        .then(data => {
          req.user.invites.remove(req.params.id)
          req.user.save()
          res.redirect(`/group/${req.params.id}`)
        })
      }else if(err == 'Group does not exist'){
        req.user.invites.remove(req.params.id)
        req.user.save()
        res.redirect('/dashboard')
      }else {
        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/group-invite/decline/:id', (req, res) => {
    //Remove the invite
    req.user.invites.remove(req.params.id)
    req.user.save()
    res.redirect('/dashboard')
  })

  router.post('/borrow-request/accept/:bookId/:requestId/:borrowerId', (req, res) => {
    let findBorrower = Users.findOne({_id: req.params.borrowerId})
    //Remove the request
    let updateOwner = Users.findOneAndUpdate({_id: req.user._id}, {$pull: {borrowRequests: {_id: req.params.requestId}}},{safe: true, multi:true}).exec()
    .then(user => user)
    Promise.all([findBorrower, updateOwner])
    .then( data => {
      let borrower = data[0]
      let book = data[1].books.id(req.params.bookId)
      if(!book) throw 'Book does not exist'
      if(!borrower) throw 'Borrower does not exist'
      if(book.borrower) throw 'Book is already being borrowed'
      //Update book
      book.borrower = borrower.username
      data[1].save()
      //Add book to borrower
      borrower.borrowedBooks.push(book._id)
      return borrower.save()
    })
    .then(() => {
      res.redirect('/dashboard')
    })
    .catch(err => {
      if(err == 'Book does not exist' || err == 'Borrower does not exist' || err == 'Book is already being borrowed') {
        console.log(err)
        res.redirect('/dashboard')
      }else {
        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/borrow-request/decline/:requestId', (req, res) => {
    //Find and remove the reques
    Users.findOneAndUpdate({_id: req.user._id}, {$pull: {borrowRequests: {_id: req.params.requestId}}},{safe: true, multi:true}).exec()
    .then(user => {
      res.redirect('/dashboard')
    })
    .catch(err => {
      console.log(err)
      req.render('error')
    })
  })

  router.post('/return-request/approve/:bookId/:borrowerId/:returnId', (req, res) => {
    let findOwner = Users.findOne({_id: req.user._id})
    let findBorrower = Users.findOne({_id: req.params.borrowerId})
    let removeReturn = Users.findOneAndUpdate({_id: req.user._id}, {$pull: {bookReturns: {_id: req.params.returnId}}},{safe:true,multi:true})

    Promise.all([findOwner, findBorrower, removeReturn])
    .then(data => {
      let owner = data[0]
      let borrower = data[1]
      let book = owner.books.id(req.params.bookId)

      if(!book) throw 'Book does not exist'

      //Remove book borrower
      book.borrower = null
      //Remove book from borrower
      if(borrower) {
        borrower.borrowedBooks.remove(book._id)
        borrower.save()
      }
      return owner.save()
    })
    .then(() => res.redirect('/dashboard'))
    .catch(err => {
      if(err == 'Book does not exist') {
        res.redirect('/dashboard')
      }else {

        console.log(err)
        res.render('error')
      }
    })
  })

  router.post('/return-request/reject/:returnId', (req, res) => {
    Users.findOneAndUpdate({_id: req.user._id}, {$pull: {bookReturns: {_id: req.params.returnId}}}, {safe:true,multi:true})
    .then(() => {
      res.redirect('/dashboard')
    })
    .catch(err => {
      console.log(err)
      res.render('error')
    })
  })
}

function databaseException(msg) {
  this.name = 'Database inconsistency'
  this.msg = msg
}
<|endoftext|>


<commit_before>/* istanbul ignore next */
const root = (function() {
	if (typeof window !== 'undefined') {
		// Browser window
		return window;
	}

	if (typeof self !== 'undefined') {
		// Web Worker
		return self;
	}

	if (typeof global !== 'undefined') {
		// Node
		return global;
	}

	// Other environments
	return this; // eslint-disable-line no-invalid-this
}());

const locales = {};

const isObject = obj => Object.prototype.toString.call(obj) === '[object Object]';

class VI18N {
	constructor(locale = 'nl-NL', currency = 'EUR' /* options = {} */) {
		// Fail fast when the Internationalization API isn't supported
		/* istanbul ignore if */
		if (!VI18N.isSupported()) {
			throw new Error('Internationalization API not supported, did you forget to include a polyfill?');
		}

		// const { locale = 'nl-NL', currency = 'EUR' } = options;

		this.locale = locale;
		this.currency = currency;
		this.formatters = {};
		this.months = {};
		this.days = {};
		this.decimalSeparator = null;
		this.thousandSeparator = null;

		// Keep track of this instance
		locales[locale] = this;

		this.initialize(locale, currency);
	}

	initialize(locale, currency) {
		this.formatters.number = new Intl.NumberFormat(locale);
		this.formatters.currency = new Intl.NumberFormat(locale, {
			style: 'currency',
			currency,
		});
		this.formatters.percent = new Intl.NumberFormat(locale, {
			style: 'percent',
		});
		this.formatters.date = new Intl.DateTimeFormat(locale);
	}

	// Format a number to a locale string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
	formatNumber(number, options) {
		return isObject(options)
			? number.toLocaleString(this.locale, options)
			: this.formatters.number.format(number);
	}

	// Format a number to a locale currency string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
	formatCurrency(number, options) {
		if (isObject(options)) {
			const { style = 'currency', currency = this.currency } = options;

			Object.assign(options, { style, currency });

			return number.toLocaleString(this.locale, options);
		}

		return this.formatters.currency.format(number);
	}

	formatPercent(number, options) {
		if (isObject(options)) {
			options.style = 'percent';

			return number.toLocaleString(this.locale, options);
		}

		return this.formatters.percent.format(number);
	}

	// Format a date object to a locale string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
	formatDate(date, options) {
		return isObject(options)
			? date.toLocaleDateString(this.locale, options)
			: this.formatters.date.format(date);
	}

	formatTime(date, options = {}) {
		return date.toLocaleTimeString(this.locale, options);
	}

	// Assume it is always one character
	// https://en.wikipedia.org/wiki/Decimal_mark
	getDecimalSeparator() {
		return this.decimalSeparator || (this.decimalSeparator = this.formatNumber(1.1).charAt(1)); // eslint-disable-line max-len
	}

	getThousandSeparator() {
		return this.thousandSeparator || (this.thousandSeparator = (() => {
			const separator = this.formatNumber(1000).charAt(1);

			// When the separator is not a number (e.g. the decimal point in '1.000')
			// return the separator, otherwise return an empty string
			return isNaN(parseInt(separator, 10)) ? separator : '';
		})());
	}

	getMonths(type = 'long') {
		return this.months[type] || (this.months[type] = (() => {
			const date = new Date(Date.UTC(2015, 0, 1));
			const months = [];

			for (let i = 0; i < 12; i++) {
				date.setMonth(i);
				months[i] = this.formatDate(date, { month: type });
			}

			return months;
		})());
	}

	getDays(type = 'long') {
		return this.days[type] || (this.days[type] = (() => {
			const date = new Date(Date.UTC(1978, 0, 1)); // https://en.wikipedia.org/wiki/Common_year_starting_on_Sunday
			const days = [];

			for (let i = 1; i <= 7; i++) {
				date.setUTCDate(i);
				days.push(this.formatDate(date, { weekday: type }));
			}

			return days;
		})());
	}

	static getLocale(locale) {
		return locales[locale];
	}

	// TODO: also check support for methods and locales
	// Number.prototype.toLocaleString()
	// Date.prototype.toLocaleTimeString()
	// Date.prototype.toLocaleDateString()
	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString#Checking_for_support_for_locales_and_options_arguments
	static isSupported() {
		return 'Intl' in root;
	}
}

module.exports = VI18N;
<commit_msg>Improve isSupported check<commit_after>/* istanbul ignore next */
const root = (function() {
	if (typeof window !== 'undefined') {
		// Browser window
		return window;
	}

	if (typeof self !== 'undefined') {
		// Web Worker
		return self;
	}

	if (typeof global !== 'undefined') {
		// Node
		return global;
	}

	// Other environments
	return this; // eslint-disable-line no-invalid-this
}());

const locales = {};

const isObject = obj => Object.prototype.toString.call(obj) === '[object Object]';

const isSupported = (
	'Intl' in root &&
	typeof Intl.NumberFormat === 'function' &&
	typeof Intl.DateTimeFormat === 'function' &&
	typeof Number.prototype.toLocaleString === 'function' &&
	typeof Date.prototype.toLocaleDateString === 'function' &&
	typeof Date.prototype.toLocaleTimeString === 'function'
);

class VI18N {
	constructor(locale = 'nl-NL', currency = 'EUR' /* options = {} */) {
		// Fail fast when the Internationalization API isn't supported
		/* istanbul ignore if */
		if (!VI18N.isSupported()) {
			throw new Error('Internationalization API not supported, did you forget to include a polyfill?');
		}

		// const { locale = 'nl-NL', currency = 'EUR' } = options;

		this.locale = locale;
		this.currency = currency;
		this.formatters = {};
		this.months = {};
		this.days = {};
		this.decimalSeparator = null;
		this.thousandSeparator = null;

		// Keep track of this instance
		locales[locale] = this;

		this.initialize(locale, currency);
	}

	initialize(locale, currency) {
		this.formatters.number = new Intl.NumberFormat(locale);
		this.formatters.currency = new Intl.NumberFormat(locale, {
			style: 'currency',
			currency,
		});
		this.formatters.percent = new Intl.NumberFormat(locale, {
			style: 'percent',
		});
		this.formatters.date = new Intl.DateTimeFormat(locale);
	}

	// Format a number to a locale string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
	formatNumber(number, options) {
		return isObject(options)
			? number.toLocaleString(this.locale, options)
			: this.formatters.number.format(number);
	}

	// Format a number to a locale currency string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
	formatCurrency(number, options) {
		if (isObject(options)) {
			const { style = 'currency', currency = this.currency } = options;

			Object.assign(options, { style, currency });

			return number.toLocaleString(this.locale, options);
		}

		return this.formatters.currency.format(number);
	}

	formatPercent(number, options) {
		if (isObject(options)) {
			options.style = 'percent';

			return number.toLocaleString(this.locale, options);
		}

		return this.formatters.percent.format(number);
	}

	// Format a date object to a locale string
	// For more information about the options see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
	formatDate(date, options) {
		return isObject(options)
			? date.toLocaleDateString(this.locale, options)
			: this.formatters.date.format(date);
	}

	formatTime(date, options = {}) {
		return date.toLocaleTimeString(this.locale, options);
	}

	// Assume it is always one character
	// https://en.wikipedia.org/wiki/Decimal_mark
	getDecimalSeparator() {
		return this.decimalSeparator || (this.decimalSeparator = this.formatNumber(1.1).charAt(1)); // eslint-disable-line max-len
	}

	getThousandSeparator() {
		return this.thousandSeparator || (this.thousandSeparator = (() => {
			const separator = this.formatNumber(1000).charAt(1);

			// When the separator is not a number (e.g. the decimal point in '1.000')
			// return the separator, otherwise return an empty string
			return isNaN(parseInt(separator, 10)) ? separator : '';
		})());
	}

	getMonths(type = 'long') {
		return this.months[type] || (this.months[type] = (() => {
			const date = new Date(Date.UTC(2015, 0, 1));
			const months = [];

			for (let i = 0; i < 12; i++) {
				date.setMonth(i);
				months[i] = this.formatDate(date, { month: type });
			}

			return months;
		})());
	}

	getDays(type = 'long') {
		return this.days[type] || (this.days[type] = (() => {
			const date = new Date(Date.UTC(1978, 0, 1)); // https://en.wikipedia.org/wiki/Common_year_starting_on_Sunday
			const days = [];

			for (let i = 1; i <= 7; i++) {
				date.setUTCDate(i);
				days.push(this.formatDate(date, { weekday: type }));
			}

			return days;
		})());
	}

	static getLocale(locale) {
		return locales[locale];
	}

	static isSupported() {
		return isSupported;
	}
}

module.exports = VI18N;
<|endoftext|>


<commit_before>/**
 * A Bot for Slack!
 */

/**
 * Define a function for initiating a conversation on installation
 * With custom integrations, we don't have a way to find out who installed us, so we can't message them :(
 */

function onInstallation(bot, installer) {
    if (installer) {
        bot.startPrivateConversation({user: installer}, function (err, convo) {
            if (err) {
                console.log(err);
            } else {
                convo.say('I am a bot that has just joined your team');
                convo.say('You must now /invite me to a channel so that I can be of use!');
            }
        });
    }
}

/**
 * Configure the persistence options
 */

var config = {};
if (process.env.MONGOLAB_URI) {
    var BotkitStorage = require('botkit-storage-mongo');
    config = {
        storage: BotkitStorage({mongoUri: process.env.MONGOLAB_URI}),
    };
} else {
    config = {
        json_file_store: ((process.env.TOKEN)?'./db_slack_bot_ci/':'./db_slack_bot_a/'), //use a different name if an app or CI
    };
}

/**
 * Are being run as an app or a custom integration? The initialization will differ, depending
 */

if (process.env.TOKEN || process.env.SLACK_TOKEN) {
    //Treat this as a custom integration
    var customIntegration = require('./lib/custom_integrations');
    var token = (process.env.TOKEN) ? process.env.TOKEN : process.env.SLACK_TOKEN;
    var controller = customIntegration.configure(token, config, onInstallation);
} else if (process.env.CLIENT_ID && process.env.CLIENT_SECRET && process.env.PORT) {
    //Treat this as an app
    var app = require('./lib/apps');
    var controller = app.configure(process.env.PORT, process.env.CLIENT_ID, process.env.CLIENT_SECRET, config, onInstallation);
} else {
    console.log('Error: If this is a custom integration, please specify TOKEN in the environment. If this is an app, please specify CLIENTID, CLIENTSECRET, and PORT in the environment');
    process.exit(1);
}

/**
 * A demonstration for how to handle websocket events. In this case, just log when we have and have not
 * been disconnected from the websocket. In the future, it would be super awesome to be able to specify
 * a reconnect policy, and do reconnections automatically. In the meantime, we aren't going to attempt reconnects,
 * WHICH IS A B0RKED WAY TO HANDLE BEING DISCONNECTED. So we need to fix this.
 *
 * TODO: fixed b0rked reconnect behavior
 */
// Handle events related to the websocket connection to Slack
controller.on('rtm_open', function (bot) {
    console.log('** The RTM api just connected!');
});

controller.on('rtm_close', function (bot) {
    console.log('** The RTM api just closed');
    // you may want to attempt to re-open
});

/**
 * Core bot logic goes here!
 */
// BEGIN EDITING HERE!

// setInterval(function(){ bot.say(
//       {
//         text: 'checkout http://slackercise.herokuapp.com',
//         channel: '#slacker-cise'
//       }
//     ); }, 3000);

var WORK_OUTS = [
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
]

controller.on('channel_joined', function (bot, message) {
    bot.reply(message, "I'm here!")

    bot.say({text: "What upppp", channel: "C0NNW7KLL"})
    setInterval(function(){ bot.say(
      {
        text: WORK_OUTS[0].text,
        channel: message.channel,
      }
    ); }, 18000000);
});

controller.hears(
    ['hello', 'hi', 'greetings'],
    ['direct_message','mention', 'direct_mention'],
    function (bot, message) {
    bot.reply(message, 'Hello!');
    bot.say(
      {
        text: WORK_OUTS[0].text,
        unfurl_links: true,
        channel: message.channel
      }
    );

});

controller.hears(
    ["addme"],
    ["direct_message", "direct_mention"],
    function(bot, message) {
        var request = require('request');
        request("https://slack.com/api/users.info?token=" + bot.config.token + "&user=" + message.user, function(error, response, body) {
            var data = JSON.parse(body).user
            // console.log(data)
            var user_data =
            { user: {
              team_id: data["team_id"],
              name: data["name"],
              real_name: data["real_name"],
              first_name: data["profile"]["first_name"],
              last_name: data["profile"]["last_name"],
              image: data["profile"]["image_192"],
              email: data["profile"]["email"]
            } };
        });
        request.post("http://slackercise.herokuapp.com/users").form({user_data})
    });

/**
 * AN example of what could be:
 * Any un-handled direct mention gets a reaction and a pat response!
 */
//controller.on('direct_message,mention,direct_mention', function (bot, message) {
//    bot.api.reactions.add({
//        timestamp: message.ts,
//        channel: message.channel,
//        name: 'robot_face',
//    }, function (err) {
//        if (err) {
//            console.log(err)
//        }
//        bot.reply(message, 'I heard you loud and clear boss.');
//    });
//});
<commit_msg>update with a response for bot<commit_after>/**
 * A Bot for Slack!
 */

/**
 * Define a function for initiating a conversation on installation
 * With custom integrations, we don't have a way to find out who installed us, so we can't message them :(
 */

function onInstallation(bot, installer) {
    if (installer) {
        bot.startPrivateConversation({user: installer}, function (err, convo) {
            if (err) {
                console.log(err);
            } else {
                convo.say('I am a bot that has just joined your team');
                convo.say('You must now /invite me to a channel so that I can be of use!');
            }
        });
    }
}

/**
 * Configure the persistence options
 */

var config = {};
if (process.env.MONGOLAB_URI) {
    var BotkitStorage = require('botkit-storage-mongo');
    config = {
        storage: BotkitStorage({mongoUri: process.env.MONGOLAB_URI}),
    };
} else {
    config = {
        json_file_store: ((process.env.TOKEN)?'./db_slack_bot_ci/':'./db_slack_bot_a/'), //use a different name if an app or CI
    };
}

/**
 * Are being run as an app or a custom integration? The initialization will differ, depending
 */

if (process.env.TOKEN || process.env.SLACK_TOKEN) {
    //Treat this as a custom integration
    var customIntegration = require('./lib/custom_integrations');
    var token = (process.env.TOKEN) ? process.env.TOKEN : process.env.SLACK_TOKEN;
    var controller = customIntegration.configure(token, config, onInstallation);
} else if (process.env.CLIENT_ID && process.env.CLIENT_SECRET && process.env.PORT) {
    //Treat this as an app
    var app = require('./lib/apps');
    var controller = app.configure(process.env.PORT, process.env.CLIENT_ID, process.env.CLIENT_SECRET, config, onInstallation);
} else {
    console.log('Error: If this is a custom integration, please specify TOKEN in the environment. If this is an app, please specify CLIENTID, CLIENTSECRET, and PORT in the environment');
    process.exit(1);
}

/**
 * A demonstration for how to handle websocket events. In this case, just log when we have and have not
 * been disconnected from the websocket. In the future, it would be super awesome to be able to specify
 * a reconnect policy, and do reconnections automatically. In the meantime, we aren't going to attempt reconnects,
 * WHICH IS A B0RKED WAY TO HANDLE BEING DISCONNECTED. So we need to fix this.
 *
 * TODO: fixed b0rked reconnect behavior
 */
// Handle events related to the websocket connection to Slack
controller.on('rtm_open', function (bot) {
    console.log('** The RTM api just connected!');
});

controller.on('rtm_close', function (bot) {
    console.log('** The RTM api just closed');
    // you may want to attempt to re-open
});

/**
 * Core bot logic goes here!
 */
// BEGIN EDITING HERE!

// setInterval(function(){ bot.say(
//       {
//         text: 'checkout http://slackercise.herokuapp.com',
//         channel: '#slacker-cise'
//       }
//     ); }, 3000);

var WORK_OUTS = [
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
    {text: "Do 50 squats\n http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy", gif: "http://giphy.com/gifs/transparent-gif-QcaWr0rSFenLy"},
]

controller.on('channel_joined', function (bot, message) {
    bot.reply(message, "I'm here!")

    bot.say({text: "What upppp", channel: "C0NNW7KLL"})
    setInterval(function(){ bot.say(
      {
        text: WORK_OUTS[0].text,
        channel: message.channel,
      }
    ); }, 18000000);
});

controller.hears(
    ['hello', 'hi', 'greetings'],
    ['direct_message','mention', 'direct_mention'],
    function (bot, message) {
    bot.reply(message, 'Hello!');
    bot.say(
      {
        text: WORK_OUTS[0].text,
        unfurl_links: true,
        channel: message.channel
      }
    );

});

controller.hears(
    ["addme"],
    ["direct_message", "direct_mention"],
    function(bot, message) {
        bot.say({text: "What upppp", channel: "C0NNW7KLL"})
        var request = require('request');
        request("https://slack.com/api/users.info?token=" + bot.config.token + "&user=" + message.user, function(error, response, body) {
            var data = JSON.parse(body).user
            // console.log(data)
            var user_data =
            { user: {
              team_id: data["team_id"],
              name: data["name"],
              real_name: data["real_name"],
              first_name: data["profile"]["first_name"],
              last_name: data["profile"]["last_name"],
              image: data["profile"]["image_192"],
              email: data["profile"]["email"]
            } };
        });
        request.post("https://slackercise.herokuapp.com/users").form({user_data})
    });

/**
 * AN example of what could be:
 * Any un-handled direct mention gets a reaction and a pat response!
 */
//controller.on('direct_message,mention,direct_mention', function (bot, message) {
//    bot.api.reactions.add({
//        timestamp: message.ts,
//        channel: message.channel,
//        name: 'robot_face',
//    }, function (err) {
//        if (err) {
//            console.log(err)
//        }
//        bot.reply(message, 'I heard you loud and clear boss.');
//    });
//});
<|endoftext|>


<commit_before>var mixin = require('smart-mixin');
var assign = require('object-assign');

var mixinProto = mixin({
  // lifecycle stuff is as you'd expect
  componentDidMount: mixin.MANY,
  componentWillMount: mixin.MANY,
  componentWillReceiveProps: mixin.MANY,
  shouldComponentUpdate: mixin.ONCE,
  componentWillUpdate: mixin.MANY,
  componentDidUpdate: mixin.MANY,
  componentWillUnmount: mixin.MANY,
  getChildContext: mixin.MANY_MERGED
});

function setDefaultProps(reactMixin) {
  var getDefaultProps = reactMixin.getDefaultProps;

  if(getDefaultProps) {
    reactMixin.defaultProps = getDefaultProps();

    delete reactMixin.getDefaultProps;
  }
}

function setInitialState(reactMixin) {
  var getInitialState = reactMixin.getInitialState;
  var componentWillMount = reactMixin.componentWillMount;

  function applyInitialState(instance){
      var state = instance.state || {};
      assign(state, getInitialState.call(instance));
      instance.state = state;
  }

  if(getInitialState) {
    if(!componentWillMount) {
      reactMixin.componentWillMount = function() {
          applyInitialState(this);
      };
    }
    else {
      reactMixin.componentWillMount = function() {
        applyInitialState(this);
        componentWillMount.call(this);
      };
    }

    delete reactMixin.getInitialState;
  }
}

function mixinClass(reactClass, reactMixin) {
  setDefaultProps(reactMixin);
  setInitialState(reactMixin);

  var prototypeMethods = {};
  var staticProps = {};

  Object.keys(reactMixin).forEach(function(key) {
    if(typeof reactMixin[key] === 'function') {
      prototypeMethods[key] = reactMixin[key];
    }
    else {
      staticProps[key] = reactMixin[key];
    }
  });

  mixinProto(reactClass.prototype, prototypeMethods);

  mixin({
    childContextTypes: mixin.MANY_MERGED_LOOSE,
    contextTypes: mixin.MANY_MERGED_LOOSE,
    propTypes: mixin.MANY_MERGED_LOOSE,
    defaultProps: mixin.MANY_MERGED_LOOSE
  })(reactClass, staticProps);
}

module.exports = (function () {
  reactMixin = mixinProto;

  reactMixin.onClass = function(reactClass, mixin) {
    mixinClass(reactClass, mixin)
  };

  reactMixin.decorate = function(mixin) {
    return function(reactClass) {
      return reactMixin.onClass(reactClass, mixin);
    };
  }

  return reactMixin;
})();
<commit_msg>Update index.js<commit_after>var mixin = require('smart-mixin');
var assign = require('object-assign');

var mixinProto = mixin({
  // lifecycle stuff is as you'd expect
  componentDidMount: mixin.MANY,
  componentWillMount: mixin.MANY,
  componentWillReceiveProps: mixin.MANY,
  shouldComponentUpdate: mixin.ONCE,
  componentWillUpdate: mixin.MANY,
  componentDidUpdate: mixin.MANY,
  componentWillUnmount: mixin.MANY,
  getChildContext: mixin.MANY_MERGED
});

function setDefaultProps(reactMixin) {
  var getDefaultProps = reactMixin.getDefaultProps;

  if(getDefaultProps) {
    reactMixin.defaultProps = getDefaultProps();

    delete reactMixin.getDefaultProps;
  }
}

function setInitialState(reactMixin) {
  var getInitialState = reactMixin.getInitialState;
  var componentWillMount = reactMixin.componentWillMount;

  function applyInitialState(instance){
      var state = instance.state || {};
      assign(state, getInitialState.call(instance));
      instance.state = state;
  }

  if(getInitialState) {
    if(!componentWillMount) {
      reactMixin.componentWillMount = function() {
          applyInitialState(this);
      };
    }
    else {
      reactMixin.componentWillMount = function() {
        applyInitialState(this);
        componentWillMount.call(this);
      };
    }

    delete reactMixin.getInitialState;
  }
}

function mixinClass(reactClass, reactMixin) {
  setDefaultProps(reactMixin);
  setInitialState(reactMixin);

  var prototypeMethods = {};
  var staticProps = {};

  Object.keys(reactMixin).forEach(function(key) {
    if(typeof reactMixin[key] === 'function') {
      prototypeMethods[key] = reactMixin[key];
    }
    else {
      staticProps[key] = reactMixin[key];
    }
  });

  mixinProto(reactClass.prototype, prototypeMethods);

  mixin({
    childContextTypes: mixin.MANY_MERGED_LOOSE,
    contextTypes: mixin.MANY_MERGED_LOOSE,
    propTypes: mixin.MANY_MERGED_LOOSE,
    defaultProps: mixin.MANY_MERGED_LOOSE
  })(reactClass, staticProps);
}

module.exports = (function () {
  var reactMixin = mixinProto;

  reactMixin.onClass = function(reactClass, mixin) {
    mixinClass(reactClass, mixin)
  };

  reactMixin.decorate = function(mixin) {
    return function(reactClass) {
      return reactMixin.onClass(reactClass, mixin);
    };
  }

  return reactMixin;
})();
<|endoftext|>