<commit_before>var Long = require('bson').Long
  , Logger = require('./connection/logger')
  , MongoError = require('./error')
  , f = require('util').format;

/**
 * This is a cursor results callback
 *
 * @callback resultCallback
 * @param {error} error An error object. Set to null if no error present
 * @param {object} document
 */

/**
 * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
 * allowing for iteration over the results returned from the underlying query.
 *
 * **CURSORS Cannot directly be instantiated**
 * @example
 * var Server = require('mongodb-core').Server
 *   , ReadPreference = require('mongodb-core').ReadPreference
 *   , assert = require('assert');
 *
 * var server = new Server({host: 'localhost', port: 27017});
 * // Wait for the connection event
 * server.on('connect', function(server) {
 *   assert.equal(null, err);
 *
 *   // Execute the write
 *   var cursor = _server.cursor('integration_tests.inserts_example4', {
 *       find: 'integration_tests.example4'
 *     , query: {a:1}
 *   }, {
 *     readPreference: new ReadPreference('secondary');
 *   });
 *
 *   // Get the first document
 *   cursor.next(function(err, doc) {
 *     assert.equal(null, err);
 *     server.destroy();
 *   });
 * });
 *
 * // Start connecting
 * server.connect();
 */

/**
 * Creates a new Cursor, not to be used directly
 * @class
 * @param {object} bson An instance of the BSON parser
 * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
 * @param {{object}|Long} cmd The selector (can be a command or a cursorId)
 * @param {object} connection The connection used for this cursor
 * @param {object} callbacks The callbacks storage object for the server instance
 * @param {object} [options.batchSize=0] Batchsize for the operation
 * @param {array} [options.documents=[]] Initial documents list for cursor
 * @return {Cursor} A cursor instance
 * @property {number} cursorBatchSize The current cursorBatchSize for the cursor
 * @property {number} cursorLimit The current cursorLimit for the cursor
 * @property {number} cursorSkip The current cursorSkip for the cursor
 */
var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
  options = options || {};
  // Initial query
  var query = null;

  // Current limit processed, used to cut the number of returned docs correctly
  var currentLimit = 0;

  // Cursor connection
  var connection = null;
  // Cursor server
  var server = null;

  // Do we have a not connected handler
  var disconnectHandler = options.disconnectHandler;

  // Cursor reference
  var self = this;

  // All internal state
  var cursorState = {
      cursorId: null
    , documents: options.documents || []
    , dead: false
    , killed: false
    , init: false
    , notified: false
    , limit: options.limit || cmd.limit || 0
    , skip: options.skip || cmd.skip || 0
    , batchSize: options.batchSize || cmd.batchSize || 0
  }

  // Callback controller
  var callbacks = null;

  // Logger
  var logger = Logger('Cursor', options);

  //
  // Did we pass in a cursor id
  if(typeof cmd == 'number') {
    cursorState.cursorId = Long.fromNumber(cmd);
  } else if(cmd instanceof Long) {
    cursorState.cursorId = cmd;
  }

  // Allow the manipulation of the batch size of the cursor
  // after creation has happened
  Object.defineProperty(this, 'cursorBatchSize', {
      enumerable:true,
      set: function(value) { cursorState.batchSize = value; }
    , get: function() { return cursorState.batchSize; }
  });

  // Allow the manipulation of the cursor limit
  Object.defineProperty(this, 'cursorLimit', {
      enumerable:true,
      set: function(value) { cursorState.limit = value; }
    , get: function() { return cursorState.limit; }
  });

  // Allow the manipulation of the cursor skip
  Object.defineProperty(this, 'cursorSkip', {
      enumerable:true,
      set: function(value) { cursorState.skip = value; }
    , get: function() { return cursorState.skip; }
  });

  //
  // Handle callback (including any exceptions thrown)
  var handleCallback = function(callback, err, result) {
    try {
      callback(err, result);
    } catch(err) {
      process.nextTick(function() {
        throw err;
      });
    }
  }

  /**
   * Clone the cursor
   * @method
   * @return {Cursor}
   */
  this.clone = function() {
    return topology.cursor(ns, cmd, options);
  }

  /**
   * Retrieve the next document from the cursor
   * @method
   * @param {resultCallback} callback A callback function
   */
  this.next = function(callback) {
    // Cursor is killed return null
    if(cursorState.killed) return handleCallback(callback, null, null);
    // Cursor is dead but not marked killed, return null
    if(cursorState.dead && !cursorState.killed) {
      cursorState.killed = true;
      return handleCallback(callback, null, null);
    }

    // We have a dead and killed cursor, attempting to call next should error
    if(cursorState.dead && cursorState.killed) {
      return handleCallback(callback, new MongoError("cursor is dead"));
    }

    // We have just started the cursor
    if(!cursorState.init) {
      // Topology is not connected, save the call in the provided store to be
      // Executed at some point when the handler deems it's reconnected
      if(!topology.isConnected(options) && disconnectHandler != null) {
        return disconnectHandler.addObjectAndMethod('cursor', self, 'next', [callback], callback);
      }

      try {
        // Get a server
        server = topology.getServer(options);
        // Get a connection
        connection = server.getConnection();
        // Get the callbacks
        callbacks = server.getCallbacks();
      } catch(err) {
        return callback(err);
      }

      // Set as init
      cursorState.init = true;

      // Get the right wire protocol command
      query = server.wireProtocolHandler.command(bson, ns, cmd, cursorState, topology, options);
    }

    // Process exhaust messages
    var processExhaustMessages = function(err, result) {
      if(err) {
        cursorState.dead = true;
        callbacks.unregister(query.requestId);
        return callback(err);
      }

      // Concatenate all the documents
      cursorState.documents = cursorState.documents.concat(result.documents);

      // If we have no documents left
      if(Long.ZERO.equals(result.cursorId)) {
        cursorState.cursorId = Long.ZERO;
        callbacks.unregister(query.requestId);
        return self.next(callback);
      }

      // Set up next listener
      callbacks.register(result.requestId, processExhaustMessages)

      // Initial result
      if(cursorState.cursorId == null) {
        cursorState.cursorId = result.cursorId;
        self.next(callback);
      }
    }

    // If we have exhaust
    if(options.exhaust && cursorState.cursorId == null) {
      // Handle all the exhaust responses
      callbacks.register(query.requestId, processExhaustMessages);
      // Write the initial command out
      return connection.write(query);
    } else if(options.exhaust && cursorState.documents.length > 0) {
      return handleCallback(callback, null, cursorState.documents.shift());
    } else if(options.exhaust && Long.ZERO.equals(cursorState.cursorId)) {
      callbacks.unregister(query.requestId);
      return handleCallback(callback, null, null);
    } else if(options.exhaust) {
      return setTimeout(function() {
        if(Long.ZERO.equals(cursorState.cursorId)) return;
        self.next(callback);
      }, 1);
    }

    // If we don't have a cursorId execute the first query
    if(cursorState.cursorId == null) {
      execInitialQuery(query, function(err, r) {
        if(err) return handleCallback(callback, err, null);
        if(cursorState.documents.length == 0) return handleCallback(callback, null, null);
        self.next(callback);
      });
    } else if(cursorState.documents.length == 0 && !Long.ZERO.equals(cursorState.cursorId)) {
      execGetMore(function(err, doc) {
        if(err) return handleCallback(callback, err);
        if(cursorState.documents.length == 0 && Long.ZERO.equals(cursorState.cursorId)) cursorState.dead = true;
        // Tailable cursor getMore result, notify owner about it
        // No attempt is made here to retry, this is left to the user of the
        // core module to handle to keep core simple
        if(cursorState.documents.length == 0 && options.tailable) {
          return handleCallback(callback, MongoError.create({
              message: "No more documents in tailed cursor"
            , tailable: options.tailable
            , awaitData: options.awaitData
          }));
        }

        if(cursorState.limit > 0 && currentLimit >= cursorState.limit) {
          cursorState.dead = true;
          cursorState.documents = [];
          return handleCallback(callback, null, null);
        }

        self.next(callback);
      });
    } else if(cursorState.documents.length == 0 && options.tailable) {
      return handleCallback(callback, MongoError.create({
          message: "No more documents in tailed cursor"
        , tailable: options.tailable
        , awaitData: options.awaitData
      }));
    } else if(cursorState.documents.length == 0 && Long.ZERO.equals(cursorState.cursorId)) {
      cursorState.dead = true;
      handleCallback(callback, null, null);
    } else {
      if(cursorState.limit > 0 && currentLimit >= cursorState.limit) {
        cursorState.dead = true;
        return handleCallback(callback, null, null);
      }

      currentLimit += 1;
      handleCallback(callback, null, cursorState.documents.shift());
    }
  }

  /**
   * Checks if the cursor is dead
   * @method
   * @return {boolean} A boolean signifying if the cursor is dead or not
   */
  this.isDead = function() {
    return cursorState.dead == true;
  }

  /**
   * Returns current buffered documents length
   * @method
   * @return {number} The number of items in the buffered documents
   */
  this.bufferedCount = function() {
    return cursorState.documents.length;
  }

  /**
   * Returns current buffered documents
   * @method
   * @return {Array} An array of buffered documents
   */
  this.readBufferedDocuments = function(number) {
    var length = number < cursorState.documents.length ? number : cursorState.documents.length;
    var elements = cursorState.documents.splice(0, length);
    currentLimit = currentLimit + length;
    return elements;
  }

  /**
   * Resets the cursor
   * @method
   * @return {null}
   */
  this.rewind = function() {
    if(cursorState.init) {
      if(!cursorState.dead) {
        this.kill();
      }

      currentLimit = 0;
      cursorState.init = false;
      cursorState.dead = false;
      cursorState.killed = false;
      cursorState.documents = [];
      cursorState.cursorId = null;
    }
  }

  /**
   * Kill the cursor
   * @method
   * @param {resultCallback} callback A callback function
   */
  this.kill = function(callback) {
    // Set cursor to dead
    cursorState.dead = true;
    cursorState.killed = true;
    // Remove documents
    cursorState.documents = [];

    // If no cursor id just return
    if(cursorState.cursorId == null || cursorState.cursorId.isZero() || cursorState.init == false) {
      if(callback) callback(null, null);
      return;
    }

    // Execute command
    server.wireProtocolHandler.killCursor(bson, cursorState.cursorId, connection, callback);
  }

  //
  // Execute getMore command
  var execGetMore = function(callback) {
    if(logger.isDebug()) logger.debug(f("schedule getMore call for query [%s]", JSON.stringify(query)))
    // Determine if it's a raw query
    var raw = options.raw || cmd.raw;
    // We have a wire protocol handler
    server.wireProtocolHandler.getMore(bson, ns, cursorState, cursorState.batchSize, raw, connection, callbacks, options, callback);
  }

  //
  // Execute the first query
  var execInitialQuery = function(query, callback) {
    if(logger.isDebug()) {
      logger.debug(f("issue initial query [%s] with flags [%s]"
        , JSON.stringify(cmd)
        , JSON.stringify(query)));
    }

    var queryCallback = function(err, result) {
      if(err) return callback(err);

      // Check if we have a command cursor
      if(Array.isArray(result.documents) && result.documents.length == 1) {
        if(result.documents[0]['$err']
          || result.documents[0]['errmsg']) {
          return callback(new MongoError(result.documents[0]), null);
        }

        if(result.documents[0].cursor != null
          && typeof result.documents[0].cursor != 'string') {
            var id = result.documents[0].cursor.id;
            // Promote id to long if needed
            cursorState.cursorId = typeof id == 'number' ? Long.fromNumber(id) : id;
            // If we have a firstBatch set it
            if(Array.isArray(result.documents[0].cursor.firstBatch)) {
              cursorState.documents = result.documents[0].cursor.firstBatch;
            }

            // Return after processing command cursor
            return callback(null, null);
        }

        if(Array.isArray(result.documents[0].result)) {
          cursorState.documents = result.documents[0].result;
          cursorState.cursorId = Long.ZERO;
          return callback(null, null);
        }
      }

      // Otherwise fall back to regular find path
      cursorState.cursorId = result.cursorId;
      cursorState.documents = result.documents;
      callback(null, null);
    }

    // If we have a raw query decorate the function
    if(options.raw || cmd.raw) {
      queryCallback.raw = options.raw || cmd.raw;
    }

    // Set up callback
    callbacks.register(query.requestId, queryCallback);

    // Write the initial command out
    connection.write(query);
  }
}

