<commit_before>'use strict';

const Schema = require('./Schema');
const Model = require('./Model');
const https = require('https');
const AWS = require('aws-sdk');
const debug = require('debug')('dynamoose');
const debugTransaction = require('debug')('dynamoose:transaction');
const Q = require('q');
const errors = require('./errors');

function createLocalDb(endpointURL) {
  const client = new AWS.DynamoDB({
    endpoint: new AWS.Endpoint(endpointURL)
  });

  if (typeof global.it !== 'function' && typeof global.after !== 'function') {
    // We're not running in a test env - just return the client without modifications.
    // This ensures that we keep BC with users that might call this method in produciton applications.
    // @TODO: Remove once DynamoDB local instance supports transactions.
    return client;
  }

  // @TODO: Remove once DynamoDB local instance supports transactions.
  // @HACK
  client.transactGetItems = (request, callback) => {
    const batchRequest = {
      RequestItems: {}
    };
    request.TransactItems.forEach((item) => {
      const operation = Object.keys(item)[0];
      const transactItem = item[operation];
      if (!batchRequest.RequestItems[transactItem.TableName]) {
        batchRequest.RequestItems[transactItem.TableName] = {
          Keys: []
        };
      }

      batchRequest.RequestItems[transactItem.TableName].Keys.push(transactItem.Key)
    });
    return client.batchGetItem(batchRequest, (err, data) => {
      if (err) {
        return callback(err);
      }
      // Re-map responses to expected format.
      data.Responses = Object.values(data.Responses).reduce(
        (list, resp) => ([...list, ...resp.map((item) => ({Item: item}))]),
        []
      )
      callback(err, data);
    });

  };

  // @TODO: Remove once DynamoDB local instance supports transactions.
  // @HACK
  client.transactWriteItems = (request, callback) => {
    const batchRequest = {
      RequestItems: {}
    };
    request.TransactItems.forEach((item) => {
      const operation = Object.keys(item)[0];
      const transactItem = item[operation];
      if (!batchRequest.RequestItems[transactItem.TableName]) {
        batchRequest.RequestItems[transactItem.TableName] = [];
      }

      // Pick only properties that we're interested in.
      const {Key, Item} = transactItem;

      const itemValue = {};

      if (operation === 'Update') {
        // Map Key to update to to item, since Put only supports Item.
        itemValue.Item = Key;
      } else if (Key) {
        itemValue.Key = Key;
      } else if (Item) {
        itemValue.Item = Item;
      }

      batchRequest.RequestItems[transactItem.TableName].push({
        // Map Update operation to Put.
        [`${operation === 'Update' ? 'Put' : operation}Request`]: itemValue
      })
    });
    return client.batchWriteItem(batchRequest, callback);
  };

  return client;
}

function Dynamoose () {
  this.models = {};

  this.defaults = {
    create: true,
    waitForActive: true, // Wait for table to be created
    waitForActiveTimeout: 180000, // 3 minutes
    prefix: '', // prefix_Table
    suffix: '' // Table_suffix
  }; // defaults
}

Dynamoose.prototype.model = function(name, schema, options) {
  options = options || {};

  for(const key in this.defaults) {
    options[key] = (typeof options[key] === 'undefined') ? this.defaults[key] : options[key];
  }

  name = options.prefix + name + options.suffix;

  debug('Looking up model %s', name);

  if(this.models[name]) {
    return this.models[name];
  }
  if (!(schema instanceof Schema)) {
    schema = new Schema(schema, options);
  }

  const model = Model.compile(name, schema, options, this);
  this.models[name] = model;
  return model;
};

/**
* The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
*
* @method VirtualType
* @api public
*/

Dynamoose.prototype.VirtualType = require('./VirtualType');

Dynamoose.prototype.AWS = AWS;

Dynamoose.prototype.local = function (url) {
  this.endpointURL = url || 'http://localhost:8000';
  this.dynamoDB = createLocalDb(this.endpointURL);
  debug('Setting DynamoDB to local (%s)', this.endpointURL);
};

/**
* Document client for executing nested scans
*/
Dynamoose.prototype.documentClient = function() {
  if (this.dynamoDocumentClient) {
    return this.dynamoDocumentClient;
  }
  if (this.endpointURL) {
    debug('Setting dynamodb document client to %s', this.endpointURL);
    this.AWS.config.update({ endpoint: this.endpointURL });
  } else {
    debug('Getting default dynamodb document client');
  }
  this.dynamoDocumentClient = new this.AWS.DynamoDB.DocumentClient();
  return this.dynamoDocumentClient;
};

Dynamoose.prototype.setDocumentClient = function(documentClient) {
  debug('Setting dynamodb document client');
  this.dynamoDocumentClient = documentClient;
};

Dynamoose.prototype.ddb = function () {
  if(this.dynamoDB) {
    return this.dynamoDB;
  }

  if(this.endpointURL) {
    debug('Setting DynamoDB to %s', this.endpointURL);
    this.dynamoDB = createLocalDb(this.endpointURL);
  } else {
    debug('Getting default DynamoDB');
    this.dynamoDB = new this.AWS.DynamoDB({
      httpOptions: {
        agent: new https.Agent({
          rejectUnauthorized: true,
          keepAlive: true
        })
      }
    });
  }
  return this.dynamoDB;
};

Dynamoose.prototype.setDefaults = function (options) {

  for(const key in this.defaults) {
    options[key] = (typeof options[key] === 'undefined') ? this.defaults[key] : options[key];
  }

  this.defaults = options;
};

Dynamoose.prototype.Schema = Schema;
Dynamoose.prototype.Table = require('./Table');
Dynamoose.prototype.Dynamoose = Dynamoose;

Dynamoose.prototype.setDDB = function (ddb) {
  debug("Setting custom DDB");
  this.dynamoDB = ddb;
};
Dynamoose.prototype.revertDDB = function () {
  debug("Reverting to default DDB");
  this.dynamoDB = null;
};

Dynamoose.prototype.transaction = async function(items, options, next) {
  debugTransaction('Run Transaction');
  const deferred = Q.defer();
  let dbClient = this.documentClient();
  let DynamoDBSet = dbClient.createSet([1, 2, 3]).constructor;

  options = options || {};
  if(typeof options === 'function') {
    next = options;
    options = {};
  }

  if(!Array.isArray(items) || items.length === 0) {
    deferred.reject(new errors.TransactionError('Items required to run transaction'));
    return deferred.promise.nodeify(next);
  }

  items = await Promise.all(items);
  let transactionReq = {
    TransactItems: items.map(item => {
      const returnItem = {...item};
      delete returnItem.$__;
      return returnItem;
    })
  };
  let transactionMethodName;
  if (options.type) {
    debugTransaction("Using custom transaction method");
    if (options.type === "get") {
      transactionMethodName = "transactGetItems";
    } else if (options.type === "write") {
      transactionMethodName = "transactWriteItems";
    } else {
      deferred.reject(new errors.TransactionError('Invalid type option, please pass in "get" or "write"'));
      return deferred.promise.nodeify(next);
    }
  } else {
    debugTransaction("Using predetermined transaction method");
    transactionMethodName = items.map(obj => Object.keys(obj)[0]).every(key => key === "Get") ? "transactGetItems" : "transactWriteItems";
  }
  debugTransaction(`Using transaction method: ${transactionMethodName}`);

  const transact = () => {
    debugTransaction('transact', transactionReq);
    this.dynamoDB[transactionMethodName](transactionReq, function(err, data) {
      if(err) {
        debugTransaction(`Error returned by ${transactionMethodName}`, err);
        return deferred.reject(err);
      }

      debugTransaction(`${transactionMethodName} response`, data);

      if(!data.Responses) {
        return deferred.resolve();
      }

      return deferred.resolve(data.Responses.map(function (item, index) {
        let model;
        const TheModel = items[index].$__.newModel$;
        const TheModel$ = TheModel.$__;
        const schema = TheModel$.schema;
        Object.keys(item).forEach(function (prop) {
          if (item[prop] instanceof DynamoDBSet) {
            item[prop] = item[prop].values;
          }
        });

        model = new TheModel();
        model.$__.isNew = false;
        // Destruct 'item' DynamoDB's returned structure.
        schema.parseDynamo(model, item.Item);
        debugTransaction(`${transactionMethodName} parsed model`, model);
        return model;
      }).filter((item, index) => {
          const TheModel = items[index].$__.newModel$;
          const TheModel$ = TheModel.$__;
          const schema = TheModel$.schema;

          return !(schema.expires && schema.expires.returnExpiredItems === false && item[schema.expires.attribute] && item[schema.expires.attribute] < new Date());
      }));
    });
  }

  if (options.returnRequest) {
    deferred.resolve(transactionReq);
  } else if (items.some(item => item.$__.newModel$.$__.table.options.waitForActive)) {
    const waitForActivePromises = Promise.all(items.filter(item => item.$__.newModel$.$__.table.options.waitForActive).map(item => item.$__.newModel$.$__.table.waitForActive()));
    waitForActivePromises.then(transact).catch(deferred.reject);
  } else {
    transact();
  }
  return deferred.promise.nodeify(next);
}

module.exports = new Dynamoose();
<commit_msg>Support conditionCheck operation in the local mock<commit_after>'use strict';

const Schema = require('./Schema');
const Model = require('./Model');
const https = require('https');
const AWS = require('aws-sdk');
const debug = require('debug')('dynamoose');
const debugTransaction = require('debug')('dynamoose:transaction');
const Q = require('q');
const errors = require('./errors');

function createLocalDb(endpointURL) {
  const client = new AWS.DynamoDB({
    endpoint: new AWS.Endpoint(endpointURL)
  });

  if (typeof global.it !== 'function' && typeof global.after !== 'function') {
    // We're not running in a test env - just return the client without modifications.
    // This ensures that we keep BC with users that might call this method in produciton applications.
    // @TODO: Remove once DynamoDB local instance supports transactions.
    return client;
  }

  // @TODO: Remove once DynamoDB local instance supports transactions.
  // @HACK
  client.transactGetItems = (request, callback) => {
    const batchRequest = {
      RequestItems: {}
    };
    request.TransactItems.forEach((item) => {
      const operation = Object.keys(item)[0];
      const transactItem = item[operation];
      if (!batchRequest.RequestItems[transactItem.TableName]) {
        batchRequest.RequestItems[transactItem.TableName] = {
          Keys: []
        };
      }

      batchRequest.RequestItems[transactItem.TableName].Keys.push(transactItem.Key)
    });
    return client.batchGetItem(batchRequest, (err, data) => {
      if (err) {
        return callback(err);
      }
      // Re-map responses to expected format.
      data.Responses = Object.values(data.Responses).reduce(
        (list, resp) => ([...list, ...resp.map((item) => ({Item: item}))]),
        []
      )
      callback(err, data);
    });

  };

  // @TODO: Remove once DynamoDB local instance supports transactions.
  // @HACK
  client.transactWriteItems = (request, callback) => {
    const batchRequest = {
      RequestItems: {}
    };
    request.TransactItems.forEach((item) => {
      let operation = Object.keys(item)[0];
      const transactItem = item[operation];

      if (operation === 'ConditionCheck') {
        // Mock does not support ConditionCheck operation, so just fail silently.
        // Bail out early to not create a request with empty table name.
        return;
      }

      if (!batchRequest.RequestItems[transactItem.TableName]) {
        batchRequest.RequestItems[transactItem.TableName] = [];
      }

      // Pick only properties that we're interested in.
      const {Key, Item} = transactItem;

      const itemValue = {};

      if (operation === 'Update') {
        // Map Key to update to to item, since Put only supports Item.
        itemValue.Item = Key;
      } else if (Key) {
        itemValue.Key = Key;
      } else if (Item) {
        itemValue.Item = Item;
      }

      if (operation === 'Update') {
        // Map Update operation to Put, as this mock does not support Update operations.
        operation = 'Put';
      }

      batchRequest.RequestItems[transactItem.TableName].push({
        [`${operation}Request`]: itemValue
      })
    });
    return client.batchWriteItem(batchRequest, callback);
  };

  return client;
}

