<commit_before>
var express   = require('express')
  , Pouch     = require('pouchdb')
  , fs        = require('fs')
  , pkg       = require('./package.json')
  , dbs       = {}
  , protocol  = 'leveldb://'
  , app       = module.exports = express();

// We'll need this for the _all_dbs route.
Pouch.enableAllDbs = true;

app.configure(function () {
  app.use(function (req, res, next) {
    var opts = {}
      , data = ''
      , prop;

    // Normalize query string parameters for direct passing
    // into Pouch queries.
    for (prop in req.query) {
      try {
        req.query[prop] = JSON.parse(req.query[prop]);
      } catch (e) {}
    }

    // Custom bodyParsing because express.bodyParser() chokes
    // on `malformed` requests.
    req.on('data', function (chunk) { data += chunk; });
    req.on('end', function () {
      if (data) {
        try {
          req.body = JSON.parse(data);
        } catch (e) {
          req.body = data;
        }
      }
      next();
    });
  });
});

// Root route, return welcome message
app.get('/', function (req, res, next) {
  res.send(200, {
    'express-pouchdb': 'Welcome!',
    'version': pkg.version
  });
});

// Generate UUIDs
app.get('/_uuids', function (req, res, next) {
  var count = req.query.count || 1
    , uuids = [];

  while (--count >= 0) { uuids.push(Pouch.uuid()); }
  res.send(200, {
    uuids: uuids
  });
});

// List all databases.
app.get('/_all_dbs', function (req, res, next) {
  Pouch.allDbs(function (err, response) {
    if (err) res.send(500, Pouch.UNKNOWN_ERROR);
    res.send(200, response);
  });
});

// Replicate a database
app.post('/_replicate', function (req, res, next) {

  var source = req.body.source
    , target = req.body.target
    , opts = { continuous: !!req.body.continuous };

  if (req.body.filter) opts.filter = req.body.filter;
  opts.complete = function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  };

  Pouch.replicate(source, target, opts);

  // if continuous pull replication return 'ok' since we cannot wait for callback
  if (target in dbs && opts.continuous) {
    res.send(200, { ok : true });
  }

});

// Create a database.
app.put('/:db', function (req, res, next) {
  var name = encodeURIComponent(req.params.db);
  if (name in dbs) {
    return res.send(412, {
      'error': 'file_exists',
      'reason': 'The database could not be created.'
    });
  }

  Pouch(protocol + name, function (err, db) {
    if (err) return res.send(412, err);
    dbs[name] = db;
    var loc = req.protocol
      + '://'
      + ((req.host === '127.0.0.1') ? '' : req.subdomains.join('.') + '.')
      + req.host
      + '/' + name;
    res.location(loc);
    res.send(201, { ok: true });
  });
});

// Delete a database
app.del('/:db', function (req, res, next) {
  var name = encodeURIComponent(req.params.db);
  Pouch.destroy(protocol + name, function (err, info) {
    if (err) return res.send(404, err);
    delete dbs[name];
    res.send(200, { ok: true });
  });
});

// At this point, some route middleware can take care of identifying the
// correct Pouch instance.
['/:db/*','/:db'].forEach(function (route) {
  app.all(route, function (req, res, next) {
    var name = encodeURIComponent(req.params.db);

    if (name in dbs) {
      req.db = dbs[name];
      return next();
    }

    // Check for the data stores, and rebuild a Pouch instance if able
    fs.stat(name, function (err, stats) {
      if (err && err.code == 'ENOENT') {
        return res.send(404, {
          status: 404,
          error: 'not_found',
          reason: 'no_db_file'
        });
      }

      if (stats.isDirectory()) {
        Pouch(protocol + name, function (err, db) {
          if (err) return res.send(412, err);
          dbs[name] = db;
          req.db = db;
          return next();
        });
      }
    });
  });
});

// Get database information
app.get('/:db', function (req, res, next) {
  req.db.info(function (err, info) {
    if (err) return res.send(404, err);
    res.send(200, info);
  });
});

// Bulk docs operations
app.post('/:db/_bulk_docs', function (req, res, next) {

  // Maybe this should be moved into the leveldb adapter itself? Not sure
  // how uncommon it is for important options to come through in the body
  // https://github.com/daleharvey/pouchdb/issues/435
  var opts = 'new_edits' in req.body
    ? { new_edits: req.body.new_edits }
    : null;

  req.db.bulkDocs(req.body, opts, function (err, response) {
    if (err) return res.send(400, err);
    res.send(201, response);
  });

});

// All docs operations
app.all('/:db/_all_docs', function (req, res, next) {
  if (req.method !== 'GET' && req.method !== 'POST') return next();

  // Check that the request body, if present, is an object.
  if (!!req.body && (typeof req.body !== 'object' || Array.isArray(req.body))) {
    return res.send(400, Pouch.BAD_REQUEST);
  }

  for (var prop in req.body) {
    req.query[prop] = req.query[prop] || req.body[prop];
  }

  req.db.allDocs(req.query, function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  });

});

// Monitor database changes
app.get('/:db/_changes', function (req, res, next) {

  // api.changes expects a property `query_params`
  // This is a pretty inefficient way to do it.. Revisit?
  req.query.query_params = JSON.parse(JSON.stringify(req.query));

  if (req.query.filter) {
    // CouchDB seems to default these to true when a filter is applied
    req.query.conflicts = true;
    req.query.include_docs = true;
  }

  var longpoll = function (err, data) {
    if (err) return res.send(409, err);
    if (data.results && data.results.length) {
      data.last_seq = Math.max.apply(Math, data.results.map(function (r) {
        return r.seq;
      }));
      res.send(200, data);
    } else {
      delete req.query.complete;
      req.query.continuous = true;
      req.query.onChange = function (change) {
        res.send(200, change);
      };
      req.db.changes(req.query);
    }
  };

  if (req.query.feed) {
    req.socket.setTimeout(86400 * 1000);
    req.query.complete = longpoll;
  } else {
    req.query.complete = function (err, response) {
      if (err) return res.send(409, err);
      res.send(200, response);
    };
  }

  req.db.changes(req.query);

});

// DB Compaction
app.post('/:db/_compact', function (req, res, next) {
  req.db.compact(function (err, response) {
    if (err) return res.send(500, err);
    res.send(200, response);
  });
});

// Revs Diff
app.post('/:db/_revs_diff', function (req, res, next) {
  req.db.revsDiff(req.body, function (err, diffs) {
    if (err) return res.send(400, err);
    res.send(200, diffs);
  });
});

// Temp Views
app.post('/:db/_temp_view', function (req, res, next) {
  if (req.body.map) req.body.map = (new Function('return ' + req.body.map))();
  req.query.conflicts = true;
  req.db.query(req.body, req.query, function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  });
});

// Put a document attachment
app.put('/:db/:id/:attachment', function (req, res, next) {

  // Be careful not to catch normal design docs or local docs
  if (req.params.id === '_design' || req.params.id === '_local') {
    return next();
  }

  var name = req.params.id + '/' + req.params.attachment
    , rev = req.query.rev
    , type = req.get('Content-Type')
    , body = typeof req.body === 'string'
        ? new Buffer(req.body)
        : new Buffer(JSON.stringify(req.body));

  req.db.putAttachment(name, rev, body, type, function (err, response) {
    if (err) return res.send(409, err);
    res.send(200, response);
  });

});

// Delete a document attachment
app.del('/:db/:id/:attachment', function (req, res, next) {

  // Be careful not to catch normal design docs or local docs
  if (req.params.id === '_design' || req.params.id === '_local') {
    return next();
  }

  var name = req.params.id + '/' + req.params.attachment
    , rev = req.query.rev;

  req.db.removeAttachment(name, rev, function (err, response) {
    if (err) return res.send(409, err);
    res.send(200, response);
  });

});

// Create or update document that has an ID
app.put('/:db/:id(*)', function (req, res, next) {
  req.body._id = req.body._id || req.query.id;
  if (!req.body._id) {
    req.body._id = (!!req.params.id && req.params.id !== 'null')
      ? req.params.id
      : null;
  }
  req.db.put(req.body, req.query, function (err, response) {
    if (err) return res.send(409, err);
    var loc = req.protocol
      + '://'
      + ((req.host === '127.0.0.1') ? '' : req.subdomains.join('.') + '.')
      + req.host
      + '/' + req.params.db
      + '/' + req.body._id;
    res.location(loc);
    res.send(201, response);
  });
});

// Create a document
app.post('/:db(*)', function (req, res, next) {
  req.db.post(req.body, req.query, function (err, response) {
    if (err) return res.send(409, err);
    res.send(201, response);
  });
});

// Query a document view
app.get('/:db/_design/:id/_view/:view', function (req, res, next) {
  var query = req.params.id + '/' + req.params.view;
  req.db.query(query, req.query, function (err, response) {
    if (err) return res.send(404, err);
    res.send(200, response);
  });
});

// Retrieve a document
app.get('/:db/:id(*)', function (req, res, next) {
  req.db.get(req.params.id, req.query, function (err, doc) {
    if (err) return res.send(404, err);
    res.send(200, doc);
  });
});

// Delete a document
app.del('/:db/:id(*)', function (req, res, next) {
  req.db.get(req.params.id, req.query, function (err, doc) {
    if (err) return res.send(404, err);
    req.db.remove(doc, function (err, response) {
      if (err) return res.send(404, err);
      res.send(200, response);
    });
  });
});

<commit_msg>Export the pouch so apps that embed express-pouchdb can access this pouch.<commit_after>var express   = require('express')
  , Pouch     = require('pouchdb')
  , fs        = require('fs')
  , pkg       = require('./package.json')
  , dbs       = {}
  , protocol  = 'leveldb://'
  , app       = module.exports = express();

module.exports.Pouch = Pouch;

// We'll need this for the _all_dbs route.
Pouch.enableAllDbs = true;

app.configure(function () {
  app.use(function (req, res, next) {
    var opts = {}
      , data = ''
      , prop;

    // Normalize query string parameters for direct passing
    // into Pouch queries.
    for (prop in req.query) {
      try {
        req.query[prop] = JSON.parse(req.query[prop]);
      } catch (e) {}
    }

    // Custom bodyParsing because express.bodyParser() chokes
    // on `malformed` requests.
    req.on('data', function (chunk) { data += chunk; });
    req.on('end', function () {
      if (data) {
        try {
          req.body = JSON.parse(data);
        } catch (e) {
          req.body = data;
        }
      }
      next();
    });
  });
});

// Root route, return welcome message
app.get('/', function (req, res, next) {
  res.send(200, {
    'express-pouchdb': 'Welcome!',
    'version': pkg.version
  });
});

// Generate UUIDs
app.get('/_uuids', function (req, res, next) {
  var count = req.query.count || 1
    , uuids = [];

  while (--count >= 0) { uuids.push(Pouch.uuid()); }
  res.send(200, {
    uuids: uuids
  });
});

// List all databases.
app.get('/_all_dbs', function (req, res, next) {
  Pouch.allDbs(function (err, response) {
    if (err) res.send(500, Pouch.UNKNOWN_ERROR);
    res.send(200, response);
  });
});