module.exports = Cursor;<commit_msg>Set default cursor batchSize to 1000 to avoid issues with node.js deep recursion<commit_after>var Long = require('bson').Long
  , Logger = require('./connection/logger')
  , MongoError = require('./error')
  , f = require('util').format;

/**
 * This is a cursor results callback
 *
 * @callback resultCallback
 * @param {error} error An error object. Set to null if no error present
 * @param {object} document
 */

/**
 * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
 * allowing for iteration over the results returned from the underlying query.
 *
 * **CURSORS Cannot directly be instantiated**
 * @example
 * var Server = require('mongodb-core').Server
 *   , ReadPreference = require('mongodb-core').ReadPreference
 *   , assert = require('assert');
 *
 * var server = new Server({host: 'localhost', port: 27017});
 * // Wait for the connection event
 * server.on('connect', function(server) {
 *   assert.equal(null, err);
 *
 *   // Execute the write
 *   var cursor = _server.cursor('integration_tests.inserts_example4', {
 *       find: 'integration_tests.example4'
 *     , query: {a:1}
 *   }, {
 *     readPreference: new ReadPreference('secondary');
 *   });
 *
 *   // Get the first document
 *   cursor.next(function(err, doc) {
 *     assert.equal(null, err);
 *     server.destroy();
 *   });
 * });
 *
 * // Start connecting
 * server.connect();
 */

/**
 * Creates a new Cursor, not to be used directly
 * @class
 * @param {object} bson An instance of the BSON parser
 * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
 * @param {{object}|Long} cmd The selector (can be a command or a cursorId)
 * @param {object} connection The connection used for this cursor
 * @param {object} callbacks The callbacks storage object for the server instance
 * @param {object} [options.batchSize=1000] Batchsize for the operation
 * @param {array} [options.documents=[]] Initial documents list for cursor
 * @return {Cursor} A cursor instance
 * @property {number} cursorBatchSize The current cursorBatchSize for the cursor
 * @property {number} cursorLimit The current cursorLimit for the cursor
 * @property {number} cursorSkip The current cursorSkip for the cursor
 */
var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
  options = options || {};
  // Initial query
  var query = null;

  // Current limit processed, used to cut the number of returned docs correctly
  var currentLimit = 0;

  // Cursor connection
  var connection = null;
  // Cursor server
  var server = null;

  // Do we have a not connected handler
  var disconnectHandler = options.disconnectHandler;

  // Cursor reference
  var self = this;

  // All internal state
  var cursorState = {
      cursorId: null
    , documents: options.documents || []
    , dead: false
    , killed: false
    , init: false
    , notified: false
    , limit: options.limit || cmd.limit || 0
    , skip: options.skip || cmd.skip || 0
    , batchSize: options.batchSize || cmd.batchSize || 1000
  }

  // Callback controller
  var callbacks = null;

  // Logger
  var logger = Logger('Cursor', options);

  //
  // Did we pass in a cursor id
  if(typeof cmd == 'number') {
    cursorState.cursorId = Long.fromNumber(cmd);
  } else if(cmd instanceof Long) {
    cursorState.cursorId = cmd;
  }

  // Allow the manipulation of the batch size of the cursor
  // after creation has happened
  Object.defineProperty(this, 'cursorBatchSize', {
      enumerable:true,
      set: function(value) { cursorState.batchSize = value; }
    , get: function() { return cursorState.batchSize; }
  });

  // Allow the manipulation of the cursor limit
  Object.defineProperty(this, 'cursorLimit', {
      enumerable:true,
      set: function(value) { cursorState.limit = value; }
    , get: function() { return cursorState.limit; }
  });

  // Allow the manipulation of the cursor skip
  Object.defineProperty(this, 'cursorSkip', {
      enumerable:true,
      set: function(value) { cursorState.skip = value; }
    , get: function() { return cursorState.skip; }
  });

  //
  // Handle callback (including any exceptions thrown)
  var handleCallback = function(callback, err, result) {
    try {
      callback(err, result);
    } catch(err) {
      process.nextTick(function() {
        throw err;
      });
    }
  }

  /**
   * Clone the cursor
   * @method
   * @return {Cursor}
   */
  this.clone = function() {
    return topology.cursor(ns, cmd, options);
  }

  /**
   * Retrieve the next document from the cursor
   * @method
   * @param {resultCallback} callback A callback function
   */
  this.next = function(callback) {
    if(cursorState.notified) return;
    // Cursor is killed return null
    if(cursorState.killed) {
      cursorState.notified = true;
      console.log("--------------------------------- killed")
      return handleCallback(callback, null, null);
    }
    // Cursor is dead but not marked killed, return null
    if(cursorState.dead && !cursorState.killed) {
      cursorState.notified = true;
      console.log("--------------------------------- dead and !killed")
      cursorState.killed = true;
      return handleCallback(callback, null, null);
    }

    // We have a dead and killed cursor, attempting to call next should error
    if(cursorState.dead && cursorState.killed) {
      return handleCallback(callback, new MongoError("cursor is dead"));
    }

    // We have just started the cursor
    if(!cursorState.init) {
      // Topology is not connected, save the call in the provided store to be
      // Executed at some point when the handler deems it's reconnected
      if(!topology.isConnected(options) && disconnectHandler != null) {
        return disconnectHandler.addObjectAndMethod('cursor', self, 'next', [callback], callback);
      }

      try {
        // Get a server
        server = topology.getServer(options);
        // Get a connection
        connection = server.getConnection();
        // Get the callbacks
        callbacks = server.getCallbacks();
      } catch(err) {
        return callback(err);
      }

      // Set as init
      cursorState.init = true;

      // Get the right wire protocol command
      query = server.wireProtocolHandler.command(bson, ns, cmd, cursorState, topology, options);
    }

    // Process exhaust messages
    var processExhaustMessages = function(err, result) {
      if(err) {
        cursorState.dead = true;
        callbacks.unregister(query.requestId);
        return callback(err);
      }

      // Concatenate all the documents
      cursorState.documents = cursorState.documents.concat(result.documents);

      // If we have no documents left
      if(Long.ZERO.equals(result.cursorId)) {
        cursorState.cursorId = Long.ZERO;
        callbacks.unregister(query.requestId);
        return self.next(callback);
      }

      // Set up next listener
      callbacks.register(result.requestId, processExhaustMessages)

      // Initial result
      if(cursorState.cursorId == null) {
        cursorState.cursorId = result.cursorId;
        self.next(callback);
      }
    }

    // If we have exhaust
    if(options.exhaust && cursorState.cursorId == null) {
      // Handle all the exhaust responses
      callbacks.register(query.requestId, processExhaustMessages);
      // Write the initial command out
      return connection.write(query);
    } else if(options.exhaust && cursorState.documents.length > 0) {
      return handleCallback(callback, null, cursorState.documents.shift());
    } else if(options.exhaust && Long.ZERO.equals(cursorState.cursorId)) {
      callbacks.unregister(query.requestId);
      console.log("----------------------------------------- 0")
      cursorState.notified = true;
      return handleCallback(callback, null, null);
    } else if(options.exhaust) {
      return setTimeout(function() {
        if(Long.ZERO.equals(cursorState.cursorId)) return;
        self.next(callback);
      }, 1);
    }

    // If we don't have a cursorId execute the first query
    if(cursorState.cursorId == null) {
      execInitialQuery(query, function(err, r) {
        if(err) return handleCallback(callback, err, null);
      console.log("----------------------------------------- 1")
        if(cursorState.documents.length == 0) {
          cursorState.notified = true;
          return handleCallback(callback, null, null);
        }
        self.next(callback);
      });
    } else if(cursorState.documents.length == 0 && !Long.ZERO.equals(cursorState.cursorId)) {
      execGetMore(function(err, doc) {
        if(err) return handleCallback(callback, err);
        if(cursorState.documents.length == 0 && Long.ZERO.equals(cursorState.cursorId)) cursorState.dead = true;
        // Tailable cursor getMore result, notify owner about it
        // No attempt is made here to retry, this is left to the user of the
        // core module to handle to keep core simple
        if(cursorState.documents.length == 0 && options.tailable) {
          return handleCallback(callback, MongoError.create({
              message: "No more documents in tailed cursor"
            , tailable: options.tailable
            , awaitData: options.awaitData
          }));
        }

        if(cursorState.limit > 0 && currentLimit >= cursorState.limit) {
          cursorState.dead = true;
          cursorState.documents = [];
      console.log("----------------------------------------- 2")
          cursorState.notified = true;
          return handleCallback(callback, null, null);
        }

        self.next(callback);
      });
    } else if(cursorState.documents.length == 0 && options.tailable) {
      return handleCallback(callback, MongoError.create({
          message: "No more documents in tailed cursor"
        , tailable: options.tailable
        , awaitData: options.awaitData
      }));
    } else if(cursorState.documents.length == 0 && Long.ZERO.equals(cursorState.cursorId)) {
      cursorState.dead = true;
      console.log("----------------------------------------- 3")
      cursorState.notified = true;
      handleCallback(callback, null, null);
    } else {
      if(cursorState.limit > 0 && currentLimit >= cursorState.limit) {
        cursorState.dead = true;
        cursorState.notified = true;
      console.log("----------------------------------------- 4")
        return handleCallback(callback, null, null);
      }

      currentLimit += 1;
      handleCallback(callback, null, cursorState.documents.shift());
    }
  }

  /**
   * Checks if the cursor is dead
   * @method
   * @return {boolean} A boolean signifying if the cursor is dead or not
   */
  this.isDead = function() {
    return cursorState.dead == true;
  }

  /**
   * Returns current buffered documents length
   * @method
   * @return {number} The number of items in the buffered documents
   */
  this.bufferedCount = function() {
    return cursorState.documents.length;
  }

  /**
   * Returns current buffered documents
   * @method
   * @return {Array} An array of buffered documents
   */
  this.readBufferedDocuments = function(number) {
    var length = number < cursorState.documents.length ? number : cursorState.documents.length;
    var elements = cursorState.documents.splice(0, length);
    currentLimit = currentLimit + length;
    return elements;
  }

  /**
   * Resets the cursor
   * @method
   * @return {null}
   */
  this.rewind = function() {
    if(cursorState.init) {
      if(!cursorState.dead) {
        this.kill();
      }

      currentLimit = 0;
      cursorState.init = false;
      cursorState.dead = false;
      cursorState.killed = false;
      cursorState.documents = [];
      cursorState.cursorId = null;
    }
  }

  /**
   * Kill the cursor
   * @method
   * @param {resultCallback} callback A callback function
   */
  this.kill = function(callback) {
    // Set cursor to dead
    cursorState.dead = true;
    cursorState.killed = true;
    // Remove documents
    cursorState.documents = [];

    // If no cursor id just return
    if(cursorState.cursorId == null || cursorState.cursorId.isZero() || cursorState.init == false) {
      if(callback) callback(null, null);
      return;
    }

    // Execute command
    server.wireProtocolHandler.killCursor(bson, cursorState.cursorId, connection, callback);
  }

  //
  // Execute getMore command
  var execGetMore = function(callback) {
    if(logger.isDebug()) logger.debug(f("schedule getMore call for query [%s]", JSON.stringify(query)))
    // Determine if it's a raw query
    var raw = options.raw || cmd.raw;
    // We have a wire protocol handler
    server.wireProtocolHandler.getMore(bson, ns, cursorState, cursorState.batchSize, raw, connection, callbacks, options, callback);
  }

  //
  // Execute the first query
  var execInitialQuery = function(query, callback) {
    if(logger.isDebug()) {
      logger.debug(f("issue initial query [%s] with flags [%s]"
        , JSON.stringify(cmd)
        , JSON.stringify(query)));
    }

    var queryCallback = function(err, result) {
      if(err) return callback(err);

      // Check if we have a command cursor
      if(Array.isArray(result.documents) && result.documents.length == 1) {
        if(result.documents[0]['$err']
          || result.documents[0]['errmsg']) {
          return callback(new MongoError(result.documents[0]), null);
        }

        if(result.documents[0].cursor != null
          && typeof result.documents[0].cursor != 'string') {
            var id = result.documents[0].cursor.id;
            // Promote id to long if needed
            cursorState.cursorId = typeof id == 'number' ? Long.fromNumber(id) : id;
            // If we have a firstBatch set it
            if(Array.isArray(result.documents[0].cursor.firstBatch)) {
              cursorState.documents = result.documents[0].cursor.firstBatch;
            }

            // Return after processing command cursor
            return callback(null, null);
        }

        if(Array.isArray(result.documents[0].result)) {
          cursorState.documents = result.documents[0].result;
          cursorState.cursorId = Long.ZERO;
          return callback(null, null);
        }
      }

      // Otherwise fall back to regular find path
      cursorState.cursorId = result.cursorId;
      cursorState.documents = result.documents;
      callback(null, null);
    }

    // If we have a raw query decorate the function
    if(options.raw || cmd.raw) {
      queryCallback.raw = options.raw || cmd.raw;
    }

    // Set up callback
    callbacks.register(query.requestId, queryCallback);

    // Write the initial command out
    connection.write(query);
  }
}

