<commit_before>// if node
var Stream = require('stream').Stream;
var EventEmitter = require('events').EventEmitter;
var BufferReadStream = require('streamers').BufferReadStream;
var WebSocket = require('ws');

var util = require('./util');
var BinaryStream = require('./stream').BinaryStream;

// end node

function BinaryClient(socket, options) {
  if (!(this instanceof BinaryClient)) return new BinaryClient(socket, options);

  EventEmitter.call(this);

  var self = this;

  this._options = util.extend({
    chunkSize: 40960
  }, options);

  this.streams = {};

  if(typeof socket === 'string') {
    this._nextId = 0;
    this._socket = new WebSocket(socket, this._options.ws || {});
  } else {
    // Use odd numbered ids for server originated streams
    this._nextId = 1;
    this._socket = socket;
  }

  //this._socket.binaryType = 'arraybuffer';

  this._socket.addEventListener('open', function(){
    self.emit('open');
  });
  this._socket.addEventListener('ping', function(data, flags){
    self.emit('ping', data, flags);
  });
  this._socket.addEventListener('pong', function(data, flags){
    self.emit('pong', data, flags);
  });
  // if node
  this._socket.on('drain', function(){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onDrain();
    }
  });
  // end node
  this._socket.addEventListener('error', function(error){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onError(error);
    }
    self.emit('error', error);
  });
  this._socket.addEventListener('close', function(code, message){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onClose();
    }
    self.emit('close', code, message);
  });
  this._socket.addEventListener('message', function(data, flags){
    //self.lastActive = Date.now();
    //util.setZeroTimeout(function(){

      // Message format
      // [type, payload, bonus ]
      //
      // Reserved
      // [ 0  , X , X ]
      //
      //
      // New stream
      // [ 1  , Meta , new streamId ]
      //
      //
      // Data
      // [ 2  , Data , streamId ]
      //
      //
      // Pause
      // [ 3  , null , streamId ]
      //
      //
      // Resume
      // [ 4  , null , streamId ]
      //
      //
      // End
      // [ 5  , null , streamId ]
      //
      //
      // Close
      // [ 6  , null , streamId ]
      //
      // 7
      // [ 7  , Notification , streamId ]
      //
      // 8
      // [ 8  , Message ]
      //

      data = data.data;

      try {
          data = util.unpack(data);
      } catch (ex) {
          return self.emit('error', new Error('Received unparsable message: ' + ex));
      }
      if (!(data instanceof Array))
          return self.emit('error', new Error('Received non-array message'));
      if (data.length != 3)
          return self.emit('error', new Error('Received message with wrong part count: ' + data.length));
      if ('number' != typeof data[0])
          return self.emit('error', new Error('Received message with non-number type: ' + data[0]));

      switch(data[0]) {
        case 0:
          // Reserved
          break;
        case 1:
          var meta = data[1];
          var streamId = data[2];
          var binaryStream = self._receiveStream(streamId);
          self.emit('stream', binaryStream, meta);
          break;
        case 2:
          var payload = data[1];
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onData(payload);
          } else {
            self.emit('warn', new Error('Received `data` message for unknown stream: ' + streamId));
          }
          break;
        case 3:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onPause();
          } else {
            self.emit('warn', new Error('Received `pause` message for unknown stream: ' + streamId));
          }
          break;
        case 4:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onResume();
          } else {
            self.emit('warn', new Error('Received `resume` message for unknown stream: ' + streamId));
          }
          break;
        case 5:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onEnd();
          } else {
            self.emit('warn', new Error('Received `end` message for unknown stream: ' + streamId));
          }
          break;
        case 6:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onClose();
          } else {
            self.emit('warn', new Error('Received `close` message for unknown stream: ' + streamId));
          }
          break;
        case 7:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            var event = data[1];
            binaryStream._onNotification(event);
          } else {
            self.emit('warn', new Error('Received `notification` message for unknown stream: ' + streamId));
          }
          break;
        case 8:
          var message = data[1];
          self.emit('message', message);
          break;
        default:
          self.emit('warn', new Error('Unrecognized message type received: ' + data[0]));
      }
    //});
  });
}

util.inherits(BinaryClient, EventEmitter);

BinaryClient.prototype.ping = function(data){
  return this._socket.ping(data, {}, true);
}

BinaryClient.prototype.pong = function(data){
  return this._socket.pong(data, {}, true);
}

BinaryClient.prototype.sendMessage = function(message){
  var data = util.pack([8, message, 0]);
  return this._socket.send(data, {binary: true});
}