// Replicate a database
app.post('/_replicate', function (req, res, next) {

  var source = req.body.source
    , target = req.body.target
    , opts = { continuous: !!req.body.continuous };

  if (req.body.filter) opts.filter = req.body.filter;
  opts.complete = function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  };

  Pouch.replicate(source, target, opts);

  // if continuous pull replication return 'ok' since we cannot wait for callback
  if (target in dbs && opts.continuous) {
    res.send(200, { ok : true });
  }

});

// Create a database.
app.put('/:db', function (req, res, next) {
  var name = encodeURIComponent(req.params.db);
  if (name in dbs) {
    return res.send(412, {
      'error': 'file_exists',
      'reason': 'The database could not be created.'
    });
  }

  Pouch(protocol + name, function (err, db) {
    if (err) return res.send(412, err);
    dbs[name] = db;
    var loc = req.protocol
      + '://'
      + ((req.host === '127.0.0.1') ? '' : req.subdomains.join('.') + '.')
      + req.host
      + '/' + name;
    res.location(loc);
    res.send(201, { ok: true });
  });
});

// Delete a database
app.del('/:db', function (req, res, next) {
  var name = encodeURIComponent(req.params.db);
  Pouch.destroy(protocol + name, function (err, info) {
    if (err) return res.send(404, err);
    delete dbs[name];
    res.send(200, { ok: true });
  });
});

// At this point, some route middleware can take care of identifying the
// correct Pouch instance.
['/:db/*','/:db'].forEach(function (route) {
  app.all(route, function (req, res, next) {
    var name = encodeURIComponent(req.params.db);

    if (name in dbs) {
      req.db = dbs[name];
      return next();
    }

    // Check for the data stores, and rebuild a Pouch instance if able
    fs.stat(name, function (err, stats) {
      if (err && err.code == 'ENOENT') {
        return res.send(404, {
          status: 404,
          error: 'not_found',
          reason: 'no_db_file'
        });
      }

      if (stats.isDirectory()) {
        Pouch(protocol + name, function (err, db) {
          if (err) return res.send(412, err);
          dbs[name] = db;
          req.db = db;
          return next();
        });
      }
    });
  });
});

// Get database information
app.get('/:db', function (req, res, next) {
  req.db.info(function (err, info) {
    if (err) return res.send(404, err);
    res.send(200, info);
  });
});

// Bulk docs operations
app.post('/:db/_bulk_docs', function (req, res, next) {

  // Maybe this should be moved into the leveldb adapter itself? Not sure
  // how uncommon it is for important options to come through in the body
  // https://github.com/daleharvey/pouchdb/issues/435
  var opts = 'new_edits' in req.body
    ? { new_edits: req.body.new_edits }
    : null;

  req.db.bulkDocs(req.body, opts, function (err, response) {
    if (err) return res.send(400, err);
    res.send(201, response);
  });

});

// All docs operations
app.all('/:db/_all_docs', function (req, res, next) {
  if (req.method !== 'GET' && req.method !== 'POST') return next();

  // Check that the request body, if present, is an object.
  if (!!req.body && (typeof req.body !== 'object' || Array.isArray(req.body))) {
    return res.send(400, Pouch.BAD_REQUEST);
  }

  for (var prop in req.body) {
    req.query[prop] = req.query[prop] || req.body[prop];
  }

  req.db.allDocs(req.query, function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  });

});

// Monitor database changes
app.get('/:db/_changes', function (req, res, next) {

  // api.changes expects a property `query_params`
  // This is a pretty inefficient way to do it.. Revisit?
  req.query.query_params = JSON.parse(JSON.stringify(req.query));

  if (req.query.filter) {
    // CouchDB seems to default these to true when a filter is applied
    req.query.conflicts = true;
    req.query.include_docs = true;
  }

  var longpoll = function (err, data) {
    if (err) return res.send(409, err);
    if (data.results && data.results.length) {
      data.last_seq = Math.max.apply(Math, data.results.map(function (r) {
        return r.seq;
      }));
      res.send(200, data);
    } else {
      delete req.query.complete;
      req.query.continuous = true;
      req.query.onChange = function (change) {
        res.send(200, change);
      };
      req.db.changes(req.query);
    }
  };

  if (req.query.feed) {
    req.socket.setTimeout(86400 * 1000);
    req.query.complete = longpoll;
  } else {
    req.query.complete = function (err, response) {
      if (err) return res.send(409, err);
      res.send(200, response);
    };
  }

  req.db.changes(req.query);

});

// DB Compaction
app.post('/:db/_compact', function (req, res, next) {
  req.db.compact(function (err, response) {
    if (err) return res.send(500, err);
    res.send(200, response);
  });
});

// Revs Diff
app.post('/:db/_revs_diff', function (req, res, next) {
  req.db.revsDiff(req.body, function (err, diffs) {
    if (err) return res.send(400, err);
    res.send(200, diffs);
  });
});

// Temp Views
app.post('/:db/_temp_view', function (req, res, next) {
  if (req.body.map) req.body.map = (new Function('return ' + req.body.map))();
  req.query.conflicts = true;
  req.db.query(req.body, req.query, function (err, response) {
    if (err) return res.send(400, err);
    res.send(200, response);
  });
});

// Put a document attachment
app.put('/:db/:id/:attachment', function (req, res, next) {

  // Be careful not to catch normal design docs or local docs
  if (req.params.id === '_design' || req.params.id === '_local') {
    return next();
  }

  var name = req.params.id + '/' + req.params.attachment
    , rev = req.query.rev
    , type = req.get('Content-Type')
    , body = typeof req.body === 'string'
        ? new Buffer(req.body)
        : new Buffer(JSON.stringify(req.body));

  req.db.putAttachment(name, rev, body, type, function (err, response) {
    if (err) return res.send(409, err);
    res.send(200, response);
  });

});

// Delete a document attachment
app.del('/:db/:id/:attachment', function (req, res, next) {

  // Be careful not to catch normal design docs or local docs
  if (req.params.id === '_design' || req.params.id === '_local') {
    return next();
  }

  var name = req.params.id + '/' + req.params.attachment
    , rev = req.query.rev;

  req.db.removeAttachment(name, rev, function (err, response) {
    if (err) return res.send(409, err);
    res.send(200, response);
  });

});

// Create or update document that has an ID
app.put('/:db/:id(*)', function (req, res, next) {
  req.body._id = req.body._id || req.query.id;
  if (!req.body._id) {
    req.body._id = (!!req.params.id && req.params.id !== 'null')
      ? req.params.id
      : null;
  }
  req.db.put(req.body, req.query, function (err, response) {
    if (err) return res.send(409, err);
    var loc = req.protocol
      + '://'
      + ((req.host === '127.0.0.1') ? '' : req.subdomains.join('.') + '.')
      + req.host
      + '/' + req.params.db
      + '/' + req.body._id;
    res.location(loc);
    res.send(201, response);
  });
});

// Create a document
app.post('/:db(*)', function (req, res, next) {
  req.db.post(req.body, req.query, function (err, response) {
    if (err) return res.send(409, err);
    res.send(201, response);
  });
});

// Query a document view
app.get('/:db/_design/:id/_view/:view', function (req, res, next) {
  var query = req.params.id + '/' + req.params.view;
  req.db.query(query, req.query, function (err, response) {
    if (err) return res.send(404, err);
    res.send(200, response);
  });
});

// Retrieve a document
app.get('/:db/:id(*)', function (req, res, next) {
  req.db.get(req.params.id, req.query, function (err, doc) {
    if (err) return res.send(404, err);
    res.send(200, doc);
  });
});

// Delete a document
app.del('/:db/:id(*)', function (req, res, next) {
  req.db.get(req.params.id, req.query, function (err, doc) {
    if (err) return res.send(404, err);
    req.db.remove(doc, function (err, response) {
      if (err) return res.send(404, err);
      res.send(200, response);
    });
  });
});

<|endoftext|>


<commit_before>const EventEmitter = require('events');
const path = require('path');

// Try use handler if runtime and ABI is compatible
try {
  const SegfaultHandler = require('segfault-handler');
  SegfaultHandler.registerHandler("iohook-crash.log");
} catch (e) {}

const runtime = process.versions['electron'] ? 'electron' : 'node';
const essential = runtime + '-v' + process.versions.modules + '-' + process.platform + '-' + process.arch;
const modulePath = path.join(__dirname, 'builds', essential, 'build', 'Release', 'iohook.node');
if (process.env.DEBUG) {
  console.info('Loading native binary:', modulePath);
}
let NodeHookAddon = require(modulePath);

const events = {
  3: 'keypress',
  4: 'keydown',
  5: 'keyup',
  6: 'mouseclick',
  7: 'mousedown',
  8: 'mouseup',
  9: 'mousemove',
  10: 'mousedrag',
  11: 'mousewheel'
};

class IOHook extends EventEmitter {
  constructor() {
    super();
    this.active = false;
    this.shortcuts = [];

    this.lastKeydownShift = false;
    this.lastKeydownAlt = false;
    this.lastKeydownCtrl = false;
    this.lastKeydownMeta = false;

    this.load();
    this.setDebug(false);
  }

  /**
   * Start hook process
   * @param enableLogger Turn on debug logging
   */
  start(enableLogger) {
    if (!this.active) {
      this.active = true;
      this.setDebug(enableLogger);
    }
  }

  /**
   * Shutdown event hook
   */
  stop() {
    if (this.active) {
      this.active = false;
    }
  }

  /**
   * Register global shortcut. When all keys in keys array pressed, callback will be called
   * @param {Array} keys Array of keycodes
   * @param {Function} callback Callback for call when shortcut pressed
   * @return {number} ShortcutId for unregister
   */
  registerShortcut(keys, callback) {
    let shortcut = {};
    let shortcutId = Date.now() + Math.random();
    keys.forEach(keyCode => {
      shortcut[keyCode] = false;
    })
    shortcut.id = shortcutId;
    shortcut.callback = callback;
    this.shortcuts.push(shortcut);
    return shortcutId;
  }

  /**
   * Unregister shortcut by ShortcutId
   * @param shortcutId
   */
  unregisterShortcut(shortcutId) {
    this.shortcuts.forEach((shortcut,i) => {
      if (shortcut.id === shortcutId) {
        this.shortcuts.splice(i, 1);
      }
    });
  }

  /**
   * Unregister all shortcuts
   */
  unregisterAllShortcuts() {
    this.shortcuts.splice(0, this.shortcuts.length);
  }

  /**
   * Load native module
   */
  load() {
    NodeHookAddon.startHook(this._handler.bind(this), this.debug || false);
  }

  /**
   * Unload native module and stop hook
   */
  unload() {
    this.stop();
    NodeHookAddon.stopHook();
  }

  /**
   * Enable or disable native debug output
   * @param {Boolean} mode
   */
  setDebug(mode) {
    NodeHookAddon.debugEnable(mode);
  }

  /**
   * Disable mouse click propagation.
   * The click event are captured and the event emitted but not propagated to the window.
   */
  disableClickPropagation() {
    NodeHookAddon.grabMouseClick(true);
  }

  /**
   * Enable mouse click propagation (enabled by default).
   * The click event are emitted and propagated.
   */
  enableClickPropagation() {
    NodeHookAddon.grabMouseClick(false);
  }