module.exports = Cursor;<|endoftext|>


<commit_before>import koa_router from 'koa-router';
import koa_body from 'koa-body';
import config from 'config';
import models from 'db/models';
import {checkCSRF, getRemoteIp, rateLimitReq} from 'server/utils/misc';
import {hash} from 'golos-js/lib/auth/ecc';
import secureRandom from "secure-random";
import tt from 'counterpart';

function digits(text) {
  const digitArray = text.match(/\d+/g);
  return digitArray ? digitArray.join("") : "";
}

/**
 * return status types:
 * session - new user without identity in DB
 * waiting - user verification phone in progress
 * done - user verification phone is successfuly done
 * already_used -
 * attempts_10 - Confirmation was attempted a moment ago. You can try again only in 10 seconds
 * attempts_300 - Confirmation was attempted a moment ago. You can try again only in 5 minutes
 * @param {*} app
 */
export default function useRegistrationApi(app) {
  const router = koa_router({prefix: '/api/v1'});
  app.use(router.routes());
  const koaBody = koa_body();

  router.post("/verify_code", koaBody, function*() {
    if (! this.request.body) return;

    const accountSid = this.request.body.AccountSid
      ? this.request.body.AccountSid
      : ''
    ;
    if (accountSid.localeCompare(config.get('twilio.account_sid')) != 0) return;

    let phone;
    if (this.request.body.From) {
      phone = this.request.body.From.substr(1)
    }
    else if (this.request.body.phone) {
      phone = this.request.body.phone;
    }
    if (!phone || digits(phone).length === 0) return;

    let confirmation_code;
    if (this.request.body.Body) {
      confirmation_code = this.request.body.Body.substr(0,4);
    }
    else if (this.request.body.mes) {
      confirmation_code = this.request.body.mes.substr(0,4);
    }
    if (!confirmation_code || digits(confirmation_code).length !== 4) return;

    console.log(
      "-- /api/v1/confirm_provider -->",
      phone,
      confirmation_code
    );

    let mid = yield models.Identity.findOne({
      attributes: ["id", "user_id", "verified", "updated_at", "phone"],
      where: {
        phone: hash.sha256(phone, 'hex'),
        confirmation_code,
        provider: "phone"
      },
      order: "id DESC"
    });
    if (!mid) {
      this.status = 401;
      this.body = "Wrong confirmation code";
      return;
    }
    if (mid.verified) {
      this.status = 401;
      this.body = "Phone number has already been verified";
      return;
    }

    const hours_ago = (Date.now() - mid.updated_at) / 1000.0 / 3600.0;
    if (hours_ago > 24.0) {
      this.status = 401;
      this.body = "Confirmation code has been expired";
      return;
    }
    yield mid.update({ verified: true });
    this.body = "GOLOS.io \nСпасибо за подтверждение вашего номера телефона";
  });

  router.post("/check_code", koaBody, function*() {
    if (rateLimitReq(this, this.req)) return;
    const body = this.request.body;
    let params = {};
    if (typeof(body) === 'string') {
      try {
        params = JSON.parse(body)
      } catch (e) {}
    }
    else {
      params = body;
    }
    if (!checkCSRF(this, params.csrf)) return;

    this.body = JSON.stringify({ status: "session" });

    let user_id = this.session.user;
    if (!user_id) {
      return;
    }

    let mid = yield models.Identity.findOne({
      attributes: ["id", "phone", "verified", "updated_at", "confirmation_code"],
      where: { user_id, provider: "phone" },
      order: "id DESC"
    });
    if (mid) {
      if (mid.verified) {
        this.body = JSON.stringify({ status: "done" });
        return;
      }
      this.body = JSON.stringify({ status: "waiting", code: mid.confirmation_code });
      const seconds_ago = (Date.now() - mid.updated_at) / 1000.0;
      const timeAgo = 10;
      if (seconds_ago < timeAgo) {
        this.body = JSON.stringify({ status: "attempts_10" });
        return;
      }
    }
  });

  router.post("/send_code", koaBody, function*() {
    if (rateLimitReq(this, this.req)) return;
    const body = this.request.body;
    let params = {};
    if (typeof(body) === 'string') {
      try {
        params = JSON.parse(body)
      } catch (e) {}
    }
    else {
      params = body;
    }
    if (!checkCSRF(this, params.csrf)) return;

    const country = params.country ? params.country : null;
    const localPhone = params.phone ? params.phone : null;
    const retry = params.retry ? params.retry : null;
    console.log(params);

    if (!country || country === "") {
      this.body = JSON.stringify({ status: "select_country" });
      return;
    }

    if (!localPhone || digits(localPhone).length === 0) {
      this.body = JSON.stringify({ status: "provide_phone" });
      return;
    }

    const phone = digits(parseInt(country) + localPhone);
    const phoneHash = hash.sha256(phone, 'hex')
    const existing_phone = yield models.Identity.findOne({
      attributes: ["user_id"],
      where: { phone: phoneHash, provider: "phone", verified: true },
      order: "id DESC"
    });

    let user_id = this.session.user;
    if (existing_phone && existing_phone.user_id != user_id) {
      console.log(
        "-- /send_code existing_phone -->",
        user_id,
        this.session.uid,
        phoneHash,
        existing_phone.user_id
      );
      this.body = JSON.stringify({ status: "already_used" });
      return;
    }

    let confirmation_code = parseInt(secureRandom.randomBuffer(8).toString("hex"),16).toString(10).substring(0, 4); // 4 digit code
    let mid = yield models.Identity.findOne({
      attributes: ["id", "phone", "verified", "updated_at", "confirmation_code"],
      where: { user_id, provider: "phone" },
      order: "id DESC"
    });
    if (mid) {
      if (mid.verified) {
        if (mid.phone === phoneHash) {
          this.body = JSON.stringify({ status: "done" });
          return;
        }
        yield mid.update({ verified: false, phone: phoneHash });
      }
      const seconds_ago = (Date.now() - mid.updated_at) / 1000.0;
      const timeAgo = process.env.NODE_ENV === "production" ? 300 : 10;
      if (retry) {
        confirmation_code = mid.confirmation_code
      }
      else {
        if (seconds_ago < timeAgo) {
          this.body = JSON.stringify({ status: "attempts_300" });
          return;
        }
        yield mid.update({ confirmation_code, phone: phoneHash });
      }
    }
    else {
      let user;
      if (user_id) {
        user = yield models.User.findOne({
          attributes: ["id"],
          where: { id: user_id }
        });
      }
      if (!user) {
        user = yield models.User.create({
          uid: this.session.uid,
          remote_ip: getRemoteIp(this.request.req)
        });
        this.session.user = user_id = user.id;
      }
      mid = yield models.Identity.create({
        provider: "phone",
        user_id,
        uid: this.session.uid,
        phone: phoneHash,
        verified: false,
        confirmation_code
      });
    }
    this.body = JSON.stringify({ status: "waiting", code: confirmation_code });
  });
}
<commit_msg>#562 Add usefull errors<commit_after>import koa_router from 'koa-router';
import koa_body from 'koa-body';
import config from 'config';
import models from 'db/models';
import {checkCSRF, getRemoteIp, rateLimitReq} from 'server/utils/misc';
import {hash} from 'golos-js/lib/auth/ecc';
import secureRandom from "secure-random";
import tt from 'counterpart';