BinaryClient.prototype.send = function(data, meta){
  var stream = this.createStream(meta);
  if(data instanceof Stream) {
    data.pipe(stream);
  } else if (util.isNode === true) {
    if(Buffer.isBuffer(data)) {
      (new BufferReadStream(data, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else {
      stream.write(data);
    }
  } else if (util.isNode !== true) {
    if(data.constructor == Blob || data.constructor == File) {
      (new BlobReadStream(data, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else if (data.constructor == ArrayBuffer) {
      var blob;
      if(binaryFeatures.useArrayBufferView) {
        data = new Uint8Array(data);
      }
      if(binaryFeatures.useBlobBuilder) {
        var builder = new BlobBuilder();
        builder.append(data);
        blob = builder.getBlob()
      } else {
        blob = new Blob([data]);
      }
      (new BlobReadStream(blob, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else if (typeof data === 'object' && 'BYTES_PER_ELEMENT' in data) {
      var blob;
      if(!binaryFeatures.useArrayBufferView) {
        // Warn
        data = data.buffer;
      }
      if(binaryFeatures.useBlobBuilder) {
        var builder = new BlobBuilder();
        builder.append(data);
        blob = builder.getBlob()
      } else {
        blob = new Blob([data]);
      }
      (new BlobReadStream(blob, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else {
      stream.write(data);
    }
  }
  return stream;
};

BinaryClient.prototype._receiveStream = function(streamId){
  var self = this;
  var binaryStream = new BinaryStream(this._socket, streamId, false);
  binaryStream.on('close', function(){
    delete self.streams[streamId];
  });
  this.streams[streamId] = binaryStream;
  return binaryStream;
};

BinaryClient.prototype.createStream = function(meta){
  if(this._socket.readyState !== WebSocket.OPEN) {
    throw new Error('Client is not yet connected or has closed');
    return;
  }
  var self = this;
  var streamId = this._nextId;
  this._nextId += 2;
  var binaryStream = new BinaryStream(this._socket, streamId, true, meta);
  binaryStream.on('close', function(){
    delete self.streams[streamId];
  });
  this.streams[streamId] = binaryStream;
  return binaryStream;
};

BinaryClient.prototype.close = BinaryClient.prototype.destroy = function() {
  this._socket.close();
};

exports.BinaryClient = BinaryClient;
<commit_msg>support create stream with data<commit_after>// if node
var Stream = require('stream').Stream;
var EventEmitter = require('events').EventEmitter;
var BufferReadStream = require('streamers').BufferReadStream;
var WebSocket = require('ws');

var util = require('./util');
var BinaryStream = require('./stream').BinaryStream;

// end node

function BinaryClient(socket, options) {
  if (!(this instanceof BinaryClient)) return new BinaryClient(socket, options);

  EventEmitter.call(this);

  var self = this;

  this._options = util.extend({
    chunkSize: 40960
  }, options);

  this.streams = {};

  if(typeof socket === 'string') {
    this._nextId = 0;
    this._socket = new WebSocket(socket, this._options.ws || {});
  } else {
    // Use odd numbered ids for server originated streams
    this._nextId = 1;
    this._socket = socket;
  }

  //this._socket.binaryType = 'arraybuffer';

  this._socket.addEventListener('open', function(){
    self.emit('open');
  });
  this._socket.addEventListener('ping', function(data, flags){
    self.emit('ping', data, flags);
  });
  this._socket.addEventListener('pong', function(data, flags){
    self.emit('pong', data, flags);
  });
  // if node
  this._socket.on('drain', function(){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onDrain();
    }
  });
  // end node
  this._socket.addEventListener('error', function(error){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onError(error);
    }
    self.emit('error', error);
  });
  this._socket.addEventListener('close', function(code, message){
    var ids = Object.keys(self.streams);
    for (var i = 0, ii = ids.length; i < ii; i++) {
      self.streams[ids[i]]._onClose();
    }
    self.emit('close', code, message);
  });
  this._socket.addEventListener('message', function(data, flags){
    //self.lastActive = Date.now();
    //util.setZeroTimeout(function(){

      // Message format
      // [type, payload, bonus ]
      //
      // Reserved
      // [ 0  , X , X ]
      //
      //
      // New stream
      // [ 1  , Meta , new streamId ]
      //
      //
      // Data
      // [ 2  , Data , streamId ]
      //
      //
      // Pause
      // [ 3  , null , streamId ]
      //
      //
      // Resume
      // [ 4  , null , streamId ]
      //
      //
      // End
      // [ 5  , null , streamId ]
      //
      //
      // Close
      // [ 6  , null , streamId ]
      //
      // 7
      // [ 7  , Notification , streamId ]
      //
      // 8
      // [ 8  , Message ]
      //

      data = data.data;

      try {
          data = util.unpack(data);
      } catch (ex) {
          return self.emit('error', new Error('Received unparsable message: ' + ex));
      }
      if (!(data instanceof Array))
          return self.emit('error', new Error('Received non-array message'));
      if (data.length != 3)
          return self.emit('error', new Error('Received message with wrong part count: ' + data.length));
      if ('number' != typeof data[0])
          return self.emit('error', new Error('Received message with non-number type: ' + data[0]));

      switch(data[0]) {
        case 0:
          // Reserved
          break;
        case 1:
          var meta = data[1];
          var streamId = data[2];
          var binaryStream = self._receiveStream(streamId);
          self.emit('stream', binaryStream, meta);
          if(meta.head) {
            binaryStream._onData(meta.head);
          }
          break;
        case 2:
          var payload = data[1];
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onData(payload);
          } else {
            self.emit('warn', new Error('Received `data` message for unknown stream: ' + streamId));
          }
          break;
        case 3:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onPause();
          } else {
            self.emit('warn', new Error('Received `pause` message for unknown stream: ' + streamId));
          }
          break;
        case 4:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onResume();
          } else {
            self.emit('warn', new Error('Received `resume` message for unknown stream: ' + streamId));
          }
          break;
        case 5:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onEnd();
          } else {
            self.emit('warn', new Error('Received `end` message for unknown stream: ' + streamId));
          }
          break;
        case 6:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            binaryStream._onClose();
          } else {
            self.emit('warn', new Error('Received `close` message for unknown stream: ' + streamId));
          }
          break;
        case 7:
          var streamId = data[2];
          var binaryStream = self.streams[streamId];
          if(binaryStream) {
            var event = data[1];
            binaryStream._onNotification(event);
          } else {
            self.emit('warn', new Error('Received `notification` message for unknown stream: ' + streamId));
          }
          break;
        case 8:
          var message = data[1];
          self.emit('message', message);
          break;
        default:
          self.emit('warn', new Error('Unrecognized message type received: ' + data[0]));
      }
    //});
  });
}

util.inherits(BinaryClient, EventEmitter);

BinaryClient.prototype.ping = function(data){
  return this._socket.ping(data, {}, true);
}

BinaryClient.prototype.pong = function(data){
  return this._socket.pong(data, {}, true);
}

BinaryClient.prototype.sendMessage = function(message){
  var data = util.pack([8, message, 0]);
  return this._socket.send(data, {binary: true});
}

BinaryClient.prototype.send = function(data, meta){
  var stream = this.createStream(meta);
  if(data instanceof Stream) {
    data.pipe(stream);
  } else if (util.isNode === true) {
    if(Buffer.isBuffer(data)) {
      (new BufferReadStream(data, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else {
      stream.write(data);
    }
  } else if (util.isNode !== true) {
    if(data.constructor == Blob || data.constructor == File) {
      (new BlobReadStream(data, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else if (data.constructor == ArrayBuffer) {
      var blob;
      if(binaryFeatures.useArrayBufferView) {
        data = new Uint8Array(data);
      }
      if(binaryFeatures.useBlobBuilder) {
        var builder = new BlobBuilder();
        builder.append(data);
        blob = builder.getBlob()
      } else {
        blob = new Blob([data]);
      }
      (new BlobReadStream(blob, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else if (typeof data === 'object' && 'BYTES_PER_ELEMENT' in data) {
      var blob;
      if(!binaryFeatures.useArrayBufferView) {
        // Warn
        data = data.buffer;
      }
      if(binaryFeatures.useBlobBuilder) {
        var builder = new BlobBuilder();
        builder.append(data);
        blob = builder.getBlob()
      } else {
        blob = new Blob([data]);
      }
      (new BlobReadStream(blob, {chunkSize: this._options.chunkSize})).pipe(stream);
    } else {
      stream.write(data);
    }
  }
  return stream;
};

BinaryClient.prototype._receiveStream = function(streamId){
  var self = this;
  var binaryStream = new BinaryStream(this._socket, streamId, false);
  binaryStream.on('close', function(){
    delete self.streams[streamId];
  });
  this.streams[streamId] = binaryStream;
  return binaryStream;
};

BinaryClient.prototype.createStream = function(meta){
  if(this._socket.readyState !== WebSocket.OPEN) {
    throw new Error('Client is not yet connected or has closed');
    return;
  }
  var self = this;
  var streamId = this._nextId;
  this._nextId += 2;
  var binaryStream = new BinaryStream(this._socket, streamId, true, meta);
  binaryStream.on('close', function(){
    delete self.streams[streamId];
  });
  this.streams[streamId] = binaryStream;
  return binaryStream;
};

BinaryClient.prototype.close = BinaryClient.prototype.destroy = function() {
  this._socket.close();
};

exports.BinaryClient = BinaryClient;
<|endoftext|>


<commit_before>var modulus = require('../modulus'),
    librarian = require('../common/api').librarian,
    userConfig = require('../common/api').userConfig,
    fs = require('fs'),
    path = require('path'),
    ProgressBar = require('progress'),
    Progress = require('../util/progress'),
    Errors = require('../util/errors'),
    request = require('request'),
    http = require('http'),
    uploader = require('chunk-loader').Client,
    https = require('https');

http.globalAgent.maxSockets = Number.MAX_VALUE;
https.globalAgent.maxSockets = Number.MAX_VALUE;

//-----------------------------------------------------------------------------
var Project = function() {

};

//-----------------------------------------------------------------------------
Project.prototype.create = function(name, creatorId, callback) {
  librarian.project.create({
    name: name,
    creator: creatorId
  }, false, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.restart = function(projectId, callback) {
  librarian.project.restart(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Restarting [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.stop = function(projectId, callback) {
  librarian.project.stop(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Stopping [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.stopped) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.start = function(projectId, callback) {
  librarian.project.start(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Starting [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.find = function(opts, callback) {
  librarian.project.find(opts, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.saveVars = function(projectId, vars, callback) {
  librarian.project.saveVars(projectId, vars, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.deploy = function(projectId, file, callback) {
  var host = librarian._http._host;
  var port = librarian._http._port;
  var protocol = librarian._http._ssl ? 'https' : 'http';

  modulus.io.print('Uploading project...');
  var status = Project.status.uploading;

  // start checking for status changes
  // show progress for upload and inderminate progress for deploying
  var ubar = new ProgressBar('Upload progress [:bar] :percent', {
    complete: '=',
    incomplete: ' ',
    width: 20,
    total: 100
  });
  ubar.tick();

  var client = uploader.uploadFile(file,
    {
      beginProtocol: 'http',
      uploadProtocol: 'http',
      beginPort: '443',
      uploadPort: '80',
      host: host,
      port: port,
      debug: false,
      encrypted: true,
      tag: { projectId: projectId, authToken: userConfig.data.apiKey }
    }
  );

  client.on('progress', function(p) {
    ubar.tick(((p.sent / p.total) * 100) - ubar.curr);
  });

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

  client.on('complete', function() {
    //var dbar = new Progress.indeterminate('Deploying [:bar]');

    // check every second for project status change
    var projectStatus = function () {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {
        if(!err) {
          if(proj && proj.status) {
            if(proj.status.toLowerCase() !== status) {
              var newStatus = proj.status.toLowerCase();
              if(newStatus === Project.status.deploying) {
                status = newStatus;
                modulus.io.print('\nDeploying Project...');
                //dbar.start();
              } else if(newStatus === Project.status.running && status !== Project.status.uploading) {
                //dbar.stop();
                modulus.io.print(' ');
                return callback(null, proj.domain);
              }
            }
          }
        }

        if(status !== Project.status.running) {
          setTimeout(projectStatus, 1000);
        }
      });
    };
    projectStatus();

    var logLength = 0;
    var deployLogs = function() {
      if(status === Project.status.deploying) {
        librarian.project.getDeployLogs(projectId, userConfig.data.apiKey, function(err, result) {
          for(var key in result) {
            var log = result[key];
            modulus.io.write(log.substring(logLength));
            logLength = log.length;
            break;
          }
        });
      }

      if(status !== Project.status.running) {
        setTimeout(deployLogs, 1000);
      }
    };
    deployLogs();
  });
};

/**
 * Gets the logs for the specified project id.
 * @param {string} projectId The ID of the project.
 * @param {function} callback Function invoked with log results.
 */
//-----------------------------------------------------------------------------
Project.prototype.getLogs = function(projectId, callback) {
  librarian.project.getLog(projectId, userConfig.data.apiKey, callback);
};

/**
 * Downloads the logs as a tarball for the specified project id.
 * @param {string} projectId - the ID of the project.
 * @param {string} projectName - the name of the project
 * @param {string} outLocation - the path to the directory where the tarball should be downloaded
 * @param {function} callback - function invoked with the file stream. Responsible for the actual download.
 */
//-----------------------------------------------------------------------------
Project.prototype.downloadLogs = function(projectId, projectName, outLocation, callback) {
  librarian.project.downloadLogs(projectId, userConfig.data.apiKey, function(err, req, res){
    if(err){
      callback(Errors.getMessage(err));
    }
    var date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
    var outFile = projectName + '_' + date + '.tar.gz';
    outFile = outFile.replace(/ /g, '_').replace(/:/g,'.'); // TODO - escape special characters in projectName
    if(outLocation!=null){
      if(outLocation != true){
        outFile = outLocation;
      }
    }

    var result = {};
    var stream = fs.createWriteStream(outFile);

    res.pipe(stream);
    res.on('end', function(err, stdout, stderr){
      if(err){
        callback(Errors.getMessage(err));
      }
      if(stderr){
        result.stderr = stderr;
      }
      if(stdout){
        result.stdout = stdout;
      }
      result.msg = ' - ' + outFile + ' downloaded.';
      result.outFile = outFile;
      callback(null, result);
    });
  });
};

/**
 * Wipes all project logs for a given project
 * @param {integer} projectId - project id
 * @param {function} callback - callback function
*/
//-----------------------------------------------------------------------------
Project.prototype.clearLogs = function(projectId, callback){
  librarian.project.clearLogs(projectId, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.scale = function(projectId, instances, callback) {
  librarian.project.scale(projectId, {instances:instances}, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Scaling [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.status = {
  uploading : 'uploading',
  deploying : 'deploying',
  running : 'running',
  stopped: 'stopped'
};

module.exports = new Project();<commit_msg>Added output file location validation.<commit_after>var modulus = require('../modulus'),
    librarian = require('../common/api').librarian,
    userConfig = require('../common/api').userConfig,
    fs = require('fs'),
    path = require('path'),
    ProgressBar = require('progress'),
    Progress = require('../util/progress'),
    Errors = require('../util/errors'),
    request = require('request'),
    http = require('http'),
    uploader = require('chunk-loader').Client,
    https = require('https');

http.globalAgent.maxSockets = Number.MAX_VALUE;
https.globalAgent.maxSockets = Number.MAX_VALUE;

//-----------------------------------------------------------------------------
var Project = function() {

};

//-----------------------------------------------------------------------------
Project.prototype.create = function(name, creatorId, callback) {
  librarian.project.create({
    name: name,
    creator: creatorId
  }, false, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.restart = function(projectId, callback) {
  librarian.project.restart(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Restarting [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.stop = function(projectId, callback) {
  librarian.project.stop(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Stopping [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.stopped) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.start = function(projectId, callback) {
  librarian.project.start(projectId, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Starting [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.prototype.find = function(opts, callback) {
  librarian.project.find(opts, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.saveVars = function(projectId, vars, callback) {
  librarian.project.saveVars(projectId, vars, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.deploy = function(projectId, file, callback) {
  var host = librarian._http._host;
  var port = librarian._http._port;
  var protocol = librarian._http._ssl ? 'https' : 'http';

  modulus.io.print('Uploading project...');
  var status = Project.status.uploading;

  // start checking for status changes
  // show progress for upload and inderminate progress for deploying
  var ubar = new ProgressBar('Upload progress [:bar] :percent', {
    complete: '=',
    incomplete: ' ',
    width: 20,
    total: 100
  });
  ubar.tick();

  var client = uploader.uploadFile(file,
    {
      beginProtocol: 'http',
      uploadProtocol: 'http',
      beginPort: '5000',
      uploadPort: '5000',
      host: host,
      port: port,
      debug: false,
      encrypted: true,
      tag: { projectId: projectId, authToken: userConfig.data.apiKey }
    }
  );

  client.on('progress', function(p) {
    ubar.tick(((p.sent / p.total) * 100) - ubar.curr);
  });

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

  client.on('complete', function() {
    //var dbar = new Progress.indeterminate('Deploying [:bar]');

    // check every second for project status change
    var projectStatus = function () {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {
        if(!err) {
          if(proj && proj.status) {
            if(proj.status.toLowerCase() !== status) {
              var newStatus = proj.status.toLowerCase();
              if(newStatus === Project.status.deploying) {
                status = newStatus;
                modulus.io.print('\nDeploying Project...');
                //dbar.start();
              } else if(newStatus === Project.status.running && status !== Project.status.uploading) {
                //dbar.stop();
                modulus.io.print(' ');
                return callback(null, proj.domain);
              }
            }
          }
        }

        if(status !== Project.status.running) {
          setTimeout(projectStatus, 1000);
        }
      });
    };
    projectStatus();

    var logLength = 0;
    var deployLogs = function() {
      if(status === Project.status.deploying) {
        librarian.project.getDeployLogs(projectId, userConfig.data.apiKey, function(err, result) {
          for(var key in result) {
            var log = result[key];
            modulus.io.write(log.substring(logLength));
            logLength = log.length;
            break;
          }
        });
      }

      if(status !== Project.status.running) {
        setTimeout(deployLogs, 1000);
      }
    };
    deployLogs();
  });
};

/**
 * Gets the logs for the specified project id.
 * @param {string} projectId The ID of the project.
 * @param {function} callback Function invoked with log results.
 */
//-----------------------------------------------------------------------------
Project.prototype.getLogs = function(projectId, callback) {
  librarian.project.getLog(projectId, userConfig.data.apiKey, callback);
};

/**
 * Downloads the logs as a tarball for the specified project id.
 * @param {string} projectId - the ID of the project.
 * @param {string} projectName - the name of the project
 * @param {string} outLocation - the path to the directory where the tarball should be downloaded
 * @param {function} callback - function invoked with the file stream. Responsible for the actual download.
 */
//-----------------------------------------------------------------------------
Project.prototype.downloadLogs = function(projectId, projectName, outLocation, callback) {
  librarian.project.downloadLogs(projectId, userConfig.data.apiKey, function(err, req, res){
    if(err){
      callback(Errors.getMessage(err));
    }
    if(res.statusCode == 404){
      callback("Problem downloading logs: " + res.statusCode);
    }

    var date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
    var outFile = projectName + '_' + date + '.tar.gz';
    outFile = outFile.replace(/ /g, '_').replace(/:/g,'.'); // TODO - escape special characters in projectName
    if(outLocation!=null){
      if(!outLocation){
        fs.exists(outLocation, function(exists){
          if(exists){
            outFile = outLocation;
          }
        });
      }
    }

    var result = {};
    var stream = fs.createWriteStream(outFile);

    res.pipe(stream);
    res.on('end', function(err, stdout, stderr){
      if(err){
        callback(Errors.getMessage(err));
      }
      if(stderr){
        result.stderr = stderr;
      }
      if(stdout){
        result.stdout = stdout;
      }
      result.msg = ' - ' + outFile + ' downloaded.';
      result.outFile = outFile;
      callback(null, result);
    });
  });
};

/**
 * Wipes all project logs for a given project
 * @param {integer} projectId - project id
 * @param {function} callback - callback function
*/
//-----------------------------------------------------------------------------
Project.prototype.clearLogs = function(projectId, callback){
  librarian.project.clearLogs(projectId, userConfig.data.apiKey, callback);
};

//-----------------------------------------------------------------------------
Project.prototype.scale = function(projectId, instances, callback) {
  librarian.project.scale(projectId, {instances:instances}, userConfig.data.apiKey, function(err, result) {
    if(err) {
      return callback(Errors.getMessage(err));
    }

    var dbar = new Progress.indeterminate('Scaling [:bar]');
    dbar.start();

    var checkStatus = function() {
      librarian.project.find({projectId : projectId}, userConfig.data.apiKey, function(err, proj) {

        if(err) {
          return callback(Errors.getMessage(err));
        }

        if(proj.status.toLowerCase() === Project.status.running) {
          dbar.stop();
          modulus.io.print(' ');
          return callback(null, proj);
        }
        else {
          setTimeout(checkStatus, 1000);
        }
      });
    };

    setTimeout(checkStatus, 1000);
  });
};

//-----------------------------------------------------------------------------
Project.status = {
  uploading : 'uploading',
  deploying : 'deploying',
  running : 'running',
  stopped: 'stopped'
};

module.exports = new Project();<|endoftext|>


<commit_before>/**
 * @file Rhino host adapter
 * @since 0.1.5
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfExit:true*/ // Exit function
/*global _gpfHost*/ // Host type
/*global _gpfMainContext*/ // Main context object
/*#endif*/

/*jshint rhino: true*/
/*eslint-env rhino*/

/* istanbul ignore next */ // Tested with NodeJS
if (_GPF_HOST.RHINO === _gpfHost) {

    // Define console APIs
    _gpfMainContext.console = {
        log: function (t) {
            print("    " + t);
        },
        info: function (t) {
            print("[?] " + t);
        },
        warn: function (t) {
            print("/!\\ " + t);
        },
        error: function (t) {
            print("(X) " + t);
        }
    };

    _gpfExit = function (code) {
        java.lang.System.exit(code);
    };

    /**
     * @namespace gpf.rhino
     * @description Root namespace for Rhino specifics
     */
    gpf.rhino = {};

}
<commit_msg>Improves coverage / simplify<commit_after>/**
 * @file Rhino host adapter
 * @since 0.1.5
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfBootImplByHost*/ // Boot host specific implementation per host
/*global _gpfConsoleGenerate*/ // Generate an object that can be used to simulate console methods
/*global _gpfExit:true*/ // Exit function
/*global _gpfMainContext*/ // Main context object
/*#endif*/

/*jshint rhino: true*/
/*eslint-env rhino*/

/**
 * @namespace gpf.rhino
 * @description Root namespace for Rhino specifics
 */
gpf.rhino = {};

_gpfBootImplByHost[_GPF_HOST.RHINO] = function () {

    // Define console APIs
    _gpfMainContext.console = _gpfConsoleGenerate(print);

    /* istanbul ignore next */ // Not testable
    _gpfExit = function (code) {
        java.lang.System.exit(code);
    };

};
<|endoftext|>


<commit_before>var events = require('events');
var util = require('util');
var Chrome = require('chrome-remote-interface');
var common = require('./common.js');
var Page = require('./page.js');
var har = require('./har.js');

var NEUTRAL_URL = 'about:blank';
var GRACE_TIME = 1000;

var CLEANUP_SCRIPT =
    'chrome.benchmarking.clearCache();' +
    'chrome.benchmarking.clearHostResolverCache();' +
    'chrome.benchmarking.clearPredictorCache();' +
    'chrome.benchmarking.closeConnections();';

var PAGE_DELAY = 1000;

function Client(urls, options) {
    var self = this;
    var pages = [];
    options = options || {};
    options.fetchContent = !!(options.fetchContent) || false;
    options.onLoadDelay = options.onLoadDelay || 0;
    options.force = !!(options.force) || false;
    // start the instrumentation
    Chrome(options, function (chrome) {
        function loadUrl(index) {
            if (index < urls.length) {
                var url = urls[index];
                var page = new Page(index, url, chrome, options.fetchContent);
                var loadEventTimeout;
                var giveUpTimeout;
                pages[index] = page;
                // proceed with the next page
                var next = function () {
                    clearTimeout(giveUpTimeout);
                    common.dump('--- End: ' + url);
                    self.emit(page.isFailed() ? 'pageError' : 'pageEnd', url);
                    chrome.removeAllListeners('event');
                    // start the next URL after a certain delay
                    // so to "purge" any spurious requests
                    setTimeout(function () {
                        loadUrl(index + 1);
                    }, PAGE_DELAY);
                };
                // load a neutral page before the user provided URL since
                // there's no way to stop pending loadings using the protocol
                chrome.Page.navigate({'url': NEUTRAL_URL}, function (error, response) {
                    if (error) {
                        // probably never emitted...
                        self.emit('error', new Error('Cannot load URL'));
                        chrome.close();
                    }
                });
                // give up after a certain amount of time
                if (options.giveUpTime) {
                    giveUpTimeout = setTimeout(function () {
                        clearTimeout(loadEventTimeout);
                        common.dump('--- Giving up: ' + url);
                        page.markAsFailed();
                        next();
                    }, options.giveUpTime * 1000); // seconds
                }
                // wait its completion before starting with the next user-defined URL
                var neutralFrameid;
                chrome.on('event', function (message) {
                    switch (message.method) {
                    case 'Page.frameNavigated':
                        // save the frame id of the neutral URL
                        var frame = message.params.frame;
                        if (frame.url === NEUTRAL_URL) {
                            neutralFrameid = frame.id;
                        }
                        break;
                    case 'Page.frameStoppedLoading':
                        // load the next URL when done
                        if (message.params.frameId === neutralFrameid) {
                            // inject the JavaScript code and load this URL after the grace time
                            setTimeout(function () {
                            // reset events
                            chrome.removeAllListeners('event');
                            chrome.on('event', function (message) {
                                page.processMessage(message);
                                // check if done with the current URL
                                if (page.isFinished() && typeof loadEventTimeout === 'undefined') {
                                    // keep listening for events for a certain amount of time
                                    // after the load event is triggered
                                    loadEventTimeout = setTimeout(next, options.onLoadDelay);
                                }
                            });
                                common.dump('--- Start: ' + url);
                                self.emit('pageStart', url);
                                chrome.Runtime.evaluate({'expression': CLEANUP_SCRIPT}, function (error, response) {
                                    // error with the communication or with the JavaScript code
                                    if (!options.force && (error || (response && (response.wasThrown || response.exceptionDetails)))) {
                                        var errorDetails = JSON.stringify(response, null, 4);
                                        var errorMessage = 'Cannot inject JavaScript: ' + errorDetails;
                                        common.dump(errorMessage);
                                        self.emit('error', new Error(errorMessage));
                                        chrome.close();
                                    } else {
                                        chrome.Page.navigate({'url': url}, function (error, response) {
                                            if (error) {
                                                self.emit('error', new Error('Cannot load URL'));
                                                chrome.close();
                                            }
                                        });
                                    }
                                });
                            }, GRACE_TIME);
                        }
                        break;
                    }
                });
            } else {
                // no more URLs to process
                self.emit('end', har.create(pages));
                // load the neutral URL then exit
                chrome.Page.navigate({'url': NEUTRAL_URL}, function (error, response) {
                    chrome.close();
                });
            }
        }
        self.emit('connect');
        // preliminary global setup
        chrome.Page.enable();
        chrome.Network.enable();
        chrome.Network.setCacheDisabled({'cacheDisabled': true});
        if (typeof options.userAgent === 'string') {
            chrome.Network.setUserAgentOverride({'userAgent': options.userAgent});
        }
        // start!
        chrome.once('ready', function () {
            loadUrl(0);
        });
    }).on('error', function (err) {
        common.dump("Emitting 'error' event: " + err.message);
        self.emit('error', err);
    });
}

util.inherits(Client, events.EventEmitter);

module.exports = Client;
<commit_msg>Ensure that the 'end' event is emitted when the connection is closed<commit_after>var events = require('events');
var util = require('util');
var Chrome = require('chrome-remote-interface');
var common = require('./common.js');
var Page = require('./page.js');
var har = require('./har.js');

var NEUTRAL_URL = 'about:blank';
var GRACE_TIME = 1000;

var CLEANUP_SCRIPT =
    'chrome.benchmarking.clearCache();' +
    'chrome.benchmarking.clearHostResolverCache();' +
    'chrome.benchmarking.clearPredictorCache();' +
    'chrome.benchmarking.closeConnections();';

var PAGE_DELAY = 1000;

function Client(urls, options) {
    var self = this;
    var pages = [];
    options = options || {};
    options.fetchContent = !!(options.fetchContent) || false;
    options.onLoadDelay = options.onLoadDelay || 0;
    options.force = !!(options.force) || false;
    // start the instrumentation
    Chrome(options, function (chrome) {
        function loadUrl(index) {
            if (index < urls.length) {
                var url = urls[index];
                var page = new Page(index, url, chrome, options.fetchContent);
                var loadEventTimeout;
                var giveUpTimeout;
                pages[index] = page;
                // proceed with the next page
                var next = function () {
                    clearTimeout(giveUpTimeout);
                    common.dump('--- End: ' + url);
                    self.emit(page.isFailed() ? 'pageError' : 'pageEnd', url);
                    chrome.removeAllListeners('event');
                    // start the next URL after a certain delay
                    // so to "purge" any spurious requests
                    setTimeout(function () {
                        loadUrl(index + 1);
                    }, PAGE_DELAY);
                };
                // load a neutral page before the user provided URL since
                // there's no way to stop pending loadings using the protocol
                chrome.Page.navigate({'url': NEUTRAL_URL}, function (error, response) {
                    if (error) {
                        // probably never emitted...
                        self.emit('error', new Error('Cannot load URL'));
                        chrome.close();
                    }
                });
                // give up after a certain amount of time
                if (options.giveUpTime) {
                    giveUpTimeout = setTimeout(function () {
                        clearTimeout(loadEventTimeout);
                        common.dump('--- Giving up: ' + url);
                        page.markAsFailed();
                        next();
                    }, options.giveUpTime * 1000); // seconds
                }
                // wait its completion before starting with the next user-defined URL
                var neutralFrameid;
                chrome.on('event', function (message) {
                    switch (message.method) {
                    case 'Page.frameNavigated':
                        // save the frame id of the neutral URL
                        var frame = message.params.frame;
                        if (frame.url === NEUTRAL_URL) {
                            neutralFrameid = frame.id;
                        }
                        break;
                    case 'Page.frameStoppedLoading':
                        // load the next URL when done
                        if (message.params.frameId === neutralFrameid) {
                            // inject the JavaScript code and load this URL after the grace time
                            setTimeout(function () {
                            // reset events
                            chrome.removeAllListeners('event');
                            chrome.on('event', function (message) {
                                page.processMessage(message);
                                // check if done with the current URL
                                if (page.isFinished() && typeof loadEventTimeout === 'undefined') {
                                    // keep listening for events for a certain amount of time
                                    // after the load event is triggered
                                    loadEventTimeout = setTimeout(next, options.onLoadDelay);
                                }
                            });
                                common.dump('--- Start: ' + url);
                                self.emit('pageStart', url);
                                chrome.Runtime.evaluate({'expression': CLEANUP_SCRIPT}, function (error, response) {
                                    // error with the communication or with the JavaScript code
                                    if (!options.force && (error || (response && (response.wasThrown || response.exceptionDetails)))) {
                                        var errorDetails = JSON.stringify(response, null, 4);
                                        var errorMessage = 'Cannot inject JavaScript: ' + errorDetails;
                                        common.dump(errorMessage);
                                        self.emit('error', new Error(errorMessage));
                                        chrome.close();
                                    } else {
                                        chrome.Page.navigate({'url': url}, function (error, response) {
                                            if (error) {
                                                self.emit('error', new Error('Cannot load URL'));
                                                chrome.close();
                                            }
                                        });
                                    }
                                });
                            }, GRACE_TIME);
                        }
                        break;
                    }
                });
            } else {
                // no more URLs to process; load the neutral URL then exit
                chrome.Page.navigate({'url': NEUTRAL_URL}, function (error, response) {
                    chrome.close(function () {
                        self.emit('end', har.create(pages));
                    });
                });
            }
        }
        self.emit('connect');
        // preliminary global setup
        chrome.Page.enable();
        chrome.Network.enable();
        chrome.Network.setCacheDisabled({'cacheDisabled': true});
        if (typeof options.userAgent === 'string') {
            chrome.Network.setUserAgentOverride({'userAgent': options.userAgent});
        }
        // start!
        chrome.once('ready', function () {
            loadUrl(0);
        });
    }).on('error', function (err) {
        common.dump("Emitting 'error' event: " + err.message);
        self.emit('error', err);
    });
}

util.inherits(Client, events.EventEmitter);

module.exports = Client;
<|endoftext|>


<commit_before>(function($) {

  var addMethods = function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = $.keys(source);

    if (!$.keys({ toString: true }).length) properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && $.isFunction(value) && $.argumentNames(value)[0] == "$super") {

        var method = value, value = $.extend($.wrap((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property), method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }

  $.extend({
    keys: function(obj) {
      var keys = [];
      for (var key in obj) keys.push(key);
      return keys;
    },

    argumentNames: function(func) {
      var names = func.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(/, ?/);
      return names.length == 1 && !names[0] ? [] : names;
    },

    bind: function(func, scope) {
      return function() {
        return func.apply(scope, $.makeArray(arguments));
      }
    },

    wrap: function(func, wrapper) {
      var __method = func;
      return function() {
        return wrapper.apply(this, [$.bind(__method, this)].concat($.makeArray(arguments)));
      }
    },

    klass: function() {
      var parent = null, properties = $.makeArray(arguments);
      if ($.isFunction(properties[0])) parent = properties.shift();

      var klass = function() {
        this.initialize.apply(this, arguments);
      };

      klass.superclass = parent;
      klass.subclasses = [];
      klass.addMethods = addMethods;

      if (parent) {
        var subclass = function() { };
        subclass.prototype = parent.prototype;
        klass.prototype = new subclass;
        parent.subclasses.push(klass);
      }

      for (var i = 0; i < properties.length; i++)
        klass.addMethods(properties[i]);

      if (!klass.prototype.initialize)
        klass.prototype.initialize = function() {};

      klass.prototype.constructor = klass;

      return klass;
    },
    delegate: function(rules) {
      return function(e) {
        var target = $(e.target), parent = null;
        for (var selector in rules) {
          if (target.is(selector) || ((parent = target.parents(selector)) && parent.length > 0)) {
            return rules[selector].apply(this, [parent || target].concat($.makeArray(arguments)));
          }
          parent = null;
        }
      }
    }
  });

  var bindEvents = function(instance) {
    for (var member in instance) {
      if (member.match(/^on(.+)/) && typeof instance[member] == 'function') {
        instance.element.bind(RegExp.$1, $.bind(instance[member], instance));
      }
    }
  }

  var behaviorWrapper = function(behavior) {
    return $.klass(behavior, {
      initialize: function($super, element, args) {
        this.element = $(element);
        if ($super) $super.apply(this, args);
      }
    });
  }

  var attachBehavior = function(el, behavior, args) {
      var wrapper = behaviorWrapper(behavior);
      instance = new wrapper(el, args);

      bindEvents(instance);

      if (!behavior.instances) behavior.instances = [];

      behavior.instances.push(instance);

      return instance;
  };

  $.fn.extend({
    attach: function() {
      var args = $.makeArray(arguments), behavior = args.shift();

      if ($.livequery && this.selector) {
        return this.livequery(function() {
          attachBehavior(this, behavior, args);
        });
      } else {
        return this.each(function() {
          attachBehavior(this, behavior, args);
        });
      }
    },
    attachAndReturn: function() {
      var args = $.makeArray(arguments), behavior = args.shift();

      return $.map(this, function(el) {
        return attachBehavior(el, behavior, args);
      });
    },
    delegate: function(type, rules) {
      return this.bind(type, $.delegate(rules));
    },
    attached: function(behavior) {
      var instances = [];

      if (!behavior.instances) return instances;

      this.each(function(i, element) {
        $.each(behavior.instances, function(i, instance) {
          if (instance.element.get(0) == element) instances.push(instance);
        });
      });

      return instances;
    },
    firstAttached: function(behavior) {
      return this.attached(behavior)[0];
    }
  });

  Remote = $.klass({
    initialize: function(options) {
      if (this.element.attr('nodeName') == 'FORM') this.element.attach(Remote.Form, options);
      else this.element.attach(Remote.Link, options);
    }
  });

  Remote.Base = $.klass({
    initialize : function(options) {
      this.options = $.extend({

      }, options || {});
    },
    _makeRequest : function(options) {
      $.ajax(options);
      return false;
    }
  });

  Remote.Link = $.klass(Remote.Base, {
    onclick: function() {
      var options = $.extend({ url: this.element.attr('href'), type: 'GET' }, this.options);
      return this._makeRequest(options);
    }
  });

  Remote.Form = $.klass(Remote.Base, {
    onclick: function(e) {
      var target = e.target;

      if ($.inArray(target.nodeName.toLowerCase(), ['input', 'button']) >= 0 && target.type.match(/submit|image/))
        this._submitButton = target;
    },
    onsubmit: function() {
      var data = this.element.serializeArray();

      if (this._submitButton) data.push({ name: this._submitButton.name, value: this._submitButton.value });

      var options = $.extend({
        url : this.element.attr('action'),
        type : this.element.attr('method') || 'GET',
        data : data
      }, this.options);

      this._makeRequest(options);

      return false;
    }
  });

  $.ajaxSetup({
    beforeSend: function(xhr) {
      xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, */*");
    }
  });

})(jQuery);<commit_msg>tweakage<commit_after>(function($) {

  var addMethods = function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = $.keys(source);

    if (!$.keys({ toString: true }).length) properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && $.isFunction(value) && $.argumentNames(value)[0] == "$super") {

        var method = value, value = $.extend($.wrap((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property), method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }

  $.extend({
    keys: function(obj) {
      var keys = [];
      for (var key in obj) keys.push(key);
      return keys;
    },

    argumentNames: function(func) {
      var names = func.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(/, ?/);
      return names.length == 1 && !names[0] ? [] : names;
    },

    bind: function(func, scope) {
      return function() {
        return func.apply(scope, $.makeArray(arguments));
      }
    },

    wrap: function(func, wrapper) {
      var __method = func;
      return function() {
        return wrapper.apply(this, [$.bind(__method, this)].concat($.makeArray(arguments)));
      }
    },

    klass: function() {
      var parent = null, properties = $.makeArray(arguments);
      if ($.isFunction(properties[0])) parent = properties.shift();

      var klass = function() {
        this.initialize.apply(this, arguments);
      };

      klass.superclass = parent;
      klass.subclasses = [];
      klass.addMethods = addMethods;

      if (parent) {
        var subclass = function() { };
        subclass.prototype = parent.prototype;
        klass.prototype = new subclass;
        parent.subclasses.push(klass);
      }

      for (var i = 0; i < properties.length; i++)
        klass.addMethods(properties[i]);

      if (!klass.prototype.initialize)
        klass.prototype.initialize = function() {};

      klass.prototype.constructor = klass;

      return klass;
    },
    delegate: function(rules) {
      return function(e) {
        var target = $(e.target), parent = null;
        for (var selector in rules) {
          if (target.is(selector) || ((parent = target.parents(selector)) && parent.length > 0)) {
            return rules[selector].apply(this, [parent || target].concat($.makeArray(arguments)));
          }
          parent = null;
        }
      }
    }
  });

  var bindEvents = function(instance) {
    for (var member in instance) {
      if (member.match(/^on(.+)/) && typeof instance[member] == 'function') {
        instance.element.bind(RegExp.$1, $.bind(instance[member], instance));
      }
    }
  }

  var behaviorWrapper = function(behavior) {
    return $.klass(behavior, {
      initialize: function($super, element, args) {
        this.element = $(element);
        if ($super) $super.apply(this, args);
      }
    });
  }

  var attachBehavior = function(el, behavior, args) {
      var wrapper = behaviorWrapper(behavior);
      instance = new wrapper(el, args);

      bindEvents(instance);

      if (!behavior.instances) behavior.instances = [];

      behavior.instances.push(instance);

      return instance;
  };

  $.fn.extend({
    attach: function() {
      var args = $.makeArray(arguments), behavior = args.shift();

      if ($.livequery && this.selector) {
        return this.livequery(function() {
          attachBehavior(this, behavior, args);
        });
      } else {
        return this.each(function() {
          attachBehavior(this, behavior, args);
        });
      }
    },
    attachAndReturn: function() {
      var args = $.makeArray(arguments), behavior = args.shift();

      return $.map(this, function(el) {
        return attachBehavior(el, behavior, args);
      });
    },
    delegate: function(type, rules) {
      return this.bind(type, $.delegate(rules));
    },
    attached: function(behavior) {
      var instances = [];

      if (!behavior.instances) return instances;

      this.each(function(i, element) {
        $.each(behavior.instances, function(i, instance) {
          if (instance.element.get(0) == element) instances.push(instance);
        });
      });

      return instances;
    },
    firstAttached: function(behavior) {
      return this.attached(behavior)[0];
    }
  });

  Remote = $.klass({
    initialize: function(options) {
      if (this.element.attr('nodeName') == 'FORM') this.element.attach(Remote.Form, options);
      else this.element.attach(Remote.Link, options);
    }
  });

  Remote.Base = $.klass({
    initialize : function(options) {
      this.options = options;
    },
    _makeRequest : function(options) {
      $.ajax(options);
      return false;
    }
  });

  Remote.Link = $.klass(Remote.Base, {
    onclick: function() {
      var options = $.extend({
        url: this.element.attr('href'),
        type: 'GET'
      }, this.options);
      return this._makeRequest(options);
    }
  });

  Remote.Form = $.klass(Remote.Base, {
    onclick: function(e) {
      var target = e.target;

      if ($.inArray(target.nodeName.toLowerCase(), ['input', 'button']) >= 0 && target.type.match(/submit|image/))
        this._submitButton = target;
    },
    onsubmit: function() {
      var data = this.element.serializeArray();

      if (this._submitButton) data.push({ name: this._submitButton.name, value: this._submitButton.value });

      var options = $.extend({
        url : this.element.attr('action'),
        type : this.element.attr('method') || 'GET',
        data : data
      }, this.options);

      this._makeRequest(options);

      return false;
    }
  });

  $.ajaxSetup({
    beforeSend: function(xhr) {
      xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, */*");
    }
  });

})(jQuery);<|endoftext|>