  /**
   * Local event handler. Don't use it in your code!
   * @param msg Raw event message
   * @private
   */
  _handler(msg) {
    if (this.active === false || !msg) return;

    if (events[msg.type]) {
      const event = msg.mouse || msg.keyboard || msg.wheel;

      event.type = events[msg.type];

      this._handleShift(event);
      this._handleAlt(event);
      this._handleCtrl(event);
      this._handleMeta(event);

      this.emit(events[msg.type], event);

      // If there is any registered shortcuts then handle them.
      if ((event.type === 'keydown' || event.type === 'keyup') && iohook.shortcuts.length > 0) {
        this._handleShortcut(event);
      }
    }
  }

  /**
   * Handles the shift key. Whenever shift is pressed, all future events would
   * contain { shiftKey: true } in its object, until the shift key is released.
   * @param event Event object
   * @private
   */
  _handleShift(event) {
    if (event.type === 'keyup' && event.shiftKey) {
      this.lastKeydownShift = false;
    }

    if (event.type === 'keydown' && event.shiftKey) {
      this.lastKeydownShift = true;
    }

    if (event.type === 'keypress' && this.lastKeydownShift) {
      event.shiftKey = true;
    }
  }

  /**
   * Handles the alt key. Whenever alt is pressed, all future events would
   * contain { altKey: true } in its object, until the alt key is released.
   * @param event Event object
   * @private
   */
  _handleAlt(event) {
    if (event.type === 'keyup' && event.altKey) {
      this.lastKeydownAlt = false;
    }

    if (event.type === 'keydown' && event.altKey) {
      this.lastKeydownAlt = true;
    }

    if (event.type === 'keypress' && this.lastKeydownAlt) {
      event.altKey = true;
    }
  }

  /**
   * Handles the ctrl key. Whenever ctrl is pressed, all future events would
   * contain { ctrlKey: true } in its object, until the ctrl key is released.
   * @param event Event object
   * @private
   */
  _handleCtrl(event) {
    if (event.type === 'keyup' && event.ctrlKey) {
      this.lastKeydownCtrl = false;
    }

    if (event.type === 'keydown' && event.ctrlKey) {
      this.lastKeydownCtrl = true;
    }

    if (event.type === 'keypress' && this.lastKeydownCtrl) {
      event.ctrlKey = true;
    }
  }

  /**
   * Handles the meta key. Whenever meta is pressed, all future events would
   * contain { metaKey: true } in its object, until the meta key is released.
   * @param event Event object
   * @private
   */
  _handleMeta(event) {
    if (event.type === 'keyup' && event.metaKey) {
      this.lastKeydownMeta = false;
    }

    if (event.type === 'keydown' && event.metaKey) {
      this.lastKeydownMeta = true;
    }

    if (event.type === 'keypress' && this.lastKeydownMeta) {
      event.metaKey = true;
    }
  }

  /**
   * Local shortcut event handler
   * @param event Event object
   * @private
   */
  _handleShortcut(event) {
    if (this.active === false) {
      return;
    }
    if (event.type === 'keydown') {
      this.shortcuts.forEach(shortcut => {
        if (shortcut[event.keycode] !== undefined) {
          shortcut[event.keycode] = true;

          let keysTmpArray = [];
          let callme = true;
          Object.keys(shortcut).forEach(key => {
            if (key === 'callback' || key === 'id') return;
            if (shortcut[key] === false) {
              callme = false;
              keysTmpArray.splice(0, keysTmpArray.length);
              return;
            }
            keysTmpArray.push(key);
          });
          if (callme) {
            shortcut.callback(keysTmpArray);
          }
        }
      });
    } else if (event.type === 'keyup') {
      this.shortcuts.forEach(shortcut => {
        if (shortcut[event.keycode] !== undefined) shortcut[event.keycode] = false;
      });
    }
  }
}

const iohook = new IOHook();

module.exports = iohook;
<commit_msg>Fix modifier, to be logged with keydown and keyup<commit_after>const EventEmitter = require('events');
const path = require('path');

// Try use handler if runtime and ABI is compatible
try {
  const SegfaultHandler = require('segfault-handler');
  SegfaultHandler.registerHandler("iohook-crash.log");
} catch (e) {}

const runtime = process.versions['electron'] ? 'electron' : 'node';
const essential = runtime + '-v' + process.versions.modules + '-' + process.platform + '-' + process.arch;
const modulePath = path.join(__dirname, 'builds', essential, 'build', 'Release', 'iohook.node');
if (process.env.DEBUG) {
  console.info('Loading native binary:', modulePath);
}
let NodeHookAddon = require(modulePath);

const events = {
  3: 'keypress',
  4: 'keydown',
  5: 'keyup',
  6: 'mouseclick',
  7: 'mousedown',
  8: 'mouseup',
  9: 'mousemove',
  10: 'mousedrag',
  11: 'mousewheel'
};

class IOHook extends EventEmitter {
  constructor() {
    super();
    this.active = false;
    this.shortcuts = [];

    this.lastKeydownShift = false;
    this.lastKeydownAlt = false;
    this.lastKeydownCtrl = false;
    this.lastKeydownMeta = false;

    this.load();
    this.setDebug(false);
  }

  /**
   * Start hook process
   * @param enableLogger Turn on debug logging
   */
  start(enableLogger) {
    if (!this.active) {
      this.active = true;
      this.setDebug(enableLogger);
    }
  }

  /**
   * Shutdown event hook
   */
  stop() {
    if (this.active) {
      this.active = false;
    }
  }

  /**
   * Register global shortcut. When all keys in keys array pressed, callback will be called
   * @param {Array} keys Array of keycodes
   * @param {Function} callback Callback for call when shortcut pressed
   * @return {number} ShortcutId for unregister
   */
  registerShortcut(keys, callback) {
    let shortcut = {};
    let shortcutId = Date.now() + Math.random();
    keys.forEach(keyCode => {
      shortcut[keyCode] = false;
    })
    shortcut.id = shortcutId;
    shortcut.callback = callback;
    this.shortcuts.push(shortcut);
    return shortcutId;
  }

  /**
   * Unregister shortcut by ShortcutId
   * @param shortcutId
   */
  unregisterShortcut(shortcutId) {
    this.shortcuts.forEach((shortcut,i) => {
      if (shortcut.id === shortcutId) {
        this.shortcuts.splice(i, 1);
      }
    });
  }

  /**
   * Unregister all shortcuts
   */
  unregisterAllShortcuts() {
    this.shortcuts.splice(0, this.shortcuts.length);
  }

  /**
   * Load native module
   */
  load() {
    NodeHookAddon.startHook(this._handler.bind(this), this.debug || false);
  }

  /**
   * Unload native module and stop hook
   */
  unload() {
    this.stop();
    NodeHookAddon.stopHook();
  }

  /**
   * Enable or disable native debug output
   * @param {Boolean} mode
   */
  setDebug(mode) {
    NodeHookAddon.debugEnable(mode);
  }

  /**
   * Disable mouse click propagation.
   * The click event are captured and the event emitted but not propagated to the window.
   */
  disableClickPropagation() {
    NodeHookAddon.grabMouseClick(true);
  }

  /**
   * Enable mouse click propagation (enabled by default).
   * The click event are emitted and propagated.
   */
  enableClickPropagation() {
    NodeHookAddon.grabMouseClick(false);
  }

  /**
   * Local event handler. Don't use it in your code!
   * @param msg Raw event message
   * @private
   */
  _handler(msg) {
    if (this.active === false || !msg) return;

    if (events[msg.type]) {
      const event = msg.mouse || msg.keyboard || msg.wheel;

      event.type = events[msg.type];

      this._handleShift(event);
      this._handleAlt(event);
      this._handleCtrl(event);
      this._handleMeta(event);

      this.emit(events[msg.type], event);

      // If there is any registered shortcuts then handle them.
      if ((event.type === 'keydown' || event.type === 'keyup') && iohook.shortcuts.length > 0) {
        this._handleShortcut(event);
      }
    }
  }

  /**
   * Handles the shift key. Whenever shift is pressed, all future events would
   * contain { shiftKey: true } in its object, until the shift key is released.
   * @param event Event object
   * @private
   */
  _handleShift(event) {
    if (event.type === 'keyup' && event.shiftKey) {
      this.lastKeydownShift = false;
    }

    if (event.type === 'keydown' && event.shiftKey) {
      this.lastKeydownShift = true;
    }

    if (this.lastKeydownShift) {
      event.shiftKey = true;
    }
  }

  /**
   * Handles the alt key. Whenever alt is pressed, all future events would
   * contain { altKey: true } in its object, until the alt key is released.
   * @param event Event object
   * @private
   */
  _handleAlt(event) {
    if (event.type === 'keyup' && event.altKey) {
      this.lastKeydownAlt = false;
    }

    if (event.type === 'keydown' && event.altKey) {
      this.lastKeydownAlt = true;
    }

    if (this.lastKeydownAlt) {
      event.altKey = true;
    }
  }

  /**
   * Handles the ctrl key. Whenever ctrl is pressed, all future events would
   * contain { ctrlKey: true } in its object, until the ctrl key is released.
   * @param event Event object
   * @private
   */
  _handleCtrl(event) {
    if (event.type === 'keyup' && event.ctrlKey) {
      this.lastKeydownCtrl = false;
    }

    if (event.type === 'keydown' && event.ctrlKey) {
      this.lastKeydownCtrl = true;
    }

    if (this.lastKeydownCtrl) {
      event.ctrlKey = true;
    }
  }

  /**
   * Handles the meta key. Whenever meta is pressed, all future events would
   * contain { metaKey: true } in its object, until the meta key is released.
   * @param event Event object
   * @private
   */
  _handleMeta(event) {
    if (event.type === 'keyup' && event.metaKey) {
      this.lastKeydownMeta = false;
    }

    if (event.type === 'keydown' && event.metaKey) {
      this.lastKeydownMeta = true;
    }

    if (this.lastKeydownMeta) {
      event.metaKey = true;
    }
  }

  /**
   * Local shortcut event handler
   * @param event Event object
   * @private
   */
  _handleShortcut(event) {
    if (this.active === false) {
      return;
    }
    if (event.type === 'keydown') {
      this.shortcuts.forEach(shortcut => {
        if (shortcut[event.keycode] !== undefined) {
          shortcut[event.keycode] = true;

          let keysTmpArray = [];
          let callme = true;
          Object.keys(shortcut).forEach(key => {
            if (key === 'callback' || key === 'id') return;
            if (shortcut[key] === false) {
              callme = false;
              keysTmpArray.splice(0, keysTmpArray.length);
              return;
            }
            keysTmpArray.push(key);
          });
          if (callme) {
            shortcut.callback(keysTmpArray);
          }
        }
      });
    } else if (event.type === 'keyup') {
      this.shortcuts.forEach(shortcut => {
        if (shortcut[event.keycode] !== undefined) shortcut[event.keycode] = false;
      });
    }
  }
}

const iohook = new IOHook();

module.exports = iohook;
<|endoftext|>


<commit_before>'use strict';

var FeedParser = require('feedparser');