function digits(text) {
  const digitArray = text.match(/\d+/g);
  return digitArray ? digitArray.join("") : "";
}

/**
 * return status types:
 * session - new user without identity in DB
 * waiting - user verification phone in progress
 * done - user verification phone is successfuly done
 * already_used -
 * attempts_10 - Confirmation was attempted a moment ago. You can try again only in 10 seconds
 * attempts_300 - Confirmation was attempted a moment ago. You can try again only in 5 minutes
 * @param {*} app
 */
export default function useRegistrationApi(app) {
  const router = koa_router({prefix: '/api/v1'});
  app.use(router.routes());
  const koaBody = koa_body();

  router.post("/verify_code", koaBody, function*() {
    if (! this.request.body) {
      this.status = 400;
      this.body = "Bad Request";
      return;
    }

    const accountSid = this.request.body.AccountSid
      ? this.request.body.AccountSid
      : ''
    ;
    if (accountSid.localeCompare(config.get('twilio.account_sid')) != 0) {
      this.status = 401;
      this.body = "Unauthorized";
      return;
    }

    let phone;
    if (this.request.body.From) {
      phone = this.request.body.From.substr(1)
    }
    else if (this.request.body.phone) {
      phone = this.request.body.phone;
    }
    if (!phone || digits(phone).length === 0) {
      this.status = 401;
      this.body = "Bad Request Data from";
      return;
    }

    let confirmation_code;
    if (this.request.body.Body) {
      confirmation_code = this.request.body.Body.substr(0,4);
    }
    else if (this.request.body.mes) {
      confirmation_code = this.request.body.mes.substr(0,4);
    }
    if (!confirmation_code || digits(confirmation_code).length !== 4) {
      this.status = 400;
      this.body = "Bad Request Data body";
      return;
    }

    console.log(
      "-- /api/v1/confirm_provider -->",
      phone,
      confirmation_code
    );

    let mid = yield models.Identity.findOne({
      attributes: ["id", "user_id", "verified", "updated_at", "phone"],
      where: {
        phone: hash.sha256(phone, 'hex'),
        confirmation_code,
        provider: "phone"
      },
      order: "id DESC"
    });
    if (!mid) {
      this.status = 401;
      this.body = "Wrong confirmation code";
      return;
    }
    if (mid.verified) {
      this.status = 401;
      this.body = "Phone number has already been verified";
      return;
    }

    const hours_ago = (Date.now() - mid.updated_at) / 1000.0 / 3600.0;
    if (hours_ago > 24.0) {
      this.status = 401;
      this.body = "Confirmation code has been expired";
      return;
    }
    yield mid.update({ verified: true });
    this.body = "GOLOS.io \nСпасибо за подтверждение вашего номера телефона";
  });

  router.post("/check_code", koaBody, function*() {
    if (rateLimitReq(this, this.req)) return;
    const body = this.request.body;
    let params = {};
    if (typeof(body) === 'string') {
      try {
        params = JSON.parse(body)
      } catch (e) {}
    }
    else {
      params = body;
    }
    if (!checkCSRF(this, params.csrf)) return;

    this.body = JSON.stringify({ status: "session" });

    let user_id = this.session.user;
    if (!user_id) {
      return;
    }

    let mid = yield models.Identity.findOne({
      attributes: ["id", "phone", "verified", "updated_at", "confirmation_code"],
      where: { user_id, provider: "phone" },
      order: "id DESC"
    });
    if (mid) {
      if (mid.verified) {
        this.body = JSON.stringify({ status: "done" });
        return;
      }
      this.body = JSON.stringify({ status: "waiting", code: mid.confirmation_code });
      const seconds_ago = (Date.now() - mid.updated_at) / 1000.0;
      const timeAgo = 10;
      if (seconds_ago < timeAgo) {
        this.body = JSON.stringify({ status: "attempts_10" });
        return;
      }
    }
  });

  router.post("/send_code", koaBody, function*() {
    if (rateLimitReq(this, this.req)) return;
    const body = this.request.body;
    let params = {};
    if (typeof(body) === 'string') {
      try {
        params = JSON.parse(body)
      } catch (e) {}
    }
    else {
      params = body;
    }
    if (!checkCSRF(this, params.csrf)) return;

    const country = params.country ? params.country : null;
    const localPhone = params.phone ? params.phone : null;
    const retry = params.retry ? params.retry : null;
    console.log(params);

    if (!country || country === "") {
      this.body = JSON.stringify({ status: "select_country" });
      return;
    }

    if (!localPhone || digits(localPhone).length === 0) {
      this.body = JSON.stringify({ status: "provide_phone" });
      return;
    }

    const phone = digits(parseInt(country) + localPhone);
    const phoneHash = hash.sha256(phone, 'hex')
    const existing_phone = yield models.Identity.findOne({
      attributes: ["user_id"],
      where: { phone: phoneHash, provider: "phone", verified: true },
      order: "id DESC"
    });

    let user_id = this.session.user;
    if (existing_phone && existing_phone.user_id != user_id) {
      console.log(
        "-- /send_code existing_phone -->",
        user_id,
        this.session.uid,
        phoneHash,
        existing_phone.user_id
      );
      this.body = JSON.stringify({ status: "already_used" });
      return;
    }

    let confirmation_code = parseInt(secureRandom.randomBuffer(8).toString("hex"),16).toString(10).substring(0, 4); // 4 digit code
    let mid = yield models.Identity.findOne({
      attributes: ["id", "phone", "verified", "updated_at", "confirmation_code"],
      where: { user_id, provider: "phone" },
      order: "id DESC"
    });
    if (mid) {
      if (mid.verified) {
        if (mid.phone === phoneHash) {
          this.body = JSON.stringify({ status: "done" });
          return;
        }
        yield mid.update({ verified: false, phone: phoneHash });
      }
      const seconds_ago = (Date.now() - mid.updated_at) / 1000.0;
      const timeAgo = process.env.NODE_ENV === "production" ? 300 : 10;
      if (retry) {
        confirmation_code = mid.confirmation_code
      }
      else {
        if (seconds_ago < timeAgo) {
          this.body = JSON.stringify({ status: "attempts_300" });
          return;
        }
        yield mid.update({ confirmation_code, phone: phoneHash });
      }
    }
    else {
      let user;
      if (user_id) {
        user = yield models.User.findOne({
          attributes: ["id"],
          where: { id: user_id }
        });
      }
      if (!user) {
        user = yield models.User.create({
          uid: this.session.uid,
          remote_ip: getRemoteIp(this.request.req)
        });
        this.session.user = user_id = user.id;
      }
      mid = yield models.Identity.create({
        provider: "phone",
        user_id,
        uid: this.session.uid,
        phone: phoneHash,
        verified: false,
        confirmation_code
      });
    }
    this.body = JSON.stringify({ status: "waiting", code: confirmation_code });
  });
}
<|endoftext|>


<commit_before>import readline from 'readline';

export default function daemon() {
  const rlInterface = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false,
  });

  rlInterface.on('line', (str: string) => {
    console.log('You just typed: ' + str);
  });
}
<commit_msg>Make daemon use Importer<commit_after>import readline from 'readline';

import Importer from './Importer';

export default function daemon() {
  const rlInterface = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false,
  });

  rlInterface.on('line', (jsonCommand: string) => {
    const command = JSON.parse(jsonCommand);
    const importer = new Importer(
      command.fileContent.split('\n'), command.pathToFile);

    // TODO: don't automatically invoke function here because of security issues
    importer[command.command](...command.args).then((result) => {
      process.stdout.write(`${JSON.stringify(result)}\n`);
    }).catch((error) => {
      // TODO: print entire stack trace here
      process.stderr.write(error.toString());
    });
  });
}
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn,
    http = require('http'),
    urlmod = require('url'),
    fs = require('fs');
