<commit_before>'use strict';

var fs = require('fs')
  , path = require('path')
  , url = require('url')
  , util = require('util')
  , events = require('events');

var async = require('async')
  , Nano = require('nano');

function Guy(options) {
  var _this = this;
  events.EventEmitter.call(this);

  this.options = options || {};
  this.options.database = this.options.database || 'user_databases';
  this.options.local = this.options.local || url.parse('http://127.0.0.1:5984');
  this.options.remote = this.options.remote;
  this.logger = this.options.log || null;
  this.localNano = null;
  this.remoteNano = null;
  this.queueTasks = {};
  this.queue = async.queue(this._queueWorker.bind(this), this.options.concurrency || 4);
  this.ready = false;
  this._init();
}

util.inherits(Guy, events.EventEmitter);

Guy.prototype._init = function() {
  var _this = this;
  this.localNano = Nano(this.options.local.href);
  this.remoteNano = Nano(this.options.remote.href);

  this.logger && this.logger.debug('checking if remote user database exists');
  this.remoteNano.db[this.options.createRemote ? 'create' : 'get'](this.options.database, function (err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      _this.emit('error', new Error('Error communicating with remote database "' + _this._buildUrl(_this.options.remote, { auth: '****', pathname: _this.options.database }) + '". Use option createRemote: true to create it'));
      return;
    }
    _this._initDatabase(function(err) {
      if (err) {
        return _this.emit('error', err);
      }
      _this._syncLocal(function(err) {
        if (err) {
          return _this.emit('error', err);
        }
        _this.logger && _this.logger.debug('sync and watch has run; emitting ready as soon as queue drains');
        _this.queue.drain = function() {
          if (!_this.ready) {
            _this.emit('ready');
            _this.ready = true;
          }
        };
        // if the queue is empty, manually trigger drain (bug in async?)
        if (!_this.queue.length()) {
          _this.queue.drain();
        }
      });
    });
  });
};

Guy.prototype._initDatabase = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('init local database');
  var _this = this;
  this.localNano.db.create(this.options.database, function(err, body) {
    // TODO: check error to make sure it's an "already exists" error?
    if (!err) {
      _this.logger && _this.logger.debug('init local database: creating local, replicating');
      _this._replicate(_this.options.database, function(err) {
        if (err) {
          return callback(err);
        }
        _this._watchLocal(callback);
      });
    }
    else {
      _this._watchLocal(callback);
    }
  });
};

Guy.prototype._watchLocal = function(callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);
  _this.logger && _this.logger.debug('init local database: watching for changes on ' + this.options.database);
  var feed = db.follow({ since: 'now' });
  feed.on('change', function (change) {
    _this.logger && _this.logger.debug(change, 'change');
    _this._enqueue(change.id, !change.deleted);
  });
  feed.on('error', function (err) {
    _this.emit('error', err);
  });
  feed.follow();
  callback(null);
};

// syncs the current data of options.database i.e. adds/removes databases
Guy.prototype._syncLocal = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('starting to sync offline user database changes');
  this.localNano.db.list(function(err, allLocalDatabases) {
    if (err) {
      return callback(err);
    }
    // FIXME: convert to paging otherwise a large number of databases could spike the memory usage
    _this.localNano.use(_this.options.database).list(function(err, userDatabases) {
      if (err) {
        return callback(err);
      }
      userDatabases.rows.forEach(function(row) {
        var userDatabase = row.id;
        if (!(userDatabase in _this.queueTasks)) {
          if (allLocalDatabases.indexOf(userDatabase) < 0) {
            _this.logger && _this.logger.debug('user database created while offline ' + userDatabase);
            _this._enqueue(userDatabase, true);
          }
        }
      });
      // TODO: handle user databases that are deleted while offline
      callback(null);
    });
  });
};

Guy.prototype._enqueue = function(database, create) {
  if (!(database in this.queueTasks)) {
    // only add it to the queue if it doesn't already exist
    this.queue.push({ database: database });
  }
  this.queueTasks[database] = create;
};

Guy.prototype._queueWorker = function(task, callback) {
  var _this = this
    , create = this.queueTasks[task.database]
    , database = task.database;
  delete this.queueTasks[database];
  this[create ? '_create' : '_remove'](database, function(err) {
    if (err) {
      _this.emit('error', err);
      return callback(err);
    }
    _this.emit((create ? 'create:' : 'remove:') + database);
    _this.emit('database:' + database, create);
    _this.emit(create ? 'create' : 'remove', database);
    callback(null);
  });
};

// inserts two-way replication between database on local and remote
Guy.prototype._replicate = function(database, callback) {
  var _this = this;
  var rep = this.localNano.use('_replicator')
    , localUrl = this.databaseUrl('local', database)
    , remoteUrl = this.databaseUrl('remote', database);
  _this.logger && _this.logger.debug('replicating database: ', database);

  this.remoteNano.db.create(database, function(err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      return callback(err);
    }
    _this.logger && _this.logger.debug('replicating database: inserting replication task');
    rep.insert({
      source: localUrl,
      target: remoteUrl,
      continuous: true
    }, null, function(err, body) {
      if (err) {
        return callback(err);
      }
      _this.logger && _this.logger.debug('replicating database: replicated partially complete');
      rep.insert({
        target: localUrl,
        source: remoteUrl,
        continuous: true
      }, null, callback);
    });
  });
};

Guy.prototype._buildUrl = function(urlObj, updates, returnObject) {
  var clonedUrlObj = Object.create(urlObj);
  for (var k in updates) {
    clonedUrlObj[k] = updates[k];
  }
  return returnObject ? clonedUrlObj : url.format(clonedUrlObj);
};

Guy.prototype.databaseUrl = function(localOrRemote, database) {
  return this._buildUrl(this.options[localOrRemote], { pathname: database });
}

Guy.prototype._create = function(database, callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);

  _this.logger && _this.logger.debug('creating database: ' + database);

  // create database locally
  this.localNano.db.create(database, function(err) {
    if (err) {
      if (/\bexists\b/i.test(err.message)) {
        return callback(null);
      }
      return callback(err);
    }
    _this.logger && _this.logger.debug('creating database: created locally; adding tracking row in user db');
    // insert it into the list of all user databases
    db.insert({ created: new Date() }, database, function(err, body) {
      if (err && !/\bconflict\b/i.test(err.message)) {
        return callback(err);
      }
      // replicate the newly created database
      _this.logger && _this.logger.debug('creating database: tracking row inserted and triggering replication for new db');
      _this._replicate(database, callback);
    });
  });
};

Guy.prototype._remove = function(database, callback) {
  var _this = this;
  this.localNano.db.destroy(database, function(err) {
    if (err && !/\bmissing\b/i.test(err.message)) {
      return  callback(err);
    }
    callback(null);
  });
};

Guy.prototype.create = function(database, callback) {
  var _this = this;
  this._enqueue(database, true);
  this.once('database:' + database, function(created) {
    if (!created) {
      return callback(new Error('Database "' + database + '" was removed before it could be created'));
    }
    callback(null, _this.localNano.use(database));
  });
};

Guy.prototype.remove = function(database, callback) {
  this._enqueue(database, false);
  this.once('database:' + database, function(created) {
    if (created) {
      return callback(new Error('Database "' + database + '" was created before it could be removed'));
    }
    callback(null);
  });
};

Guy.prototype.get = function(database, create, callback) {
  var _this = this;
  if (typeof create === 'function') {
    callback = create;
    create = false;
  }
  if (true === create) {
    this.create(database, callback);
  }
  else {
    this.localNano.db.get(database, function(err, body) {
      if (err) {
        return callback(err);
      }
      callback(null, _this.localNano.use(database));
    });
  }
};

module.exports = Guy;

<commit_msg>add pre sync event<commit_after>'use strict';

var fs = require('fs')
  , path = require('path')
  , url = require('url')
  , util = require('util')
  , events = require('events');

var async = require('async')
  , Nano = require('nano');

function Guy(options) {
  var _this = this;
  events.EventEmitter.call(this);

  this.options = options || {};
  this.options.database = this.options.database || 'user_databases';
  this.options.local = this.options.local || url.parse('http://127.0.0.1:5984');
  this.options.remote = this.options.remote;
  this.logger = this.options.log || null;
  this.localNano = null;
  this.remoteNano = null;
  this.queueTasks = {};
  this.queue = async.queue(this._queueWorker.bind(this), this.options.concurrency || 4);
  this.ready = false;
  this._init();
}

util.inherits(Guy, events.EventEmitter);

Guy.prototype._init = function() {
  var _this = this;
  this.localNano = Nano(this.options.local.href);
  this.remoteNano = Nano(this.options.remote.href);

  this.logger && this.logger.debug('checking if remote user database exists');
  this.remoteNano.db[this.options.createRemote ? 'create' : 'get'](this.options.database, function (err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      _this.emit('error', new Error('Error communicating with remote database "' + _this._buildUrl(_this.options.remote, { auth: '****', pathname: _this.options.database }) + '". Use option createRemote: true to create it'));
      return;
    }
    _this._initDatabase(function(err) {
      if (err) {
        return _this.emit('error', err);
      }
      _this.emit('online');
      _this._syncLocal(function(err) {
        if (err) {
          return _this.emit('error', err);
        }
        _this.logger && _this.logger.debug('sync and watch has run; emitting ready as soon as queue drains');
        _this.queue.drain = function() {
          if (!_this.ready) {
            _this.emit('ready');
            _this.ready = true;
          }
        };
        // if the queue is empty, manually trigger drain (bug in async?)
        if (!_this.queue.length()) {
          _this.queue.drain();
        }
      });
    });
  });
};

Guy.prototype._initDatabase = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('init local database');
  var _this = this;
  this.localNano.db.create(this.options.database, function(err, body) {
    // TODO: check error to make sure it's an "already exists" error?
    if (!err) {
      _this.logger && _this.logger.debug('init local database: creating local, replicating');
      _this._replicate(_this.options.database, function(err) {
        if (err) {
          return callback(err);
        }
        _this._watchLocal(callback);
      });
    }
    else {
      _this._watchLocal(callback);
    }
  });
};