function parse (src, max, callback) {
  var parser = new FeedParser();
  var c = 0;

  src.pipe(parser);

  if (max == null)
    max = 10;

  var res = {
    meta: {},
    articles: []
  };

  parser.on('error', function (err) {
    return callback(err);
  });

  parser.on('readable', function () {
    var stream = this;
    res.meta = this.meta;
    var item;

    while (item = stream.read()) {
      c += 1;
      if (c <= max || max === 0)
        res.articles.push(item);
    }

    if (c === max && max !== 0)
      return callback(null, res);
  });

  parser.on('end', function () {
    if (c <= max && max !== 0)
      return callback(null, res);
  });
}

function getUrl (url, max, callback) {
  var request = require('request');
  var Iconv = require('iconv').Iconv;

  var req = request({
    method: 'GET',
    uri: url
  });

  req.on('response', function (response) {
    var stream = this
        , iconv
        , charset;

    if (response.statusCode !== 200)
      return this.emit('error', new Error('Bad status code'));

    charset = getParams(res.headers['content-type'] || '').charset;
    if (!iconv && charset && !/utf-*8/i.test(charset)) {
        try {
            iconv = new Iconv(charset, 'utf-8');
            iconv.on('error', done);
            stream = this.pipe(iconv);
        } catch(err) {
            this.emit('error', err);
        }
    }

    parse(stream, max, callback);
  });

  req.on('error', function (err) {
    return callback(err);
  });
}

function getFile (path, max, callback) {
  var file = require('fs').createReadStream(path);
  parse(file, max, callback);
}

module.exports = getUrl;
module.exports.parse = parse;
module.exports.getUrl = getUrl;
module.exports.getFile = getFile;
<commit_msg>Fixing some issue about Codeclimate<commit_after>'use strict';

var FeedParser = require('feedparser');
var fs = require('fs');
var request = require('request');
var Iconv = require('iconv').Iconv;

function parse (src, max, callback) {
  var parser = new FeedParser();
  var c = 0;

  src.pipe(parser);

  if (max === null)
    max = 10;

  var res = {
    meta: {},
    articles: []
  };

  parser.on('error', function (err) {
    return callback(err);
  });

  parser.on('readable', function () {
    var stream = this;
    res.meta = this.meta;
    var item;

    while ((item = stream.read())) {
      c += 1;
      if (c <= max || max === 0)
        res.articles.push(item);
    }

    if (c === max && max !== 0)
      return callback(null, res);
  });

  parser.on('end', function () {
    if (c <= max && max !== 0)
      return callback(null, res);
  });
}

function getUrl (url, max, callback) {
  var req = request({
    method: 'GET',
    uri: url
  });

  req.on('response', function (response) {
    var stream = this
        , iconv
        , charset;

    if (response.statusCode !== 200)
      return this.emit('error', new Error('Bad status code'));

    charset = getParams(res.headers['content-type'] || '').charset;
    if (!iconv && charset && !/utf-*8/i.test(charset)) {
        try {
            iconv = new Iconv(charset, 'utf-8');
            iconv.on('error', done);
            stream = this.pipe(iconv);
        } catch(err) {
            this.emit('error', err);
        }
    }

    parse(stream, max, callback);
  });

  req.on('error', function (err) {
    return callback(err);
  });
}

function getFile (path, max, callback) {
  var file = fs.createReadStream(path);
  parse(file, max, callback);
}

module.exports = getUrl;
module.exports.parse = parse;
module.exports.getUrl = getUrl;
module.exports.getFile = getFile;
<|endoftext|>


<commit_before>/**
 * Copyright 2016, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict'

const config = require('./config.json'),
  apiai = require('apiai'),
  axios = require('axios')

// api.ai client
const apiapp = apiai(config.APIAI_TOKEN)

// slack client
const slack = axios.create({
  params: { token: config.SLACK_TOKEN },
  baseURL: 'https://slack.com/api/',
  headers: { 'User-Agent': 'keanu-bot' }
})

/**
 * Post a message to Slack
 *
 * @param {string} channel - the channel id to post to
 * @param {object} fields - the response fields to post
 * @returns A Promise with the http response
 */
function respondInSlack(channel, fields) {
  console.log('building slack message\n%O', fields)

  let attachment = {
    color: '#3367d6',
    text: fields.text,
    image_url: fields.url,
    fallback: "whoa"
  }
  console.log('slack attachment\n%O', attachment)

  let params = {
    channel: channel,
    attachments: JSON.stringify([attachment])
  }

  console.log('sending slack message\n%O', params)
  return slack.get('chat.postMessage', { params })
}

/**
 * Send text request to api.ai
 *
 * @param {string} text - the text to submit
 * @returns A Promise with the response result
 */
function sendToAPIAI(text) {
  console.log('sending text', text)

  let sessionId = new Date().getTime()
  let request = apiapp.textRequest(text, { sessionId })
  request.end()

  return new Promise((resolve, reject) => {
    // successful response
    request.on('response', response => {
      console.log('response\n%O', response)
      resolve(response.result)
    })

    // error
    request.on('error', error => {
      console.log('error\n%O', error)
      reject(error)
    })
  })
}

/**
 * Parse api.ai result
 *
 * @param {object} result - api.ai response result
 * @returns A Promise with the parsed fields
 */
function parseResponse(result) {
  console.log('parsing result\n%O', result)
  let { score, fulfillment } = result

  // no match
  if (score <= 0.1) return Promise.reject()

  // parse text and url from the speech
  let fields = {}
  fulfillment.speech.split(',').forEach(text => {
    if (!text.match(/(?:jpeg|jpg|gif|png)$/i)) fields.text = text
    else fields.url = text.replace(/ /g, '')
  })

  console.log('return fields\n%O', fields)
  return Promise.resolve(fields)
}

/**
 * Process a Slack event
 *
 * @param {object} event - the Slack message event
 * @returns A Promise with the event results
 */
function processEvent(event) {
  let { channel, text } = event
  let respond = respondInSlack.bind(null, channel)
  return sendToAPIAI(text).then(parseResponse).then(respond)
}

/**
 * @param {object} req Cloud Function request object.
 * @param {object} res Cloud Function response object.
 */
function handler(req, res) {
  console.log('payload received\n%O', req.body)

  let { token, challenge, event } = req.body

  // ignore retries
  if (req.headers["X-Slack-Retry-Num"]) {
    console.log('ignoring event api retry', req.headers["X-Slack-Retry-Num"])
    return res.send()
  }

  // verify slack request token
  if (token !== config.VERIFICATION_TOKEN) {
    console.log('invalid verification token', token)
    return res.status(401).send('Invalid request')
  }

  // slack events api challenge request
  if (challenge) {
    console.log('challenge request', challenge)
    return res.send(challenge)
  }

  // ignore bot events
  if (event && event.bot_id) {
    console.log('bot event ignored', event.bot_id)
    return res.send()
  }

  // process the event
  let complete = () => res.send()
  processEvent(event).then(complete).catch(complete)
}

// public endpoint
exports.handler = handler<commit_msg>Made some minor edits to index.js for the scoring threshold<commit_after>/**
 * Copyright 2016, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict'

const config = require('./config.json'),
  apiai = require('apiai'),
  axios = require('axios')

// api.ai client
const apiapp = apiai(config.APIAI_TOKEN)

// slack client
const slack = axios.create({
  params: { token: config.SLACK_TOKEN },
  baseURL: 'https://slack.com/api/',
  headers: { 'User-Agent': 'keanu-bot' }
})

/**
 * Post a message to Slack
 *
 * @param {string} channel - the channel id to post to
 * @param {object} fields - the response fields to post
 * @returns A Promise with the http response
 */
function respondInSlack(channel, fields) {
  console.log('building slack message\n%O', fields)

  let attachment = {
    color: '#3367d6',
    text: fields.text,
    image_url: fields.url,
    fallback: "whoa"
  }
  console.log('slack attachment\n%O', attachment)

  let params = {
    channel: channel,
    text: fields.text,
    attachments: JSON.stringify([attachment])
  }

  console.log('sending slack message\n%O', params)
  return slack.get('chat.postMessage', { params })
}

/**
 * Send text request to api.ai
 *
 * @param {string} text - the text to submit
 * @returns A Promise with the response result
 */
function sendToAPIAI(text) {
  console.log('sending text', text)

  let sessionId = new Date().getTime()
  let request = apiapp.textRequest(text, { sessionId })
  request.end()

  return new Promise((resolve, reject) => {
    // successful response
    request.on('response', response => {
      console.log('response\n%O', response)
      resolve(response.result)
    })

    // error
    request.on('error', error => {
      console.log('error\n%O', error)
      reject(error)
    })
  })
}

/**
 * Parse api.ai result
 *
 * @param {object} result - api.ai response result
 * @returns A Promise with the parsed fields
 */
function parseResponse(result) {
  console.log('parsing result\n%O', result)
  let { score, fulfillment } = result

  // no match
  if (score <= 0.) return Promise.reject()

  // parse text and url from the speech
  let fields = {}
  fulfillment.speech.split(',').forEach(text => {
    if (!text.match(/(?:jpeg|jpg|gif|png)$/i)) fields.text = text
    else fields.url = text.replace(/ /g, '')
  })

  console.log('return fields\n%O', fields)
  return Promise.resolve(fields)
}

/**
 * Process a Slack event
 *
 * @param {object} event - the Slack message event
 * @returns A Promise with the event results
 */
function processEvent(event) {
  let { channel, text } = event
  let respond = respondInSlack.bind(null, channel)
  return sendToAPIAI(text).then(parseResponse).then(respond)
}

/**
 * @param {object} req Cloud Function request object.
 * @param {object} res Cloud Function response object.
 */
function handler(req, res) {
  console.log('payload received\n%O', req.body)

  let { token, challenge, event } = req.body

  // ignore retries
  if (req.headers["X-Slack-Retry-Num"]) {
    console.log('ignoring event api retry', req.headers["X-Slack-Retry-Num"])
    return res.send()
  }

  // verify slack request token
  if (token !== config.VERIFICATION_TOKEN) {
    console.log('invalid verification token', token)
    return res.status(401).send('Invalid request')
  }

  // slack events api challenge request
  if (challenge) {
    console.log('challenge request', challenge)
    return res.send(challenge)
  }

  // ignore bot events

  if (event && event.bot_id) {
    console.log('bot event ignored', event.bot_id)
    return res.send()
  }

  // process the event
  let complete = () => res.send()
  processEvent(event).then(complete).catch(complete)
}

// public endpoint
exports.handler = handler
<|endoftext|>


<commit_before>#!/usr/bin/env node

const path = require('path');
const http = require('http');
const express = require('express');

const app = express();

const server = http.Server(app); // eslint-disable-line new-cap
const io = require('socket.io')(server);

const log = require('yalm');
const Mqtt = require('mqtt');
const mw = require('mqtt-wildcard');
const config = require('./config.js');
const pkg = require('./package.json');
const Core = require('./lib/core.js');

log.setLevel(config.verbosity);

const core = new Core(config, log);

let mqttConnected = false;

log.info(pkg.name + ' ' + pkg.version + ' starting');
log.info('mqtt trying to connect', config.url);