var vidProc,
    player,
    files = [],
    currFile = 0,
    playing = false;
var localAddress = '',
    peerAddress = '',
    port = 3000,
    req,
    res;

// INIT ////////////////////////////////////

var logLevel = 2;

// standardized exit function
var exitFunction = function (code) {
    console.log('exiting');
    if (code) console.log('exited with code '+code);
    // show cursor
    console.log('\033[?12l\033[?25h');
    process.exit();
}

var warn = function (msg) {
    if (logLevel > 0) console.log(msg);
}
var echo = function (msg) {
    if (logLevel > 1) console.log(msg);
}

// HTTP SERVER /////////////////////////////

// find local ip address
var findLocalAddress = function () {
  var ip_re = /(?!127)\d{1,3}\.(?!0)\d{1,3}\.(?!0)\d{1,3}\.\d{1,3}/;
    require('child_process').exec('ifconfig eth0 | grep \'inet addr:\' | cut -d: -f2 | awk \'{ print $1}\'', function (error, stdout, stderr) {
        if (stdout.search(ip_re) !== -1) {
            localAddress = stdout.trim();
            echo('local ip address: '+localAddress);
            startServer();
        } else {
          require('child_process').exec('ifconfig wlan0 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
              if (stdout.search(ip_re) !== -1) {
                  localAddress = stdout.trim();
                  echo('local ip address: '+localAddress);
                  startServer();
              } else {
                require('child_process').exec('ifconfig en0 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
                    if (stdout.search(ip_re) !== -1) {
                        localAddress = stdout.trim();
                        echo('local ip address: '+localAddress);
                        startServer();
                    } else {
                      require('child_process').exec('ifconfig en1 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
                          if (stdout.search(ip_re) !== -1) {
                              localAddress = stdout.trim();
                              echo('local ip address: '+localAddress);
                              startServer();
                          } else {
                            require('child_process').exec('ip addr show | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\' | cut -d/ -f1', function (error, stdout, stderr) {
                                if (stdout.search(ip_re) !== -1) {
                                    localAddress = stdout.trim();
                                    echo('local ip address: '+localAddress);
                                    startServer();
                                } else {
                                    echo('couldn\'t find local ip address, play in offline mode');
                                    echo('.-.');
                                    playNextVideo();
                                }
                            });
                          }
                      });
                    }
                });
              }
          });
        }
    });
}

// start local http server
var startServer = function () {
    http.createServer(function (req_, res_) {
        req = req_;
        res = res_;
        if (req.method === 'GET') {
            req.on('close', function() { echo('connection remotely closed'); });
            req.on('data', function(data) { /* void */ });
            req.on('end', function() { parseRequest(); });
        } else {
            echo('error: no accepted HTTP method');
            respond('no');
        }
    }).listen(port, localAddress);
    echo('local server running at http://'+localAddress+':'+port);
    echo(',-´');
    // call peer for status
    callPeer('playing');
}

// parse incoming http requests
var parseRequest = function () {
    var url = urlmod.parse(req.url);
    if (url.href) {
        var cmd = url.href.slice(1);
        echo('peer call: '+cmd);
        if (cmd === 'playing') respond(isPlaying());
        else if (cmd === 'ended') playNextVideo();
        else respond('bad command');
    } else {
        echo('bad request: '+url);
        respond('bad request');
    }
}

// respond to peer http requests
var respond = function (data) {
    echo('response to peer: '+ data);
    var headers = {
        'Content-Length': Buffer.byteLength(data),
        'Content-Type': 'text/plain; charset=utf-8',
        'Expires': (new Date(Date.now)).toUTCString()
    }
    res.writeHead(200, headers);
    res.end(data);
}

// PEER QUERIES //////////////////////////

// call peer
var callPeer = function (msg) {
    echo('call peer: '+ msg);
    var url = 'http://'+peerAddress+':'+port+'/'+msg;
    http.get(url, function(res_) {
        res_.on('data', function (data) { parsePeerResponse(data) });
    }).on('error', function(e) {
        if (e.code === 'ECONNREFUSED') {
            echo('peer isn\'t ready, wait for a call')
            echo('|');
        }
    });
}

// parse peer's response to call
var parsePeerResponse = function (data) {
    echo('peer response: '+ data);
    if (data == 'no') {
        // peer is not playing, play local file
        echo('peer isn\'t playing, play');
        playNextVideo();
    } else {
        echo('peer is playing, wait for a call');
        echo('|');
        // wait for peer message, so, do nothing
    }
}

// VIDEO ///////////////////////////////////

// establish video playing status
var isPlaying = function () {
    if (playing) return 'yes';
    else return 'no';
}

// play video files
var playNextVideo = function () {
    // next file to play
    var filename = files[currFile];
    // if the next file doesn't exist, reset filename
    if (!filename) {
        currFile = 0;
        filename = files[0];
        warn('filename reset to: '+filename);
    }
    // play only if the file really exists
    if (!filename) {
        warn('filename is not valid: '+filename);
        exitFunction();
    } else {
      if (fs.existsSync(filename)) {
        currFile++;
        playing = true;
        echo('play video: '+filename);
        echo('..');
        // vidProc = (player === 'omxplayer') ? spawn('omxplayer', ['-o', 'local', filename]) : spawn('mplayer', ['-vm', filename]);
        switch (player) {
          case 'omxplayer':
            vidProc =  spawn(player, ['-o', 'local', filename], { stdio: 'silent' });
            break;
          case 'mplayer':
            vidProc = spawn(player, ['-vm', '-fs', filename], { stdio: 'silent' });
            break;
          case 'vlc':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'silent' });
            break;
          case '/Applications/VLC.app/Contents/MacOS/VLC':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'silent' });
            break;
          case '~/Applications/VLC.app/Contents/MacOS/VLC':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'silent' });
            break;
          default:
            vidProc = '';
        }
        vidProc.stdout.on('data', function (data) { echo(data.toString()); });
        vidProc.stderr.on('data', function (data) { echo(data.toString()); });
        vidProc.on('exit', function (code) {
            echo(player+' exited with code '+code);
            playing = false;
            callPeer('ended');
            echo('|');
        });
      } else {
        warn(filename+' doesn´t exist');
        exitFunction();
      }
    }
}

// PROCESS /////////////////////////////////

// parse process' incoming arguments
var parseArgv = function () {
    var conf;
    files = [];

    // parse arguments
    if (process.argv.length < 3) {
        // no arguments case
        conf = 'v-sync.conf';
        echo('no input arguments, will play from: '+conf);
    } else {
        process.argv.forEach(function (val, idx, arr) {
            if (val.search(/^\.*[^\.]+\.conf$/) !== -1) {
                // configuration file case
                conf = val;
                // readConf();
            } else if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                // video filename case
                files.push(val);
            } else if (val.search(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) !== -1) {
                // peer address case
                peerAddress = val;
            }
        });
        if (conf) echo('input conf file(s): '+conf);
        if (files.length) echo('input video file(s): '+JSON.stringify(files));
        if (peerAddress) echo('input peer ip: '+peerAddress);
    }

    // if a configuration file was given
    if (conf) {
        var data;
        try {
          data = fs.readFileSync(conf, {encoding:'utf-8'});
        } catch (e) {
          warn('couldn´t load '+ conf);
          exitFunction();
          return;
        }

        if (data.length) {
            data.split('\n').forEach(function (val, idx, arr) {
                if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                    // video filename case
                    files.push(val);
                    echo('will play: '+val);
                } else if (val.search(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) !== -1) {
                    // peer address case
                    peerAddress = val;
                    echo('will connect to: '+val);
                }
            });
        }
        if (files.length) echo('conf video file(s): '+JSON.stringify(files));
        if (peerAddress) echo('conf peer ip: '+peerAddress);
    }

    // if video files were given
    if (files.length) {
        // clear terminal, move cursor to top left and hide it
        // echo('\033[2J\033\033[H\033[?25l');

        // if a peer address was given
        if (peerAddress.length) {
            findLocalAddress();
        } else {
            echo('-.-');
            playNextVideo();
        }
    } else {
      exitFunction();
      return;
    }

    // failsafe
    if (!conf && !files.length) {
        exitFunction();
    }
}

// check whether other v-sync process is running on the system
var checkForDuplicates = function () {
    require('child_process').exec('ps aux | grep '+player+' | grep -v grep', function (error, stdout, stderr) {
        if (stdout.length) {
            warn('another video player is already running on this machine');
            warn(stdout);
            exitFunction();
        } else {
            echo('no other video player is running, v-sync will start');
            parseArgv();
        }
    });
}

// handle ctrl-C gracefully
process.on('SIGINT', function () {
    console.log(' ');
    exitFunction();
});

// START ///////////////////////////////////

// check which player is available on the system
require('child_process').exec('which omxplayer', function (error, stdout, stderr) {
    if (stdout[0] !== '/') {
        require('child_process').exec('which mplayer', function (error, stdout, stderr) {
            if (stdout[0] !== '/') {
              require('child_process').exec('which vlc', function (error, stdout, stderr) {
                  if (stdout[0] !== '/') {
                    require('child_process').exec('which /Applications/VLC.app/Contents/MacOS/VLC', function (error, stdout, stderr) {
                        if (stdout[0] !== '/') {
                          require('child_process').exec('which ~/Applications/VLC.app/Contents/MacOS/VLC', function (error, stdout, stderr) {
                              if (stdout[0] !== '/') {
                                  warn('no video player available');
                                  exitFunction();
                              } else {
                                  player = '~/Applications/VLC.app/Contents/MacOS/VLC';
                                  echo('available video player: '+player);
                                  checkForDuplicates();
                              }
                          });
                        } else {
                            player = '/Applications/VLC.app/Contents/MacOS/VLC';
                            echo('available video player: '+player);
                            checkForDuplicates();
                        }
                    });
                  } else {
                      player = 'vlc';
                      echo('available video player: '+player);
                      checkForDuplicates();
                  }
              });
            } else {
                player = 'mplayer';
                echo('available video player: '+player);
                checkForDuplicates();
            }
        });
    } else {
        player = 'omxplayer';
        echo('available video player: '+player);
        checkForDuplicates();
    }
});
<commit_msg>corrected stdio syntax<commit_after>var spawn = require('child_process').spawn,
    http = require('http'),
    urlmod = require('url'),
    fs = require('fs');