Guy.prototype._watchLocal = function(callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);
  _this.logger && _this.logger.debug('init local database: watching for changes on ' + this.options.database);
  var feed = db.follow({ since: 'now' });
  feed.on('change', function (change) {
    _this.logger && _this.logger.debug(change, 'change');
    _this._enqueue(change.id, !change.deleted);
  });
  feed.on('error', function (err) {
    _this.emit('error', err);
  });
  feed.follow();
  callback(null);
};

// syncs the current data of options.database i.e. adds/removes databases
Guy.prototype._syncLocal = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('starting to sync offline user database changes');
  this.localNano.db.list(function(err, allLocalDatabases) {
    if (err) {
      return callback(err);
    }
    // FIXME: convert to paging otherwise a large number of databases could spike the memory usage
    _this.localNano.use(_this.options.database).list(function(err, userDatabases) {
      if (err) {
        return callback(err);
      }
      userDatabases.rows.forEach(function(row) {
        var userDatabase = row.id;
        if (!(userDatabase in _this.queueTasks)) {
          if (allLocalDatabases.indexOf(userDatabase) < 0) {
            _this.logger && _this.logger.debug('user database created while offline ' + userDatabase);
            _this._enqueue(userDatabase, true);
          }
        }
      });
      // TODO: handle user databases that are deleted while offline
      callback(null);
    });
  });
};

Guy.prototype._enqueue = function(database, create) {
  if (!(database in this.queueTasks)) {
    // only add it to the queue if it doesn't already exist
    this.queue.push({ database: database });
  }
  this.queueTasks[database] = create;
};

Guy.prototype._queueWorker = function(task, callback) {
  var _this = this
    , create = this.queueTasks[task.database]
    , database = task.database;
  delete this.queueTasks[database];
  this[create ? '_create' : '_remove'](database, function(err) {
    if (err) {
      _this.emit('error', err);
      return callback(err);
    }
    _this.emit((create ? 'create:' : 'remove:') + database);
    _this.emit('database:' + database, create);
    _this.emit(create ? 'create' : 'remove', database);
    callback(null);
  });
};

// inserts two-way replication between database on local and remote
Guy.prototype._replicate = function(database, callback) {
  var _this = this;
  var rep = this.localNano.use('_replicator')
    , localUrl = this.databaseUrl('local', database)
    , remoteUrl = this.databaseUrl('remote', database);
  _this.logger && _this.logger.debug('replicating database: ', database);

  this.remoteNano.db.create(database, function(err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      return callback(err);
    }
    _this.logger && _this.logger.debug('replicating database: inserting replication task');
    rep.insert({
      source: localUrl,
      target: remoteUrl,
      continuous: true
    }, null, function(err, body) {
      if (err) {
        return callback(err);
      }
      _this.logger && _this.logger.debug('replicating database: replicated partially complete');
      rep.insert({
        target: localUrl,
        source: remoteUrl,
        continuous: true
      }, null, callback);
    });
  });
};

Guy.prototype._buildUrl = function(urlObj, updates, returnObject) {
  var clonedUrlObj = Object.create(urlObj);
  for (var k in updates) {
    clonedUrlObj[k] = updates[k];
  }
  return returnObject ? clonedUrlObj : url.format(clonedUrlObj);
};

Guy.prototype.databaseUrl = function(localOrRemote, database) {
  return this._buildUrl(this.options[localOrRemote], { pathname: database });
}

Guy.prototype._create = function(database, callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);

  _this.logger && _this.logger.debug('creating database: ' + database);

  // create database locally
  this.localNano.db.create(database, function(err) {
    if (err) {
      if (/\bexists\b/i.test(err.message)) {
        return callback(null);
      }
      return callback(err);
    }
    _this.logger && _this.logger.debug('creating database: created locally; adding tracking row in user db');
    // insert it into the list of all user databases
    db.insert({ created: new Date() }, database, function(err, body) {
      if (err && !/\bconflict\b/i.test(err.message)) {
        return callback(err);
      }
      // replicate the newly created database
      _this.logger && _this.logger.debug('creating database: tracking row inserted and triggering replication for new db');
      _this._replicate(database, callback);
    });
  });
};

Guy.prototype._remove = function(database, callback) {
  var _this = this;
  this.localNano.db.destroy(database, function(err) {
    if (err && !/\bmissing\b/i.test(err.message)) {
      return  callback(err);
    }
    callback(null);
  });
};

Guy.prototype.create = function(database, callback) {
  var _this = this;
  this._enqueue(database, true);
  this.once('database:' + database, function(created) {
    if (!created) {
      return callback(new Error('Database "' + database + '" was removed before it could be created'));
    }
    callback(null, _this.localNano.use(database));
  });
};

Guy.prototype.remove = function(database, callback) {
  this._enqueue(database, false);
  this.once('database:' + database, function(created) {
    if (created) {
      return callback(new Error('Database "' + database + '" was created before it could be removed'));
    }
    callback(null);
  });
};

Guy.prototype.get = function(database, create, callback) {
  var _this = this;
  if (typeof create === 'function') {
    callback = create;
    create = false;
  }
  if (true === create) {
    this.create(database, callback);
  }
  else {
    this.localNano.db.get(database, function(err, body) {
      if (err) {
        return callback(err);
      }
      callback(null, _this.localNano.use(database));
    });
  }
};

module.exports = Guy;

<|endoftext|>


<commit_before>'use strict';

var chalk = require('chalk');
var moment = require('moment');
var open = require('open');
var editor = process.env.EDITOR;
var spawn = require('child_process').spawn;
var path = require('path');
var inquirer = require('inquirer');

hexo.extend.console.register('edit', 'Edit a post or draft with your favorite $EDITOR', {
  desc: 'Edit a post or draft with your favorite $EDITOR',
  usage: '[title] [-f|--folder] [-g|--gui]',
  arguments: [
    {name: 'title', desc: '(Part of) the title of a post. If more posts match this regex, a menu will be called.'},
  ],
  options: [
    {name: '-a, --after', desc: 'Only consider posts after this date (MM-DD-YYYY)'},
    {name: '-b, --before', desc: 'Only consider posts before this date (MM-DD-YYYY)'},
    {name: '-c, --category', desc: 'Category to filter on.'},
    {name: '-f, --folder', desc: 'Name of subfolder to filter on.'},
    {name: '-g, --gui', desc: 'Open file with associated GUI text editor. Default is to open in terminal using $EDITOR. If no $EDITOR is found, it will fall back to gui mode.'},
    {name: '-t, --tag', desc: 'Tag to filter on.'},
  ],
}, edit);

// extend `hexo new` to open newly created post/draft
hexo.on('new', function(post) {
  var edit;
  var content = post.content;

  // only open a new empty post -- prevent opening on publishing an already written one
  if (content.substr(content.indexOf('\n---\n')).length == 5) {
    if (!editor) {
      open(file);
    } else {
      edit = spawn(editor, [post.path], {stdio: 'inherit'});
      edit.on('exit', process.exit);
    }
  }
});