const mqtt = Mqtt.connect(config.url, {will: {topic: config.name + '/connected', payload: '0', retain: true}});

mqtt.on('connect', () => {
    mqttConnected = true;

    log.info('mqtt connected', config.url);
    mqtt.publish(config.name + '/connected', '1', {retain: true});

    log.debug('mqtt subscribe', config.name + '/set/#');
    mqtt.subscribe(config.name + '/set/#');
    log.debug('mqtt subscribe', config.name + '/extend/#');
    mqtt.subscribe(config.name + '/extend/#');
    log.debug('mqtt subscribe', config.name + '/prop/#');
    mqtt.subscribe(config.name + '/prop/#');
    log.debug('mqtt subscribe', config.name + '/query/#');
    mqtt.subscribe(config.name + '/query/#');
    log.debug('mqtt subscribe', config.name + '/get/+/#');
    mqtt.subscribe(config.name + '/get/+/#');
});

mqtt.on('close', () => {
    if (mqttConnected) {
        mqttConnected = false;
        log.info('mqtt closed ' + config.url);
    }
});

/* istanbul ignore next */
mqtt.on('error', err => {
    log.error('mqtt', err);
});

mqtt.on('offline', () => {
    log.warn('mqtt offline');
});

mqtt.on('reconnect', () => {
    log.debug('mqtt reconnect');
});

mqtt.on('message', (topic, payload) => {
    payload = payload.toString();
    log.debug('mqtt <', topic, payload);
    const match = mw(topic, config.name + '/+/#');
    const [cmd, id] = match;

    if (!match || !id) {
        log.error('malformed topic', topic);
        return;
    }

    /* eslint-disable no-case-declarations */
    switch (cmd) {
        case 'set':
        case 'extend':
        case 'query':
        case 'prop':
            let data;
            if (payload === '') {
                data = payload;
            } else {
                try {
                    data = JSON.parse(payload);
                } catch (err) {
                    log.error('malformed payload', err);
                    return;
                }
            }
            try {
                core[cmd](id, data);
            } catch (err) {
                /* istanbul ignore next */
                log.error('error in mqtt message handler', err.message);
            }

            break;

        case 'get':
            let [type, gid] = mw(topic, config.name + '/get/+/#');
            get(type, id);
            break;

        /* istanbul ignore next */
        default:
            log.error('unknown cmd', cmd);
    }
});

function get(type, id) {
    switch (type) {
        case 'doc':
            mqtt.publish(config.name + '/doc/' + id, core.db[id] ? JSON.stringify(core.db[id]) : '');
            break;
        case 'view':
            mqtt.publish(config.name + '/view/' + id, core.views[id] ? JSON.stringify(core.views[id]) : '');
            break;
        default:
            log.error('unknown get type', type);
    }
}

core.on('ready', () => {
    if (!config.retainDisable) {
        const did = Object.keys(core.db);
        did.forEach(id => {
            mqtt.publish(config.name + '/doc/' + id, JSON.stringify(core.db[id]), {retain: true});
        });
        if (did.length > 0) {
            log.info('published ' + did.length + ' docs');
        }
        const vid = Object.keys(core.views);
        vid.forEach(id => {
            mqtt.publish(config.name + '/view/' + id, JSON.stringify(core.views[id]), {retain: true});
        });
        if (vid.length > 0) {
            log.info('published ' + vid.length + ' views');
        }
    }
    mqtt.publish(config.name + '/rev', String(core.rev), {retain: true});
    mqtt.publish(config.name + '/connected', '2', {retain: true});
});

core.on('update', (id, data) => {
    log.debug('mqtt >', id, 'rev', data.rev);
    mqtt.publish(config.name + '/doc/' + id, JSON.stringify(data), {retain: !config.retainDisable});
    log.debug('mqtt > rev', core.rev);
    mqtt.publish(config.name + '/rev', String(core.rev), {retain: true});
    io.emit('objectIds', Object.keys(core.db));
});

core.on('view', (id, data) => {
    io.emit('updateView', id);
    if (data && data.error) {
        log.error('view', id, ':', data);
    } else {
        log.debug('view', id, 'rev', core.views[id] && core.views[id]._rev);
    }
    const payload = data ? JSON.stringify(data) : '';
    mqtt.publish(config.name + '/view/' + id, payload, {retain: !config.retainDisable});
    io.emit('viewIds', Object.keys(core.views));
});

/* istanbul ignore next */
core.on('error', err => {
    log.error(err);
});

/* istanbul ignore else */
if (!config.webDisable) {
    server.listen(config.webPort, config.webInterface);
    log.info('http server listening on ' + config.webInterface + ':' + config.webPort);

    app.get('/', (req, res) => {
        res.redirect(301, '/ui');
    });
    app.use('/ui', express.static(path.join(__dirname, '/ui')));
    app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));

    io.on('connection', socket => {
        io.emit('objectIds', Object.keys(core.db));
        io.emit('viewIds', Object.keys(core.views));

        socket.on('getObject', (id, cb) => {
            cb(core.db[id]);
        });

        socket.on('getView', (id, cb) => {
            cb({id, query: core.queries[id], view: core.views[id]});
        });

        socket.on('set', (id, data, cb) => {
            if (data._rev === null || !core.db[id] || data._rev === core.db[id]._rev) {
                core.set(id, data);
                socket.emit('objectIds', Object.keys(core.db).sort());
                cb('ok');
            } else {
                cb('rev mismatch ' + core.db[id]._rev);
            }
        });

        socket.on('del', (id, cb) => {
            core.del(id);
            cb('ok');
            socket.emit('objectIds', Object.keys(core.db).sort());
        });

        socket.on('query', (id, payload, cb) => {
            core.query(id, payload);
            cb('ok');
            socket.emit('viewIds', Object.keys(core.views).sort());
        });
    });
}
<commit_msg>fix get<commit_after>#!/usr/bin/env node

const path = require('path');
const http = require('http');
const express = require('express');

const app = express();

const server = http.Server(app); // eslint-disable-line new-cap
const io = require('socket.io')(server);

const log = require('yalm');
const Mqtt = require('mqtt');
const mw = require('mqtt-wildcard');
const config = require('./config.js');
const pkg = require('./package.json');
const Core = require('./lib/core.js');

log.setLevel(config.verbosity);

const core = new Core(config, log);

let mqttConnected = false;

log.info(pkg.name + ' ' + pkg.version + ' starting');
log.info('mqtt trying to connect', config.url);

const mqtt = Mqtt.connect(config.url, {will: {topic: config.name + '/connected', payload: '0', retain: true}});

mqtt.on('connect', () => {
    mqttConnected = true;

    log.info('mqtt connected', config.url);
    mqtt.publish(config.name + '/connected', '1', {retain: true});

    log.debug('mqtt subscribe', config.name + '/set/#');
    mqtt.subscribe(config.name + '/set/#');
    log.debug('mqtt subscribe', config.name + '/extend/#');
    mqtt.subscribe(config.name + '/extend/#');
    log.debug('mqtt subscribe', config.name + '/prop/#');
    mqtt.subscribe(config.name + '/prop/#');
    log.debug('mqtt subscribe', config.name + '/query/#');
    mqtt.subscribe(config.name + '/query/#');
    log.debug('mqtt subscribe', config.name + '/get/+/#');
    mqtt.subscribe(config.name + '/get/+/#');
});

mqtt.on('close', () => {
    if (mqttConnected) {
        mqttConnected = false;
        log.info('mqtt closed ' + config.url);
    }
});

/* istanbul ignore next */
mqtt.on('error', err => {
    log.error('mqtt', err);
});

mqtt.on('offline', () => {
    log.warn('mqtt offline');
});

mqtt.on('reconnect', () => {
    log.debug('mqtt reconnect');
});

mqtt.on('message', (topic, payload) => {
    payload = payload.toString();
    log.debug('mqtt <', topic, payload);
    const match = mw(topic, config.name + '/+/#');
    const [cmd, id] = match;

    if (!match || !id) {
        log.error('malformed topic', topic);
        return;
    }

    /* eslint-disable no-case-declarations */
    switch (cmd) {
        case 'set':
        case 'extend':
        case 'query':
        case 'prop':
            let data;
            if (payload === '') {
                data = payload;
            } else {
                try {
                    data = JSON.parse(payload);
                } catch (err) {
                    log.error('malformed payload', err);
                    return;
                }
            }
            try {
                core[cmd](id, data);
            } catch (err) {
                /* istanbul ignore next */
                log.error('error in mqtt message handler', err.message);
            }

            break;

        case 'get':
            let [type, gid] = mw(topic, config.name + '/get/+/#');
            get(type, gid);
            break;

        /* istanbul ignore next */
        default:
            log.error('unknown cmd', cmd);
    }
});

function get(type, id) {
    switch (type) {
        case 'doc':
            mqtt.publish(config.name + '/doc/' + id, core.db[id] ? JSON.stringify(core.db[id]) : '');
            break;
        case 'view':
            mqtt.publish(config.name + '/view/' + id, core.views[id] ? JSON.stringify(core.views[id]) : '');
            break;
        default:
            log.error('unknown get type', type);
    }
}

core.on('ready', () => {
    if (!config.retainDisable) {
        const did = Object.keys(core.db);
        did.forEach(id => {
            mqtt.publish(config.name + '/doc/' + id, JSON.stringify(core.db[id]), {retain: true});
        });
        if (did.length > 0) {
            log.info('published ' + did.length + ' docs');
        }
        const vid = Object.keys(core.views);
        vid.forEach(id => {
            mqtt.publish(config.name + '/view/' + id, JSON.stringify(core.views[id]), {retain: true});
        });
        if (vid.length > 0) {
            log.info('published ' + vid.length + ' views');
        }
    }
    mqtt.publish(config.name + '/rev', String(core.rev), {retain: true});
    mqtt.publish(config.name + '/connected', '2', {retain: true});
});

core.on('update', (id, data) => {
    log.debug('mqtt >', id, 'rev', data.rev);
    mqtt.publish(config.name + '/doc/' + id, JSON.stringify(data), {retain: !config.retainDisable});
    log.debug('mqtt > rev', core.rev);
    mqtt.publish(config.name + '/rev', String(core.rev), {retain: true});
    io.emit('objectIds', Object.keys(core.db));
});

core.on('view', (id, data) => {
    io.emit('updateView', id);
    if (data && data.error) {
        log.error('view', id, ':', data);
    } else {
        log.debug('view', id, 'rev', core.views[id] && core.views[id]._rev);
    }
    const payload = data ? JSON.stringify(data) : '';
    mqtt.publish(config.name + '/view/' + id, payload, {retain: !config.retainDisable});
    io.emit('viewIds', Object.keys(core.views));
});

/* istanbul ignore next */
core.on('error', err => {
    log.error(err);
});