var vidProc,
    player,
    files = [],
    currFile = 0,
    playing = false;
var localAddress = '',
    peerAddress = '',
    port = 3000,
    req,
    res;

// INIT ////////////////////////////////////

var logLevel = 2;

// standardized exit function
var exitFunction = function (code) {
    console.log('exiting');
    if (code) console.log('exited with code '+code);
    // show cursor
    console.log('\033[?12l\033[?25h');
    process.exit();
}

var warn = function (msg) {
    if (logLevel > 0) console.log(msg);
}
var echo = function (msg) {
    if (logLevel > 1) console.log(msg);
}

// HTTP SERVER /////////////////////////////

// find local ip address
var findLocalAddress = function () {
  var ip_re = /(?!127)\d{1,3}\.(?!0)\d{1,3}\.(?!0)\d{1,3}\.\d{1,3}/;
    require('child_process').exec('ifconfig eth0 | grep \'inet addr:\' | cut -d: -f2 | awk \'{ print $1}\'', function (error, stdout, stderr) {
        if (stdout.search(ip_re) !== -1) {
            localAddress = stdout.trim();
            echo('local ip address: '+localAddress);
            startServer();
        } else {
          require('child_process').exec('ifconfig wlan0 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
              if (stdout.search(ip_re) !== -1) {
                  localAddress = stdout.trim();
                  echo('local ip address: '+localAddress);
                  startServer();
              } else {
                require('child_process').exec('ifconfig en0 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
                    if (stdout.search(ip_re) !== -1) {
                        localAddress = stdout.trim();
                        echo('local ip address: '+localAddress);
                        startServer();
                    } else {
                      require('child_process').exec('ifconfig en1 | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\'', function (error, stdout, stderr) {
                          if (stdout.search(ip_re) !== -1) {
                              localAddress = stdout.trim();
                              echo('local ip address: '+localAddress);
                              startServer();
                          } else {
                            require('child_process').exec('ip addr show | grep \'inet\' | cut -d: -f2 | awk \'{ print $2}\' | cut -d/ -f1', function (error, stdout, stderr) {
                                if (stdout.search(ip_re) !== -1) {
                                    localAddress = stdout.trim();
                                    echo('local ip address: '+localAddress);
                                    startServer();
                                } else {
                                    echo('couldn\'t find local ip address, play in offline mode');
                                    echo('.-.');
                                    playNextVideo();
                                }
                            });
                          }
                      });
                    }
                });
              }
          });
        }
    });
}

// start local http server
var startServer = function () {
    http.createServer(function (req_, res_) {
        req = req_;
        res = res_;
        if (req.method === 'GET') {
            req.on('close', function() { echo('connection remotely closed'); });
            req.on('data', function(data) { /* void */ });
            req.on('end', function() { parseRequest(); });
        } else {
            echo('error: no accepted HTTP method');
            respond('no');
        }
    }).listen(port, localAddress);
    echo('local server running at http://'+localAddress+':'+port);
    echo(',-´');
    // call peer for status
    callPeer('playing');
}

// parse incoming http requests
var parseRequest = function () {
    var url = urlmod.parse(req.url);
    if (url.href) {
        var cmd = url.href.slice(1);
        echo('peer call: '+cmd);
        if (cmd === 'playing') respond(isPlaying());
        else if (cmd === 'ended') playNextVideo();
        else respond('bad command');
    } else {
        echo('bad request: '+url);
        respond('bad request');
    }
}

// respond to peer http requests
var respond = function (data) {
    echo('response to peer: '+ data);
    var headers = {
        'Content-Length': Buffer.byteLength(data),
        'Content-Type': 'text/plain; charset=utf-8',
        'Expires': (new Date(Date.now)).toUTCString()
    }
    res.writeHead(200, headers);
    res.end(data);
}

// PEER QUERIES //////////////////////////

// call peer
var callPeer = function (msg) {
    echo('call peer: '+ msg);
    var url = 'http://'+peerAddress+':'+port+'/'+msg;
    http.get(url, function(res_) {
        res_.on('data', function (data) { parsePeerResponse(data) });
    }).on('error', function(e) {
        if (e.code === 'ECONNREFUSED') {
            echo('peer isn\'t ready, wait for a call')
            echo('|');
        }
    });
}

// parse peer's response to call
var parsePeerResponse = function (data) {
    echo('peer response: '+ data);
    if (data == 'no') {
        // peer is not playing, play local file
        echo('peer isn\'t playing, play');
        playNextVideo();
    } else {
        echo('peer is playing, wait for a call');
        echo('|');
        // wait for peer message, so, do nothing
    }
}

// VIDEO ///////////////////////////////////

// establish video playing status
var isPlaying = function () {
    if (playing) return 'yes';
    else return 'no';
}

// play video files
var playNextVideo = function () {
    // next file to play
    var filename = files[currFile];
    // if the next file doesn't exist, reset filename
    if (!filename) {
        currFile = 0;
        filename = files[0];
        warn('filename reset to: '+filename);
    }
    // play only if the file really exists
    if (!filename) {
        warn('filename is not valid: '+filename);
        exitFunction();
    } else {
      if (fs.existsSync(filename)) {
        currFile++;
        playing = true;
        echo('play video: '+filename);
        echo('..');
        // vidProc = (player === 'omxplayer') ? spawn('omxplayer', ['-o', 'local', filename]) : spawn('mplayer', ['-vm', filename]);
        switch (player) {
          case 'omxplayer':
            vidProc =  spawn(player, ['-o', 'local', filename], { stdio: 'ignore' });
            break;
          case 'mplayer':
            vidProc = spawn(player, ['-vm', '-fs', filename], { stdio: 'ignore' });
            break;
          case 'vlc':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'ignore' });
            break;
          case '/Applications/VLC.app/Contents/MacOS/VLC':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'ignore' });
            break;
          case '~/Applications/VLC.app/Contents/MacOS/VLC':
            vidProc = spawn(player, ['-f', '--play-and-exit', filename], { stdio: 'ignore' });
            break;
          default:
            vidProc = '';
        }
        vidProc.stdout.on('data', function (data) { echo(data.toString()); });
        vidProc.stderr.on('data', function (data) { echo(data.toString()); });
        vidProc.on('exit', function (code) {
            echo(player+' exited with code '+code);
            playing = false;
            callPeer('ended');
            echo('|');
        });
      } else {
        warn(filename+' doesn´t exist');
        exitFunction();
      }
    }
}

// PROCESS /////////////////////////////////

// parse process' incoming arguments
var parseArgv = function () {
    var conf;
    files = [];

    // parse arguments
    if (process.argv.length < 3) {
        // no arguments case
        conf = 'v-sync.conf';
        echo('no input arguments, will play from: '+conf);
    } else {
        process.argv.forEach(function (val, idx, arr) {
            if (val.search(/^\.*[^\.]+\.conf$/) !== -1) {
                // configuration file case
                conf = val;
                // readConf();
            } else if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                // video filename case
                files.push(val);
            } else if (val.search(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) !== -1) {
                // peer address case
                peerAddress = val;
            }
        });
        if (conf) echo('input conf file(s): '+conf);
        if (files.length) echo('input video file(s): '+JSON.stringify(files));
        if (peerAddress) echo('input peer ip: '+peerAddress);
    }

    // if a configuration file was given
    if (conf) {
        var data;
        try {
          data = fs.readFileSync(conf, {encoding:'utf-8'});
        } catch (e) {
          warn('couldn´t load '+ conf);
          exitFunction();
          return;
        }

        if (data.length) {
            data.split('\n').forEach(function (val, idx, arr) {
                if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                    // video filename case
                    files.push(val);
                    echo('will play: '+val);
                } else if (val.search(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) !== -1) {
                    // peer address case
                    peerAddress = val;
                    echo('will connect to: '+val);
                }
            });
        }
        if (files.length) echo('conf video file(s): '+JSON.stringify(files));
        if (peerAddress) echo('conf peer ip: '+peerAddress);
    }

    // if video files were given
    if (files.length) {
        // clear terminal, move cursor to top left and hide it
        // echo('\033[2J\033\033[H\033[?25l');

        // if a peer address was given
        if (peerAddress.length) {
            findLocalAddress();
        } else {
            echo('-.-');
            playNextVideo();
        }
    } else {
      exitFunction();
      return;
    }

    // failsafe
    if (!conf && !files.length) {
        exitFunction();
    }
}

// check whether other v-sync process is running on the system
var checkForDuplicates = function () {
    require('child_process').exec('ps aux | grep '+player+' | grep -v grep', function (error, stdout, stderr) {
        if (stdout.length) {
            warn('another video player is already running on this machine');
            warn(stdout);
            exitFunction();
        } else {
            echo('no other video player is running, v-sync will start');
            parseArgv();
        }
    });
}

// handle ctrl-C gracefully
process.on('SIGINT', function () {
    console.log(' ');
    exitFunction();
});

// START ///////////////////////////////////

// check which player is available on the system
require('child_process').exec('which omxplayer', function (error, stdout, stderr) {
    if (stdout[0] !== '/') {
        require('child_process').exec('which mplayer', function (error, stdout, stderr) {
            if (stdout[0] !== '/') {
              require('child_process').exec('which vlc', function (error, stdout, stderr) {
                  if (stdout[0] !== '/') {
                    require('child_process').exec('which /Applications/VLC.app/Contents/MacOS/VLC', function (error, stdout, stderr) {
                        if (stdout[0] !== '/') {
                          require('child_process').exec('which ~/Applications/VLC.app/Contents/MacOS/VLC', function (error, stdout, stderr) {
                              if (stdout[0] !== '/') {
                                  warn('no video player available');
                                  exitFunction();
                              } else {
                                  player = '~/Applications/VLC.app/Contents/MacOS/VLC';
                                  echo('available video player: '+player);
                                  checkForDuplicates();
                              }
                          });
                        } else {
                            player = '/Applications/VLC.app/Contents/MacOS/VLC';
                            echo('available video player: '+player);
                            checkForDuplicates();
                        }
                    });
                  } else {
                      player = 'vlc';
                      echo('available video player: '+player);
                      checkForDuplicates();
                  }
              });
            } else {
                player = 'mplayer';
                echo('available video player: '+player);
                checkForDuplicates();
            }
        });
    } else {
        player = 'omxplayer';
        echo('available video player: '+player);
        checkForDuplicates();
    }
});
<|endoftext|>