function Dynamoose () {
  this.models = {};

  this.defaults = {
    create: true,
    waitForActive: true, // Wait for table to be created
    waitForActiveTimeout: 180000, // 3 minutes
    prefix: '', // prefix_Table
    suffix: '' // Table_suffix
  }; // defaults
}

Dynamoose.prototype.model = function(name, schema, options) {
  options = options || {};

  for(const key in this.defaults) {
    options[key] = (typeof options[key] === 'undefined') ? this.defaults[key] : options[key];
  }

  name = options.prefix + name + options.suffix;

  debug('Looking up model %s', name);

  if(this.models[name]) {
    return this.models[name];
  }
  if (!(schema instanceof Schema)) {
    schema = new Schema(schema, options);
  }

  const model = Model.compile(name, schema, options, this);
  this.models[name] = model;
  return model;
};

/**
* The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
*
* @method VirtualType
* @api public
*/

Dynamoose.prototype.VirtualType = require('./VirtualType');

Dynamoose.prototype.AWS = AWS;

Dynamoose.prototype.local = function (url) {
  this.endpointURL = url || 'http://localhost:8000';
  this.dynamoDB = createLocalDb(this.endpointURL);
  debug('Setting DynamoDB to local (%s)', this.endpointURL);
};

/**
* Document client for executing nested scans
*/
Dynamoose.prototype.documentClient = function() {
  if (this.dynamoDocumentClient) {
    return this.dynamoDocumentClient;
  }
  if (this.endpointURL) {
    debug('Setting dynamodb document client to %s', this.endpointURL);
    this.AWS.config.update({ endpoint: this.endpointURL });
  } else {
    debug('Getting default dynamodb document client');
  }
  this.dynamoDocumentClient = new this.AWS.DynamoDB.DocumentClient();
  return this.dynamoDocumentClient;
};

Dynamoose.prototype.setDocumentClient = function(documentClient) {
  debug('Setting dynamodb document client');
  this.dynamoDocumentClient = documentClient;
};

Dynamoose.prototype.ddb = function () {
  if(this.dynamoDB) {
    return this.dynamoDB;
  }

  if(this.endpointURL) {
    debug('Setting DynamoDB to %s', this.endpointURL);
    this.dynamoDB = createLocalDb(this.endpointURL);
  } else {
    debug('Getting default DynamoDB');
    this.dynamoDB = new this.AWS.DynamoDB({
      httpOptions: {
        agent: new https.Agent({
          rejectUnauthorized: true,
          keepAlive: true
        })
      }
    });
  }
  return this.dynamoDB;
};

Dynamoose.prototype.setDefaults = function (options) {

  for(const key in this.defaults) {
    options[key] = (typeof options[key] === 'undefined') ? this.defaults[key] : options[key];
  }

  this.defaults = options;
};

Dynamoose.prototype.Schema = Schema;
Dynamoose.prototype.Table = require('./Table');
Dynamoose.prototype.Dynamoose = Dynamoose;

Dynamoose.prototype.setDDB = function (ddb) {
  debug("Setting custom DDB");
  this.dynamoDB = ddb;
};
Dynamoose.prototype.revertDDB = function () {
  debug("Reverting to default DDB");
  this.dynamoDB = null;
};

Dynamoose.prototype.transaction = async function(items, options, next) {
  debugTransaction('Run Transaction');
  const deferred = Q.defer();
  let dbClient = this.documentClient();
  let DynamoDBSet = dbClient.createSet([1, 2, 3]).constructor;

  options = options || {};
  if(typeof options === 'function') {
    next = options;
    options = {};
  }

  if(!Array.isArray(items) || items.length === 0) {
    deferred.reject(new errors.TransactionError('Items required to run transaction'));
    return deferred.promise.nodeify(next);
  }

  items = await Promise.all(items);
  let transactionReq = {
    TransactItems: items.map(item => {
      const returnItem = {...item};
      delete returnItem.$__;
      return returnItem;
    })
  };
  let transactionMethodName;
  if (options.type) {
    debugTransaction("Using custom transaction method");
    if (options.type === "get") {
      transactionMethodName = "transactGetItems";
    } else if (options.type === "write") {
      transactionMethodName = "transactWriteItems";
    } else {
      deferred.reject(new errors.TransactionError('Invalid type option, please pass in "get" or "write"'));
      return deferred.promise.nodeify(next);
    }
  } else {
    debugTransaction("Using predetermined transaction method");
    transactionMethodName = items.map(obj => Object.keys(obj)[0]).every(key => key === "Get") ? "transactGetItems" : "transactWriteItems";
  }
  debugTransaction(`Using transaction method: ${transactionMethodName}`);

  const transact = () => {
    debugTransaction('transact', transactionReq);
    this.dynamoDB[transactionMethodName](transactionReq, function(err, data) {
      if(err) {
        debugTransaction(`Error returned by ${transactionMethodName}`, err);
        return deferred.reject(err);
      }

      debugTransaction(`${transactionMethodName} response`, data);

      if(!data.Responses) {
        return deferred.resolve();
      }

      return deferred.resolve(data.Responses.map(function (item, index) {
        let model;
        const TheModel = items[index].$__.newModel$;
        const TheModel$ = TheModel.$__;
        const schema = TheModel$.schema;
        Object.keys(item).forEach(function (prop) {
          if (item[prop] instanceof DynamoDBSet) {
            item[prop] = item[prop].values;
          }
        });

        model = new TheModel();
        model.$__.isNew = false;
        // Destruct 'item' DynamoDB's returned structure.
        schema.parseDynamo(model, item.Item);
        debugTransaction(`${transactionMethodName} parsed model`, model);
        return model;
      }).filter((item, index) => {
          const TheModel = items[index].$__.newModel$;
          const TheModel$ = TheModel.$__;
          const schema = TheModel$.schema;

          return !(schema.expires && schema.expires.returnExpiredItems === false && item[schema.expires.attribute] && item[schema.expires.attribute] < new Date());
      }));
    });
  }

  if (options.returnRequest) {
    deferred.resolve(transactionReq);
  } else if (items.some(item => item.$__.newModel$.$__.table.options.waitForActive)) {
    const waitForActivePromises = Promise.all(items.filter(item => item.$__.newModel$.$__.table.options.waitForActive).map(item => item.$__.newModel$.$__.table.waitForActive()));
    waitForActivePromises.then(transact).catch(deferred.reject);
  } else {
    transact();
  }
  return deferred.promise.nodeify(next);
}

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


<commit_before>'use strict'

var debug = require('debug-log')('galileo')
var extend = require('xtend')
var helpers = require('./helpers')
var Queue = require('./queue')
var url = require('url')
var util = require('util')

module.exports = function Agent (serviceToken, environment, options) {
  // ensure agent key exists
  if (!serviceToken) {
    throw new Error('a service token is required, visit: ' +
      'https://galileo.mashape.com/ to obtain one')
  }

  // ensure instance type
  if (!(this instanceof Agent)) {
    return new Agent(serviceToken, environment, options)
  }

  // this alias
  var self = this

  // no environment specified
  if (typeof environment === 'object') {
    options = environment
    environment = null
  }

  // setup options with defaults
  self.opts = extend({
    logBody: false, // LOG_BODY agent spec
    failLog: '/dev/null', // FAIL_LOG agent spec
    failLogName: 'galileo-agent-errors.log', // FAIL_LOG agent spec
    limits: {
      bodySize: 1000, // bytes
      retry: 2, // RETRY_COUNT agent spec
      retryTime: 5, // seconds
      flush: 5, // seconds, FLUSH_TIMEOUT agent spec
      connection: 30 // seconds, CONNECTION_TIMEOUT agent spec
    },
    queue: { // QUEUE_SIZE agent spec
      batch: 1, // number in a batch, if >1 switches path; `single` to `batch`
      entries: 100 // number of entries per ALF record
    },
    collector: {
      host: 'collector.galileo.next.mashape.com', // HOST agent spec
      port: 443, // PORT agent spec
      path: '/1.1.0/single',
      ssl: true
    }

  }, options)
  debug('[agent] plugin options: %s, %s. %s', JSON.stringify(self.opts, null, ' '), serviceToken, environment)

  // setup request queue
  this.queue = new Queue(serviceToken, environment, self.opts)

  // API Recorder Middleware
  // TODO use tamper or tamper-esque method to get raw body
  //      to determine raw content size to get infer compression size
  return function (req, res, next) {
    var reqReceived = new Date()
    var reqEndFired = false
    // assign clientIpAddress for each call
    self.clientIPAddress = helpers.getClientAddress(req)

    // body container
    var bytes = {
      req: 0,
      res: 0
    }

    var bodies = {
      req: {
        size: 0,
        base64: ''
      },

      res: {
        size: 0,
        base64: ''
      }
    }

    // buffer container
    var chunked = {
      req: [],
      res: []
    }

    // grab the request body
    if (self.opts.logBody) {
      req.on('data', function (chunk) {
        bytes.req += chunk.length

        if (bytes.req <= self.opts.limits.bodySize) {
          chunked.req.push(chunk)
        }
      })
    }

    // construct the request body
    if (self.opts.logBody) {
      req.on('end', function () {
        reqEndFired = true
        var body = Buffer.concat(chunked.req)
        bodies.req.size = body.length
        bodies.req.base64 = body ? body.toString('base64') : ''
      })
    }

    // store original methods for later use
    var func = {
      end: res.end,
      write: res.write
    }

    // override node's http.ServerResponse.write method
    res.write = function (chunk, encoding) {
      // call the original http.ServerResponse.write method
      func.write.call(res, chunk, encoding)
      bytes.res += chunk.length

      if (bytes.res <= self.opts.limits.bodySize) {
        chunked.res.push(chunk)
      }
    }

    // override node's http.ServerResponse.end method
    res.end = function (data, encoding) {
      // call the original http.ServerResponse.end method
      func.end.call(res, data, encoding)

      if (chunked.res.length) {
        chunked.res = chunked.res.map(function (chunk) {
          if (chunk instanceof Buffer) {
            return chunk
          }
          return new Buffer(chunk)
        })
        data = Buffer.concat(chunked.res)
      }

      // construct body
      bodies.res.size = data ? data.length : 0
      bodies.res.base64 = bodies.res.size && data ? data.toString('base64') : ''

      var agentResStartTime = new Date()
      var reqHeadersArr = helpers.objectToArray(req.headers)

      var resHeaders = helpers.parseResponseHeaderString(res._header)

      var resContentLength = parseInt(helpers.getHeaderValue(resHeaders.headersArr, 'content-length', 0), 10)
      var resBodySize = resContentLength === 0 && bodies.res.size > 0 ? bodies.res.size : resContentLength

      var reqContentLength = parseInt(helpers.getHeaderValue(reqHeadersArr, 'content-length', 0), 10)
      var reqBodySize = reqContentLength === 0 && bodies.req.size > 0 ? bodies.req.size : reqContentLength

      var waitTime = agentResStartTime.getTime() - reqReceived.getTime()
      var protocol = req.connection.encrypted ? 'https' : 'http'

      var entry = {
        time: waitTime, // TODO
        startedDateTime: agentResStartTime.toISOString(),

        request: {
          method: req.method,
          url: util.format('%s://%s%s', protocol, req.headers.host, req.url),
          httpVersion: 'HTTP/' + req.httpVersion,
          queryString: helpers.objectToArray(url.parse(req.url, true).query),
          headers: reqHeadersArr,
          headersSize: helpers.getReqHeaderSize(req),
          bodySize: reqBodySize,
          bodyCaptured: !!bodies.req.base64.length
        },

        response: {
          status: res.statusCode,
          statusText: resHeaders.statusText,
          httpVersion: resHeaders.version,
          headers: resHeaders.headersArr,
          headersSize: res._header ? new Buffer(res._header).length : 0,
          bodySize: resBodySize,
          bodyCaptured: !!bodies.res.base64.length
        },

        timings: {
          send: 0, // TODO
          wait: waitTime,
          receive: 0 // TODO
        }
      }
      if (self.clientIPAddress && self.clientIPAddress !== '') {
        entry.clientIPAddress = self.clientIPAddress
      }
      if (helpers.getServerAddress() && helpers.getServerAddress() !== '') {
        entry.serverIPAddress = helpers.getServerAddress()
      }
      if (self.opts.logBody && bodies.req.base64.length) {
        entry.request.postData = {
          mimeType: req.headers['content-type'],
          text: bodies.req.base64,
          encoding: 'base64'
        }
      }
      if (self.opts.logBody && bodies.res.base64.length) {
        var contentType = 'text/plain'
        if (res._header && res._header.indexOf('Content-Type:')) {
          contentType = res._header.split('Content-Type: ')[1].split('\r\n')[0]
        }
        entry.response.content = {
          mimeType: contentType,
          text: bodies.res.base64,
          encoding: 'base64'
        }
      }

      debug('[agent] triggered on [%s] %s %s', res.statusCode, entry.request.method, entry.request.url)

      // send to queue
      if (self.opts.logBody && !reqEndFired) { // only run this if req.on('end') has not fired yet
        // for some reason, req.on('end', fn) is being fired after res.end(fn)
        // this event is here to make sure the request body is being logged
        req.on('end', function () {
          if (bodies.req.base64.length) {
            entry.request.postData = {
              mimeType: req.headers['content-type'],
              text: bodies.req.base64,
              encoding: 'base64'
            }
            entry.request.bodyCaptured = true
            reqContentLength = parseInt(helpers.getHeaderValue(reqHeadersArr, 'content-length', 0), 10)
            reqBodySize = reqContentLength === 0 && bodies.req.size > 0 ? bodies.req.size : reqContentLength
            entry.request.bodySize = reqBodySize
          }
          reqEndFired = false // reset flag
          self.queue.push(entry)
        })
      } else {
        reqEndFired = false // reset flag
        self.queue.push(entry)
      }
    }

    if (typeof next === 'function') {
      next()
    }
  }
}
<commit_msg>fix(defaults): correcting errant defaults<commit_after>'use strict'