/* istanbul ignore else */
if (!config.webDisable) {
    server.listen(config.webPort, config.webInterface);
    log.info('http server listening on ' + config.webInterface + ':' + config.webPort);

    app.get('/', (req, res) => {
        res.redirect(301, '/ui');
    });
    app.use('/ui', express.static(path.join(__dirname, '/ui')));
    app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));

    io.on('connection', socket => {
        io.emit('objectIds', Object.keys(core.db));
        io.emit('viewIds', Object.keys(core.views));

        socket.on('getObject', (id, cb) => {
            cb(core.db[id]);
        });

        socket.on('getView', (id, cb) => {
            cb({id, query: core.queries[id], view: core.views[id]});
        });

        socket.on('set', (id, data, cb) => {
            if (data._rev === null || !core.db[id] || data._rev === core.db[id]._rev) {
                core.set(id, data);
                socket.emit('objectIds', Object.keys(core.db).sort());
                cb('ok');
            } else {
                cb('rev mismatch ' + core.db[id]._rev);
            }
        });

        socket.on('del', (id, cb) => {
            core.del(id);
            cb('ok');
            socket.emit('objectIds', Object.keys(core.db).sort());
        });

        socket.on('query', (id, payload, cb) => {
            core.query(id, payload);
            cb('ok');
            socket.emit('viewIds', Object.keys(core.views).sort());
        });
    });
}
<|endoftext|>


<commit_before>module.exports = function pick(target, query) {
  if (typeof target !== 'object' || target === null) {
    return target;
  } else if (Array.isArray(target)) {
    return target.map(item => pick(item, query[Object.keys(query)[0]]));
  } else if (typeof query === 'string') {
    return { [query]: target[query] };
  } else if (Array.isArray(query)) {
    return query.filter(q => typeof q === 'string')
        .filter(q => target.hasOwnProperty(q))
        .reduce((result, key) => Object.assign(result, { [key]: target[key] }), {});
  } else if (typeof query === 'object' && query !== null) {
    return Object.keys(query).filter(q => target.hasOwnProperty(q))
        .reduce((result, key) => Object.assign(result, (
          query[key] === true || typeof query[key] === 'object' && query[key] !== null
        ) ? { [key]: pick(target[key], query[key]) } : {}), {});
  }
  return target;
};
<commit_msg>fix string query bug<commit_after>module.exports = function pick(target, query) {
  if (typeof target !== 'object' || target === null) {
    return target;
  } else if (Array.isArray(target)) {
    return target.map(item => pick(item, query[Object.keys(query)[0]]));
  } else if (typeof query === 'string') {
    return target.hasOwnProperty(query) ? { [query]: target[query] } : {};
  } else if (Array.isArray(query)) {
    return query.filter(q => typeof q === 'string')
        .filter(q => target.hasOwnProperty(q))
        .reduce((result, key) => Object.assign(result, { [key]: target[key] }), {});
  } else if (typeof query === 'object' && query !== null) {
    return Object.keys(query).filter(q => target.hasOwnProperty(q))
        .reduce((result, key) => Object.assign(result, (
          query[key] === true || typeof query[key] === 'object' && query[key] !== null ||
              typeof query[key] === 'string'
        ) ? { [key]: pick(target[key], query[key]) } : {}), {});
  }
  return target;
};
<|endoftext|>


<commit_before>window.onload = function () {
    "use strict";

    d3.text("facebook-links.txt", function (text) {
        var data,
            nll,
            nodeTable,
            adapter,
            graph,
            cmap,
            view;

        console.log("Loading data...");
        data = d3.tsv.parseRows(text, function (row) {
            return [Number(row[0]), Number(row[1])];
        });
        console.log("done");

        // Construct a node link list.
        nll = {
            nodes: [],
            links: []
        };

        nodeTable = {};
        console.log("building graph data...");
        _.each(data, function (row) {
            _.each(row, function (node) {
                if (!_.has(nodeTable, node)) {
                    nodeTable[node] = _.size(nll.nodes);
                    nll.nodes.push({
                        id: node
                    });
                }
            });

            nll.links.push({
                source: nodeTable[row[0]],
                target: nodeTable[row[1]],
                undirected: true,
                data: {}
            });
        });
        console.log("done");

        // Create a graph data adapter from the node link data.
        adapter = new clique.adapter.NodeLinkList(nll);

        // Create a graph model useing the adapter.
        window.graph = graph = new clique.Graph({
            adapter: adapter
        });

        // Create a view to visualize the graph.
        cmap = d3.scale.category10();
        window.view = view = new clique.view.Cola({
            model: graph,
            el: "#graph",
            fill: function (d) {
                return cmap(_.last(d.key));
            }
        });

        view.selection.on("focused", function (focused) {
            if (!_.isUndefined(focused)) {
                console.log(focused.slice(5));
            }
        });

        view.once("render", function () {
            view.nodes.on("dblclick", function (d) {
                expandNode(_.last(d.key));
            });
        });

        // Some functions to drive the visualization from the console.
        //
        // Add a node to the graph by id number.
        window.addNode = function (i) {
            adapter.findNodeByKey("node_" + i).then(function (node) {
                if (!node) {
                    console.warn("No such node with id " + i);
                    return;
                }

                return graph.addNode(node);
            });
        };

        // Expand a node already in the graph.
        window.expandNode = function (i) {
            var key = "node_" + i;
            if (!_.has(graph.nodes, key)) {
                console.warn("No such node with id " + i + " in graph");
                return;
            }

            return graph.addNeighborhood({
                center: graph.adapter.getAccessor(key),
                radius: 1
            });
        };

    });
};
<commit_msg>Making Jeff-requested changes<commit_after>window.onload = function () {
    "use strict";

    d3.text("facebook-sample-data.txt", function (text) {
        var data,
            nll,
            nodeTable,
            adapter,
            graph,
            cmap,
            view,
            oldNodeEnter;

        console.log("Loading data...");
        data = d3.tsv.parseRows(text, function (row) {
            return [Number(row[0]), Number(row[1])];
        });
        console.log("done");

        // Construct a node link list.
        nll = {
            nodes: [],
            links: []
        };

        nodeTable = {};
        console.log("building graph data...");
        _.each(data, function (row) {
            _.each(row, function (node) {
                if (!_.has(nodeTable, node)) {
                    nodeTable[node] = _.size(nll.nodes);
                    nll.nodes.push({
                        id: node
                    });
                }
            });

            nll.links.push({
                source: nodeTable[row[0]],
                target: nodeTable[row[1]],
                undirected: true,
                data: {}
            });
        });
        console.log("done");

        // Create a graph data adapter from the node link data.
        adapter = new clique.adapter.NodeLinkList(nll);

        // Create a graph model useing the adapter.
        window.graph = graph = new clique.Graph({
            adapter: adapter
        });

        // Create a view to visualize the graph.
        cmap = d3.scale.category10();
        window.view = view = new clique.view.Cola({
            model: graph,
            el: "#graph",
            fill: function (d) {
                return cmap(_.last(d.key));
            }
        });

        view.selection.on("focused", function (focused) {
            if (!_.isUndefined(focused)) {
                console.log(focused);
            }
        });

        oldNodeEnter = view.nodeEnter;
        view.nodeEnter = _.bind(function (enter) {
            oldNodeEnter(enter);
            this.nodes.on("dblclick", function (d) {
                expandNode(d.key);
            });

        }, view);

        // Some functions to drive the visualization from the console.
        //
        // Add a node to the graph by id number.
        window.addNode = function (key) {
            adapter.findNodeByKey(key).then(function (node) {
                if (!node) {
                    console.warn("No such node with id " + key);
                    return;
                }

                return graph.addNode(node);
            });
        };

        // Expand a node already in the graph.
        window.expandNode = function (key) {
            if (!_.has(graph.nodes, key)) {
                console.warn("No such node with id " + key + " in graph");
                return;
            }

            return graph.addNeighborhood({
                center: graph.adapter.getAccessor(key),
                radius: 1
            });
        };

        window.addNode("node_1");
    });
};
<|endoftext|>


<commit_before>// Promise returned by Parse sucks.
var morgan = require('morgan');
var Promise = require('promise');
var express = require('express');
var multer = require('multer');
var mime = require('mime-types');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var stringify = require('csv-stringify');

var config = require('./config');

var app = express();
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, __dirname + '/public/uploads')
  },
  filename: function (req, file, cb) {
    var extension = mime.extension(file.mimetype);
    var newFileName = file.originalname.replace(/[^a-zA-Z]/g, '').toLowerCase().replace(/\.[^.]*|$/, '.' + extension);
    cb(null, Date.now() + newFileName);
  }
});
var upload = multer({ storage });
var singleUpload = upload.single('picture');
var jsonParser = bodyParser.json();

var Entry = Parse.Object.extend('Entry');
var Comment = Parse.Object.extend('Comment');
var User = Parse.Object.extend('User');

Parse.initialize(config.parseAppID, config.parseKey);

app.use(morgan('combined'));

app.use(express.static(__dirname + '/public'))

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