<commit_before>var _ = require('lodash');
var Q = require('q');
var path = require('path');
var config = root_require('config');
var build = require('./build');
var logger = require('./logger');
var Dropbox = require('./dropbox');
var ErrorReporter = require('./error_reporter');
var Bucket = require('./bucket');
var store = new (require('./store'))(config.key_bucket);

function deploy(id) {

  if(!id) {
    logger.error('No user passed.');
    return Q.reject('No user passed.');
  }

  var staging_dir = path.join(config.source, id.toString());
  var build_dir = path.join(config.destination, id.toString());

  var user = config.users[id];

  if(!user) {
    logger.error('Unknown User: ' + id + '.');
    return Q.reject('Unknown User: ' + id + '.');
  }

  var bucket = new Bucket(build_dir, user.bucket);

  return store.get(id).then(function(result) {
    logger.info(id, 'Credentials Found.');
    return new Dropbox(result, staging_dir).sync();
  }).then(function() {
    logger.info(id, 'Fetch Succeeded.');
    return build(config.root, staging_dir, build_dir, user.middleware(staging_dir));
  }).then(function() {
    logger.info(id, 'Build Succeeded.');
    return bucket.push();
  }).then(function() {
    logger.info(id, 'Deploy Succeeded.')
    return bucket.del('_error/index.html');
  }, function(reason) {
    return new ErrorReporter(bucket).set(reason.stack).catch(function(r) {
      logger.error('Problem pushing error: %s', r.stack);
    }).fin(function() {
      logger.error('Deploy failed: %s', reason.stack);
    });
  });
}

module.exports = function(ids) {
  if(_.isArray(ids)) {
    return Q.all(_.map(ids, function(id) {
      return deploy(id);
    }));
  }
  else {
    return deploy(ids);
  }
}
<commit_msg>Log bucket name rather than dropbox id.<commit_after>var _ = require('lodash');
var Q = require('q');
var path = require('path');
var config = root_require('config');
var build = require('./build');
var logger = require('./logger');
var Dropbox = require('./dropbox');
var ErrorReporter = require('./error_reporter');
var Bucket = require('./bucket');
var store = new (require('./store'))(config.key_bucket);

function deploy(id) {

  if(!id) {
    logger.error('No user passed.');
    return Q.reject('No user passed.');
  }

  var staging_dir = path.join(config.source, id.toString());
  var build_dir = path.join(config.destination, id.toString());

  var user = config.users[id];

  if(!user) {
    logger.error('Unknown User: ' + id + '.');
    return Q.reject('Unknown User: ' + id + '.');
  }

  var bucket_name = user.bucket;
  var bucket = new Bucket(build_dir, bucket_name);

  return store.get(id).then(function(result) {
    logger.info(bucket_name, 'Credentials Found.');
    return new Dropbox(result, staging_dir).sync();
  }).then(function() {
    logger.info(bucket_name, 'Fetch Succeeded.');
    return build(config.root, staging_dir, build_dir, user.middleware(staging_dir));
  }).then(function() {
    logger.info(bucket_name, 'Build Succeeded.');
    return bucket.push();
  }).then(function() {
    logger.info(bucket_name, 'Deploy Succeeded.')
    return bucket.del('_error/index.html');
  }, function(reason) {
    return new ErrorReporter(bucket).set(reason.stack).catch(function(r) {
      logger.error(bucket_name, 'Problem pushing error: %s', r.stack);
    }).fin(function() {
      logger.error(bucket_name, 'Deploy failed: %s', reason.stack);
    });
  });
}

module.exports = function(ids) {
  if(_.isArray(ids)) {
    return Q.all(_.map(ids, function(id) {
      return deploy(id);
    }));
  }
  else {
    return deploy(ids);
  }
}
<|endoftext|>


<commit_before>var express = require('express'),
    HTTPSServer = express.HTTPSServer,
    HTTPServer = express.HTTPServer;

exports.version = '0.0.1';
exports.namespace = 'express';

exports.capture = function () {
    return function (req, res, next) {
        req.device = req.device || {};

        // todo: parse user-agent to get desktop | phone | tablet
        req.device.type = 'tablet';

        if(next) return next();
    };
};

HTTPServer.prototype.enableDeviceHelpers =
HTTPSServer.prototype.enableDeviceHelpers = function() {
    var app = this.app || this;
    var check_request = function(req) {
        if (typeof req.device === 'undefined')
            throw new Error('Must enable the device capture by using app.use(device.capture())');

        return true;
    };

    var helpers = {
        is_desktop: function(req, res) {
            check_request(req);
            return req.device.type === 'desktop';
        },
        is_mobile: function(req, res) {
            check_request(req);
            return req.device.type === 'phone' || req.device.type === 'tablet';
        },
        is_phone: function(req, res) {
            check_request(req);
            return req.device.type === 'phone';
        },
        is_tablet: function(req, res) {
            check_request(req);
            return req.device.type === 'tablet';
        },
        device_type: function(req, res) {
            check_request(req);
            return req.device.type;
        }
    };
    app.dynamicHelpers(helpers);
};<commit_msg>get device type tv|desktop|tablet|phone<commit_after>/* Based on Categorizr (https://github.com/bjankord/Categorizr) by Brett Jankord (http://www.brettjankord.com) */
var express = require('express'),
    HTTPSServer = express.HTTPSServer,
    HTTPServer = express.HTTPServer;

exports.version = '0.0.1';
exports.namespace = 'express';

function DeviceParser(req) {
    var self = this;

    self.user_agent = function() {
        return req.headers['user-agent'];
    };

    self.get_type = function() {
        var ua = self.user_agent();
        // Check if user agent is a smart TV - http://goo.gl/FocDk
        if (ua.match(/GoogleTV|SmartTV|Internet.TV|NetCast|NETTV|AppleTV|boxee|Kylo|Roku|DLNADOC|CE\-HTML/i)) {
        	return 'tv';
    	}
    	// Check if user agent is a TV Based Gaming Console
    	else if (ua.match(/Xbox|PLAYSTATION.3|Wii/i)) {
    		return 'tv';
    	}
    	// Check if user agent is a Tablet
    	else if(ua.match(/iP(a|ro)d/i) || ua.match(/tablet/i) && !ua.match(/RX-34/i) || ua.match(/FOLIO/i)) {
    		return 'tablet';
    	}
    	// Check if user agent is an Android Tablet
    	else if (ua.match(/Linux/i) && ua.match(/Android/i) && !ua.match(/Fennec|mobi|HTC.Magic|HTCX06HT|Nexus.One|SC-02B|fone.945/i)) {
    		return 'tablet';
    	}
    	// Check if user agent is a Kindle or Kindle Fire
    	else if (ua.match(/Kindle/i) || ua.match(/Mac.OS/i) && ua.match(/Silk/i)) {
    		return 'tablet';
    	}
    	// Check if user agent is a pre Android 3.0 Tablet
    	else if (ua.match(/GT-P10|SC-01C|SHW-M180S|SGH-T849|SCH-I800|SHW-M180L|SPH-P100|SGH-I987|zt180|HTC(.Flyer|\_Flyer)|Sprint.ATP51|ViewPad7|pandigital(sprnova|nova)|Ideos.S7|Dell.Streak.7|Advent.Vega|A101IT|A70BHT|MID7015|Next2|nook/i) || ua.match(/MB511/i) && ua.match(/RUTEM/i)) {
    		return 'tablet';
    	}
    	// Check if user agent is unique phone User Agent
    	else if (ua.match(/BOLT|Fennec|Iris|Maemo|Minimo|Mobi|mowser|NetFront|Novarra|Prism|RX-34|Skyfire|Tear|XV6875|XV6975|Google.Wireless.Transcoder/i)) {
    		return 'phone';
    	}
    	// Check if user agent is an odd Opera User Agent - http://goo.gl/nK90K
    	else if (ua.match(/Opera/i) && ua.match(/Windows.NT.5/i) && ua.match(/HTC|Xda|Mini|Vario|SAMSUNG\-GT\-i8000|SAMSUNG\-SGH\-i9/i)) {
    		return 'phone';
    	}
    	// Check if user agent is Windows Desktop
    	else if (ua.match(/Windows.(NT|XP|ME|9)/) && !ua.match(/Phone/i) || ua.match(/Win(9|.9|NT)/i)) {
    		return 'desktop';
    	}
    	// Check if agent is Mac Desktop
    	else if (ua.match(/Macintosh|PowerPC/i) && !ua.match(/Silk/i)) {
    		return 'desktop';
    	}
    	// Check if user agent is a Linux Desktop
    	else if (ua.match(/Linux/i) && ua.match(/X11/i)) {
    		return 'desktop';
    	}
    	// Check if user agent is a Solaris, SunOS, BSD Desktop
    	else if (ua.match(/Solaris|SunOS|BSD/i)) {
    		return 'desktop';
    	}
    	// Check if user agent is a Desktop BOT/Crawler/Spider
    	else if (ua.match(/Bot|Crawler|Spider|Yahoo|ia_archiver|Covario-IDS|findlinks|DataparkSearch|larbin|Mediapartners-Google|NG-Search|Snappy|Teoma|Jeeves|TinEye/i) && !ua.match(/phone/i)) {
    		return 'desktop';
    	}
    	// Otherwise assume it is a phone Device
    	else { return 'phone'; }
    };
};