var debug = require('debug-log')('galileo')
var extend = require('xtend')
var helpers = require('./helpers')
var Queue = require('./queue')
var url = require('url')
var util = require('util')

module.exports = function Agent (serviceToken, environment, options) {
  // ensure agent key exists
  if (!serviceToken) {
    throw new Error('a service token is required, visit: ' +
      'https://galileo.mashape.com/ to obtain one')
  }

  // ensure instance type
  if (!(this instanceof Agent)) {
    return new Agent(serviceToken, environment, options)
  }

  // this alias
  var self = this

  // no environment specified
  if (typeof environment === 'object') {
    options = environment
    environment = null
  }

  // setup options with defaults
  self.opts = extend({
    logBody: false, // LOG_BODY agent spec
    failLog: '/dev/null', // FAIL_LOG agent spec
    failLogName: 'galileo-agent-errors.log', // FAIL_LOG agent spec
    limits: {
      bodySize: 10000, // bytes
      retry: 0, // RETRY_COUNT agent spec
      retryTime: 5, // seconds
      flush: 2, // seconds, FLUSH_TIMEOUT agent spec
      connection: 30 // seconds, CONNECTION_TIMEOUT agent spec
    },
    queue: { // QUEUE_SIZE agent spec
      batch: 1, // number in a batch, if >1 switches path; `single` to `batch`
      entries: 1000 // number of entries per ALF record
    },
    collector: {
      host: 'collector.galileo.mashape.com', // HOST agent spec
      port: 443, // PORT agent spec
      path: '/1.1.0/single',
      ssl: true
    }

  }, options)
  debug('[agent] plugin options: %s, %s. %s', JSON.stringify(self.opts, null, ' '), serviceToken, environment)

  // setup request queue
  this.queue = new Queue(serviceToken, environment, self.opts)

  // API Recorder Middleware
  // TODO use tamper or tamper-esque method to get raw body
  //      to determine raw content size to get infer compression size
  return function (req, res, next) {
    var reqReceived = new Date()
    var reqEndFired = false
    // assign clientIpAddress for each call
    self.clientIPAddress = helpers.getClientAddress(req)

    // body container
    var bytes = {
      req: 0,
      res: 0
    }

    var bodies = {
      req: {
        size: 0,
        base64: ''
      },

      res: {
        size: 0,
        base64: ''
      }
    }

    // buffer container
    var chunked = {
      req: [],
      res: []
    }

    // grab the request body
    if (self.opts.logBody) {
      req.on('data', function (chunk) {
        bytes.req += chunk.length

        if (bytes.req <= self.opts.limits.bodySize) {
          chunked.req.push(chunk)
        }
      })
    }

    // construct the request body
    if (self.opts.logBody) {
      req.on('end', function () {
        reqEndFired = true
        var body = Buffer.concat(chunked.req)
        bodies.req.size = body.length
        bodies.req.base64 = body ? body.toString('base64') : ''
      })
    }

    // store original methods for later use
    var func = {
      end: res.end,
      write: res.write
    }

    // override node's http.ServerResponse.write method
    res.write = function (chunk, encoding) {
      // call the original http.ServerResponse.write method
      func.write.call(res, chunk, encoding)
      bytes.res += chunk.length

      if (bytes.res <= self.opts.limits.bodySize) {
        chunked.res.push(chunk)
      }
    }

    // override node's http.ServerResponse.end method
    res.end = function (data, encoding) {
      // call the original http.ServerResponse.end method
      func.end.call(res, data, encoding)

      if (chunked.res.length) {
        chunked.res = chunked.res.map(function (chunk) {
          if (chunk instanceof Buffer) {
            return chunk
          }
          return new Buffer(chunk)
        })
        data = Buffer.concat(chunked.res)
      }

      // construct body
      bodies.res.size = data ? data.length : 0
      bodies.res.base64 = bodies.res.size && data ? data.toString('base64') : ''

      var agentResStartTime = new Date()
      var reqHeadersArr = helpers.objectToArray(req.headers)

      var resHeaders = helpers.parseResponseHeaderString(res._header)

      var resContentLength = parseInt(helpers.getHeaderValue(resHeaders.headersArr, 'content-length', 0), 10)
      var resBodySize = resContentLength === 0 && bodies.res.size > 0 ? bodies.res.size : resContentLength

      var reqContentLength = parseInt(helpers.getHeaderValue(reqHeadersArr, 'content-length', 0), 10)
      var reqBodySize = reqContentLength === 0 && bodies.req.size > 0 ? bodies.req.size : reqContentLength

      var waitTime = agentResStartTime.getTime() - reqReceived.getTime()
      var protocol = req.connection.encrypted ? 'https' : 'http'

      var entry = {
        time: waitTime, // TODO
        startedDateTime: agentResStartTime.toISOString(),

        request: {
          method: req.method,
          url: util.format('%s://%s%s', protocol, req.headers.host, req.url),
          httpVersion: 'HTTP/' + req.httpVersion,
          queryString: helpers.objectToArray(url.parse(req.url, true).query),
          headers: reqHeadersArr,
          headersSize: helpers.getReqHeaderSize(req),
          bodySize: reqBodySize,
          bodyCaptured: !!bodies.req.base64.length
        },

        response: {
          status: res.statusCode,
          statusText: resHeaders.statusText,
          httpVersion: resHeaders.version,
          headers: resHeaders.headersArr,
          headersSize: res._header ? new Buffer(res._header).length : 0,
          bodySize: resBodySize,
          bodyCaptured: !!bodies.res.base64.length
        },

        timings: {
          send: 0, // TODO
          wait: waitTime,
          receive: 0 // TODO
        }
      }
      if (self.clientIPAddress && self.clientIPAddress !== '') {
        entry.clientIPAddress = self.clientIPAddress
      }
      if (helpers.getServerAddress() && helpers.getServerAddress() !== '') {
        entry.serverIPAddress = helpers.getServerAddress()
      }
      if (self.opts.logBody && bodies.req.base64.length) {
        entry.request.postData = {
          mimeType: req.headers['content-type'],
          text: bodies.req.base64,
          encoding: 'base64'
        }
      }
      if (self.opts.logBody && bodies.res.base64.length) {
        var contentType = 'text/plain'
        if (res._header && res._header.indexOf('Content-Type:')) {
          contentType = res._header.split('Content-Type: ')[1].split('\r\n')[0]
        }
        entry.response.content = {
          mimeType: contentType,
          text: bodies.res.base64,
          encoding: 'base64'
        }
      }

      debug('[agent] triggered on [%s] %s %s', res.statusCode, entry.request.method, entry.request.url)

      // send to queue
      if (self.opts.logBody && !reqEndFired) { // only run this if req.on('end') has not fired yet
        // for some reason, req.on('end', fn) is being fired after res.end(fn)
        // this event is here to make sure the request body is being logged
        req.on('end', function () {
          if (bodies.req.base64.length) {
            entry.request.postData = {
              mimeType: req.headers['content-type'],
              text: bodies.req.base64,
              encoding: 'base64'
            }
            entry.request.bodyCaptured = true
            reqContentLength = parseInt(helpers.getHeaderValue(reqHeadersArr, 'content-length', 0), 10)
            reqBodySize = reqContentLength === 0 && bodies.req.size > 0 ? bodies.req.size : reqContentLength
            entry.request.bodySize = reqBodySize
          }
          reqEndFired = false // reset flag
          self.queue.push(entry)
        })
      } else {
        reqEndFired = false // reset flag
        self.queue.push(entry)
      }
    }

    if (typeof next === 'function') {
      next()
    }
  }
}
<|endoftext|>


<commit_before>var conf = require('./package.json');
var gui = require('nw.gui');