app.post('/api/1.0/upload', singleUpload, function (req, res) {
  var file = req.file;
  var entry = new Entry();
  Promise.resolve(entry.save({
    votes: 0,
    pictures: [ 'uploads/' + file.filename ],
    description: req.body.description,
    location: new Parse.GeoPoint(+req.body.latitude, +req.body.longitude)
  })).then(function () {
    res.send({
      response: 200,
      text: 'OK'
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

function postVoteRoute (increment) {
  return function (req, res) {
    res.set('Content-Type', 'text/plain');
    var after = 0;
    Promise.resolve(new Parse.Query(Entry).get(req.params.id))
    .then(function (entry) {
      var curInc = increment * (req.body.unvote ? -1 : 1);
      after = entry.get('votes') + curInc;
      if (!entry.set('votes', after)) {
        console.trace('entry set failed');
        res.status(500).send('0');
        return;
      }
      return Promise.resolve(entry.save()).then(function () {
        res.send('' + after);
      }).catch(function (err) {
        if (err) {
          console.error(err.stack || err.message || err);
        } else {
          console.trace('500')
        }
        res.status(500).send('0');
      });
    }, function (err) {
      res.status(404).send('0');
    });
  };
}

app.post('/api/1.0/upvote/:id',   jsonParser, postVoteRoute(1));
app.post('/api/1.0/downvote/:id', jsonParser, postVoteRoute(-1));

app.get('/api/1.0/votes/:id', function (req, res) {
  res.set('Content-Type', 'text/plain');
  Promise.resolve(new Parse.Query(Entry).get(req.params.id))
  .then(function (entry) {
    res.send('' + entry.get('votes'));
  }, function (err) {
    res.status(404).send('0');
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500');
    }
    res.status(500).send('0');
  });
});

app.get('/api/1.0/getAll', function (req, res) {
  res.set('Content-Type', 'text/csv');
  var schema = [
    'objectId',
    'votes',
    'latitude',
    'longitude',
    'picture',
    'description'
  ];
  var stringifier = stringify();
  stringifier.pipe(res);
  stringifier.write(schema);
  Promise.resolve(new Parse.Query(Entry).each(function (entry) {
    var serialized = [];
    serialized.push(entry.id);
    serialized.push(entry.get('votes'));
    var loc = entry.get('location');
    serialized.push(loc.latitude);
    serialized.push(loc.longitude);
    serialized.push(entry.get('pictures')[0]);
    serialized.push(entry.get('description'));
    stringifier.write(serialized);
  })).then(function () {
    stringifier.end();
  });
});

app.get('/api/1.0/getAllJSON', function (req, res) {
  var out = [];
  Promise.resolve(new Parse.Query(Entry).each(function (entry) {
    out.push(entry)
  })).then(function () {
    res.send(out);
  });
});

app.get('/api/1.0/get/:id', function (req, res) {
  Promise.resolve(new Parse.Query(Entry).get(req.params.id)).then(function (entry) {
    var obj = {
      objectId: entry.id,
      description: entry.get('description'),
      location: entry.get('location'),
      picture: entry.get('pictures')[0],
      votes: entry.get('votes'),
      createdAt: entry.createdAt,
      updatedAt: entry.updatedAt
    };
    res.send(obj);
  }, function (err) {
    res.status(404).send({
      response: 404,
      text: 'Not found'
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.post('/api/1.0/comment/:id', jsonParser, function (req, res) {
  var comment = new Comment();

  Promise.all([
    Promise.resolve(comment.save({
      data: req.body.data,
      name: req.body.uuid,
      target: req.params.id,
      admin: req.body.uuid === 'admin'
    })),
  ]).then(function () {
    res.send({
      response: 200,
      text: 'OK',
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.get('/api/1.0/getComments/:id', function (req, res) {
  var query = new Parse.Query(Comment)
    .equalTo('target', req.params.id);

  Promise.resolve(query.find()).then(function (results) {
    if (!results || !results.length) {
      return res.status(404).send({
        response: 404,
        text: 'Not found',
      });
    }

    return res.send(results);
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.listen(8083, '0.0.0.0', function () {
  console.log('listening on 8083');
});
<commit_msg>Add votes 1.1<commit_after>// Promise returned by Parse sucks.
var morgan = require('morgan');
var Promise = require('promise');
var express = require('express');
var multer = require('multer');
var mime = require('mime-types');
var bodyParser = require('body-parser');
var Parse = require('parse/node');
var stringify = require('csv-stringify');

var config = require('./config');

var app = express();
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, __dirname + '/public/uploads')
  },
  filename: function (req, file, cb) {
    var extension = mime.extension(file.mimetype);
    var newFileName = file.originalname.replace(/[^a-zA-Z]/g, '').toLowerCase().replace(/\.[^.]*|$/, '.' + extension);
    cb(null, Date.now() + newFileName);
  }
});
var upload = multer({ storage });
var singleUpload = upload.single('picture');
var jsonParser = bodyParser.json();

var Entry = Parse.Object.extend('Entry');
var Comment = Parse.Object.extend('Comment');
var User = Parse.Object.extend('User');

Parse.initialize(config.parseAppID, config.parseKey);

app.use(morgan('combined'));

app.use(express.static(__dirname + '/public'))

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

app.post('/api/1.0/upload', singleUpload, function (req, res) {
  var file = req.file;
  var entry = new Entry();
  Promise.resolve(entry.save({
    votes: 0,
    pictures: [ 'uploads/' + file.filename ],
    description: req.body.description,
    location: new Parse.GeoPoint(+req.body.latitude, +req.body.longitude)
  })).then(function () {
    res.send({
      response: 200,
      text: 'OK'
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

function postVoteRoute (increment) {
  return function (req, res) {
    res.set('Content-Type', 'text/plain');
    var after = 0;
    Promise.resolve(new Parse.Query(Entry).get(req.params.id))
    .then(function (entry) {
      var curInc = increment * (req.body.unvote ? -1 : 1);
      after = entry.get('votes') + curInc;
      if (!entry.set('votes', after)) {
        console.trace('entry set failed');
        res.status(500).send('0');
        return;
      }
      return Promise.resolve(entry.save()).then(function () {
        res.send('' + after);
      }).catch(function (err) {
        if (err) {
          console.error(err.stack || err.message || err);
        } else {
          console.trace('500')
        }
        res.status(500).send('0');
      });
    }, function (err) {
      res.status(404).send('0');
    });
  };
}

app.post('/api/1.0/upvote/:id',   jsonParser, postVoteRoute(1));
app.post('/api/1.0/downvote/:id', jsonParser, postVoteRoute(-1));

app.post('/api/1.1/vote/:id', jsonParser, function (req, res) {
  res.set('Content-Type', 'text/plain');
  var votes = req.body.votes;

  if (votes > 10 || votes < -10) res.status(400).send('');
  Promise.resolve(new Parse.Query(Entry).get(req.params.id))
    .then(function (entry) {
      entry.increment('votes', votes);
      return Promise.resolve(entry.save()).then(function () {
        res.send('');
      }).catch(function (err) {
        if (err) {
          console.error(err.stack || err.message || err);
        } else {
          console.trace('500')
        }
        res.status(500).send('');
      });
    }, function (err) {
      res.status(404).send('');
    });
});

app.get('/api/1.0/votes/:id', function (req, res) {
  res.set('Content-Type', 'text/plain');
  Promise.resolve(new Parse.Query(Entry).get(req.params.id))
  .then(function (entry) {
    res.send('' + entry.get('votes'));
  }, function (err) {
    res.status(404).send('0');
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500');
    }
    res.status(500).send('0');
  });
});

app.get('/api/1.0/getAll', function (req, res) {
  res.set('Content-Type', 'text/csv');
  var schema = [
    'objectId',
    'votes',
    'latitude',
    'longitude',
    'picture',
    'description'
  ];
  var stringifier = stringify();
  stringifier.pipe(res);
  stringifier.write(schema);
  Promise.resolve(new Parse.Query(Entry).each(function (entry) {
    var serialized = [];
    serialized.push(entry.id);
    serialized.push(entry.get('votes'));
    var loc = entry.get('location');
    serialized.push(loc.latitude);
    serialized.push(loc.longitude);
    serialized.push(entry.get('pictures')[0]);
    serialized.push(entry.get('description'));
    stringifier.write(serialized);
  })).then(function () {
    stringifier.end();
  });
});

app.get('/api/1.0/getAllJSON', function (req, res) {
  var out = [];
  Promise.resolve(new Parse.Query(Entry).each(function (entry) {
    out.push(entry)
  })).then(function () {
    res.send(out);
  });
});

app.get('/api/1.0/get/:id', function (req, res) {
  Promise.resolve(new Parse.Query(Entry).get(req.params.id)).then(function (entry) {
    var obj = {
      objectId: entry.id,
      description: entry.get('description'),
      location: entry.get('location'),
      picture: entry.get('pictures')[0],
      votes: entry.get('votes'),
      createdAt: entry.createdAt,
      updatedAt: entry.updatedAt
    };
    res.send(obj);
  }, function (err) {
    res.status(404).send({
      response: 404,
      text: 'Not found'
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.post('/api/1.0/comment/:id', jsonParser, function (req, res) {
  var comment = new Comment();

  Promise.all([
    Promise.resolve(comment.save({
      data: req.body.data,
      name: req.body.uuid,
      target: req.params.id,
      admin: req.body.uuid === 'admin'
    })),
  ]).then(function () {
    res.send({
      response: 200,
      text: 'OK',
    });
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.get('/api/1.0/getComments/:id', function (req, res) {
  var query = new Parse.Query(Comment)
    .equalTo('target', req.params.id);

  Promise.resolve(query.find()).then(function (results) {
    if (!results || !results.length) {
      return res.status(404).send({
        response: 404,
        text: 'Not found',
      });
    }

    return res.send(results);
  }).catch(function (err) {
    if (err) {
      console.error(err.stack || err.message || err);
    } else {
      console.trace('500')
    }
    res.status(500).send({
      response: 500,
      text: 'Internal server error'
    });
  });
});

app.listen(8083, '0.0.0.0', function () {
  console.log('listening on 8083');
});
<|endoftext|>


<commit_before>'use strict'

var debug = require('debug')('monster-drift')
delete process.env.DEBUG // hackrf doesn't like this flag

var devices = require('hackrf')()
var ook = require('./lib/ook')
var commands = require('./lib/commands')

module.exports = MonsterDrift

function MonsterDrift (opts) {
  if (!(this instanceof MonsterDrift)) return new MonsterDrift()
  if (!opts) opts = {}

  this._freq = opts.freq || 27143550
  this._index = 0
  this._stream = null
  this._stopIn = opts.stop || null
  this._stopTimer = null

  var encode = ook({
    freq: this._freq,
    gain: 32,
    symbolPeriod: 0.463753
  })

  var self = this
  this._signal = {}
  Object.keys(commands).forEach(function (key) {
    var cmd = commands[key]
    self._signal[key] = encode(Array(100).join(cmd[0]))
    self._signal[key].name = cmd[1]
  })

  this._device = devices.open(opts.id || 0)
  this._device.setTxGain(opts.gain || 30) // TX VGA (IF) gain, 0-47 dB in 1 dB steps
  this._device.setFrequency(this._freq)
}

MonsterDrift.prototype.turn180 = function (cb) {
  this.batch([
    [this.forward, 1000],
    [this.right, 125],
    [this.reverseLeft, 100],
    [this.reverse, 1000]
  ], cb)
}

MonsterDrift.prototype._start = function () {
  var self = this
  debug('starting')
  this._device.startTx(function (buf, cb) {
    var i
    if (self._stream) {
      for (i = 0; i < buf.length; i++) {
        buf[i] = self._stream[self._index++]
        if (self._index === self._stream.length) self._index = 0
      }
    } else {
      for (i = 0; i < buf.length; i++) buf[i] = 0
    }
    cb()
  })
}

MonsterDrift.prototype.stop = function (cb) {
  if (!this._stream) return cb()
  debug('stopping')
  this._stream = null
  this._device.stopTx(function () {
    debug('stopped!')
    if (cb) cb()
  })
}

MonsterDrift.prototype.close = function (cb) {
  var self = this
  this.stop(function () {
    self._device.close(cb)
  })
}

MonsterDrift.prototype.left = function () {
  this._drive(this._signal.wl)
}

MonsterDrift.prototype.right = function () {
  this._drive(this._signal.wr)
}

MonsterDrift.prototype.forward = function () {
  this._drive(this._signal.f)
}

MonsterDrift.prototype.forwardRight = function () {
  this._drive(this._signal.fr)
}

MonsterDrift.prototype.forwardLeft = function () {
  this._drive(this._signal.fl)
}

MonsterDrift.prototype.reverse = function () {
  this._drive(this._signal.r)
}

MonsterDrift.prototype.reverseRight = function () {
  this._drive(this._signal.rr)
}

MonsterDrift.prototype.reverseLeft = function () {
  this._drive(this._signal.rl)
}

MonsterDrift.prototype.batch = function (commands, cb) {
  var self = this
  next()

  function next (i) {
    var command = commands[i || 0]
    if (!command) return self.stop(cb)
    var fn = commands[0]
    var ms = commands[1]
    fn.call(self)
    if (ms) {
      setTimeout(function () {
        next(++i)
      }, ms)
    } else if (cb) {
      cb()
    }
  }
}

MonsterDrift.prototype._drive = function (s) {
  debug(s.name)
  if (this._stopTimer) clearTimeout(this._stopTimer)
  if (this._stream === s) return
  else if (!this._stream) this._start()

  debug('new direction')
  this._index = 0
  this._stream = s

  if (this._stopIn) {
    var self = this
    this._stopTimer = setTimeout(function () {
      self.stop()
    }, this._stopIn)
  }
}
<commit_msg>Code cleanup<commit_after>'use strict'

var debug = require('debug')('monster-drift')
delete process.env.DEBUG // hackrf doesn't like this flag

var devices = require('hackrf')()
var ook = require('./lib/ook')
var commands = require('./lib/commands')

module.exports = MonsterDrift

function MonsterDrift (opts) {
  if (!(this instanceof MonsterDrift)) return new MonsterDrift()
  if (!opts) opts = {}

  this._freq = opts.freq || 27143550
  this._index = 0
  this._stream = null
  this._stopIn = opts.stop || null
  this._stopTimer = null

  var encode = ook({
    freq: this._freq,
    gain: 32,
    symbolPeriod: 0.463753
  })

  var self = this
  this._signal = {}
  Object.keys(commands).forEach(function (key) {
    var cmd = commands[key]
    self._signal[key] = encode(Array(100).join(cmd[0]))
    self._signal[key].name = cmd[1]
  })

  this._device = devices.open(opts.id || 0)
  this._device.setTxGain(opts.gain || 30) // TX VGA (IF) gain, 0-47 dB in 1 dB steps
  this._device.setFrequency(this._freq)
}

MonsterDrift.prototype.turn180 = function (cb) {
  this.batch([
    [this.forward, 1000],
    [this.right, 125],
    [this.reverseLeft, 100],
    [this.reverse, 1000]
  ], cb)
}

MonsterDrift.prototype._start = function () {
  var self = this
  debug('starting')
  this._device.startTx(function (buf, cb) {
    var i
    if (self._stream) {
      for (i = 0; i < buf.length; i++) {
        buf[i] = self._stream[self._index++]
        if (self._index === self._stream.length) self._index = 0
      }
    } else {
      for (i = 0; i < buf.length; i++) buf[i] = 0
    }
    cb()
  })
}

MonsterDrift.prototype.stop = function (cb) {
  if (!this._stream) return cb()
  debug('stopping')
  this._stream = null
  this._device.stopTx(function () {
    debug('stopped!')
    if (cb) cb()
  })
}

MonsterDrift.prototype.close = function (cb) {
  var self = this
  this.stop(function () {
    self._device.close(cb)
  })
}

MonsterDrift.prototype.forward = function () {
  this._drive(this._signal.f)
}

MonsterDrift.prototype.forwardLeft = function () {
  this._drive(this._signal.fl)
}

MonsterDrift.prototype.forwardRight = function () {
  this._drive(this._signal.fr)
}

MonsterDrift.prototype.reverse = function () {
  this._drive(this._signal.r)
}

MonsterDrift.prototype.reverseLeft = function () {
  this._drive(this._signal.rl)
}

MonsterDrift.prototype.reverseRight = function () {
  this._drive(this._signal.rr)
}

MonsterDrift.prototype.right = function () {
  this._drive(this._signal.wr)
}

MonsterDrift.prototype.left = function () {
  this._drive(this._signal.wl)
}

MonsterDrift.prototype.batch = function (commands, cb) {
  var self = this
  next()

  function next (i) {
    var command = commands[i || 0]
    if (!command) return self.stop(cb)
    var fn = commands[0]
    var ms = commands[1]
    fn.call(self)
    if (ms) {
      setTimeout(function () {
        next(++i)
      }, ms)
    } else if (cb) {
      cb()
    }
  }
}

MonsterDrift.prototype._drive = function (s) {
  debug(s.name)
  if (this._stopTimer) clearTimeout(this._stopTimer)
  if (this._stream === s) return
  else if (!this._stream) this._start()

  debug('new direction')
  this._index = 0
  this._stream = s

  if (this._stopIn) {
    var self = this
    this._stopTimer = setTimeout(function () {
      self.stop()
    }, this._stopIn)
  }
}
<|endoftext|>


<commit_before>/*!
 * native-promise <https://github.com/tunnckoCore/native-promise>
 *
 * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

try {
  module.exports = global.Promise || Promise
} catch (err) {
  module.exports = false
}
<commit_msg>Refactor to accept Promise from various sources better (#3)<commit_after>/*!
 * native-promise <https://github.com/tunnckoCore/native-promise>
 *
 * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

module.exports = typeof global === 'object' && global.Promise ||
  typeof window === 'object' && window.Promise ||
  typeof Promise !== 'undefined' && Promise ||
  false
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var Funnel = require('broccoli-funnel');
var mergeTrees = require('broccoli-merge-trees');
var rename = require('broccoli-stew').rename;

module.exports = {
  name: 'moment',

  included: function included(app) {
    this._super.included(app);
    var options = this.projectConfig();
    var vendor = this.treePaths.vendor;
    app.import(path.join(vendor, 'moment', 'min', 'moment.min.js'));

    if (options.moment && options.moment.includeTimezone) {
      app.import(path.join(vendor, 'moment-timezone', 'tz.js'));
    }
  },

  projectConfig: function projectConfig() {
    return this.project.config(process.env.EMBER_ENV) || {};
  },

  treeForVendor: function treeForVendor(vendorTree) {
    var trees = [];
    var app = this.app;
    var options = this.projectConfig();
    var momentPath = path.dirname(require.resolve('moment'));

    if (vendorTree) {
      trees.push(vendorTree);
    }

    options = options.moment || {};

    trees.push(new Funnel(momentPath, {
      destDir: 'moment',
      include: [new RegExp(/\.js$/)],
      exclude: ['tests', 'ender', 'package'].map(function(key) {
        return new RegExp(key + '\.js$');
      })
    }));

    if (options.includeTimezone) {
      var timezonePath = [this.project.bowerDirectory, 'moment-timezone', 'builds'];

      switch(options.includeTimezone) {
        case 'all':
          timezonePath.push('moment-timezone-with-data.min.js');
          break;
        case '2010-2020':
          timezonePath.push('moment-timezone-with-data-2010-2020.min.js');
          break;
        case 'none':
          timezonePath.push('moment-timezone.min.js');
          break;
        default:
          throw new Error("Ember Moment: Please specify the moment-timezone dataset to include as either 'all', '2010-2020', or 'none'.");
          break;
      }

      trees.push(rename(new Funnel(path.join(this.project.bowerDirectory, 'moment-timezone', 'builds'), {
        files: [timezonePath[timezonePath.length - 1]]
      }), function(filepath) {
        return path.join('moment-timezone', 'tz.js');
      }));
    }

    return mergeTrees(trees);
  }
};
<commit_msg>working around ember-cli issue<commit_after>'use strict';

var path = require('path');
var Funnel = require('broccoli-funnel');
var mergeTrees = require('broccoli-merge-trees');
var rename = require('broccoli-stew').rename;

module.exports = {
  name: 'moment',

  included: function(app) {
    this._super.included.apply(this, arguments);

    // see: https://github.com/ember-cli/ember-cli/issues/3718
    if (app.app) {
      app = app.app;
    }

    var options = this.projectConfig();
    var vendor = this.treePaths.vendor;
    app.import(path.join(vendor, 'moment', 'min', 'moment.min.js'));

    if (options.moment && options.moment.includeTimezone) {
      app.import(path.join(vendor, 'moment-timezone', 'tz.js'));
    }
  },

  projectConfig: function() {
    return this.project.config(process.env.EMBER_ENV) || {};
  },

  treeForVendor: function(vendorTree) {
    var trees = [];
    var app = this.app;
    var options = this.projectConfig();
    var momentPath = path.dirname(require.resolve('moment'));

    if (vendorTree) {
      trees.push(vendorTree);
    }

    options = options.moment || {};

    trees.push(new Funnel(momentPath, {
      destDir: 'moment',
      include: [new RegExp(/\.js$/)],
      exclude: ['tests', 'ender', 'package'].map(function(key) {
        return new RegExp(key + '\.js$');
      })
    }));

    if (options.includeTimezone) {
      var timezonePath = [this.project.bowerDirectory, 'moment-timezone', 'builds'];

      switch(options.includeTimezone) {
        case 'all':
          timezonePath.push('moment-timezone-with-data.min.js');
          break;
        case '2010-2020':
          timezonePath.push('moment-timezone-with-data-2010-2020.min.js');
          break;
        case 'none':
          timezonePath.push('moment-timezone.min.js');
          break;
        default:
          throw new Error("Ember Moment: Please specify the moment-timezone dataset to include as either 'all', '2010-2020', or 'none'.");
          break;
      }

      trees.push(rename(new Funnel(path.join(this.project.bowerDirectory, 'moment-timezone', 'builds'), {
        files: [timezonePath[timezonePath.length - 1]]
      }), function(filepath) {
        return path.join('moment-timezone', 'tz.js');
      }));
    }

    return mergeTrees(trees);
  }
};
<|endoftext|>


<commit_before>'use strict';

const createAbortError = () => {
	const error = new Error('Delay aborted');
	error.name = 'AbortError';
	return error;
};

const createDelay = willResolve => (ms, {value, signal} = {}) => {
	if (signal && signal.aborted) {
		return Promise.reject(createAbortError());
	}

	let timeoutId;
	let settle;
	let rejectFn;

	const signalListener = () => {
		clearTimeout(timeoutId);
		rejectFn(createAbortError());
	};

	const cleanup = () => {
		if (signal) {
			signal.removeEventListener('abort', signalListener);
		}
	};

	const delayPromise = new Promise((resolve, reject) => {
		settle = () => {
			cleanup();
			if (willResolve) {
				resolve(value);
			} else {
				reject(value);
			}
		};
		rejectFn = reject;
		timeoutId = setTimeout(settle, ms);
	});

	if (signal) {
		signal.addEventListener('abort', signalListener, {once: true});
	}

	delayPromise.clear = () => {
		cleanup();
		if (timeoutId) {
			clearTimeout(timeoutId);
			timeoutId = null;
			settle();
		}
	};

	return delayPromise;
};

const delay = createDelay(true);
delay.reject = createDelay(false);
module.exports = delay;
module.exports.default = delay;
<commit_msg>Remove moot if-statement<commit_after>'use strict';

const createAbortError = () => {
	const error = new Error('Delay aborted');
	error.name = 'AbortError';
	return error;
};

const createDelay = willResolve => (ms, {value, signal} = {}) => {
	if (signal && signal.aborted) {
		return Promise.reject(createAbortError());
	}

	let timeoutId;
	let settle;
	let rejectFn;

	const signalListener = () => {
		clearTimeout(timeoutId);
		rejectFn(createAbortError());
	};

	const cleanup = () => {
		if (signal) {
			signal.removeEventListener('abort', signalListener);
		}
	};

	const delayPromise = new Promise((resolve, reject) => {
		settle = () => {
			cleanup();
			if (willResolve) {
				resolve(value);
			} else {
				reject(value);
			}
		};
		rejectFn = reject;
		timeoutId = setTimeout(settle, ms);
	});

	if (signal) {
		signal.addEventListener('abort', signalListener, {once: true});
	}

	delayPromise.clear = () => {
		clearTimeout(timeoutId);
		timeoutId = null;
		cleanup();
		settle();
	};

	return delayPromise;
};

const delay = createDelay(true);
delay.reject = createDelay(false);
module.exports = delay;
module.exports.default = delay;
<|endoftext|>