function edit(args) {

  var title = args._.join(' ').replace(/ /g, '-') || '';
  var folder = args.f || args.folder || '';
  var tag = args.t || args.tag || '';
  var cat = args.c || args.category || '';
  var before = args.b || args.before || '';
  before = before.replace(/\//g, '-');
  var after = args.a || args.after || '';
  after = after.replace(/\//g, '-');

  var gui = args.g || args.gui || !editor;

  // load in the posts before processing them
  hexo.load().then(function() {
    var sourceDir = hexo.source_dir;
    var searchDir = sourceDir;
    var editor = process.env.EDITOR;

    var selected;
    var entries;

    Promise.resolve(hexo.locals.get('posts').sort('-date').toArray()).then(function(posts) {
      var filtered = posts.slice();

      // allow omission of leading underscore or trailing s for the common _drafts and _posts folders
      if (/post|draft/.test(folder)) {
        folder = (/^_/.test(folder)) ? folder : '_' + folder;
        folder = (/s$/.test(folder)) ? folder : folder + 's';
      }

      filtered = (folder) ? filterFolder(filtered) : filtered;

      filtered = (title) ? filterTitle(filtered) : filtered;

      filtered = (tag) ? filterTag(filtered) : filtered;

      filtered = (cat) ? filterCategory(filtered) : filtered;

      filtered = (before) ? filterBefore(filtered) : filtered;

      filtered = (after) ? filterAfter(filtered) : filtered;

      if (filtered.length == 0) {
        console.log('Sorry, no filtered matched your query. Exiting.');
        process.exit();
      } else if (filtered.length == 1) {

        // no menu necessary if there is only one matching file
        selected = path.join(searchDir, filtered[0].source);
        openFile(selected);
      } else {

        // get a list of entries to put in the menu -- slugs are easy because it shows the subfolder and can easily be put back together with the searchDir to open it
        entries = filtered.map(function(post) {
          var entry = '';
          var folder = post.source.substr(0, post.source.lastIndexOf(path.sep));
          if (post.published) {
            entry = ['[', chalk.gray(post.date.format('MM-DD-YYYY')), '] ', post.title, ' (', chalk.green(folder), ')'].join('');
          } else {
            entry = ['[', chalk.yellow.bgBlack('draft'), '] ', post.title].join('');
          }

          return entry;
        });

        inquirer.prompt([
          {
            type: 'list',
            name: 'file',
            message: 'Select the file you wish to edit.',
            choices: entries,
          },
        ], function(answer) {
          var pos = entries.indexOf(answer.file);
          selected = path.join(sourceDir, filtered[pos].source);
          openFile(selected);
        });
      }

    });

    // filter the posts using a subfolder if supplied
    function filterFolder(posts) {
      var reFolder = new RegExp(folder);
      return posts.filter(function(post) {
        return reFolder.test(post.source.substr(0, post.source.lastIndexOf(path.sep)));
      });
    }

    // filter the posts using a tag if supplied
    function filterTag(posts) {
      var reTag = new RegExp(tag);
      return posts.filter(function(post) {
        return post.tags.data.some(function(postTag) {
          return reTag.test(postTag.name);
        });
      });
    }

    // filter the posts using a category if supplied
    function filterCategory(posts) {
      var reCat = new RegExp(cat);
      return posts.filter(function(post) {
        return post.categories.data.some(function(postCat) {
          return reCat.test(postCat.name);
        });
      });
    }

    // filter the posts using a before date if supplied
    function filterBefore(posts) {
      before = moment(before, 'MM-DD-YYYY', true);
      if (!before.isValid()) {
        console.log(chalk.red('Before date is not valid (expecting `MM-DD-YYYY`), ignoring argument.'));
        return posts;
      }

      return posts.filter(function(post) {
        return moment(post.date).isBefore(before);
      });
    }

    // filter the posts using an after date if supplied
    function filterAfter(posts) {
      after = moment(after, 'MM-DD-YYYY', true);
      if (!after.isValid()) {
        console.log(chalk.red('After date is not valid (expecting `MM-DD-YYYY`), ignoring argument.'));
        return posts;
      }

      return posts.filter(function(post) {
        return moment(post.date).isAfter(after);
      });
    }

    // filter the posts with the supplied regular expression -- uses the slug to avoid capitalization and spacing shenanigans
    function filterTitle(posts) {
      var reTitle = new RegExp(title, 'i');
      return posts.filter(function(post) {
        return reTitle.test(post.slug);
      });
    }

    // spawn process and open with associated gui or terminal editor
    function openFile(file) {
      if (!editor || gui) {
        open(file);
      } else {
        var edit = spawn(editor, [file], {stdio: 'inherit'});
        edit.on('exit', process.exit);
      }
    }

  });
};
<commit_msg>can now filter just on drafts<commit_after>'use strict';

var chalk = require('chalk');
var moment = require('moment');
var open = require('open');
var editor = process.env.EDITOR;
var spawn = require('child_process').spawn;
var path = require('path');
var inquirer = require('inquirer');

hexo.extend.console.register('edit', 'Edit a post or draft with your favorite $EDITOR', {
  desc: 'Edit a post or draft with your favorite $EDITOR',
  usage: '[title] [-f|--folder] [-g|--gui]',
  arguments: [
    {name: 'title', desc: '(Part of) the title of a post. If more posts match this regex, a menu will be called.'},
  ],
  options: [
    {name: '-a, --after', desc: 'Only consider posts after this date (MM-DD-YYYY)'},
    {name: '-b, --before', desc: 'Only consider posts before this date (MM-DD-YYYY)'},
    {name: '-c, --category', desc: 'Category to filter on.'},
    {name: '-d, --draft', desc: 'Only consider drafts'},
    {name: '-f, --folder', desc: 'Name of subfolder to filter on.'},
    {name: '-g, --gui', desc: 'Open file with associated GUI text editor. Default is to open in terminal using $EDITOR. If no $EDITOR is found, it will fall back to gui mode.'},
    {name: '-t, --tag', desc: 'Tag to filter on.'},
  ],
}, edit);

// extend `hexo new` to open newly created post/draft
hexo.on('new', function(post) {
  var edit;
  var content = post.content;

  // only open a new empty post -- prevent opening on publishing an already written one
  if (content.substr(content.indexOf('\n---\n')).length == 5) {
    if (!editor) {
      open(file);
    } else {
      edit = spawn(editor, [post.path], {stdio: 'inherit'});
      edit.on('exit', process.exit);
    }
  }
});

function edit(args) {

  var title = args._.join(' ').replace(/ /g, '-') || '';
  var folder = args.f || args.folder || '';
  var draft = args.d || args.draft || '';
  var tag = args.t || args.tag || '';
  var cat = args.c || args.category || '';
  var before = args.b || args.before || '';
  before = before.replace(/\//g, '-');
  var after = args.a || args.after || '';
  after = after.replace(/\//g, '-');

  var gui = args.g || args.gui || !editor;

  // load in the posts before processing them
  hexo.load().then(function() {
    var sourceDir = hexo.source_dir;
    var searchDir = sourceDir;
    var editor = process.env.EDITOR;

    var selected;
    var entries;

    Promise.resolve(hexo.locals.get('posts').sort('-date').toArray()).then(function(posts) {
      var filtered = posts.slice();

      // allow omission of leading underscore or trailing s for the common _drafts and _posts folders
      if (/post|draft/.test(folder)) {
        folder = (/^_/.test(folder)) ? folder : '_' + folder;
        folder = (/s$/.test(folder)) ? folder : folder + 's';
      }

      filtered = (draft) ? filterDrafts(filtered) : filtered;

      filtered = (folder) ? filterFolder(filtered) : filtered;

      filtered = (title) ? filterTitle(filtered) : filtered;

      filtered = (tag) ? filterTag(filtered) : filtered;

      filtered = (cat) ? filterCategory(filtered) : filtered;

      filtered = (before) ? filterBefore(filtered) : filtered;

      filtered = (after) ? filterAfter(filtered) : filtered;

      if (filtered.length == 0) {
        console.log('Sorry, no filtered matched your query. Exiting.');
        process.exit();
      } else if (filtered.length == 1) {

        // no menu necessary if there is only one matching file
        selected = path.join(searchDir, filtered[0].source);
        openFile(selected);
      } else {

        // get a list of entries to put in the menu -- slugs are easy because it shows the subfolder and can easily be put back together with the searchDir to open it
        entries = filtered.map(function(post) {
          var entry = '';
          var folder = post.source.substr(0, post.source.lastIndexOf(path.sep));
          if (post.published) {
            entry = ['[', chalk.gray(post.date.format('MM-DD-YYYY')), '] ', post.title, ' (', chalk.green(folder), ')'].join('');
          } else {
            entry = ['[', chalk.yellow.bgBlack('draft'), '] ', post.title].join('');
          }

          return entry;
        });

        inquirer.prompt([
          {
            type: 'list',
            name: 'file',
            message: 'Select the file you wish to edit.',
            choices: entries,
          },
        ], function(answer) {
          var pos = entries.indexOf(answer.file);
          selected = path.join(sourceDir, filtered[pos].source);
          openFile(selected);
        });
      }

    });

    // filter the posts using a subfolder if supplied
    function filterFolder(posts) {
      var reFolder = new RegExp(folder);
      return posts.filter(function(post) {
        return reFolder.test(post.source.substr(0, post.source.lastIndexOf(path.sep)));
      });
    }

    // filter the posts using a tag if supplied
    function filterTag(posts) {
      var reTag = new RegExp(tag);
      return posts.filter(function(post) {
        return post.tags.data.some(function(postTag) {
          return reTag.test(postTag.name);
        });
      });
    }

    // filter the posts using a category if supplied
    function filterCategory(posts) {
      var reCat = new RegExp(cat);
      return posts.filter(function(post) {
        return post.categories.data.some(function(postCat) {
          return reCat.test(postCat.name);
        });
      });
    }

    // filter out all non-published posts
    function filterDrafts(posts) {
      return posts.filter(function(post) {
        return !post.published;
      });
    }

    // filter the posts using a before date if supplied
    function filterBefore(posts) {
      before = moment(before, 'MM-DD-YYYY', true);
      if (!before.isValid()) {
        console.log(chalk.red('Before date is not valid (expecting `MM-DD-YYYY`), ignoring argument.'));
        return posts;
      }

      return posts.filter(function(post) {
        return moment(post.date).isBefore(before);
      });
    }

    // filter the posts using an after date if supplied
    function filterAfter(posts) {
      after = moment(after, 'MM-DD-YYYY', true);
      if (!after.isValid()) {
        console.log(chalk.red('After date is not valid (expecting `MM-DD-YYYY`), ignoring argument.'));
        return posts;
      }

      return posts.filter(function(post) {
        return moment(post.date).isAfter(after);
      });
    }

    // filter the posts with the supplied regular expression -- uses the slug to avoid capitalization and spacing shenanigans
    function filterTitle(posts) {
      var reTitle = new RegExp(title, 'i');
      return posts.filter(function(post) {
        return reTitle.test(post.slug);
      });
    }

    // spawn process and open with associated gui or terminal editor
    function openFile(file) {
      if (!editor || gui) {
        open(file);
      } else {
        var edit = spawn(editor, [file], {stdio: 'inherit'});
        edit.on('exit', process.exit);
      }
    }

  });
};
<|endoftext|>


<commit_before>/*
 * @TODO Makes the callback mandatory or automatically turns synchronous if not present
 *
 */

var _ = require('underscore'),
    findit = require('./lib/traverse');

/*
 * Default function in case no callback is provided
 *
 */
function noop () {  }

/*
 * Throws if no callback is available or cb is  noop
 *
 */
function _ThrowOrCallback (err, cb) {
  if (cb && cb !== noop) {
    cb(err);
  } else {
    throw err;
  }
}

/*
 * Adds properties to `this`, where `this` is an object literal
 * representing an entry in the filesystem
 *
 */
function _addProperties(file, relativePath, stat) {

  var type;
  if (stat.isFile())          type = 'file';
  if (stat.isSymbolicLink())  type = 'symlink';
  if (stat.isDirectory()) {
    type = 'directory';
    this.children = [];
  }

  var name = file.split('/').filter(function (e) {
    return e.length;
  }).pop();

  var size = stat.size;

  var fullPath = (require('path')).resolve(file);

  this.name = name;
  this.relativePath = relativePath;
  this.fullPath = fullPath;
  this.size = size;
  this.type = type;
}

function _findChild (data, name) {
  if (!data.children) {
    return null;
  }
  var filtered = data.children.filter(function (elt) {
    return elt.name === name;
  });
  if (filtered.length) {
    return filtered[0];
  }
  return null;
}

module.exports = function () {
  "use strict";

  var _entryProps = ['name', 'relativePath', 'fullPath', 'size', 'type'];

  /*
   * The returned object
   */
  var obj = {
    include: _include,
    describe: _describe,
    traverse: _traverse
  };

  function _include () {
    return obj;
  }

  function _describe () {
    return obj;
  }

  function _traverse (rootPath, opts, cb) {
    if (_.isFunction(opts)) {
      cb = opts;
      opts = {};
    }
    if (cb && !_.isFunction(cb)) {
      return _ThrowOrCallback(new TypeError('The callback must be a function.'));
    }
    if (_.isObject(rootPath)) {
      opts = rootPath;
      rootPath = opts.path;
    }

    if (!_.isString(rootPath)) {
      return _ThrowOrCallback(new Error('no path given'), cb);
    }

    var finder = findit.find(rootPath, opts);
    var _hasErrors = false;
    var data = {};

    finder.on('path', function (file, stat) {
      var splitPath = file.replace(rootPath, '').split('/').filter(function (e) {
        return e.length;
      });
      var relativePathToSearchRoot = file.replace(rootPath, '').replace('/', '');
      if (relativePathToSearchRoot.length) {
        relativePathToSearchRoot = relativePathToSearchRoot.split('/'); //a '/' could confuse with the FS root
      } else {
        relativePathToSearchRoot = [];
      }

      var _data = data;
      for (var i = 0; i < relativePathToSearchRoot.length; i++) {
        var _child = _findChild(_data, relativePathToSearchRoot[i]);
        if (!_child) {
          _child = {};
          // @TODO The following sucks monkey balls
          _data.children = _data.children || [];
          _data.children.push(_child);
        }
        _data = _child;
      }
      _addProperties.call(_data, file, relativePathToSearchRoot.join('/'), stat);
    });

    finder.on('end', function () {
      if (_hasErrors) {
        return _ThrowOrCallback(_hasErrors, cb);
      } else {
        cb && cb(null, data);
      }
    });

    finder.on('error', function (err) {
      _hasErrors = err;
    });
  }

  return obj;
};
<commit_msg>Restores findit for the moment<commit_after>/*
 * @TODO Makes the callback mandatory or automatically turns synchronous if not present
 *
 */

var _ = require('underscore'),
    findit = require('findit');

/*
 * Default function in case no callback is provided
 *
 */
function noop () {  }

/*
 * Throws if no callback is available or cb is  noop
 *
 */
function _ThrowOrCallback (err, cb) {
  if (cb && cb !== noop) {
    cb(err);
  } else {
    throw err;
  }
}

/*
 * Adds properties to `this`, where `this` is an object literal
 * representing an entry in the filesystem
 *
 */
function _addProperties(file, relativePath, stat) {

  var type;
  if (stat.isFile())          type = 'file';
  if (stat.isSymbolicLink())  type = 'symlink';
  if (stat.isDirectory()) {
    type = 'directory';
    this.children = [];
  }

  var name = file.split('/').filter(function (e) {
    return e.length;
  }).pop();

  var size = stat.size;

  var fullPath = (require('path')).resolve(file);

  this.name = name;
  this.relativePath = relativePath;
  this.fullPath = fullPath;
  this.size = size;
  this.type = type;
}

function _findChild (data, name) {
  if (!data.children) {
    return null;
  }
  var filtered = data.children.filter(function (elt) {
    return elt.name === name;
  });
  if (filtered.length) {
    return filtered[0];
  }
  return null;
}

module.exports = function () {
  "use strict";

  var _entryProps = ['name', 'relativePath', 'fullPath', 'size', 'type'];

  /*
   * The returned object
   */
  var obj = {
    include: _include,
    describe: _describe,
    traverse: _traverse
  };

  function _include () {
    return obj;
  }

  function _describe () {
    return obj;
  }

  function _traverse (rootPath, opts, cb) {
    if (_.isFunction(opts)) {
      cb = opts;
      opts = {};
    }
    if (cb && !_.isFunction(cb)) {
      return _ThrowOrCallback(new TypeError('The callback must be a function.'));
    }
    if (_.isObject(rootPath)) {
      opts = rootPath;
      rootPath = opts.path;
    }

    if (!_.isString(rootPath)) {
      return _ThrowOrCallback(new Error('no path given'), cb);
    }

    var finder = findit.find(rootPath, opts);
    var _hasErrors = false;
    var data = {};

    finder.on('path', function (file, stat) {
      var splitPath = file.replace(rootPath, '').split('/').filter(function (e) {
        return e.length;
      });
      var relativePathToSearchRoot = file.replace(rootPath, '').replace('/', '');
      if (relativePathToSearchRoot.length) {
        relativePathToSearchRoot = relativePathToSearchRoot.split('/'); //a '/' could confuse with the FS root
      } else {
        relativePathToSearchRoot = [];
      }

      var _data = data;
      for (var i = 0; i < relativePathToSearchRoot.length; i++) {
        var _child = _findChild(_data, relativePathToSearchRoot[i]);
        if (!_child) {
          _child = {};
          // @TODO The following sucks monkey balls
          _data.children = _data.children || [];
          _data.children.push(_child);
        }
        _data = _child;
      }
      _addProperties.call(_data, file, relativePathToSearchRoot.join('/'), stat);
    });

    finder.on('end', function () {
      if (_hasErrors) {
        return _ThrowOrCallback(_hasErrors, cb);
      } else {
        cb && cb(null, data);
      }
    });

    finder.on('error', function (err) {
      _hasErrors = err;
    });
  }

  return obj;
};
<|endoftext|>


<commit_before>module.exports = {
	on: bind,
	off: unbind,
	emit: fire
};

var _ = require('mutypes');

//jquery guarant
var $ = typeof jQuery === 'undefined' ? undefined : jQuery;

//set of target callbacks, {target: [cb1, cb2, ...]}
var targetCbCache = new WeakMap;

/**
* Bind fn to a target
*/
function bind(target, evt, fn){
	//DOM events
	if (isEventTarget(target)) {
		//bind target fn
		if ($){
			//delegate to jquery
			$(target).on(evt, fn);
		} else {
			//listen element
			target.addEventListener(evt, fn)
		}
		//FIXME: old IE
	}

	//Non-DOM events
	//ensure callbacks array for target exist
	if (!targetCbCache.has(target)) targetCbCache.set(target, {});
	var targetCallbacks = targetCbCache.get(target);

	//save callback
	(targetCallbacks[evt] = targetCallbacks[evt] || []).push(fn);
}

/**
* Bind fn to a target
*/
function unbind(target, evt, fn){
	//unbind all listeners passed
	if (_.isArray(fn)){
		for (var i = fn.length; i--;){
			unbind(target, evt, fn[i]);
		}
		return;
	}

	//unbind all listeners if no fn specified
	if (fn === undefined) {
		var callbacks = targetCbCache.get(target);
		if (!callbacks) return;
		//unbind all if no evtRef defined
		if (evt === undefined) {
			for (var evtName in callbacks) {
				unbind(target, evtName, callbacks[evtName]);
			}
		}
		else if (callbacks[evt]) {
			unbind(target, evt, callbacks[evt]);
		}
		return;
	}

	//DOM events on elements
	if (isEventTarget(target)) {
		//delegate to jquery
		if ($){
			$(target).off(evt, fn);
		}

		//listen element
		else {
			target.removeEventListener(evt, fn)
		}
	}

	//ignore if no event specified
	if (!targetCbCache.has(target)) return;

	var evtCallbacks = targetCbCache.get(target)[evt];

	if (!evtCallbacks) return;

	//remove specific handler
	for (var i = 0; i < evtCallbacks.length; i++) {
		if (evtCallbacks[i] === fn) {
			evtCallbacks.splice(i, 1);
			break;
		}
	}
}

/**
* Event trigger
*/
function fire(target, eventName, data, bubbles){
	//DOM events
	if (isEventTarget(target)) {
		if ($){
			//TODO: decide how to pass data
			var evt = $.Event( eventName, data );
			evt.detail = data;
			bubbles ? $(target).trigger(evt) : $(target).triggerHandler(evt);
		} else {
			//NOTE: this doesnot bubble on disattached elements
			var evt;

			if (eventName instanceof Event) {
				evt = eventName;
			} else {
				evt =  document.createEvent('CustomEvent');
				evt.initCustomEvent(eventName, bubbles, null, data)
			}

			// var evt = new CustomEvent(eventName, { detail: data, bubbles: bubbles })

			target.dispatchEvent(evt);
		}
	}

	//no-DOM events
	else {
		//ignore if no event specified
		if (!targetCbCache.has(target)) return;

		var evtCallbacks = targetCbCache.get(target)[eventName];

		if (!evtCallbacks) return;
		for (var i = evtCallbacks.length; i--; ) {
			evtCallbacks[i] && evtCallbacks[i].call(target, {
				detail: data,
				type: eventName
			});
		}
	}
}

//detects whether element is able to emit/dispatch events
//TODO: detect eventful objects in a more wide way
function isEventTarget (target){
	return target && !!target.addEventListener;
}<commit_msg>Fix firing order<commit_after>module.exports = {
	on: bind,
	off: unbind,
	emit: fire
};

var _ = require('mutypes');

//jquery guarant
var $ = typeof jQuery === 'undefined' ? undefined : jQuery;

//set of target callbacks, {target: [cb1, cb2, ...]}
var targetCbCache = new WeakMap;

/**
* Bind fn to a target
*/
function bind(target, evt, fn){
	//DOM events
	if (isEventTarget(target)) {
		//bind target fn
		if ($){
			//delegate to jquery
			$(target).on(evt, fn);
		} else {
			//listen element
			target.addEventListener(evt, fn)
		}
		//FIXME: old IE
	}

	//Non-DOM events
	//ensure callbacks array for target exist
	if (!targetCbCache.has(target)) targetCbCache.set(target, {});
	var targetCallbacks = targetCbCache.get(target);

	//save callback
	(targetCallbacks[evt] = targetCallbacks[evt] || []).push(fn);
}

/**
* Bind fn to a target
*/
function unbind(target, evt, fn){
	//unbind all listeners passed
	if (_.isArray(fn)){
		for (var i = fn.length; i--;){
			unbind(target, evt, fn[i]);
		}
		return;
	}

	//unbind all listeners if no fn specified
	if (fn === undefined) {
		var callbacks = targetCbCache.get(target);
		if (!callbacks) return;
		//unbind all if no evtRef defined
		if (evt === undefined) {
			for (var evtName in callbacks) {
				unbind(target, evtName, callbacks[evtName]);
			}
		}
		else if (callbacks[evt]) {
			unbind(target, evt, callbacks[evt]);
		}
		return;
	}

	//DOM events on elements
	if (isEventTarget(target)) {
		//delegate to jquery
		if ($){
			$(target).off(evt, fn);
		}

		//listen element
		else {
			target.removeEventListener(evt, fn)
		}
	}

	//ignore if no event specified
	if (!targetCbCache.has(target)) return;

	var evtCallbacks = targetCbCache.get(target)[evt];

	if (!evtCallbacks) return;

	//remove specific handler
	for (var i = 0; i < evtCallbacks.length; i++) {
		if (evtCallbacks[i] === fn) {
			evtCallbacks.splice(i, 1);
			break;
		}
	}
}

/**
* Event trigger
*/
function fire(target, eventName, data, bubbles){
	//DOM events
	if (isEventTarget(target)) {
		if ($){
			//TODO: decide how to pass data
			var evt = $.Event( eventName, data );
			evt.detail = data;
			bubbles ? $(target).trigger(evt) : $(target).triggerHandler(evt);
		} else {
			//NOTE: this doesnot bubble on disattached elements
			var evt;

			if (eventName instanceof Event) {
				evt = eventName;
			} else {
				evt =  document.createEvent('CustomEvent');
				evt.initCustomEvent(eventName, bubbles, null, data)
			}

			// var evt = new CustomEvent(eventName, { detail: data, bubbles: bubbles })

			target.dispatchEvent(evt);
		}
	}

	//no-DOM events
	else {
		//ignore if no event specified
		if (!targetCbCache.has(target)) return;

		var evtCallbacks = targetCbCache.get(target)[eventName];

		if (!evtCallbacks) return;

		//copy callbacks to fire because list can change in some handler
		var fireList = evtCallbacks.slice();
		for (var i = 0; i < fireList.length; i++ ) {
			evtCallbacks[i] && evtCallbacks[i].call(target, {
				detail: data,
				type: eventName
			});
		}
	}
}

//detects whether element is able to emit/dispatch events
//TODO: detect eventful objects in a more wide way
function isEventTarget (target){
	return target && !!target.addEventListener;
}<|endoftext|>


<commit_before>'use strict'
const url = require('url')
const qs = require('querystring')
const EventEmitter = require('events').EventEmitter
const request = require('request')
const crypto = require('crypto')

class Bot extends EventEmitter {
  constructor (opts) {
    super()

    opts = opts || {}
    if (!opts.token) {
      throw new Error('Missing page token. See FB documentation for details: https://developers.facebook.com/docs/messenger-platform/quickstart')
    }
    this.token = opts.token
    this.app_secret = opts.app_secret || false
    this.verify_token = opts.verify || false
  }

  getProfile (id, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'GET',
      uri: `https://graph.facebook.com/v2.6/${id}`,
      qs: {
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender',
        access_token: this.token
      },
      json: true
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  sendMessage (recipient, payload, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {
        access_token: this.token
      },
      json: {
        recipient: { id: recipient },
        message: payload
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setTyping(recipient, typing, cb) {
    if (!cb) cb = Function.prototype
    var typing_status = typing ? 'typing_on' : 'typing_off';

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {
        access_token: this.token
      },
      json: {
        recipient: {
          id: recipient
        },
        sender_action: typing_status
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setThreadSettings (thread_state, call_to_actions, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/thread_settings',
      qs: {
        access_token: this.token
      },
      json: {
        setting_type: 'call_to_actions',
        thread_state: thread_state,
        call_to_actions: call_to_actions
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setGetStartedButton (payload, cb) {
    if (!cb) cb = Function.prototype

    return this.setThreadSettings('new_thread', payload, cb);
  }

  setPersistentMenu(payload, cb) {
    if (!cb) cb = Function.prototype

    return this.setThreadSettings('existing_thread', payload, cb);
  }

  middleware () {
    return (req, res) => {
      // we always write 200, otherwise facebook will keep retrying the request
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (req.url === '/_status') return res.end(JSON.stringify({status: 'ok'}))
      if (this.verify_token && req.method === 'GET') return this._verify(req, res)
      if (req.method !== 'POST') return res.end()

      let body = ''

      req.on('data', (chunk) => {
        body += chunk
      })

      req.on('end', () => {
        // check message integrity
        if (this.app_secret) {
          let hmac = crypto.createHmac('sha1', this.app_secret)
          hmac.update(body)

          if (req.headers['x-hub-signature'] !== `sha1=${hmac.digest('hex')}`) {
            this.emit('error', new Error('Message integrity check failed'))
            return res.end(JSON.stringify({status: 'not ok', error: 'Message integrity check failed'}))
          }
        }

        let parsed = JSON.parse(body)
        this._handleMessage(parsed)

        res.end(JSON.stringify({status: 'ok'}))
      })
    }
  }

  _handleMessage (json) {
    let entries = json.entry

    entries.forEach((entry) => {
      let events = entry.messaging

      events.forEach((event) => {
        // handle inbound messages
        if (event.message) {
          this._handleEvent('message', event)
        }

        // handle echos
        if (event.message && event.message.is_echo) {
          this._handleEvent('echo', event)
        }

        // handle postbacks
        if (event.postback) {
          this._handleEvent('postback', event)
        }

        // handle message delivered
        if (event.delivery) {
          this._handleEvent('delivery', event)
        }

        // handle message read
        if (event.read) {
          this._handleEvent('read', event)
        }

        // handle authentication
        if (event.optin) {
          this._handleEvent('authentication', event)
        }

        // handle account_linking
        if (event.account_linking && event.account_linking.status) {
          if (event.account_linking.status == 'linked') {
            this._handleEvent('accountLinked', event)
          } else if (event.account_linking.status == 'unlinked') {
            this._handleEvent('accountUnlinked', event)
          }
        }
      })
    })
  }

  _verify (req, res) {
    let query = qs.parse(url.parse(req.url).query)

    if (query['hub.verify_token'] === this.verify_token) {
      return res.end(query['hub.challenge'])
    }

    return res.end('Error, wrong validation token')
  }

  _handleEvent (type, event) {
    this.emit(type, event, this.sendMessage.bind(this, event.sender.id))
  }
}

module.exports = Bot
<commit_msg>Syntax changes<commit_after>'use strict'
const url = require('url')
const qs = require('querystring')
const EventEmitter = require('events').EventEmitter
const request = require('request')
const crypto = require('crypto')

class Bot extends EventEmitter {
  constructor (opts) {
    super()

    opts = opts || {}
    if (!opts.token) {
      throw new Error('Missing page token. See FB documentation for details: https://developers.facebook.com/docs/messenger-platform/quickstart')
    }
    this.token = opts.token
    this.app_secret = opts.app_secret || false
    this.verify_token = opts.verify || false
  }

  getProfile (id, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'GET',
      uri: `https://graph.facebook.com/v2.6/${id}`,
      qs: {
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender',
        access_token: this.token
      },
      json: true
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  sendMessage (recipient, payload, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {
        access_token: this.token
      },
      json: {
        recipient: { id: recipient },
        message: payload
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setTyping (recipient, typing, cb) {
    if (!cb) cb = Function.prototype
    var typingStatus = typing ? 'typing_on' : 'typing_off'

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/messages',
      qs: {
        access_token: this.token
      },
      json: {
        recipient: {
          id: recipient
        },
        sender_action: typingStatus
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setThreadSettings (threadState, callToActions, cb) {
    if (!cb) cb = Function.prototype

    request({
      method: 'POST',
      uri: 'https://graph.facebook.com/v2.6/me/thread_settings',
      qs: {
        access_token: this.token
      },
      json: {
        setting_type: 'call_to_actions',
        thread_state: threadState,
        call_to_actions: callToActions
      }
    }, (err, res, body) => {
      if (err) return cb(err)
      if (body.error) return cb(body.error)

      cb(null, body)
    })
  }

  setGetStartedButton (payload, cb) {
    if (!cb) cb = Function.prototype

    return this.setThreadSettings('new_thread', payload, cb)
  }

  setPersistentMenu (payload, cb) {
    if (!cb) cb = Function.prototype

    return this.setThreadSettings('existing_thread', payload, cb)
  }

  middleware () {
    return (req, res) => {
      // we always write 200, otherwise facebook will keep retrying the request
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (req.url === '/_status') return res.end(JSON.stringify({status: 'ok'}))
      if (this.verify_token && req.method === 'GET') return this._verify(req, res)
      if (req.method !== 'POST') return res.end()

      let body = ''

      req.on('data', (chunk) => {
        body += chunk
      })

      req.on('end', () => {
        // check message integrity
        if (this.app_secret) {
          let hmac = crypto.createHmac('sha1', this.app_secret)
          hmac.update(body)

          if (req.headers['x-hub-signature'] !== `sha1=${hmac.digest('hex')}`) {
            this.emit('error', new Error('Message integrity check failed'))
            return res.end(JSON.stringify({status: 'not ok', error: 'Message integrity check failed'}))
          }
        }

        let parsed = JSON.parse(body)
        this._handleMessage(parsed)

        res.end(JSON.stringify({status: 'ok'}))
      })
    }
  }

  _handleMessage (json) {
    let entries = json.entry

    entries.forEach((entry) => {
      let events = entry.messaging

      events.forEach((event) => {
        // handle inbound messages
        if (event.message) {
          this._handleEvent('message', event)
        }

        // handle echos
        if (event.message && event.message.is_echo) {
          this._handleEvent('echo', event)
        }

        // handle postbacks
        if (event.postback) {
          this._handleEvent('postback', event)
        }

        // handle message delivered
        if (event.delivery) {
          this._handleEvent('delivery', event)
        }

        // handle message read
        if (event.read) {
          this._handleEvent('read', event)
        }

        // handle authentication
        if (event.optin) {
          this._handleEvent('authentication', event)
        }

        // handle account_linking
        if (event.account_linking && event.account_linking.status) {
          if (event.account_linking.status === 'linked') {
            this._handleEvent('accountLinked', event)
          } else if (event.account_linking.status === 'unlinked') {
            this._handleEvent('accountUnlinked', event)
          }
        }
      })
    })
  }

  _verify (req, res) {
    let query = qs.parse(url.parse(req.url).query)

    if (query['hub.verify_token'] === this.verify_token) {
      return res.end(query['hub.challenge'])
    }

    return res.end('Error, wrong validation token')
  }

  _handleEvent (type, event) {
    this.emit(type, event, this.sendMessage.bind(this, event.sender.id))
  }
}

module.exports = Bot
<|endoftext|>


<commit_before>'use strict';
var util = require('util');

function createTree(list, rootNodes, customID) {
  var tree = [];

  for (var prop in rootNodes) {
    if (!rootNodes.hasOwnProperty(prop)) {
      continue;
    }

    var node = rootNodes[prop];
    var listItem = list[node[customID]];

    if (listItem) {
      node.children = createTree(list, listItem, customID);
    }

    tree.push(node);
  }

  return tree;
}

function orderByParents(list, config) {
  var parents = {};
  var parentProperty = config.parentProperty;

  list.forEach(function(item) {
    var parentID = item[parentProperty] || 0;
    parents[parentID] = parents[parentID] || [];
    parents[parentID].push(item);
  });

  return parents;
}

/**
 * arrayToTree
 * Convert a plain array of nodes (with pointers to parent nodes) to a tree
 *
 * @name arrayToTree
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `parentProperty` (String): A name of a property where a link to
 *     a parent node could be found. Default: 'parent_id'
 *  - `data` (Array): An array of data
 *  - `customID` (String): An unique node identifier. Default: 'id'
 *
 * @return {Array} Result of transformation
 */

module.exports = function arrayToTree(options) {
  var config = util._extend({
      parentProperty: 'parent_id',
      data: [],
      customID: 'id'
    }, options);

  var data = config.data;

  if (!util.isArray(data)) {
    throw new Error('Expected an object but got an invalid argument');
  }

  var cloned = data.slice();
  var ordered = orderByParents(cloned, config);
  return createTree(ordered, ordered[0], config.customID);
};
<commit_msg>Refactoring<commit_after>'use strict';
var util = require('util');

var exists = function(obj, key) {
  return obj != null && Object.hasOwnProperty.call(obj, key);
};

var createTree = function(array, rootNodes, customID) {
  var tree = [];

  for (var key in rootNodes) {
    if (!exists(rootNodes, key)) {
      continue ;
    }
    var parentNode = rootNodes[key];
    var childNode = array[parentNode[customID]];

    if (childNode) {
      parentNode.children = createTree(array, childNode, customID);
    }

    tree.push(parentNode);
  }

  return tree;
};

var groupByParents = function(array, options) {
  var parents = {};
  var parentProperty = options.parentProperty;

  array.forEach(function(item) {
    var parentID = item[parentProperty] || options.rootID;
    if (exists(parents, parentID)) {
      parents[parentID].push(item);
    } else {
      parents[parentID] = [item];
    }
  });

  return parents;
};

/**
 * arrayToTree
 * Convert a plain array of nodes (with pointers to parent nodes) to a tree
 *
 * @name arrayToTree
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `parentProperty` (String): A name of a property where a link to
 *     a parent node could be found. Default: 'parent_id'
 *  - `data` (Array): An array of data
 *  - `customID` (String): An unique node identifier. Default: 'id'
 *
 * @return {Array} Result of transformation
 */

module.exports = function arrayToTree(options) {
  options = util._extend({
    parentProperty: 'parent_id',
    data: [],
    customID: 'id',
    rootID: '0'
  }, options);

  var data = options.data;

  if (!util.isArray(data)) {
    throw new Error('Expected an object but got an invalid argument');
  }

  var cloned = data.slice();
  var grouped = groupByParents(cloned, options);
  return createTree(grouped, grouped[options.rootID], options.customID);
};
<|endoftext|>


<commit_before>var SPACE_WIDTH = 40,
    SPACE_HEIGHT = 30,
    GAME_WIDTH = 400,
    GAME_HEIGHT = 300;

var data = [
    [ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 1, 0, 0, 0, 2, 0 ],
    [ 0, 0, 2, 0, 2, 0, 1, 0, 0, 0 ],
    [ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 ],
    [ 2, 0, 0, 0, 0, 1, 0, 0, 0, 1 ],
    [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 ],
    [ 0, 0, 2, 0, 0, 0, 1, 0, 0, 0 ],
    [ 1, 0, 0, 0, 2, 0, 0, 0, 0, 1 ],
    [ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 ],
    [ 0, 0, 2, 0, 0, 0, 0, 0, 0, 2 ]
];

function Level(data, rows, columns) {
    this._data = data;

    this.container = new PIXI.Container();

    this._gridGraphic = new PIXI.Graphics();

    this._rects = [];

    this.leftHeld = false;
    this.rightHeld = false;

    // grid background
    this._gridGraphic.lineStyle(0.5, 0xFFFFFF, 1);

    for (var i = 0; i < rows; i++) {
        this._gridGraphic.moveTo(0, SPACE_HEIGHT * i);
        this._gridGraphic.lineTo(GAME_WIDTH, SPACE_HEIGHT * i);
    }

    for (i = 0; i < columns; i++) {
        this._gridGraphic.moveTo(SPACE_WIDTH * i, 0);
        this._gridGraphic.lineTo(SPACE_WIDTH * i, GAME_HEIGHT);
    }

    this.container.addChild(this._gridGraphic);

    data.forEach(function(row, r) {
        row.forEach(function(column, c) {
            if (column !== 0) {
                var special = new PIXI.Graphics();

                if (column === 1) {
                    special.beginFill(0xFFFFFF, 0.75);
                } else if (column === 2) {
                    special.beginFill(0xB1B1B1, 0.5);
                }

                special.drawEllipse((SPACE_WIDTH * c) + (SPACE_WIDTH / 2), (SPACE_HEIGHT * r) + (SPACE_HEIGHT / 2), SPACE_WIDTH / 3, SPACE_HEIGHT / 3);
                special.endFill();

                this.container.addChild(special);
            }
        }.bind(this));
    }.bind(this));

    // rects
    for (r = 0; r < rows; r++) {
        for (c = 0; c < columns; c++) {
            var rect = new PIXI.Rectangle(SPACE_WIDTH * c, SPACE_HEIGHT * r, SPACE_WIDTH, SPACE_HEIGHT);

            rect.row = r;
            rect.column = c;

            rect.centerX = rect.x + rect.width / 2;
            rect.centerY = rect.y + rect.height / 2;

            this._rects.push(rect);
        }
    }
}

Level.prototype = {};

function onMouseDown(e) {
    var eventData = e.data.originalEvent;

    level.leftHeld = (eventData.buttons & 1) !== 0;
    level.rightHeld = (eventData.buttons & 4) !== 0;
}

function onMouseUp(e) {
    var eventData = e.data.originalEvent;

    level.leftHeld = (eventData.buttons & 1) !== 0;
    level.rightHeld = (eventData.buttons & 4) !== 0;
}

function onMouseMove(e) {
    var eventData = e.data.originalEvent;

    level._rects.forEach(function(rect) {
        if (rect.contains(e.data.global.x, e.data.global.y)) {
            if (typeof(level.lastRect) !== 'undefined' && level.lastRect !== null) {
                var lr = level.lastRect;

                if ((lr.row === rect.row - 1 || lr.row === rect.row + 1) &&
                    lr.column === rect.column) {

                    if (level.leftHeld &&
                        ((lr.row === rect.row - 1 && (typeof(lr.downLine) === 'undefined' || lr.downLine === null)) ||
                        (lr.row === rect.row + 1 && (typeof(rect.downLine) === 'undefined' || rect.downLine === null)))) {

                        var dl = new PIXI.Graphics();

                        dl.lineStyle(2, 0xFFFF00, 1);

                        dl.moveTo(lr.centerX, lr.centerY);
                        dl.lineTo(rect.centerX, rect.centerY);

                        if (lr.row === rect.row - 1) {
                            lr.downLine = dl;
                        } else {
                            rect.downLine = dl;
                        }

                        level.container.addChild(dl);

                    } else if (level.rightHeld &&
                               ((lr.row === rect.row - 1 && (typeof(lr.downLine) !== 'undefined' && lr.downLine !== null)) ||
                                (lr.row === rect.row + 1 && (typeof(rect.downLine) !== 'undefined' && rect.downLine !== null)))) {

                        if (lr.row === rect.row - 1) {
                            level.container.removeChild(lr.downLine);
                        } else {
                            level.container.removeChild(rect.downLine);
                        }
                    }
                }

                if (lr.row === rect.row &&
                    (lr.column === rect.column - 1 || lr.column === rect.column + 1)) {

                    if (level.leftHeld &&
                        ((lr.column === rect.column - 1 && (typeof(lr.rightLine) === 'undefined' || lr.rightLine === null)) ||
                         (lr.column === rect.column + 1 && (typeof(rect.rightLine) === 'undefined' || rect.rightLine === null)))) {

                        var rl = new PIXI.Graphics();

                        rl.lineStyle(2, 0xFFFF00, 1);

                        rl.moveTo(lr.centerX, lr.centerY);
                        rl.lineTo(rect.centerX, rect.centerY);

                        if (lr.column === rect.column - 1) {
                            lr.rightLine = rl;
                        } else {
                            rect.rightLine = rl;
                        }

                        level.container.addChild(rl);

                    } else if (level.rightHeld &&
                               ((lr.column === rect.column - 1 && (typeof(lr.rightLine) !== 'undefined' && lr.rightLine !== null)) ||
                                (lr.column === rect.column + 1 && (typeof(rect.rightLine) !== 'undefined' && rect.rightLine !== null)))) {

                        if (lr.column === rect.column - 1) {
                            level.container.removeChild(lr.rightLine);
                        } else {
                            level.container.removeChild(rect.rightLine);
                        }
                    }
                }
            }

            level.lastRect = rect;
        }
    });
}

var renderer = PIXI.autoDetectRenderer(GAME_WIDTH, GAME_HEIGHT, { backgroundColor: 0x000000 });

document.body.appendChild(renderer.view);

var stage = new PIXI.Container();

stage.hitArea = new PIXI.Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT);

stage.interactive = true;
stage.buttonMode = true;

stage.on('mousedown', onMouseDown)
     .on('mousemove', onMouseMove)
     .on('mouseup', onMouseUp);

//stage.interactive = true;

//stage.on('click', function() { console.log('FUCK YOU'); });

//stage.on('mousedown', onMouseDown)
     //.on('mousemove', onMouseMove)
     //.on('mouseup', onMouseUp)
     //.on('click', function() { console.log('FUCK'); });

//stage.mousedown = onMouseDown;
//stage.mousemove = onMouseMove;
//stage.mouseup = onMouseUp;

//document.body.onmousedown = onMouseDown;
//document.body.onmousemove = onMouseMove;
//document.body.onmouseup = onMouseUp;

var level = new Level(data, 10, 10);

stage.addChild(level.container);

function animate() {
    requestAnimationFrame(animate);

    renderer.render(stage);
}

animate();
<commit_msg>specials oncomplete working<commit_after>var SPACE_WIDTH = 40,
    SPACE_HEIGHT = 30,
    GAME_WIDTH = 400,
    GAME_HEIGHT = 300;

var data = [
    [ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 1, 0, 0, 0, 2, 0 ],
    [ 0, 0, 2, 0, 2, 0, 1, 0, 0, 0 ],
    [ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 ],
    [ 2, 0, 0, 0, 0, 1, 0, 0, 0, 1 ],
    [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 ],
    [ 0, 0, 2, 0, 0, 0, 1, 0, 0, 0 ],
    [ 1, 0, 0, 0, 2, 0, 0, 0, 0, 1 ],
    [ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 ],
    [ 0, 0, 2, 0, 0, 0, 0, 0, 0, 2 ]
];

function Level(data, rows, columns) {
    this.rows = rows;

    this.columns = columns;

    this._data = data;

    this.container = new PIXI.Container();

    this._gridGraphic = new PIXI.Graphics();

    this._rects = [];

    this.leftHeld = false;
    this.rightHeld = false;

    // grid background
    this._gridGraphic.lineStyle(0.5, 0xFFFFFF, 1);

    for (var i = 0; i < rows; i++) {
        this._gridGraphic.moveTo(0, SPACE_HEIGHT * i);
        this._gridGraphic.lineTo(GAME_WIDTH, SPACE_HEIGHT * i);
    }

    for (i = 0; i < columns; i++) {
        this._gridGraphic.moveTo(SPACE_WIDTH * i, 0);
        this._gridGraphic.lineTo(SPACE_WIDTH * i, GAME_HEIGHT);
    }

    this.container.addChild(this._gridGraphic);

    // rects
    for (r = 0; r < rows; r++) {
        var row = [];

        for (c = 0; c < columns; c++) {
            var rect = new PIXI.Rectangle(SPACE_WIDTH * c, SPACE_HEIGHT * r, SPACE_WIDTH, SPACE_HEIGHT);

            rect.row = r;
            rect.column = c;

            rect.centerX = rect.x + rect.width / 2;
            rect.centerY = rect.y + rect.height / 2;

            rect.left = false;
            rect.right = false;
            rect.up = false;
            rect.down = false;

            row.push(rect);
        }

        this._rects.push(row);
    }

    data.forEach(function(row, r) {
        row.forEach(function(column, c) {
            if (column !== 0) {
                var special = new PIXI.Graphics();

                if (column === 1) {
                    special.beginFill(0xFFFFFF, 0.75);
                } else if (column === 2) {
                    special.beginFill(0xB1B1B1, 0.5);
                }

                special.drawEllipse((SPACE_WIDTH * c) + (SPACE_WIDTH / 2), (SPACE_HEIGHT * r) + (SPACE_HEIGHT / 2), SPACE_WIDTH / 3, SPACE_HEIGHT / 3);
                special.endFill();

                this.container.addChild(special);

                this._rects[r][c].graphic = special;
            }
        }.bind(this));
    }.bind(this));
}

Level.prototype = {
    isComplete: function() {
        var specials = [];

        this._data.forEach(function (row, r) {
            row.forEach(function (column, c) {
                if (column !== 0) {
                    var passed = false,
                        middleRect = this._rects[r][c],
                        leftRect = (c - 1 >= 0) ? this._rects[r][c - 1] : null,
                        rightRect = (c + 1 < this._rects[r].length) ? this._rects[r][c + 1] : null,
                        upRect = (r - 1 >= 0) ? this._rects[r - 1][c] : null,
                        downRect = (r + 1 < this._rects.length) ? this._rects[r + 1][c] : null;

                    middleRect.graphic.tint = 0xFFFFFF;

                    if (column === 1) {
                        if (middleRect.left && middleRect.right && !middleRect.up && !middleRect.down) {
                            if (leftRect !== null &&
                                (leftRect.up || leftRect.down)) {

                                passed = true;
                            } else if (rightRect !== null &&
                                       (rightRect.up || rightRect.down)) {

                                passed = true;
                            }
                        } else if (middleRect.up && middleRect.down && !middleRect.left && !middleRect.right) {

                            if (upRect !== null &&
                                (upRect.left || upRect.right)) {

                                passed = true;
                            } else if (downRect !== null &&
                                       (downRect.left || downRect.right)) {

                                passed = true;
                            }
                        }
                    } else if (column === 2) {
                        var horizRect = null,
                            vertRect = null;

                        if (middleRect.left && !middleRect.right) {
                            horizRect = leftRect;
                        } else if (middleRect.right && !middleRect.left) {
                            horizRect = rightRect;
                        }

                        if (middleRect.up && !middleRect.down) {
                            vertRect = upRect;
                        } else if (middleRect.down && !middleRect.up) {
                            vertRect = downRect;
                        }

                        if (horizRect !== null && horizRect.left && horizRect.right && !horizRect.down && !horizRect.up &&
                            vertRect !== null && vertRect.up && vertRect.down && !vertRect.left && !vertRect.right) {

                            passed = true;
                        }
                    }

                    if (passed) {
                        middleRect.graphic.tint = 0x00FF00;
                    }

                    specials.push(passed);
                }

            }.bind(this));
        }.bind(this));

        if (specials.filter(function(s) { return s === false; }).length === 0) console.log('yay!');
    }
};

function onMouseDown(e) {
    var eventData = e.data.originalEvent;

    level.leftHeld = (eventData.buttons & 1) !== 0;
    level.rightHeld = (eventData.buttons & 4) !== 0;
}

function onMouseUp(e) {
    var eventData = e.data.originalEvent;

    level.leftHeld = (eventData.buttons & 1) !== 0;
    level.rightHeld = (eventData.buttons & 4) !== 0;
}

function onMouseMove(e) {
    var eventData = e.data.originalEvent;

    level._rects.forEach(function(row) {
        row.forEach(function (rect) {
            if (rect.contains(e.data.global.x, e.data.global.y)) {
                if (typeof(level.lastRect) !== 'undefined' && level.lastRect !== null) {
                    var lr = level.lastRect;

                    if ((lr.row === rect.row - 1 || lr.row === rect.row + 1) &&
                        lr.column === rect.column) {

                        if (level.leftHeld &&
                            ((lr.row === rect.row - 1 && (typeof(lr.downLine) === 'undefined' || lr.downLine === null)) ||
                            (lr.row === rect.row + 1 && (typeof(rect.downLine) === 'undefined' || rect.downLine === null)))) {

                            var dl = new PIXI.Graphics();

                            dl.lineStyle(2, 0xFFFF00, 1);

                            dl.moveTo(lr.centerX, lr.centerY);
                            dl.lineTo(rect.centerX, rect.centerY);

                            if (lr.row === rect.row - 1) {
                                lr.downLine = dl;

                                lr.down = true;
                                rect.up = true;
                            } else {
                                rect.downLine = dl;

                                rect.down = true;
                                lr.up = true;
                            }

                            level.container.addChild(dl);

                        } else if (level.rightHeld &&
                                   ((lr.row === rect.row - 1 && (typeof(lr.downLine) !== 'undefined' && lr.downLine !== null)) ||
                                    (lr.row === rect.row + 1 && (typeof(rect.downLine) !== 'undefined' && rect.downLine !== null)))) {

                            if (lr.row === rect.row - 1) {
                                level.container.removeChild(lr.downLine);

                                lr.down = false;
                                rect.up = false;
                            } else {
                                level.container.removeChild(rect.downLine);

                                rect.down = false;
                                lr.up = false;
                            }
                        }
                    }

                    if (lr.row === rect.row &&
                        (lr.column === rect.column - 1 || lr.column === rect.column + 1)) {

                        if (level.leftHeld &&
                            ((lr.column === rect.column - 1 && (typeof(lr.rightLine) === 'undefined' || lr.rightLine === null)) ||
                             (lr.column === rect.column + 1 && (typeof(rect.rightLine) === 'undefined' || rect.rightLine === null)))) {

                            var rl = new PIXI.Graphics();

                            rl.lineStyle(2, 0xFFFF00, 1);

                            rl.moveTo(lr.centerX, lr.centerY);
                            rl.lineTo(rect.centerX, rect.centerY);

                            if (lr.column === rect.column - 1) {
                                lr.rightLine = rl;

                                lr.right = true;
                                rect.left = true;
                            } else {
                                rect.rightLine = rl;

                                rect.right = true;
                                lr.left = true;
                            }

                            level.container.addChild(rl);

                        } else if (level.rightHeld &&
                                   ((lr.column === rect.column - 1 && (typeof(lr.rightLine) !== 'undefined' && lr.rightLine !== null)) ||
                                    (lr.column === rect.column + 1 && (typeof(rect.rightLine) !== 'undefined' && rect.rightLine !== null)))) {

                            if (lr.column === rect.column - 1) {
                                level.container.removeChild(lr.rightLine);

                                lr.right = false;
                                rect.left = false;
                            } else {
                                level.container.removeChild(rect.rightLine);

                                rect.right = false;
                                lr.left = false;
                            }
                        }
                    }
                }

                level.lastRect = rect;
            }
        });
    });
}

var renderer = PIXI.autoDetectRenderer(GAME_WIDTH, GAME_HEIGHT, { backgroundColor: 0x000000 });

document.body.appendChild(renderer.view);

var stage = new PIXI.Container();

stage.hitArea = new PIXI.Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT);

stage.interactive = true;
stage.buttonMode = true;

stage.on('mousedown', onMouseDown)
     .on('mousemove', onMouseMove)
     .on('mouseup', onMouseUp);

//stage.interactive = true;

//stage.on('click', function() { console.log('FUCK YOU'); });

//stage.on('mousedown', onMouseDown)
     //.on('mousemove', onMouseMove)
     //.on('mouseup', onMouseUp)
     //.on('click', function() { console.log('FUCK'); });

//stage.mousedown = onMouseDown;
//stage.mousemove = onMouseMove;
//stage.mouseup = onMouseUp;

//document.body.onmousedown = onMouseDown;
//document.body.onmousemove = onMouseMove;
//document.body.onmouseup = onMouseUp;

var level = new Level(data, 10, 10);

stage.addChild(level.container);

function animate() {
    requestAnimationFrame(animate);

    level.isComplete();

    renderer.render(stage);
}

animate();
<|endoftext|>


<commit_before>exports.PasswordCreator = (function () {
		function PasswordCreator () {
			this.sets = {
				letters: "abcdefghijklmnopqrstuvwxyz",
				digits: "0123456789",
				special: "!@#$%^&*()_+-={}[]|:;\"\'<>,.?/\\~`";
			};
		}

		PasswordCreator.prototype.create = function(config) {
			var password = "";

			// creating algorithm
			// ...

			return password;
		}

		return PasswordCreator;
})();<commit_msg>Settings of password that is to be created<commit_after>exports.PasswordCreator = (function () {
		// constructor
		function PasswordCreator () {
			// available sets of signs those can be used
			this.sets = {
				letters: "abcdefghijklmnopqrstuvwxyz",
				digits: "0123456789",
				special: "!@#$%^&*()_+-={}[]|:;\"\'<>,.?/\\~`";
			};
		}

		// main algorithm function
		PasswordCreator.prototype.create = function(config) {
			// here result will be stored
			var password = "";

			// defines default configuration
			var settings = {
				sets: {
					letters: true,
					lowercase: true,
					uppercase: true,
					digits: true,
					special: true,
					space: false,
					include: []
				},
				length: 6
			};

			// changes configuration if specified to do so
			if(typeof config == "number"){
				// only length was specified
				settings.length = (config >= 0) ? Math.floor(config) : 0;
			}
			else if(typeof config == "object"){
				// overwrite
				settings.sets.letters = (typeof config.sets.letters == "boolean") ? config.sets.letters : settings.sets.letters;
				settings.sets.lowercase = (typeof config.sets.lowercase == "boolean") ? config.sets.lowercase : settings.sets.lowercase;
				settings.sets.uppercase = (typeof config.sets.uppercase == "boolean") ? config.sets.uppercase : settings.sets.uppercase;
				settings.sets.digits = (typeof config.sets.digits == "boolean") ? config.sets.digits : settings.sets.digits;
				settings.sets.special = (typeof config.sets.special == "boolean") ? config.sets.special : settings.sets.special;
				settings.sets.space = (typeof config.sets.space == "boolean") ? config.sets.space : settings.sets.space;
				settings.sets.include = (Object.prototype.toString.call(config.sets.include) == "[object Array]") ? config.sets.include : settings.sets.include;

				settings.length = (typeof config.length == "number" && config.length >= 0) ? Math.floor(config.length) : 0;
			}

			// creating algorithm
			// ...

			return password;
		}

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


<commit_before>var _ = require('underscore');
var util = require('util');

function find(object, path) {
  if (!_.isString(path)) { return object; }

  return _.reduce(path.split('.'), function(memo, p) {
    if (memo) { return memo[p]; }
  }, object);
}

function format(value) {
  if (_.isString(value)) {
    return util.format('\'%s\'', value);
  }

  if (_.isNumber(value)) {
    return value;
  }

  if (_.isObject(value)) {
    return util.format('%s', JSON.stringify(value));
  }
}

function Validator() {
  var self = this;
  self.results = [];

  var addResult = function(message) {
    otherArgs = _.map(_.tail(arguments, 1), function(arg) {
      return format(arg);
    });
    otherArgs.unshift(message);

    self.results.push(util.format.apply(this, otherArgs));
  }

  self.expect = function(subject, path) {
    var value = find(subject, path);
    var notTo = {};
    var to = {};
    var be = {};

    var equal = function(equalTo) {
      if ((value === equalTo) === this.negate) {
        addResult('Expected %s to equal %s', path || value, equalTo);
        return false;
      }

      return true;
    }

    var eql = function(equalTo) {
      if (_.isObject(value)) {
        if (_.isEqual(value, equalTo) === this.negate) {
          addResult('Expected %s to kind of equal %s', path || value, equalTo);
          return false;
        }
      } else {
        if ((value == equalTo) === this.negate) {
          addResult('Expected %s to kind of equal %s', path || value, equalTo);
          return false;
        }
      }

      return true;
    }

    var ok = function() {
      if (!value && this.negate === false) {
        addResult('Expected %s to be truthy', path || value);
        return false;
      }

      if (value && this.negate === true) {
        addResult('Expected %s to be truthy', path || value);
        return false;
      }

      return true;
    }

    Object.defineProperty(be, 'ok', {
      get: ok
    });

    notTo.negate = to.negate = false;
    notTo.equal = to.equal = equal;
    notTo.eql = to.eql = eql;

    Object.defineProperty(to, 'not', {
      get: function() {
        notTo.negate = true;
        return notTo;
      }
    });

    Object.defineProperty(to, 'be', {
      get: function() {
        be.negate = false;
        return be;
      }
    });

    Object.defineProperty(notTo, 'be', {
      get: function() {
        be.negate = true;
        return be;
      }
    });

    return {
      value: value,
      to: to
    }
  }
}

module.exports = Validator;
<commit_msg>Remove duplicate statements<commit_after>var _ = require('underscore');
var util = require('util');

function find(object, path) {
  if (!_.isString(path)) { return object; }

  return _.reduce(path.split('.'), function(memo, p) {
    if (memo) { return memo[p]; }
  }, object);
}

function format(value) {
  if (_.isString(value)) {
    return util.format('\'%s\'', value);
  }

  if (_.isNumber(value)) {
    return value;
  }

  if (_.isObject(value)) {
    return util.format('%s', JSON.stringify(value));
  }
}

function Validator() {
  var self = this;
  self.results = [];

  var addResult = function(message) {
    otherArgs = _.map(_.tail(arguments, 1), function(arg) {
      return format(arg);
    });
    otherArgs.unshift(message);

    self.results.push(util.format.apply(this, otherArgs));
  }

  self.expect = function(subject, path) {
    var value = find(subject, path);
    var notTo = {};
    var to = {};
    var be = {};

    var equal = function(equalTo) {
      if ((value === equalTo) === this.negate) {
        addResult('Expected %s to equal %s', path || value, equalTo);
        return false;
      }

      return true;
    }

    var eql = function(equalTo) {
      if (_.isObject(value)) {
        if (_.isEqual(value, equalTo) === this.negate) {
          addResult('Expected %s to kind of equal %s', path || value, equalTo);
          return false;
        }
      } else {
        if ((value == equalTo) === this.negate) {
          addResult('Expected %s to kind of equal %s', path || value, equalTo);
          return false;
        }
      }

      return true;
    }

    var ok = function() {
      if ((!value && this.negate === false) ||
          (value && this.negate === true)) {
        addResult('Expected %s to be truthy', path || value);
        return false;
      }

      return true;
    }

    Object.defineProperty(be, 'ok', {
      get: ok
    });

    notTo.negate = to.negate = false;
    notTo.equal = to.equal = equal;
    notTo.eql = to.eql = eql;

    Object.defineProperty(to, 'not', {
      get: function() {
        notTo.negate = true;
        return notTo;
      }
    });

    Object.defineProperty(to, 'be', {
      get: function() {
        be.negate = false;
        return be;
      }
    });

    Object.defineProperty(notTo, 'be', {
      get: function() {
        be.negate = true;
        return be;
      }
    });

    return {
      value: value,
      to: to
    }
  }
}

module.exports = Validator;
<|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!

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

controller.hears(['hello','aloha'], ['direct_message','direct_mention','mention'], function(bot, message) {
    var message_options = [
    "How was your weekend?",
    "What are you excited about today?",
    "What did you have for breakfast?",
    "What is your favorite food?",
    "What TV Shows are you watching right now?",
    "Add Extreme to a random activity, what are the rules to your new sport?",
    "Any vacations coming up?"
	]
	var random_index = Math.floor(Math.random() * message_options.length)
	var chosen_message = message_options[random_index]

	bot.reply(message, chosen_message)

});

/**
 * 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>make it better<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!

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

controller.hears(['hello'], ['direct_message','direct_mention','mention'], function(bot, message) {
    var message_options = [
        "What did you do last weekend?",
        "What are you excited about today?",
        "What did you have for breakfast?",
        "What is your favorite food?",
        "What TV Shows are you watching right now?",
        "Add Extreme to a random activity, what are the rules to your new sport?",
        "Any vacations coming up?",
        "What was the first time you ever used a computer?",
        "What do you want to do after you retire?",
        "Any plans this weekend?",
        "Who is your favorite entertainer?",
        "Do you have any pets?",
        "What is your favorite fad?",
        "Who is your oldest friend? How did you meet them?",
        "If you could have any animal as a pet, what would you have?",
        "What is the most useful thing you own?",
        "What is the largest group of people you've ever spoken in front of?",
        "What is your favorite subreddit?",
        "What is your Every Day Carry?",
        "Outside of work, how much time do you spend on the internet per day?",
        "What's your favorite SFW joke?"
	]
	var random_index = Math.floor(Math.random() * message_options.length)
	var chosen_message = message_options[random_index]

	bot.reply(message, chosen_message)

});

/**
 * 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|>