exports.capture = function () {
    return function (req, res, next) {
        var parser = new DeviceParser(req);
        req.device = req.device || {};

        req.device.type = parser.get_type();

        if(next) return next();
    };
};

HTTPServer.prototype.enableDeviceHelpers =
HTTPSServer.prototype.enableDeviceHelpers = function() {
    var app = this.app || this;
    var check_request = function(req) {
        if (typeof req.device === 'undefined')
            throw new Error('Must enable the device capture by using app.use(device.capture())');

        return true;
    };

    var helpers = {
        is_desktop: function(req, res) {
            check_request(req);
            return req.device.type === 'desktop';
        },
        is_phone: function(req, res) {
            check_request(req);
            return req.device.type === 'phone' || req.device.type === 'tablet';
        },
        is_phone: function(req, res) {
            check_request(req);
            return req.device.type === 'phone';
        },
        is_tablet: function(req, res) {
            check_request(req);
            return req.device.type === 'tablet';
        },
        device_type: function(req, res) {
            check_request(req);
            return req.device.type;
        }
    };
    app.dynamicHelpers(helpers);
};

<|endoftext|>


<commit_before>// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

var crypto = require('crypto');
var fs = require('fs');
var _ = require('lodash');

function _summarize(method, hashes) {
  var keys = Object.keys(hashes);
  keys.sort();

  var obj = {};
  obj.files = hashes;
  var hash = crypto.createHash(method);
  for (var i = 0; i < keys.length; i++) {
    if (typeof(hashes[keys[i]]) === 'string') {
      hash.update(hashes[keys[i]]);
    } else if (typeof(hashes[keys[i]]) === 'object') {
      hash.update(hashes[keys[i]].hash);
    } else {
      console.error('Unknown type found in hash: ' + typeof(hashes[keys[i]]));
    }
  }

  obj.hash = hash.digest('hex');
  return obj;
}

function digest(root, method, ignore, callback) {
  if (!root || typeof(root) !== 'string') {
    throw new TypeError('root is required (string)');
  }
  if (method) {
    if (typeof(method) === 'string') {
      // NO-OP
    } else if (typeof(method) === 'function') {
      callback = method;
      method = 'md5';
    } else {
      throw new TypeError('hash must be a string');
    }
  } else {
    throw new TypeError('callback is required (function)');
  }
  if (!callback) {
    throw new TypeError('callback is required (function)');
  }

  var hashes = {};

  fs.readdir(root, function(err, files) {
    if (err) return callback(err);

    files = _.difference(files, ignore);

    if (files.length === 0) {
      return callback(undefined, {hash: 'd41d8cd98f00b204e9800998ecf8427e', files: {}});
    }

    var hashed = 0;

    files.forEach(function(f) {

        var path = root + '/' + f;
        fs.stat(path, function(err, stats) {
          if (err) return callback(err);

          if (stats.isDirectory()) {
            return digest(path, method, function(err, hash) {
              if (err) return hash;

              hashes[f] = hash;
              if (++hashed >= files.length) {
                return callback(undefined, _summarize(method, hashes));
              }
            });
          } else if (stats.isFile()) {
            fs.readFile(path, 'utf8', function(err, data) {
              if (err) return callback(err);

              var hash = crypto.createHash(method);
              hash.update(data);
              hashes[f] = hash.digest('hex');

              if (++hashed >= files.length) {
                return callback(undefined, _summarize(method, hashes));
              }
            });
          } else {
            console.error('Skipping hash of %s', f);
            if (++hashed > files.length) {
              return callback(undefined, _summarize(method, hashes));
            }
          }
        });
    });
  });
}

module.exports = {
  digest: digest
};
<commit_msg>bug ignore<commit_after>// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

var crypto = require('crypto');
var fs = require('fs');
var _ = require('lodash');

function _summarize(method, hashes) {
  var keys = Object.keys(hashes);
  keys.sort();

  var obj = {};
  obj.files = hashes;
  var hash = crypto.createHash(method);
  for (var i = 0; i < keys.length; i++) {
    if (typeof(hashes[keys[i]]) === 'string') {
      hash.update(hashes[keys[i]]);
    } else if (typeof(hashes[keys[i]]) === 'object') {
      hash.update(hashes[keys[i]].hash);
    } else {
      console.error('Unknown type found in hash: ' + typeof(hashes[keys[i]]));
    }
  }

  obj.hash = hash.digest('hex');
  return obj;
}

function digest(root, method, ignore, callback) {
  if (!root || typeof(root) !== 'string') {
    throw new TypeError('root is required (string)');
  }
  if (method) {
    if (typeof(method) === 'string') {
      // NO-OP
    } else if (typeof(method) === 'function') {
      callback = method;
      method = 'md5';
    } else {
      throw new TypeError('hash must be a string');
    }
  } else {
    throw new TypeError('callback is required (function)');
  }
  if (!callback) {
    throw new TypeError('callback is required (function)');
  }

  var hashes = {};

  fs.readdir(root, function(err, files) {
    if (err) return callback(err);

    files = _.difference(files, ignore);

    if (files.length === 0) {
      return callback(undefined, {hash: 'd41d8cd98f00b204e9800998ecf8427e', files: {}});
    }

    var hashed = 0;

    files.forEach(function(f) {

        var path = root + '/' + f;
        fs.stat(path, function(err, stats) {
          if (err) return callback(err);

          if (stats.isDirectory()) {
            return digest(path, method, ignore, function(err, hash) {
              if (err) return hash;

              hashes[f] = hash;
              if (++hashed >= files.length) {
                return callback(undefined, _summarize(method, hashes));
              }
            });
          } else if (stats.isFile()) {
            fs.readFile(path, 'utf8', function(err, data) {
              if (err) return callback(err);

              var hash = crypto.createHash(method);
              hash.update(data);
              hashes[f] = hash.digest('hex');

              if (++hashed >= files.length) {
                return callback(undefined, _summarize(method, hashes));
              }
            });
          } else {
            console.error('Skipping hash of %s', f);
            if (++hashed > files.length) {
              return callback(undefined, _summarize(method, hashes));
            }
          }
        });
    });
  });
}

module.exports = {
  digest: digest
};
<|endoftext|>


<commit_before>// Vector implementation
//

function Vector (list) { // :: [Int] -> Vector
    this.elems = list
}

Vector.prototype.add = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var v = other.elems, ret = []
        for (var elem in v) {
            ret.push(v[elem] + this.elems[elem])
        }
        return ret
    }).bind(this)())
}

Vector.prototype.subtract = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var v = other.elems, ret = []
        for (var elem in v) {
            ret.push(this.elems[elem] - v[elem])
        }
        return ret
    }).bind(this)())
}

Vector.prototype.multiply = function (s) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        for (var v in this.elems) {
            this.elems[v] = this.elems[v] * s
        }
        return this.elems
    }).bind(this)()
}

Vector.prototype.equals = function (other) { // :: Vector -> Bool
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return false
    for (var v in other.elems) {
        if (other.elems[v] !== this.elems[v]) return false
    }
    return true
}

Vector.prototype.divide = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var ret = []
        for (var v in this.elems) {
            ret.push(this.elems[v] / other.elems[v])
        }
        return ret
    }).bind(this)
}

Vector.prototype.dot = function (other) { // :: Vector -> Int
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    var ret = 0
    for (var v in this.elems) {
        ret += this.elems[v] * other.elems[v]
    }
    return ret
}

Vector.prototype.cross = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var stuff = []
        for (var v in this.elems) {
            stuff.push(this.elems[v] * other.elems[v])
        }
        return stuff
    }
}

Vector.prototype.max = function () { // :: -> Int
    return Math.max(this.elems)
}

Vector.prototype.min = function () { // :: -> Int
    return Math.min(this.elems)
}

Vector.prototype.modulus = function () { // :: -> Int
    var ret = 0;
    for (var v in this.elems) {
        ret += Math.pow(this.elems[v], 2)
    }
    return ret / 2;
}

Vector.prototype.copy = function () { // :: -> Vector
    return new Vector(this.elems)
}
<commit_msg>Modulo next.<commit_after>// Vector implementation

function Vector (list) { // :: [Int] -> Vector
    this.elems = list
}

Vector.prototype.add = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var v = other.elems, ret = []
        for (var elem in v) {
            ret.push(v[elem] + this.elems[elem])
        }
        return ret
    }).bind(this)())
}

Vector.prototype.subtract = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var v = other.elems, ret = []
        for (var elem in v) {
            ret.push(this.elems[elem] - v[elem])
        }
        return ret
    }).bind(this)())
}

Vector.prototype.multiply = function (s) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        for (var v in this.elems) {
            this.elems[v] = this.elems[v] * s
        }
        return this.elems
    }).bind(this)()
}

Vector.prototype.equals = function (other) { // :: Vector -> Bool
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return false
    for (var v in other.elems) {
        if (other.elems[v] !== this.elems[v]) return false
    }
    return true
}

Vector.prototype.divide = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var ret = []
        for (var v in this.elems) {
            ret.push(this.elems[v] / other.elems[v])
        }
        return ret
    }).bind(this)
}

Vector.prototype.dot = function (other) { // :: Vector -> Int
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    var ret = 0
    for (var v in this.elems) {
        ret += this.elems[v] * other.elems[v]
    }
    return ret
}

Vector.prototype.cross = function (other) { // :: Vector -> Vector
    if (!(other instanceof Vector)) return null
    if (this.elems.length !== other.elems.length) return null
    return new Vector((function () {
        var stuff = []
        for (var v in this.elems) {
            stuff.push(this.elems[v] * other.elems[v])
        }
        return stuff
    }
}

Vector.prototype.max = function () { // :: -> Int
    return Math.max(this.elems)
}

Vector.prototype.min = function () { // :: -> Int
    return Math.min(this.elems)
}

Vector.prototype.modulus = function () { // :: -> Int
    var ret = 0;
    for (var v in this.elems) {
        ret += Math.pow(this.elems[v], 2)
    }
    return ret / 2;
}
Vector.prototype.modulo = function (s) { // :: -> Int
}

Vector.prototype.copy = function () { // :: -> Vector
    return new Vector(this.elems)
}
<|endoftext|>