(function(apiRoot) {
    var Tempo = {};

    function noop() {}
    function logop(req) {console.log(req.response);}

    var authed = false;
    Tempo.authenticate = function(cb) {
        authed = false;

        var newWindow = gui.Window.open(apiRoot+"login.jsp", {
            frame: true,
            toolbar: false,
            width: 850,
            height: 500,
            'always-on-top': true,
            show: true,
            resizable: true
        });
        newWindow.cookies.onChanged.addListener(function(cookieChanged) {
            if (cookieChanged.cause === "overwrite") {
                var cookie = cookieChanged.cookie;
                if (cookie.name === "JSESSIONID") { //Good indicator of a login
                    newWindow.close(true);
                    authed = true;
                    cb();
                }
            }
        });
    };

    Tempo.authStatus = function() {
        return authed;
    };

    var userEndpoint = apiRoot+"rest/tempo-rest/2.0/user";
    Tempo.getActiveUser = function(cb) {
        WinJS.xhr({
            type: 'GET',
            url: userEndpoint,
            responseType: 'json',
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    var issueEndpoint = apiRoot+"rest/api/2/issue/";
    Tempo.getIssue = function (key, cb) {
        var issueUrl = issueEndpoint+key;

        WinJS.xhr({
            type: 'GET',
            url: issueUrl,
            responseType: 'json',
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    var newIssueEndpoint = apiRoot+"rest/api/2/issue";
    Tempo.postNewIssue = function (fields, cb) {
        var request = {};
        request.fields = fields;

        WinJS.xhr({
            type: 'POST',
            url: newIssueEndpoint,
            responseType: 'json',
            data: request
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    Tempo.addTime = function(key, time, message, cb) {
        var addTimeEndpoint = issueEndpoint+key+"/worklog";
        var timekey = "timeSpentSeconds";
        if (time instanceof String) {
            timekey = "timeSpent";
        }

        var request = {};
        request[timekey] = time;
        request.comment = message;

        WinJS.xhr({
            type: 'POST',
            url: addTimeEndpoint,
            responseType: 'json',
            data: request
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    if (window) {
        window.Tempo = Tempo;
    }

    return Tempo;
})(conf.settings.jira);<commit_msg>content type headers<commit_after>var conf = require('./package.json');
var gui = require('nw.gui');

(function(apiRoot) {
    var Tempo = {};

    function noop() {}
    function logop(req) {console.log(req.response);}

    var authed = false;
    Tempo.authenticate = function(cb) {
        authed = false;

        var newWindow = gui.Window.open(apiRoot+"login.jsp", {
            frame: true,
            toolbar: false,
            width: 850,
            height: 500,
            'always-on-top': true,
            show: true,
            resizable: true
        });
        newWindow.cookies.onChanged.addListener(function(cookieChanged) {
            if (cookieChanged.cause === "overwrite") {
                var cookie = cookieChanged.cookie;
                if (cookie.name === "JSESSIONID") { //Good indicator of a login
                    newWindow.close(true);
                    authed = true;
                    cb();
                }
            }
        });
    };

    Tempo.authStatus = function() {
        return authed;
    };

    var userEndpoint = apiRoot+"rest/tempo-rest/2.0/user";
    Tempo.getActiveUser = function(cb) {
        WinJS.xhr({
            type: 'GET',
            url: userEndpoint,
            responseType: 'json',
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    var issueEndpoint = apiRoot+"rest/api/2/issue/";
    Tempo.getIssue = function (key, cb) {
        var issueUrl = issueEndpoint+key;

        WinJS.xhr({
            type: 'GET',
            url: issueUrl,
            responseType: 'json',
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    var newIssueEndpoint = apiRoot+"rest/api/2/issue";
    Tempo.postNewIssue = function (fields, cb) {
        var request = {};
        request.fields = fields;

        WinJS.xhr({
            type: 'POST',
            url: newIssueEndpoint,
            responseType: 'json',
            data: request,
            headers: { "Content-type": "application/json" }
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    Tempo.addTime = function(key, time, message, cb) {
        var addTimeEndpoint = issueEndpoint+key+"/worklog";
        var timekey = "timeSpentSeconds";
        if (time instanceof String) {
            timekey = "timeSpent";
        }

        var request = {};
        request[timekey] = time;
        request.comment = message;

        WinJS.xhr({
            type: 'POST',
            url: addTimeEndpoint,
            responseType: 'json',
            data: request,
            headers: { "Content-type": "application/json" }
        }).done(
            function(req) {
                cb(req.response);
            }, logop, noop
        ); //We only care about success
    };

    if (window) {
        window.Tempo = Tempo;
    }

    return Tempo;
})(conf.settings.jira);<|endoftext|>


<commit_before>// include gulp
var gulp = require('gulp');

// include plug-ins
//var gulpif = require('gulp-if');
//var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
//var gutil = require('gulp-util');

//buildConfig:
var buildConf = require('./build.json');

/**********************
  Linting files
**********************/

// JS and coffee lint task
gulp.task('lint', function() {
  var jshint = require('gulp-jshint');
  var stylish = require('jshint-stylish');
  var coffeelint = require('gulp-coffeelint');
  //Js linting.
  gulp
    .src('./lib/*/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter(stylish));
  //Coffee linting
  gulp
    .src('./lib/*/*.coffee')
    .pipe(coffeelint())
    .pipe(coffeelint.reporter());
});

//Eslint

gulp.task('eslint', function() {
  //gulp eslint 2>lint/lintErrors.txt
  var eslint = require('gulp-eslint');
  var options = {
    "globals": {
      "jQuery": false,
      "$": true,
      "require": true,
      "Backbone": true,
      "Fmk": true,
      "_": true,
      "Promise": true,
      "module": true,
    },
    "env": {
      "browser": true,
      "node": true
    },
    rules: {
      "valid-jsdoc": [2, {
        "prefer": {
          "return": "returns"
        },
        "requireParamDescription": true
      }],
      "quotes": [0]
    }
  };
  var format = "compact"; //"compact", "checkstyle", "jslint-xml", "junit" and "tap".
  gulp
    .src('./lib/*/*.js')
    .pipe(eslint(options))
  //.pipe(eslint.format(undefined, process.stdout))
  //.pipe(eslint.failOnError())
  .pipe(eslint.formatEach(format, process.stderr));
  //.on('error', gutil.log);
});

/*********************
Documentation generation using jsDoc
***/
// JS and coffee lint task
gulp.task('jsdoc', function() {
  var jsdoc = require('gulp-jsdoc');
  var infos = require('./package.json');
  var name = 'focus';
  //Js linting.
  gulp.src([
    './lib/helpers/binder_helper.js',
    "lib/views/consult-edit-view.js",
    "lib/views/core-view.js",
    "lib/views/index.js",
    "lib/views/search-view.js"
    ])
    .pipe(jsdoc.parser(infos, name))
    .pipe(jsdoc.generator('./jsDoc/'));
});
var concat = require("gulp-concat");

gulp.task("markdox", function(){

  var markdox = require("gulp-markdox");

  gulp.src([
    './lib/helpers/binder_helper.js'
    ])
    .pipe(markdox())
    .pipe(concat("doc.md"))
    .pipe(gulp.dest("./doc"));
});

/**********************
  Building css files
**********************/
gulp.task('style', function() {
  gulp.src('./lib/styles/*.css')
    .pipe(concat('focus.css'))
    .pipe(gulp.dest('./example/app/css/'))
    .pipe(gulp.dest('./dist/'))
    .pipe(gulp.dest(buildConf.spaDirectory));
});
/**********************
  Building js files
**********************/

gulp.task('browserify', function(){
  var babelify = require("babelify"); //es6
  var browserify = require('browserify'); //build the source
  var source = require('vinyl-source-stream');
    var literalify = require('literalify');
    return browserify(({
        entries: ['./index.js'],
        extensions: ['.jsx'],
        standalone: "focus"
      }))
      .transform(
        {global:true},
        literalify.configure({
        react: 'window.React'
      }))
      .transform(babelify)
      .bundle()
      //Pass desired output filename to vinyl-source-stream
      .pipe(source("focus-"+require('./package.json').version+".js"))
      .pipe(gulp.dest('./dist/'));
});

//Grouping build tasks.
//Async build
gulp.task('build', ['style', 'browserify'], function() {

});
/*gulp.task('build', function (callback) {
    var runSequence = require('run-sequence');
    console.log('runSequence');
    runSequence('infos','css-build','templates', ['browser-build', 'node-build'],callback);
});*/

/**********************
  Example templates
**********************/

//Gulp build example templates into a template.js file for the example.
gulp.task('templatesExample', function() {
  var handlebars = require('gulp-handlebars');
  var defineModule = require('gulp-define-module');
  var declare = require('gulp-declare');

  gulp.src(['example/app/templates/*.hbs', "lib/templates/*.hbs"])
    .pipe(handlebars())
    .pipe(defineModule('plain'))
    .pipe(declare({
      namespace: 'Example.templates'
    }))
    .pipe(concat('templates.js'))
    .pipe(gulp.dest('example/app/js/'));
});

//Build focus components into the other repositories.
gulp.task('focus-component', function() {
  var react = require('gulp-react');
  var babel = require('gulp-babel');
  var gulpif = require('gulp-if');
  gulp.src(['package.json','index.js','{component,application,helper,network,router,store,util}/**/*'])
  .pipe(gulpif(/[.]js$/, react({harmony: true})))
  .pipe(gulpif(/[.]js$/, babel()))
  .pipe(gulp.dest('../focus-components/node_modules/focus/'))
  .pipe(gulp.dest('../rodolphe/app/node_modules/focus/'));
});

/**********************
  Documentation
**********************/
/*
gulp.task('doc', function() {
  var docco = require("gulp-docco");
  gulp.src(['./lib/main.js', './lib/helpers/*','./lib/models/*', './lib/views/*'])
    .pipe(docco({layout: "linear"}))
    //.pipe(gulpif(/[*helpers]$/, gulp.dest('./doc/helpers')))
    .pipe(gulpif(/[*models]$/, gulp.dest('./doc/models')))
    .pipe(gulpif(/[*views]$/, gulp.dest('./doc/views')));
});

*/
/**********************
  Local example server
**********************/

var browserSync = require('browser-sync');
var reload = browserSync.reload;
// Watch Files For Changes & Reload
gulp.task('serve', ['build'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['example/app']
    }
  });

  gulp.watch(['lib/**/*.{json,js, coffee}'],['browserify',reload]);
  gulp.watch(['lib/styles/*.{styl,css}'], ['style', reload]);
  gulp.watch(['package.json'], ['browserify',reload]);
  //gulp.watch(['app/scripts/**/*.js'], jshint);
  //gulp.watch(['app/images/**/*'], reload);
});

// The default task (called when you run `gulp` from cli)
gulp.task('default', ['build']);
<commit_msg>[build] Add build into external application.<commit_after>// include gulp
var gulp = require('gulp');

// include plug-ins
//var gulpif = require('gulp-if');
//var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
//var gutil = require('gulp-util');

//buildConfig:
var buildConf = require('./build.json');

/**********************
  Linting files
**********************/

// JS and coffee lint task
gulp.task('lint', function() {
  var jshint = require('gulp-jshint');
  var stylish = require('jshint-stylish');
  var coffeelint = require('gulp-coffeelint');
  //Js linting.
  gulp
    .src('./lib/*/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter(stylish));
  //Coffee linting
  gulp
    .src('./lib/*/*.coffee')
    .pipe(coffeelint())
    .pipe(coffeelint.reporter());
});

//Eslint

gulp.task('eslint', function() {
  //gulp eslint 2>lint/lintErrors.txt
  var eslint = require('gulp-eslint');
  var options = {
    "globals": {
      "jQuery": false,
      "$": true,
      "require": true,
      "Backbone": true,
      "Fmk": true,
      "_": true,
      "Promise": true,
      "module": true,
    },
    "env": {
      "browser": true,
      "node": true
    },
    rules: {
      "valid-jsdoc": [2, {
        "prefer": {
          "return": "returns"
        },
        "requireParamDescription": true
      }],
      "quotes": [0]
    }
  };
  var format = "compact"; //"compact", "checkstyle", "jslint-xml", "junit" and "tap".
  gulp
    .src('./lib/*/*.js')
    .pipe(eslint(options))
  //.pipe(eslint.format(undefined, process.stdout))
  //.pipe(eslint.failOnError())
  .pipe(eslint.formatEach(format, process.stderr));
  //.on('error', gutil.log);
});

/*********************
Documentation generation using jsDoc
***/
// JS and coffee lint task
gulp.task('jsdoc', function() {
  var jsdoc = require('gulp-jsdoc');
  var infos = require('./package.json');
  var name = 'focus';
  //Js linting.
  gulp.src([
    './lib/helpers/binder_helper.js',
    "lib/views/consult-edit-view.js",
    "lib/views/core-view.js",
    "lib/views/index.js",
    "lib/views/search-view.js"
    ])
    .pipe(jsdoc.parser(infos, name))
    .pipe(jsdoc.generator('./jsDoc/'));
});
var concat = require("gulp-concat");

gulp.task("markdox", function(){

  var markdox = require("gulp-markdox");

  gulp.src([
    './lib/helpers/binder_helper.js'
    ])
    .pipe(markdox())
    .pipe(concat("doc.md"))
    .pipe(gulp.dest("./doc"));
});

/**********************
  Building css files
**********************/
gulp.task('style', function() {
  gulp.src('./lib/styles/*.css')
    .pipe(concat('focus.css'))
    .pipe(gulp.dest('./example/app/css/'))
    .pipe(gulp.dest('./dist/'))
    .pipe(gulp.dest(buildConf.spaDirectory));
});
/**********************
  Building js files
**********************/

gulp.task('browserify', function(){
  var babelify = require("babelify"); //es6
  var browserify = require('browserify'); //build the source
  var source = require('vinyl-source-stream');
    var literalify = require('literalify');
    return browserify(({
        entries: ['./index.js'],
        extensions: ['.jsx'],
        standalone: "focus"
      }))
      .transform(
        {global:true},
        literalify.configure({
        react: 'window.React'
      }))
      .transform(babelify)
      .bundle()
      //Pass desired output filename to vinyl-source-stream
      .pipe(source("focus-"+require('./package.json').version+".js"))
      .pipe(gulp.dest('./dist/'));
});

//Grouping build tasks.
//Async build
gulp.task('build', ['style', 'browserify'], function() {

});
/*gulp.task('build', function (callback) {
    var runSequence = require('run-sequence');
    console.log('runSequence');
    runSequence('infos','css-build','templates', ['browser-build', 'node-build'],callback);
});*/

/**********************
  Example templates
**********************/

//Gulp build example templates into a template.js file for the example.
gulp.task('templatesExample', function() {
  var handlebars = require('gulp-handlebars');
  var defineModule = require('gulp-define-module');
  var declare = require('gulp-declare');

  gulp.src(['example/app/templates/*.hbs', "lib/templates/*.hbs"])
    .pipe(handlebars())
    .pipe(defineModule('plain'))
    .pipe(declare({
      namespace: 'Example.templates'
    }))
    .pipe(concat('templates.js'))
    .pipe(gulp.dest('example/app/js/'));
});

//Build focus components into the other repositories.
gulp.task('focus-npm', function() {
  var react = require('gulp-react');
  var babel = require('gulp-babel');
  var gulpif = require('gulp-if');
  gulp.src(['package.json','index.js','{component,application,helper,network,router,store,util}/**/*'])
  .pipe(gulpif(/[.]js$/, react({harmony: true})))
  .pipe(gulpif(/[.]js$/, babel()))
  .pipe(gulp.dest('../focus-components/node_modules/focus/'))
  .pipe(gulp.dest('../rodolphe/app/node_modules/focus/'));
});

/**********************
  Documentation
**********************/
/*
gulp.task('doc', function() {
  var docco = require("gulp-docco");
  gulp.src(['./lib/main.js', './lib/helpers/*','./lib/models/*', './lib/views/*'])
    .pipe(docco({layout: "linear"}))
    //.pipe(gulpif(/[*helpers]$/, gulp.dest('./doc/helpers')))
    .pipe(gulpif(/[*models]$/, gulp.dest('./doc/models')))
    .pipe(gulpif(/[*views]$/, gulp.dest('./doc/views')));
});

*/
/**********************
  Local example server
**********************/

var browserSync = require('browser-sync');
var reload = browserSync.reload;
// Watch Files For Changes & Reload
gulp.task('serve', ['build'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['example/app']
    }
  });

  gulp.watch(['lib/**/*.{json,js, coffee}'],['browserify',reload]);
  gulp.watch(['lib/styles/*.{styl,css}'], ['style', reload]);
  gulp.watch(['package.json'], ['browserify',reload]);
  //gulp.watch(['app/scripts/**/*.js'], jshint);
  //gulp.watch(['app/images/**/*'], reload);
});

// The default task (called when you run `gulp` from cli)
gulp.task('default', ['build']);
<|endoftext|>


<commit_before>import React from 'react'
import { Flex, Container, Heading, Subhead } from 'rebass'
import { colors, mx, wk } from '../theme'

const tilt = n =>
  wk(`clip-path: polygon(0% ${100 - n}%, 100% 0, 100% ${n}%, 0 100%)`)
const Stripe = Flex.extend.attrs({
  align: 'center',
  justify: 'center',
  direction: 'column',
  p: [3, 0]
})`
  ${tilt(90)};
  background: ${colors.blue[5]} url('/map.svg') no-repeat;
  background-size: cover;
  background-position: center top;
  margin-top: -3rem;
  min-height: 24rem;
  ${mx[1]} {
    margin-top: -6rem;
    min-height: 75vh !important;
  }
`

const StripeContainer = Container.extend.attrs({
  maxWidth: 48 * 16,
  p: 4
})`
  text-align: center;
  z-index: 1;

  h2, h3 {
    color: ${colors.black};
  }
  mark {
    background-color: rgba(250, 247, 133, .85);
    color: ${colors.black};
    padding-left: .25em;
    padding-right: .25em;
  }
`

const Headline = Heading.extend.attrs({
  is: 'h2',
  f: 5,
  mt: 4,
  mb: 2,
  color: 'primary'
})`line-height: 1.25;`
const Subheadline = Subhead.extend.attrs({
  is: 'h3',
  f: [3, 4],
  mt: 0,
  mb: 1,
  color: 'muted'
})`
  font-weight: normal;
  line-height: 1.5;
`

export default () => (
  <Stripe id="more">
    <StripeContainer>
      <Headline f={[5, 6]} mt={0}>
        Hack Club brings coding clubs
        {' to '}
        high schools everywhere.
      </Headline>
      <Subheadline my={0}>
        We’re starting the computer science education students
        need.
      </Subheadline>
    </StripeContainer>
  </Stripe>
)
<commit_msg>Change stripe section to focus on metrics<commit_after>import React from 'react'
import { Flex, Container, Heading, Subhead } from 'rebass'
import { colors, mx, wk } from '../theme'

const tilt = n =>
  wk(`clip-path: polygon(0% ${100 - n}%, 100% 0, 100% ${n}%, 0 100%)`)
const Stripe = Flex.extend.attrs({
  align: 'center',
  justify: 'center',
  direction: 'column',
  p: [3, 0]
})`
  ${tilt(90)};
  background: ${colors.blue[5]} url('/map.svg') no-repeat;
  background-size: cover;
  background-position: center top;
  margin-top: -3rem;
  min-height: 24rem;
  ${mx[1]} {
    margin-top: -6rem;
    min-height: 75vh !important;
  }
`

const StripeContainer = Container.extend.attrs({
  maxWidth: 48 * 16,
  p: 4
})`
  text-align: center;
  z-index: 1;

  h2, h3 {
    color: ${colors.black};
  }
  mark {
    background-color: rgba(250, 247, 133, .85);
    color: ${colors.black};
    padding-left: .25em;
    padding-right: .25em;
  }
`

const Headline = Heading.extend.attrs({
  is: 'h2',
  f: 5,
  mt: 10,
  mb: 20,
  color: 'primary'
})`line-height: 1.345;`

const Subheadline = Subhead.extend.attrs({
  is: 'h3',
  f: [3, 4],
  mt: 0,
  mb: 0,
  color: 'muted'
})`
  font-weight: normal;
  line-height: 1.345;
`

export default () => (
  <Stripe id="more">
    <StripeContainer>
      <Headline f={[5, 6]} mt={0}>
        1% of US high schools. 35 states. 13 countries.
      </Headline>
      <Subheadline my={0}>

          Join the largest community of students building the class they wish
          they could take.

      </Subheadline>
    </StripeContainer>
  </Stripe>
)
<|endoftext|>


<commit_before>const EventEmitter = require('events').EventEmitter;
const request = require('request');
const https = require('https');
const http = require('http');
const utils = require('./utils');
const url = require('url');

const oldRequestGet = request.get;
const oldRequestPost = request.post;
const oldHttpsRequest = https.request;
const oldHttpRequest = http.request;

function httpModuleRequest(uri, callback, spy) {
  const thisRequest = new EventEmitter();
  const fakewebOptions = this.fakewebMatch(uri);
  const writeBuffers = [];

  thisRequest.setEncoding = () => {};
  thisRequest.setHeader = () => {};
  thisRequest.getHeader = () => {};

  thisRequest.end = () => {
    const requestBuffer = writeBuffers.length > 0 ? Buffer.concat(writeBuffers) : new Buffer(0);
    const requestBody = requestBuffer.toString('utf8');
    const thisResponse = new EventEmitter();

    // Request module checks against the connection object event emitter
    thisResponse.connection = thisResponse;
    thisResponse.pause = thisResponse.resume = () => {};
    thisResponse.setEncoding = () => {};
    thisResponse.pipe = (outputStream) => {
      outputStream.write(fakewebOptions.response(requestBody));
      outputStream.end();
      return outputStream; // support chaining
    };
    thisResponse.statusCode = utils.getStatusCode(fakewebOptions);
    thisResponse.headers = fakewebOptions.headers;

    if (fakewebOptions.contentType) {
      thisResponse.headers['content-type'] = fakewebOptions.contentType;
    }
    thisRequest.emit('response', thisResponse);

    if (callback) {
      callback(thisResponse);
    }

    spy.body = requestBody;
    thisResponse.emit('data', fakewebOptions.response(requestBody));
    thisResponse.emit('end');
    thisResponse.emit('close');
  };

  thisRequest.write = function requestWrite(buffer, encoding, cb) {
    if (buffer) {
      if (!Buffer.isBuffer(buffer)) {
        buffer = new Buffer(buffer, encoding);
      }

      writeBuffers.push(buffer);
    }
    if (cb) {
      cb();
    }
  };

  return thisRequest;
}

function requestGet(options, callback) {
  if (typeof options === 'string') {
    options = { uri: options };
  }

  const uri = options.uri || options.url;
  const followRedirect = options.followRedirect !== undefined ? options.followRedirect : true;
  if (this.interceptable(uri)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    const statusCode = utils.getStatusCode(fakewebOptions);

    if (statusCode >= 300 && statusCode < 400 && fakewebOptions.headers.Location && followRedirect) {
      const redirectTo = url.resolve(uri, fakewebOptions.headers.Location);
      return request.get({ uri: redirectTo }, callback);
    }

    const resp = { statusCode };
    resp.headers = fakewebOptions.headers;
    if (fakewebOptions.contentType) {
      resp.headers['content-type'] = fakewebOptions.contentType;
    }
    return callback(null, resp, fakewebOptions.response());
  }
  return oldRequestGet.call(request, options, callback);
}

function requestPost(options, callback) {
  if (typeof options === 'string') {
    options = { uri: options };
  }

  const uri = options.uri || options.url;
  if (this.interceptable(uri, 'POST')) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    fakewebOptions.spy.body = options.body;
    fakewebOptions.spy.form = options.form;

    const resp = { statusCode: utils.getStatusCode(fakewebOptions) };
    resp.headers = fakewebOptions.headers;
    if (fakewebOptions.contentType) {
      resp.headers['content-type'] = fakewebOptions.contentType;
    }
    return callback(null, resp, fakewebOptions.response(options.form));
  }
  return oldRequestPost.call(request, options, callback);
}

function httpsRequest(options, callback) {
  let uri = options;
  if (options.port) {
    uri = `https://${(options.hostname || options.host)}:${options.port}${options.path}`;
  } else if (options.path) {
    uri = `https://${(options.hostname || options.host)}${options.path}`;
  }
  if (this.interceptable(uri, options.method)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    return httpModuleRequest.call(this, uri, callback, fakewebOptions.spy);
  }
  return oldHttpsRequest.call(https, options, callback);
}

function httpRequest(options, callback) {
  let uri = options;
  if (options.port) {
    uri = `http://${(options.hostname || options.host)}:${options.port}${options.path}`;
  } else if (options.path) {
    uri = `http://${(options.hostname || options.host)}${options.path}`;
  }
  if (this.interceptable(uri, options.method)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    return httpModuleRequest.call(this, uri, callback, fakewebOptions.spy);
  }
  return oldHttpRequest.call(http, options, callback);
}

module.exports.httpRequest = httpRequest;
module.exports.httpsRequest = httpsRequest;
module.exports.requestGet = requestGet;
module.exports.requestPost = requestPost;
<commit_msg>Update overrides.js<commit_after>const EventEmitter = require('events').EventEmitter;
const request = require('request');
const https = require('https');
const http = require('http');
const utils = require('./utils');
const url = require('url');

const oldRequestGet = request.get;
const oldRequestPost = request.post;
const oldHttpsRequest = https.request;
const oldHttpRequest = http.request;

function httpModuleRequest(uri, callback, spy) {
  const thisRequest = new EventEmitter();
  const fakewebOptions = this.fakewebMatch(uri);
  const writeBuffers = [];

  thisRequest.setEncoding = () => {};
  thisRequest.setHeader = () => {};
  thisRequest.getHeader = () => {};
  thisRequest.setNoDelay = () => {};

  thisRequest.end = () => {
    const requestBuffer = writeBuffers.length > 0 ? Buffer.concat(writeBuffers) : new Buffer(0);
    const requestBody = requestBuffer.toString('utf8');
    const thisResponse = new EventEmitter();

    // Request module checks against the connection object event emitter
    thisResponse.connection = thisResponse;
    thisResponse.pause = thisResponse.resume = () => {};
    thisResponse.setEncoding = () => {};
    thisResponse.pipe = (outputStream) => {
      outputStream.write(fakewebOptions.response(requestBody));
      outputStream.end();
      return outputStream; // support chaining
    };
    thisResponse.statusCode = utils.getStatusCode(fakewebOptions);
    thisResponse.headers = fakewebOptions.headers;

    if (fakewebOptions.contentType) {
      thisResponse.headers['content-type'] = fakewebOptions.contentType;
    }
    thisRequest.emit('response', thisResponse);

    if (callback) {
      callback(thisResponse);
    }

    spy.body = requestBody;
    thisResponse.emit('data', fakewebOptions.response(requestBody));
    thisResponse.emit('end');
    thisResponse.emit('close');
  };

  thisRequest.write = function requestWrite(buffer, encoding, cb) {
    if (buffer) {
      if (!Buffer.isBuffer(buffer)) {
        buffer = new Buffer(buffer, encoding);
      }

      writeBuffers.push(buffer);
    }
    if (cb) {
      cb();
    }
  };

  return thisRequest;
}

function requestGet(options, callback) {
  if (typeof options === 'string') {
    options = { uri: options };
  }

  const uri = options.uri || options.url;
  const followRedirect = options.followRedirect !== undefined ? options.followRedirect : true;
  if (this.interceptable(uri)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    const statusCode = utils.getStatusCode(fakewebOptions);

    if (statusCode >= 300 && statusCode < 400 && fakewebOptions.headers.Location && followRedirect) {
      const redirectTo = url.resolve(uri, fakewebOptions.headers.Location);
      return request.get({ uri: redirectTo }, callback);
    }

    const resp = { statusCode };
    resp.headers = fakewebOptions.headers;
    if (fakewebOptions.contentType) {
      resp.headers['content-type'] = fakewebOptions.contentType;
    }
    return callback(null, resp, fakewebOptions.response());
  }
  return oldRequestGet.call(request, options, callback);
}

function requestPost(options, callback) {
  if (typeof options === 'string') {
    options = { uri: options };
  }

  const uri = options.uri || options.url;
  if (this.interceptable(uri, 'POST')) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    fakewebOptions.spy.body = options.body;
    fakewebOptions.spy.form = options.form;

    const resp = { statusCode: utils.getStatusCode(fakewebOptions) };
    resp.headers = fakewebOptions.headers;
    if (fakewebOptions.contentType) {
      resp.headers['content-type'] = fakewebOptions.contentType;
    }
    return callback(null, resp, fakewebOptions.response(options.form));
  }
  return oldRequestPost.call(request, options, callback);
}

function httpsRequest(options, callback) {
  let uri = options;
  if (options.port) {
    uri = `https://${(options.hostname || options.host)}:${options.port}${options.path}`;
  } else if (options.path) {
    uri = `https://${(options.hostname || options.host)}${options.path}`;
  }
  if (this.interceptable(uri, options.method)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    return httpModuleRequest.call(this, uri, callback, fakewebOptions.spy);
  }
  return oldHttpsRequest.call(https, options, callback);
}

function httpRequest(options, callback) {
  let uri = options;
  if (options.port) {
    uri = `http://${(options.hostname || options.host)}:${options.port}${options.path}`;
  } else if (options.path) {
    uri = `http://${(options.hostname || options.host)}${options.path}`;
  }
  if (this.interceptable(uri, options.method)) {
    const fakewebOptions = this.fakewebMatch(uri);
    fakewebOptions.spy.used = true;
    fakewebOptions.spy.useCount += 1;
    return httpModuleRequest.call(this, uri, callback, fakewebOptions.spy);
  }
  return oldHttpRequest.call(http, options, callback);
}

module.exports.httpRequest = httpRequest;
module.exports.httpsRequest = httpsRequest;
module.exports.requestGet = requestGet;
module.exports.requestPost = requestPost;
<|endoftext|>


<commit_before>'use strict';

var debug = require('debug')('thalisalti:acl');
var fast = require('./indexOf');

var noRole = 'public';
var NOTFOUND = -1;

/**
 * Acl
 * @typedef {Object} Salti.Acl
 * TODO:
 */

/**
 * Implements an Express middleware Authentication Filter
 * that validates an identity provided as a property on the request.connection object
 * against ACL represented as a json object.
 * @param {String} dbname - dbname known to provider
 * @param {Salti.Acl} inAcl - acl represented as an array of path.role.verb
 * @returns {Function} returns a handler of (req, res, next) to the middleware pipeline
 */
module.exports = function(dbname, inAcl) {

  if (!dbname || typeof dbname !== 'string') {
    throw new Error('invalid configuration - missing dbname');
  }

  if (!inAcl || !(inAcl instanceof Array)) {
    throw new Error('invalid configuration - inAcl is not an array');
  }

  var acl = JSON.parse(JSON.stringify(inAcl).replace(/{:db}/g, dbname));

  //path.role.verb
  var msg401 = { success: false, message: 'Unauthorized' };

  return function(req, res, next) {
    debug('method: %s url: %s path: %s', req.method, req.url, req.path);

    //using headers for validation of the acl engine
    var pskRole = req.connection.pskRole || noRole;
    debug('pskRole: %s', pskRole);

    //if the path is just '/' then use that, otherwise, find the path
    // //without the trailing '/'
    // var path = req.path === '/' ? '/'
    //       : req.path.slice(-1) === '/' ? req.path.slice(0, -1)
    //           : req.path;

    var roleExists = fast.indexOf(acl, pskRole, 'role');

    if (NOTFOUND === roleExists) {
      debug('unauthorized1: %s : %s', pskRole, req.path);
      return res.status(401).send(msg401);
    }

    var paths = acl[roleExists].paths;
    var pathExists = fast.indexOf(paths, req.path, 'path');

    if (NOTFOUND !== pathExists) {
      //verbs are just an array of strings
      var verbs = paths[pathExists].verbs;
      var verbExists = fast.indexOf(verbs, req.method);

      if (NOTFOUND === verbExists) {
        debug('unauthorized3: %s : %s', pskRole, req.path);
        return res.status(401).send(msg401);
      }

      //all good...
      next();
    }
    else {
      //simple regex on /dbname/word
      // /dbname/_local/thali_WORD

      /** Here's the rules -
       *     "path" :"/{:db}/{:id}",
    "verbs" :["GET"]
  }, {
    "path" :"/{:db}/{:id}/attachment",
    "verbs":["GET"]
  }, {
    "path" :"/{:db}/_local/thali_{:id}",  - this is semantically the same as the following /_local/id
    "verbs":["GET", "PUT", "DELETE"]
  }, {
    "path": "/{:db}/_local/{:id}",
    "verbs":["GET", "PUT", "DELETE"]
  }
       */

      //where into the special resource ID paths here...
      var path = req.path === '/' ? '/'
        : req.path.slice(-1) === '/' ? req.path.slice(0, -1)
          : req.path;

      debug('new path: %s', path);

      debug('unauthorized2: %s : %s', pskRole, req.path);
      return res.status(401).send(msg401);
    }

  };
};
<commit_msg>stuff<commit_after>'use strict';

var debug = require('debug')('thalisalti:acl');
var fast = require('./indexOf');

var noRole = 'public';
var NOTFOUND = -1;

/**
 * Acl
 * @typedef {Object} Salti.Acl
 * TODO:
 */

/**
 * Implements an Express middleware Authentication Filter
 * that validates an identity provided as a property on the request.connection object
 * against ACL represented as a json object.
 * @param {String} dbname - dbname known to provider
 * @param {Salti.Acl} inAcl - acl represented as an array of path.role.verb
 * @returns {Function} returns a handler of (req, res, next) to the middleware pipeline
 */
module.exports = function(dbname, inAcl) {

  if (!dbname || typeof dbname !== 'string') {
    throw new Error('invalid configuration - missing dbname');
  }

  if (!inAcl || !(inAcl instanceof Array)) {
    throw new Error('invalid configuration - inAcl is not an array');
  }

  var acl = JSON.parse(JSON.stringify(inAcl).replace(/{:db}/g, dbname));

  //path.role.verb
  var msg401 = { success: false, message: 'Unauthorized' };

  return function(req, res, next) {
    debug('method: %s url: %s path: %s', req.method, req.url, req.path);

    //using headers for validation of the acl engine
    var pskRole = req.connection.pskRole || noRole;
    debug('pskRole: %s', pskRole);

    //if the path is just '/' then use that, otherwise, find the path
    // //without the trailing '/'
    // var path = req.path === '/' ? '/'
    //       : req.path.slice(-1) === '/' ? req.path.slice(0, -1)
    //           : req.path;

    var roleExists = fast.indexOf(acl, pskRole, 'role');

    if (NOTFOUND === roleExists) {
      debug('unauthorized1: %s : %s', pskRole, req.path);
      return res.status(401).send(msg401);
    }

    var paths = acl[roleExists].paths;
    var pathExists = fast.indexOf(paths, req.path, 'path');

    if (NOTFOUND !== pathExists) {
      //verbs are just an array of strings
      var verbs = paths[pathExists].verbs;
      var verbExists = fast.indexOf(verbs, req.method);

      if (NOTFOUND === verbExists) {
        debug('unauthorized3: %s : %s', pskRole, req.path);
        return res.status(401).send(msg401);
      }

      //all good...
      next();
    }
    else {
      //simple regex on /dbname/word
      // /dbname/_local/thali_WORD

      /**
       * get the lastindex of '/'  then it should match either
       * /db   or /db/local
       *
       * if /db
       * match /{:db}/id  GET
       * match /{:db}/id/attachment   GET
       *
       * \/foobar\/([^_](.*\/attachment|.*))
       *
       *
       * else /db/local
       *
       * simple..
       *
       * (\/foobar\/_local\/([^\/]*))
       *
       * working: ([^/]+)/?(.*)$
       *
       *
       * \/foobar\/_local\/(.+)(?!\/)
       *
       * this will match and 2nd group check for xlashes
       * ****
       *
       * (\/foobar\/_local\/)(.+)
       *
       * (\/foobar\/_local\/)(.*(?!\/))
       *
       *
       * (\/foobar\/_local\/)((?!\/).+)
       * (\/foobar\/_local\/)((?!\/).+)
       *
       *
       * ////\/foobar\/_local\/((?!\/).+)
       *
       * since .../thali_ and id are same GET/PUT/DELETE just do
       * /db/local/id
       *
       *
       */

    /** Here's the rules -
*   "path" :"/{:db}/{:id}",
    "verbs" :["GET"]
  }, {
    "path" :"/{:db}/{:id}/attachment",
    "verbs":["GET"]
  }, {
    "path" :"/{:db}/_local/thali_{:id}",  - this is semantically the same as the following /_local/id
    "verbs":["GET", "PUT", "DELETE"]
  }, {
    "path": "/{:db}/_local/{:id}",
    "verbs":["GET", "PUT", "DELETE"]
  }
       */

      //where into the special resource ID paths here...
      var path = req.path === '/' ? '/'
        : req.path.slice(-1) === '/' ? req.path.slice(0, -1)
          : req.path;

      debug('new path: %s', path);

      debug('unauthorized2: %s : %s', pskRole, req.path);
      return res.status(401).send(msg401);
    }

  };
};
<|endoftext|>


<commit_before>/**
 * Randy is a country singer that sends notifications, drives a Trans Am, and is one serious bad ass.
 *
 * @package randy
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Dependencies
 */
var _       = require('underscore'),
    async   = require('async'),
    redis   = require('redis'),
    sio     = require('socket.io'),
    uuid    = require('node-uuid');

/**
 * Private methods
 */
function hash (obj, callback) {
    try {
        callback(null, JSON.stringify(obj));
    } catch (err) {
        callback(err);
    }
}

function parse (string, callback) {
    try {
        callback(null, JSON.parse(string));
    } catch (err) {
        callback(err);
    }
}

function emitter (socket, notice) {
    socket.emit('notice', notice);
}

// --------------------------------

/**
 * Constructor
 */
function Randy () {
    var self = this;

    // Setup
    self.ns         = 'randy';
    self.pub        = redis.createClient();
    self.sub        = redis.createClient();
    self.io         = null;
    self.sockets    = new Object(null);

    /**
     * Gets the socket (if available) for the specified target.
     *
     * @param {String} Target
     *
     * @return {Object}
     */
    function getSocket (target, callback) {
        if (target === null || target === '') {
            callback(null, self.io.sockets);
        } else {
            try {
                callback(null, self.sockets[target].socket);
            } catch (err) {
                callback(err);
            }
        }
    };

    /**
     * Subscription "message" event handler.
     *
     * @param {String} Channel
     * @param {String} Notice (JSON String)
     *
     * @return {void}
     */
    self.listener   = function (channel, data) {
        async.auto({
            parse:      function (callback) {
                parse(data, callback);
            },

            socket:     ['parse', function (callback, obj) {
                getSocket(obj.parse.target, callback);
            }],

            emit:       ['socket', function (callback, obj) {
                emitter(obj.socket, obj.parse);
            }]
        }, function (err) {
            console.log('Error: ' + err);
        });
    };

    /**
     * Socket.io "connection" event handler.
     *
     * @param {Object} Socket
     *
     * @return {void}
     */
    self.connection = function (socket) {

        /**
         * Registers a socket to begin recieving notifications.
         *
         * @param {Object} Generic data object
         *                      - id {Number, Required}
         *                      - type {String, Required}
         *
         * @return {void}
         */
        socket.on('register', function (data) {
            // ID
            var id = data.type + '::' + data.id;

            // Check existing
            if (typeof self.sockets[id] === 'undefined') {
                self.sockets[id] = {
                    id:         socket.id,
                    socket:     socket,
                    storage:    {
                        '982734981': {"persist":"false","target":"test::71351","message":"it works!"}
                    }
                };
            }

            // Emit from storage
            for (var item in self.sockets[id].storage) {
                self.sockets[id].socket.emit('notice', self.sockets[id].storage[item]);
            }
        });

        /**
         * Dismisses a persistent notification.
         *
         * @param {String} Notification id
         *
         * @return {void}
         */
        socket.on('dismiss', function (data) {
            console.dir(data);
        });

        /**
         * Registers a new event via the loopback interface.
         *
         * @param {Object} Notification object (see "register" method).
         *
         * @return {void}
         */
        socket.on('loopback', function (data) {
            self.register(data, function (err) {
                console.log(err);
            });
        });
    };
};

/**
 * Start listening for connections on the specified port.
 *
 * @param {Number} Port
 *
 * @return {Error}
 */
Randy.prototype.listen = function (port, callback) {
    var self = this;

    try {
        // Redis
        self.sub.subscribe(self.ns);
        self.sub.on('message', self.listener);

        // Socket.io
        self.io = sio.listen(port);
        self.io.sockets.on('connection', self.connection);
        callback(null);
    } catch (err) {
        callback(err);
    }
};

/**
 * Destroy the socket.io connection and redis subscription(s).
 *
 * @return {Error}
 */
Randy.prototype.destroy = function (callback) {
    var self = this;

    try {
        self.sub.unsubscribe();
        callback(null);
    } catch (err) {
        callback(err);
    }
};

/**
 * Registers a new notification.
 *
 * @param {Object} Notification
 *                  - message {String, Required}
 *                  - target {String, Default=null}
 *                  - persist {Boolean, Default=false}
 *
 * @return {Error}
 */
Randy.prototype.register = function (notice, callback) {
    var self = this;

    _.defaults(notice, {
        message:    null,
        target:     null,
        persist:    false
    });

    // If no message is specified, drop the request
    if (notice.message === null || notice.message === '') {
        callback('No message was specified.');
    }

    // Hash notice and publish to redis store
    async.auto({
        hash:       function (callback) {
            hash(notice, callback);
        },

        publish:    ['hash', function (callback, obj) {
            self.pub.publish(self.ns, obj.hash);
            callback();
        }]
    }, callback);
};

// --------------------------------
// --------------------------------

/**
 * Export
 */
module.exports = new Randy();<commit_msg>Fix "undefined" state of callback error<commit_after>/**
 * Randy is a country singer that sends notifications, drives a Trans Am, and is one serious bad ass.
 *
 * @package randy
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Dependencies
 */
var _       = require('underscore'),
    async   = require('async'),
    redis   = require('redis'),
    sio     = require('socket.io'),
    uuid    = require('node-uuid');

/**
 * Private methods
 */
function hash (obj, callback) {
    try {
        callback(null, JSON.stringify(obj));
    } catch (err) {
        callback(err);
    }
}

function parse (string, callback) {
    try {
        callback(null, JSON.parse(string));
    } catch (err) {
        callback(err);
    }
}

function emitter (socket, notice) {
    socket.emit('notice', notice);
}

// --------------------------------

/**
 * Constructor
 */
function Randy () {
    var self = this;

    // Setup
    self.ns         = 'randy';
    self.pub        = redis.createClient();
    self.sub        = redis.createClient();
    self.io         = null;
    self.sockets    = new Object(null);

    /**
     * Gets the socket (if available) for the specified target.
     *
     * @param {String} Target
     *
     * @return {Object}
     */
    function getSocket (target, callback) {
        if (target === null || target === '') {
            callback(null, self.io.sockets);
        } else {
            try {
                callback(null, self.sockets[target].socket);
            } catch (err) {
                callback(err);
            }
        }
    };

    /**
     * Subscription "message" event handler.
     *
     * @param {String} Channel
     * @param {String} Notice (JSON String)
     *
     * @return {void}
     */
    self.listener   = function (channel, data) {
        async.auto({
            parse:      function (callback) {
                parse(data, callback);
            },

            socket:     ['parse', function (callback, obj) {
                getSocket(obj.parse.target, callback);
            }],

            emit:       ['socket', function (callback, obj) {
                emitter(obj.socket, obj.parse);
            }]
        }, function (err) {
            console.log('Error: ' + err);
        });
    };

    /**
     * Socket.io "connection" event handler.
     *
     * @param {Object} Socket
     *
     * @return {void}
     */
    self.connection = function (socket) {

        /**
         * Registers a socket to begin recieving notifications.
         *
         * @param {Object} Generic data object
         *                      - id {Number, Required}
         *                      - type {String, Required}
         *
         * @return {void}
         */
        socket.on('register', function (data) {
            // ID
            var id = data.type + '::' + data.id;

            // Check existing
            if (typeof self.sockets[id] === 'undefined') {
                self.sockets[id] = {
                    id:         socket.id,
                    socket:     socket,
                    storage:    {
                        '982734981': {"persist":"false","target":"test::71351","message":"it works!"}
                    }
                };
            }

            // Emit from storage
            for (var item in self.sockets[id].storage) {
                self.sockets[id].socket.emit('notice', self.sockets[id].storage[item]);
            }
        });

        /**
         * Dismisses a persistent notification.
         *
         * @param {String} Notification id
         *
         * @return {void}
         */
        socket.on('dismiss', function (data) {
            console.dir(data);
        });

        /**
         * Registers a new event via the loopback interface.
         *
         * @param {Object} Notification object (see "register" method).
         *
         * @return {void}
         */
        socket.on('loopback', function (data) {
            self.register(data, function (err) {
                console.log(err);
            });
        });
    };
};

/**
 * Start listening for connections on the specified port.
 *
 * @param {Number} Port
 *
 * @return {Error}
 */
Randy.prototype.listen = function (port, callback) {
    var self = this;

    try {
        // Redis
        self.sub.subscribe(self.ns);
        self.sub.on('message', self.listener);

        // Socket.io
        self.io = sio.listen(port);
        self.io.sockets.on('connection', self.connection);
        callback(null);
    } catch (err) {
        callback(err);
    }
};

/**
 * Destroy the socket.io connection and redis subscription(s).
 *
 * @return {Error}
 */
Randy.prototype.destroy = function (callback) {
    var self = this;

    try {
        self.sub.unsubscribe();
        callback(null);
    } catch (err) {
        callback(err);
    }
};

/**
 * Registers a new notification.
 *
 * @param {Object} Notification
 *                  - message {String, Required}
 *                  - target {String, Default=null}
 *                  - persist {Boolean, Default=false}
 *
 * @return {Error}
 */
Randy.prototype.register = function (notice, callback) {
    var self = this;

    _.defaults(notice, {
        message:    null,
        target:     null,
        persist:    false
    });

    // If no message is specified, drop the request
    if (notice.message === null || notice.message === '') {
        callback('No message was specified.');
    }

    // Hash notice and publish to redis store
    async.auto({
        hash:       function (callback) {
            hash(notice, callback);
        },

        publish:    ['hash', function (callback, obj) {
            self.pub.publish(self.ns, obj.hash);
            callback(null);
        }]
    }, callback);
};

// --------------------------------
// --------------------------------

/**
 * Export
 */
module.exports = new Randy();<|endoftext|>


<commit_before>'use strict';

function add_split(){
    if(!interval_running){
        return;
    }

    calculate_time();
    document.getElementById('splits').innerHTML +=
      current_time['hours'] + ':'
      + current_time['minutes'] + ':'
      + current_time['seconds'] + '.'
      + current_time['milliseconds'] + '
';
}

function calculate_time(){
    time_ms = new Date().getTime() - start_time;
    current_time['hours'] = Math.floor(time_ms / 3600000);
    current_time['minutes'] = Math.floor(time_ms / 60000) % 60;
    current_time['seconds'] = Math.floor(time_ms / 1000) % 60;
    current_time['milliseconds'] = time_ms % 1000;

    // Extra zero for minutes?
    if(current_time['minutes'] < 10){
        current_time['minutes'] = '0' + current_time['minutes'];
    }

    // Extra zero for seconds?
    if(current_time['seconds'] < 10){
        current_time['seconds'] = '0' + current_time['seconds'];
    }

    // Extra zero(s) for milliseconds?
    if(current_time['milliseconds'] < 100){
        current_time['milliseconds'] = '0' + current_time['milliseconds'];
        if(current_time['milliseconds'] < 10){
            current_time['milliseconds'] = '0' + current_time['milliseconds'];
        }
    }
}

function draw(){
    calculate_time();
    var ids = [
      'hours',
      'milliseconds',
      'minutes',
      'seconds',
    ];
    for(var id in ids){
        document.getElementById(ids[id]).innerHTML = current_time[ids[id]];
    }
}

function reset_timer(){
    if(!window.confirm('Clear splits and reset timer?')){
        return;
    }

    stop();

    start_time = -1;

    var ids = {
      'hours': '0',
      'milliseconds': '000',
      'minutes': '00',
      'seconds': '00',
      'splits': '',
    };
    for(var id in ids){
        document.getElementById(id).innerHTML = ids[id];
    }
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('controls').style.display === 'none'
      : state;

    document.getElementById('controls').style.display =
      state
        ? 'inline'
        : 'none';
    document.getElementById('settings').style.display =
      state
        ? 'inline'
        : 'none';
}

function start(){
    stop();
    settings_save();
    document.getElementById('reset-key-display').value = 'Reset [' + settings_settings['reset-key'] + ']';
    document.getElementById('start-key-display').value = 'Start [' + settings_settings['start-key'] + ']';
    start_time = new Date().getTime() - (start_time === -1 ? 0 : time_ms);
    interval = setInterval(
      draw,
      20
    );
    interval_running = true;
}

function stop(){
    clearInterval(interval);
    interval_running = false;
}

var current_time = {
  'hours': 0,
  'minutes': 0,
  'seconds': 0,
  'milliseconds': 0,
};
var interval = 0;
var interval_running = false;
var start_time = -1;
var time_ms = 0;

window.onbeforeunload = function(){
    if(start_time > -1){
        return 'Timer and splits not yet saveable. Leave?';
    }
};

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    // Space: add split.
    if(key === 32){
        e.preventDefault();
        add_split();

    // ESC: stop timer.
    }else if(key === 27){
        stop();

    // +: show settings.
    }else if(key === 187){
        settings_toggle(true);

    // -: hide settings.
    }else if(key === 189){
        settings_toggle(false);

    }else{
        key = String.fromCharCode(key);

        if(key === settings_settings['start-key']){
            start();

        }else if(key === settings_settings['reset-key']){
            reset_timer();
        }
    }
};

window.onload = function(e){
    settings_init({
      'prefix': 'Timer.htm-',
      'settings': {
        'reset-key': 'T',
        'start-key': 'H',
      },
    });

    document.getElementById('settings').innerHTML =
      'Start: <input id=start-key maxlength=1>
'
        + 'Split: <input disabled value=Space>
'
        + 'Stop: <input disabled value=ESC>
'
        + 'Reset: <input id=reset-key maxlength=1>
'
        + 'Reset Settings';
    settings_update();

    document.getElementById('add-split').onclick = add_split;
    document.getElementById('reset-key-display').onclick = reset_timer;
    document.getElementById('reset-key-display').value = 'Reset [' + settings_settings['reset-key'] + ']';
    document.getElementById('settings-toggle').onclick = function(){
        settings_toggle();
    };
    document.getElementById('start-key-display').onclick = start;
    document.getElementById('start-key-display').value = 'Start [' + settings_settings['start-key'] + ']';
    document.getElementById('stop').onclick = stop;
};
<commit_msg>moved event bindings to onload<commit_after>'use strict';

function add_split(){
    if(!interval_running){
        return;
    }

    calculate_time();
    document.getElementById('splits').innerHTML +=
      current_time['hours'] + ':'
      + current_time['minutes'] + ':'
      + current_time['seconds'] + '.'
      + current_time['milliseconds'] + '
';
}

function calculate_time(){
    time_ms = new Date().getTime() - start_time;
    current_time['hours'] = Math.floor(time_ms / 3600000);
    current_time['minutes'] = Math.floor(time_ms / 60000) % 60;
    current_time['seconds'] = Math.floor(time_ms / 1000) % 60;
    current_time['milliseconds'] = time_ms % 1000;

    // Extra zero for minutes?
    if(current_time['minutes'] < 10){
        current_time['minutes'] = '0' + current_time['minutes'];
    }

    // Extra zero for seconds?
    if(current_time['seconds'] < 10){
        current_time['seconds'] = '0' + current_time['seconds'];
    }

    // Extra zero(s) for milliseconds?
    if(current_time['milliseconds'] < 100){
        current_time['milliseconds'] = '0' + current_time['milliseconds'];
        if(current_time['milliseconds'] < 10){
            current_time['milliseconds'] = '0' + current_time['milliseconds'];
        }
    }
}

function draw(){
    calculate_time();
    var ids = [
      'hours',
      'milliseconds',
      'minutes',
      'seconds',
    ];
    for(var id in ids){
        document.getElementById(ids[id]).innerHTML = current_time[ids[id]];
    }
}

function reset_timer(){
    if(!window.confirm('Clear splits and reset timer?')){
        return;
    }

    stop();

    start_time = -1;

    var ids = {
      'hours': '0',
      'milliseconds': '000',
      'minutes': '00',
      'seconds': '00',
      'splits': '',
    };
    for(var id in ids){
        document.getElementById(id).innerHTML = ids[id];
    }
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('controls').style.display === 'none'
      : state;

    document.getElementById('controls').style.display =
      state
        ? 'inline'
        : 'none';
    document.getElementById('settings').style.display =
      state
        ? 'inline'
        : 'none';
}

function start(){
    stop();
    settings_save();
    document.getElementById('reset-key-display').value = 'Reset [' + settings_settings['reset-key'] + ']';
    document.getElementById('start-key-display').value = 'Start [' + settings_settings['start-key'] + ']';
    start_time = new Date().getTime() - (start_time === -1 ? 0 : time_ms);
    interval = setInterval(
      draw,
      20
    );
    interval_running = true;
}

function stop(){
    clearInterval(interval);
    interval_running = false;
}

var current_time = {
  'hours': 0,
  'minutes': 0,
  'seconds': 0,
  'milliseconds': 0,
};
var interval = 0;
var interval_running = false;
var start_time = -1;
var time_ms = 0;

window.onload = function(e){
    settings_init({
      'prefix': 'Timer.htm-',
      'settings': {
        'reset-key': 'T',
        'start-key': 'H',
      },
    });

    document.getElementById('settings').innerHTML =
      'Start: <input id=start-key maxlength=1>
'
        + 'Split: <input disabled value=Space>
'
        + 'Stop: <input disabled value=ESC>
'
        + 'Reset: <input id=reset-key maxlength=1>
'
        + 'Reset Settings';
    settings_update();

    document.getElementById('add-split').onclick = add_split;
    document.getElementById('reset-key-display').onclick = reset_timer;
    document.getElementById('reset-key-display').value = 'Reset [' + settings_settings['reset-key'] + ']';
    document.getElementById('settings-toggle').onclick = function(){
        settings_toggle();
    };
    document.getElementById('start-key-display').onclick = start;
    document.getElementById('start-key-display').value = 'Start [' + settings_settings['start-key'] + ']';
    document.getElementById('stop').onclick = stop;

    window.onbeforeunload = function(){
        if(start_time > -1){
            return 'Timer and splits not yet saveable. Leave?';
        }
    };

    window.onkeydown = function(e){
        var key = e.keyCode || e.which;

        // Space: add split.
        if(key === 32){
            e.preventDefault();
            add_split();

        // ESC: stop timer.
        }else if(key === 27){
            stop();

        // +: show settings.
        }else if(key === 187){
            settings_toggle(true);

        // -: hide settings.
        }else if(key === 189){
            settings_toggle(false);

        }else{
            key = String.fromCharCode(key);

            if(key === settings_settings['start-key']){
                start();

            }else if(key === settings_settings['reset-key']){
                reset_timer();
            }
        }
    };
};
<|endoftext|>