<commit_before>'use strict';

const fs = require('fs'),
  pagexray = require('pagexray'),
  browsertime = require('browsertime'),
  path = require('path'),
  Promise = require('bluebird'),
  merger = require('./merge').merge,
  merge = require('lodash.merge'),
  pickAPage = require('./har/harCutter').pickAPage,
  harRunner = require('./har');

Promise.promisifyAll(fs);

const DEFAULT_OPTIONS = {
  browser: 'firefox',
  iterations: 1,
  headless: true
};

// We set this in the Dockerfile
if (process.env.DOCKER) {
  DEFAULT_OPTIONS.docker = true;
}

function getPagesFromHar(harJson) {
  return Promise.resolve(harJson).then(harJson =>
    pagexray.convert(harJson, {
      includeAssets: true
    })
  );
}

async function runBrowsertime(url, script, options) {
  function browsertimeify(script) {
    return Promise.resolve(script).then(script => {
      return {
        coach: {
          domAdvice: script
        }
      };
    });
  }

  browsertime.logging.configure(options);
  options.resultDir = process.cwd();

  const engine = new browsertime.Engine(options);
  const scripts = await browsertimeify(script);
  await engine.start();
  try {
    return engine.run(url, scripts);
  } finally {
    engine.stop();
  }
}

module.exports = {
  getDomAdvice() {
    return fs.readFileAsync(
      path.resolve(__dirname, '..', 'dist', 'coach.min.js'),
      'utf8'
    );
  },
  runDomAdvice(url, script, options) {
    if (!script) {
      script = this.getDomAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    options.skipHar = true;

    return runBrowsertime(url, script, options).then(result => {
      if (options.screenshot) {
        result.browserScripts[0].coach.domAdvice.screenshot =
          result.screenshots[0];
      }
      return result.browserScripts[0].coach.domAdvice;
    });
  },
  getHarAdvice() {
    let rootPath = path.resolve(__dirname, 'har', 'performance');

    return fs
      .readdirAsync(rootPath)
      .map(fileName => path.resolve(rootPath, fileName))
      .filter(file => fs.statAsync(file).then(stats => stats.isFile()))
      .map(file => require(file));
  },
  runHarAdvice(har, script, domAdvice, options) {
    if (!script) {
      script = this.getHarAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    options.skipHar = false;

    return harRunner.runAdvice(
      getPagesFromHar(har),
      script,
      domAdvice,
      options
    );
  },
  merge(domAdvice, harAdvice) {
    return merger(domAdvice, harAdvice);
  },
  pickAPage(har, pageIndex) {
    return pickAPage(har, pageIndex);
  },
  run(url, domScript, harScript, options) {
    if (!domScript) {
      domScript = this.getDomAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    return runBrowsertime(url, domScript, options).then(result => {
      const domAdvice = result.browserScripts[0].coach.domAdvice,
        har = result.har;

      if (har) {
        return this.runHarAdvice(har, harScript, domAdvice, options).then(
          harAdvice => this.merge(domAdvice, harAdvice)
        );
      } else {
        return domAdvice;
      }
    });
  }
};
<commit_msg>Check for Browsertime errors in run(). (#300)<commit_after>'use strict';

const fs = require('fs'),
  pagexray = require('pagexray'),
  browsertime = require('browsertime'),
  path = require('path'),
  Promise = require('bluebird'),
  merger = require('./merge').merge,
  merge = require('lodash.merge'),
  pickAPage = require('./har/harCutter').pickAPage,
  harRunner = require('./har');

Promise.promisifyAll(fs);

const DEFAULT_OPTIONS = {
  browser: 'firefox',
  iterations: 1,
  headless: true
};

// We set this in the Dockerfile
if (process.env.DOCKER) {
  DEFAULT_OPTIONS.docker = true;
}

function getPagesFromHar(harJson) {
  return Promise.resolve(harJson).then(harJson =>
    pagexray.convert(harJson, {
      includeAssets: true
    })
  );
}

async function runBrowsertime(url, script, options) {
  function browsertimeify(script) {
    return Promise.resolve(script).then(script => {
      return {
        coach: {
          domAdvice: script
        }
      };
    });
  }

  browsertime.logging.configure(options);
  options.resultDir = process.cwd();

  const engine = new browsertime.Engine(options);
  const scripts = await browsertimeify(script);
  await engine.start();
  try {
    return engine.run(url, scripts);
  } finally {
    engine.stop();
  }
}

module.exports = {
  getDomAdvice() {
    return fs.readFileAsync(
      path.resolve(__dirname, '..', 'dist', 'coach.min.js'),
      'utf8'
    );
  },
  runDomAdvice(url, script, options) {
    if (!script) {
      script = this.getDomAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    options.skipHar = true;

    return runBrowsertime(url, script, options).then(result => {
      if (options.screenshot) {
        result.browserScripts[0].coach.domAdvice.screenshot =
          result.screenshots[0];
      }
      return result.browserScripts[0].coach.domAdvice;
    });
  },
  getHarAdvice() {
    let rootPath = path.resolve(__dirname, 'har', 'performance');

    return fs
      .readdirAsync(rootPath)
      .map(fileName => path.resolve(rootPath, fileName))
      .filter(file => fs.statAsync(file).then(stats => stats.isFile()))
      .map(file => require(file));
  },
  runHarAdvice(har, script, domAdvice, options) {
    if (!script) {
      script = this.getHarAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    options.skipHar = false;

    return harRunner.runAdvice(
      getPagesFromHar(har),
      script,
      domAdvice,
      options
    );
  },
  merge(domAdvice, harAdvice) {
    return merger(domAdvice, harAdvice);
  },
  pickAPage(har, pageIndex) {
    return pickAPage(har, pageIndex);
  },
  run(url, domScript, harScript, options) {
    if (!domScript) {
      domScript = this.getDomAdvice();
    }

    options = merge({}, DEFAULT_OPTIONS, options);
    return runBrowsertime(url, domScript, options).then(result => {
      if (
        Array.isArray(result.errors) &&
        result.errors.length !== 0 &&
        result.errors[0].length !== 0
      ) {
        const browsertimeError = new Error(result.errors);
        browsertimeError.name = 'BROWSERTIMEERROR';
        throw browsertimeError;
      }
      const domAdvice = result.browserScripts[0].coach.domAdvice,
        har = result.har;

      if (har) {
        return this.runHarAdvice(har, harScript, domAdvice, options).then(
          harAdvice => this.merge(domAdvice, harAdvice)
        );
      } else {
        return domAdvice;
      }
    });
  }
};
<|endoftext|>


<commit_before>exports.array = require('./array');
exports.attr = require('./attr');
exports.bind = require('./bind');
exports.compose = require('./compose');
exports.curry = require('./curry');
exports.exists = require('./exists');
exports.first = require('./first');
exports.id = require('./id');
exports.iff = require('./iff');
exports.index = require('./index');
exports.nth = require('./nth');
exports.rest = require('./rest');
exports.ret = require('./ret');
exports.second = require('./second');
<commit_msg>add map and call<commit_after>exports.array = require('./array');
exports.attr = require('./attr');
exports.bind = require('./bind');
exports.call = require('./call');
exports.compose = require('./compose');
exports.curry = require('./curry');
exports.exists = require('./exists');
exports.first = require('./first');
exports.id = require('./id');
exports.iff = require('./iff');
exports.nth = require('./nth');
exports.rest = require('./rest');
exports.ret = require('./ret');
exports.second = require('./second');
exports.map = require('./map');
<|endoftext|>


<commit_before>'use strict';

var async = require('async');
var crypto = require('crypto');
var Anyfetch = require('anyfetch');

/**
 * HYDRATING FUNCTION
 *
 * @param {string} path Path of the specified file
 * @param {string} original document
 * @param {object} changes object provided by anyFetch's API. Update this object to send document's modification to anyFetch's API.
 * @param {function} cb Callback, first parameter is the error if any, then the processed data
 */
module.exports = function(path, document, changes, cb) {
  var anyfetch = new Anyfetch(document.access_token);
  anyfetch.setApiUrl(cb.apiUrl);

  async.waterfall([
    function generateHash(cb) {
      var shasum = crypto.createHash('sha1');
      shasum.update(JSON.stringify(document.metadata));
      cb(null, shasum.digest('hex'));
    },
    function getDocumentsWithSameHash(hash, cb) {
      changes.hash = hash;

      anyfetch.getDocuments({hash: hash}, cb);
    },
    function deleteOldDocuments(res, cb) {
      var documents = res.body.data;

      async.each(documents, function(document, cb) {
        console.log("DELETE", document.identifier);
        anyfetch.deleteDocumentById(document.id, cb);
      }, cb);
    }
  ], function(err) {
    cb(err, changes);
  });
};
<commit_msg>Check if deletedDocument are same than the original document<commit_after>'use strict';

var async = require('async');
var crypto = require('crypto');
var Anyfetch = require('anyfetch');

/**
 * HYDRATING FUNCTION
 *
 * @param {string} path Path of the specified file
 * @param {string} original document
 * @param {object} changes object provided by anyFetch's API. Update this object to send document's modification to anyFetch's API.
 * @param {function} cb Callback, first parameter is the error if any, then the processed data
 */
module.exports = function(path, document, changes, cb) {
  var anyfetch = new Anyfetch(document.access_token);
  anyfetch.setApiUrl(cb.apiUrl);

  async.waterfall([
    function generateHash(cb) {
      var shasum = crypto.createHash('sha1');
      shasum.update(JSON.stringify(document.metadata));
      cb(null, shasum.digest('hex'));
    },
    function getDocumentsWithSameHash(hash, cb) {
      changes.hash = hash;

      anyfetch.getDocuments({hash: hash}, cb);
    },
    function deleteOldDocuments(res, cb) {
      var documents = res.body.data;

      async.each(documents, function(deletedDocument, cb) {
        if (deletedDocument.id !== document.id) {
          console.log("DELETE", deletedDocument.identifier);
          anyfetch.deleteDocumentById(deletedDocument.id, cb);
        }
      }, cb);
    }
  ], function(err) {
    cb(err, changes);
  });
};
<|endoftext|>


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

var app = require('./app');
var config = require('x-config');

app.init(config, function(){
    app.listen();
});
<commit_msg>line endings<commit_after>#!/usr/bin/env node

var app = require('./app');
var config = require('x-config');

app.init(config, function(){
    app.listen();
});

<|endoftext|>


<commit_before>import getFiles from './get-files';
import hash from './hash';
import retry from './retry';
import bytes from 'bytes';
import Agent from './agent';
import EventEmitter from 'events';
import { resolve } from 'path';
import { stat, readFile } from 'fs-promise';

// limit of size of files to find
const ONEMB = bytes('1mb');

export default class Now extends EventEmitter {
  constructor (token, { forceNew = false, debug = false }) {
    super();
    this._token = token;
    this._debug = debug;
    this._forceNew = forceNew;
    this._agent = new Agent('api.now.sh', { debug });
    this._onRetry = this._onRetry.bind(this);
  }

  async create (path, { forceNew }) {
    this._path = path;

    try {
      await stat(path);
    } catch (err) {
      throw new Error(`Could not read directory ${path}.`);
    }

    let pkg;
    try {
      pkg = await readFile(resolve(path, 'package.json'));
      pkg = JSON.parse(pkg);
    } catch (err) {
      throw new Error(`Failed to read JSON in "${path}/package.json"`);
    }

    if (!pkg.scripts || !pkg.scripts.start) {
      throw new Error('Missing `start` script in `package.json`. ' +
        'See: https://docs.npmjs.com/cli/start.');
    }

    if (this._debug) console.time('> [debug] Getting files');
    const files = await getFiles(path, pkg, { limit: ONEMB, debug: this._debug });
    if (this._debug) console.timeEnd('> [debug] Getting files');

    if (this._debug) console.time('> [debug] Computing hashes');
    const hashes = await hash(files);
    if (this._debug) console.timeEnd('> [debug] Computing hashes');

    this._files = hashes;

    const deployment = await retry(async (bail) => {
      if (this._debug) console.time('> [debug] /create');
      const res = await this._fetch('/create', {
        method: 'POST',
        body: {
          forceNew,
          files: Array.from(this._files).map(([sha, { data, name }]) => {
            return {
              sha,
              size: Buffer.byteLength(data),
              file: toRelative(name, this._path)
            };
          })
        }
      });
      if (this._debug) console.timeEnd('> [debug] /create');

      // no retry on 403
      if (403 === res.status) {
        if (this._debug) {
          console.log('> [debug] bailing on creating due to 403');
        }
        return bail(responseError(res));
      }

      if (200 !== res.status) {
        throw new Error('Deployment initialization failed');
      }

      return res.json();
    }, { retries: 3, minTimeout: 2500, onRetry: this._onRetry });

    this._id = deployment.deploymentId;
    this._url = deployment.url;
    this._missing = deployment.missing || [];

    return this._url;
  }

  upload () {
    Promise.all(this._missing.map((sha) => retry(async (bail) => {
      const file = this._files.get(sha);
      const { data, name } = file;

      if (this._debug) console.time(`> [debug] /sync ${name}`);
      const res = await this._fetch('/sync', {
        method: 'POST',
        body: {
          sha,
          data: data.toString(),
          file: toRelative(name, this._path),
          deploymentId: this._id
        }
      });
      if (this._debug) console.timeEnd(`> [debug] /sync ${name}`);

      // no retry on 403
      if (403 === res.status) {
        if (this._debug) console.log('> [debug] bailing on creating due to 403');
        return bail(responseError(res));
      }

      this.emit('upload', file);
    }, { retries: 5, randomize: true, onRetry: this._onRetry })))
    .then(() => this.emit('complete'))
    .catch((err) => this.emit('error', err));
  }

  _onRetry (err) {
    if (this._debug) {
      console.log(`> [debug] Retrying: ${err.stack}`);
    }
  }

  close () {
    this._agent.close();
  }

  get url () {
    return this._url;
  }

  get syncAmount () {
    if (!this._syncAmount) {
      this._syncAmount = this._missing
      .map((sha) => Buffer.byteLength(this._files.get(sha).data))
      .reduce((a, b) => a + b, 0);
    }
    return this._syncAmount;
  }

  async _fetch (url, opts) {
    opts.headers = opts.headers || {};
    opts.headers.authorization = `Bearer ${this._token}`;
    return await this._agent.fetch(url, opts);
  }
}

function toRelative (path, base) {
  const fullBase = /\/$/.test(base) ? base + '/' : base;
  const relative = path.substr(fullBase.length);
  if (relative.startsWith('/')) return relative.substr(1);
  return relative;
}

function responseError (res) {
  const err = new Error('Response error');
  err.status = res.status;
  return err;
}
<commit_msg>index: send pkg metadata<commit_after>import getFiles from './get-files';
import hash from './hash';
import retry from './retry';
import bytes from 'bytes';
import Agent from './agent';
import EventEmitter from 'events';
import { resolve } from 'path';
import { stat, readFile } from 'fs-promise';

// limit of size of files to find
const ONEMB = bytes('1mb');

export default class Now extends EventEmitter {
  constructor (token, { forceNew = false, debug = false }) {
    super();
    this._token = token;
    this._debug = debug;
    this._forceNew = forceNew;
    this._agent = new Agent('api.now.sh', { debug });
    this._onRetry = this._onRetry.bind(this);
  }

  async create (path, { forceNew }) {
    this._path = path;

    try {
      await stat(path);
    } catch (err) {
      throw new Error(`Could not read directory ${path}.`);
    }

    let pkg;
    try {
      pkg = await readFile(resolve(path, 'package.json'));
      pkg = JSON.parse(pkg);
    } catch (err) {
      throw new Error(`Failed to read JSON in "${path}/package.json"`);
    }

    if (!pkg.scripts || !pkg.scripts.start) {
      throw new Error('Missing `start` script in `package.json`. ' +
        'See: https://docs.npmjs.com/cli/start.');
    }

    if (this._debug) console.time('> [debug] Getting files');
    const files = await getFiles(path, pkg, { limit: ONEMB, debug: this._debug });
    if (this._debug) console.timeEnd('> [debug] Getting files');

    if (this._debug) console.time('> [debug] Computing hashes');
    const hashes = await hash(files);
    if (this._debug) console.timeEnd('> [debug] Computing hashes');

    this._files = hashes;

    const deployment = await retry(async (bail) => {
      if (this._debug) console.time('> [debug] /create');
      const res = await this._fetch('/create', {
        method: 'POST',
        body: {
          forceNew,
          name: pkg.name,
          description: pkg.description,
          files: Array.from(this._files).map(([sha, { data, name }]) => {
            return {
              sha,
              size: Buffer.byteLength(data),
              file: toRelative(name, this._path)
            };
          })
        }
      });
      if (this._debug) console.timeEnd('> [debug] /create');

      // no retry on 403
      if (403 === res.status) {
        if (this._debug) {
          console.log('> [debug] bailing on creating due to 403');
        }
        return bail(responseError(res));
      }

      if (200 !== res.status) {
        throw new Error('Deployment initialization failed');
      }

      return res.json();
    }, { retries: 3, minTimeout: 2500, onRetry: this._onRetry });

    this._id = deployment.deploymentId;
    this._url = deployment.url;
    this._missing = deployment.missing || [];

    return this._url;
  }

  upload () {
    Promise.all(this._missing.map((sha) => retry(async (bail) => {
      const file = this._files.get(sha);
      const { data, name } = file;

      if (this._debug) console.time(`> [debug] /sync ${name}`);
      const res = await this._fetch('/sync', {
        method: 'POST',
        body: {
          sha,
          data: data.toString(),
          file: toRelative(name, this._path),
          deploymentId: this._id
        }
      });
      if (this._debug) console.timeEnd(`> [debug] /sync ${name}`);

      // no retry on 403
      if (403 === res.status) {
        if (this._debug) console.log('> [debug] bailing on creating due to 403');
        return bail(responseError(res));
      }

      this.emit('upload', file);
    }, { retries: 5, randomize: true, onRetry: this._onRetry })))
    .then(() => this.emit('complete'))
    .catch((err) => this.emit('error', err));
  }

  _onRetry (err) {
    if (this._debug) {
      console.log(`> [debug] Retrying: ${err.stack}`);
    }
  }

  close () {
    this._agent.close();
  }

  get url () {
    return this._url;
  }

  get syncAmount () {
    if (!this._syncAmount) {
      this._syncAmount = this._missing
      .map((sha) => Buffer.byteLength(this._files.get(sha).data))
      .reduce((a, b) => a + b, 0);
    }
    return this._syncAmount;
  }

  async _fetch (url, opts) {
    opts.headers = opts.headers || {};
    opts.headers.authorization = `Bearer ${this._token}`;
    return await this._agent.fetch(url, opts);
  }
}

function toRelative (path, base) {
  const fullBase = /\/$/.test(base) ? base + '/' : base;
  const relative = path.substr(fullBase.length);
  if (relative.startsWith('/')) return relative.substr(1);
  return relative;
}

function responseError (res) {
  const err = new Error('Response error');
  err.status = res.status;
  return err;
}
<|endoftext|>


<commit_before>var assert = require('assert');
var OAuth = require('OAuth');
var url = require('url');
var Promise = require('promise');

require('extend-error');
var HttpApiError = Error.extend('HttpApiError');

var Client = function(options) {
    assert(options.key, 'Must provide API key');
    assert(options.secret, 'Must provide API secret');
    assert(options.callbackURL, 'Must provide API callbackURL');
    assert(options.requestUrl, 'Must provide requestUrl');
    assert(options.accessUrl, 'Must provide accessUrl');
    assert(options.apiHostName, 'Must provide apiHostName');

    this.apiKey = options.key;
    this.apiSecret = options.secret;
    this.callbackURL = options.callbackURL;
    this.apiHostName = options.apiHostName;

    this.oauthClient = new OAuth.OAuth(
        options.requestUrl,
        options.accessUrl,
        this.apiKey,
        this.apiSecret,
        '1.0',
        this.callbackURL,
        'HMAC-SHA1');
};

Client.prototype.auth = function(token, secret) {
    assert(token, 'Must provide token');
    assert(secret, 'Must provide secret');

    this.authenticatedToken = token;
    this.authenticatedSecret = secret;
    return this;
};

Client.prototype.get = function(path, pageOrQuery) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path, pageOrQuery);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.get(url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
    }.bind(this));
};

Client.prototype.put = function(path, content) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.put(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
    }.bind(this));
};

Client.prototype.post = function(path, content) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.post(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
    }.bind(this));
};

Client.prototype['delete'] = function(path) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient['delete'](url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
    }.bind(this));
};

Client.prototype.requestToken = function(extraParams) {
    return new Promise(function(resolve, reject) {
        this.oauthClient.getOAuthRequestToken(extraParams || {}, function(err, oauthToken, oauthTokenSecret, parsedQueryString) {
            if (err) {
                return reject(err);
            }
            resolve({
                token: oauthToken,
                tokenSecret: oauthTokenSecret,
                authorizeUrl: parsedQueryString.login_url
            });
        });
    }.bind(this));
};

Client.prototype.accessToken = function(token, secret, verifier) {
    return new Promise(function(resolve, reject) {
        this.oauthClient.getOAuthAccessToken(token, secret, verifier, function (err, oauthAccessToken, oauthAccessTokenSecret) {
            if (err) {
                return reject(err);
            }
            resolve({
                token: oauthAccessToken,
                tokenSecret: oauthAccessTokenSecret
            });
        });
    }.bind(this));
};

function createResponseHandler(resolve, reject) {
    return function responseHandler(err, data, res) {
        if (res.statusCode.toString()[0] !== '2') {
            return reject(new HttpApiError({ statusCode: res.statusCode, body: data }));
        }
        if (typeof data === 'string') {
            try {
                var parsedBody = JSON.parse(data || '{}');
                resolve({
                    statusCode: res.statusCode,
                    body: parsedBody,
                    headers: res.headers
                });
            } catch (err) {
                reject('Error parsing JSON response from API. Error:' + err);
            }
        }
    };
}

function buildUrl(apiKey, apiSecret, apiHostName, path, pageOrQuery) {
    if (apiKey === null) {
        throw new Error('Must provide apiKey');
    }
    if (apiSecret === null) {
        throw new Error('Must provide apiSecret');
    }
    if (path === null) {
        throw new Error('Must provide a path');
    }
    var query = (pageOrQuery && typeof pageOrQuery === 'object')
        ? pageOrQuery
        : {};
    if (apiKey && !apiSecret) {
        query.api_key = this.apiKey;
    }
    return url.format({
        protocol: "https:",
        hostname: apiHostName,
        pathname: path,
        query: query
    });
}

module.exports = Client;<commit_msg>bug fix: add missing error check<commit_after>var assert = require('assert');
var OAuth = require('OAuth');
var url = require('url');
var Promise = require('promise');

require('extend-error');
var HttpApiError = Error.extend('HttpApiError');

var Client = function(options) {
    assert(options.key, 'Must provide API key');
    assert(options.secret, 'Must provide API secret');
    assert(options.callbackURL, 'Must provide API callbackURL');
    assert(options.requestUrl, 'Must provide requestUrl');
    assert(options.accessUrl, 'Must provide accessUrl');
    assert(options.apiHostName, 'Must provide apiHostName');

    this.apiKey = options.key;
    this.apiSecret = options.secret;
    this.callbackURL = options.callbackURL;
    this.apiHostName = options.apiHostName;

    this.oauthClient = new OAuth.OAuth(
        options.requestUrl,
        options.accessUrl,
        this.apiKey,
        this.apiSecret,
        '1.0',
        this.callbackURL,
        'HMAC-SHA1');
};

Client.prototype.auth = function(token, secret) {
    assert(token, 'Must provide token');
    assert(secret, 'Must provide secret');

    this.authenticatedToken = token;
    this.authenticatedSecret = secret;
    return this;
};

Client.prototype.get = function(path, pageOrQuery) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path, pageOrQuery);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.get(url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
    }.bind(this));
};

Client.prototype.put = function(path, content) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.put(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
    }.bind(this));
};

Client.prototype.post = function(path, content) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient.post(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
    }.bind(this));
};

Client.prototype['delete'] = function(path) {
    assert(this.authenticatedToken, 'Must set authentication token first');
    assert(this.authenticatedSecret, 'Must set authentication secret first');

    var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
    return new Promise(function(resolve, reject) {
        var responseHandler = createResponseHandler(resolve, reject);
        this.oauthClient['delete'](url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
    }.bind(this));
};

Client.prototype.requestToken = function(extraParams) {
    return new Promise(function(resolve, reject) {
        this.oauthClient.getOAuthRequestToken(extraParams || {}, function(err, oauthToken, oauthTokenSecret, parsedQueryString) {
            if (err) {
                return reject(err);
            }
            resolve({
                token: oauthToken,
                tokenSecret: oauthTokenSecret,
                authorizeUrl: parsedQueryString.login_url
            });
        });
    }.bind(this));
};

Client.prototype.accessToken = function(token, secret, verifier) {
    return new Promise(function(resolve, reject) {
        this.oauthClient.getOAuthAccessToken(token, secret, verifier, function (err, oauthAccessToken, oauthAccessTokenSecret) {
            if (err) {
                return reject(err);
            }
            resolve({
                token: oauthAccessToken,
                tokenSecret: oauthAccessTokenSecret
            });
        });
    }.bind(this));
};

function createResponseHandler(resolve, reject) {
    return function responseHandler(err, data, res) {
        if (err) {
            return reject(err);
        }
        if (res.statusCode.toString()[0] !== '2') {
            return reject(new HttpApiError({ statusCode: res.statusCode, body: data }));
        }
        if (typeof data === 'string') {
            try {
                var parsedBody = JSON.parse(data || '{}');
                resolve({
                    statusCode: res.statusCode,
                    body: parsedBody,
                    headers: res.headers
                });
            } catch (err) {
                reject('Error parsing JSON response from API. Error:' + err);
            }
        }
    };
}

function buildUrl(apiKey, apiSecret, apiHostName, path, pageOrQuery) {
    if (apiKey === null) {
        throw new Error('Must provide apiKey');
    }
    if (apiSecret === null) {
        throw new Error('Must provide apiSecret');
    }
    if (path === null) {
        throw new Error('Must provide a path');
    }
    var query = (pageOrQuery && typeof pageOrQuery === 'object')
        ? pageOrQuery
        : {};
    if (apiKey && !apiSecret) {
        query.api_key = this.apiKey;
    }
    return url.format({
        protocol: "https:",
        hostname: apiHostName,
        pathname: path,
        query: query
    });
}

module.exports = Client;<|endoftext|>


<commit_before>'use strict';

var http = require('http');
var https = require('https');
const App = require('./app').App;

http.globalAgent.maxSockets = 2;
https.globalAgent.maxSockets = 2;

const app = new App();
app.run();
<commit_msg>Fix eslint errors.<commit_after>'use strict';

const http = require('http');
const https = require('https');
const App = require('./app').App;

http.globalAgent.maxSockets = 2;
https.globalAgent.maxSockets = 2;

const app = new App();
app.run();
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs-extra');
var mode = require('stat-mode');
var Ware = require('ware');

/**
 * Initialize Imagemin
 *
 * @api public
 */

function Imagemin() {
    this.ware = new Ware();
}

/**
 * Add a plugin to the middleware stack
 *
 * @param {Function} plugin
 * @api public
 */

Imagemin.prototype.use = function (plugin) {
    this.ware.use(plugin);
    return this;
};

/**
 * Get or set the source file
 *
 * @param {String|Buffer} file
 * @api public
 */

Imagemin.prototype.src = function (file) {
    if (!arguments.length) {
        return this._src;
    }

    this._src = file;
    return this;
};

/**
 * Get or set the destination file
 *
 * @param {String} file
 * @api public
 */

Imagemin.prototype.dest = function (file) {
    if (!arguments.length) {
        return this._dest;
    }

    this._dest = file;
    return this;
};

/**
 * Optimize file
 *
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.optimize = function (cb) {
    cb = cb || function () {};
    var self = this;

    this.read(function (err, file) {
        self.run(file, function (err, file) {
            if (err) {
                return cb(err);
            }

            self.write(file, function (err) {
                cb(err, file);
            });
        });
    });
};

/**
 * Run a file through the middleware
 *
 * @param {Array} file
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.run = function (file, cb) {
    this.ware.run(file, this, cb);
};

/**
 * Read the source file
 *
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.read = function (cb) {
    var file = {};
    var src = this.src();

    if (Buffer.isBuffer(src)) {
        file.contents = src;
        file.origSize = src.length;

        return cb(null, file);
    }

    fs.stat(src, function (err, stats) {
        if (err) {
            return cb(err);
        }

        fs.readFile(src, function (err, buf) {
            if (err) {
                return cb(err);
            }

            file.contents = buf;
            file.mode = mode(stats).toOctal();
            file.origSize = buf.length;

            cb(null, file);
        });
    });
};

/**
 * Write file to destination
 *
 * @param {Object} file
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.write = function (file, cb) {
    var dest = this.dest();

    if (!dest) {
        file.destSize = file.contents.length;
        return cb();
    }

    fs.outputFile(dest, file.contents, function (err) {
        cb(err);
    });
};

/**
 * Module exports
 */

module.exports = Imagemin;
module.exports.gifsicle = require('./plugins/gifsicle');
module.exports.jpegtran = require('./plugins/jpegtran');
module.exports.optipng = require('./plugins/optipng');
module.exports.pngquant = require('./plugins/pngquant');
<commit_msg>Fix destSize not getting written for files<commit_after>'use strict';

var fs = require('fs-extra');
var mode = require('stat-mode');
var Ware = require('ware');

/**
 * Initialize Imagemin
 *
 * @api public
 */

function Imagemin() {
    this.ware = new Ware();
}

/**
 * Add a plugin to the middleware stack
 *
 * @param {Function} plugin
 * @api public
 */

Imagemin.prototype.use = function (plugin) {
    this.ware.use(plugin);
    return this;
};

/**
 * Get or set the source file
 *
 * @param {String|Buffer} file
 * @api public
 */

Imagemin.prototype.src = function (file) {
    if (!arguments.length) {
        return this._src;
    }

    this._src = file;
    return this;
};

/**
 * Get or set the destination file
 *
 * @param {String} file
 * @api public
 */

Imagemin.prototype.dest = function (file) {
    if (!arguments.length) {
        return this._dest;
    }

    this._dest = file;
    return this;
};

/**
 * Optimize file
 *
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.optimize = function (cb) {
    cb = cb || function () {};
    var self = this;

    this.read(function (err, file) {
        self.run(file, function (err, file) {
            if (err) {
                return cb(err);
            }

            self.write(file, function (err) {
                cb(err, file);
            });
        });
    });
};

/**
 * Run a file through the middleware
 *
 * @param {Array} file
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.run = function (file, cb) {
    this.ware.run(file, this, cb);
};

/**
 * Read the source file
 *
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.read = function (cb) {
    var file = {};
    var src = this.src();

    if (Buffer.isBuffer(src)) {
        file.contents = src;
        file.origSize = src.length;

        return cb(null, file);
    }

    fs.stat(src, function (err, stats) {
        if (err) {
            return cb(err);
        }

        fs.readFile(src, function (err, buf) {
            if (err) {
                return cb(err);
            }

            file.contents = buf;
            file.mode = mode(stats).toOctal();
            file.origSize = buf.length;

            cb(null, file);
        });
    });
};

/**
 * Write file to destination
 *
 * @param {Object} file
 * @param {Function} cb
 * @api public
 */

Imagemin.prototype.write = function (file, cb) {
    var dest = this.dest();

    file.destSize = file.contents.length;

    if (!dest) {
        return cb();
    }

    fs.outputFile(dest, file.contents, function (err) {
        cb(err);
    });
};

/**
 * Module exports
 */

module.exports = Imagemin;
module.exports.gifsicle = require('./plugins/gifsicle');
module.exports.jpegtran = require('./plugins/jpegtran');
module.exports.optipng = require('./plugins/optipng');
module.exports.pngquant = require('./plugins/pngquant');
<|endoftext|>


<commit_before>'use strict';

const mongoose = require('mongoose');

class DoubleType extends Number {
  constructor(v) {
    super(v);
    this.value = v;
    this._bsontype = 'Double';
  }

  // Hack to prevent mongoose from converting this into a primitive when cloning
  valueOf() {
    return this;
  }
}

class Double extends mongoose.SchemaType {
  constructor(key, options) {
    super(key, options, 'Double');
  }

  cast(val) {
    if (val == null) {
      return val;
    }
    if (val._bsontype === 'Double') {
      return new DoubleType(val.value);
    }

    const _val = Number(val);
    if (isNaN(_val)) {
      throw new mongoose.SchemaType.CastError('Double',
        val + ' is not a valid double');
    }
    return new DoubleType(_val);
  }
}

mongoose.Schema.Types.Double = Double;
mongoose.Types.Double = DoubleType;

module.exports = Double;
<commit_msg>feat: add lt, gt, and variants<commit_after>'use strict';

const mongoose = require('mongoose');

class DoubleType extends Number {
  constructor(v) {
    super(v);
    this.value = v;
    this._bsontype = 'Double';
  }

  // Hack to prevent mongoose from converting this into a primitive when cloning
  valueOf() {
    return this;
  }
}

class Double extends mongoose.SchemaType {
  constructor(key, options) {
    super(key, options, 'Double');

    Object.assign(this.$conditionalHandlers, {
      '$lt': val => this.castForQuery(val),
      '$lte': val => this.castForQuery(val),
      '$gt': val => this.castForQuery(val),
      '$gte': val => this.castForQuery(val),
    });
  }

  cast(val) {
    if (val == null) {
      return val;
    }
    if (val._bsontype === 'Double') {
      return new DoubleType(val.value);
    }

    const _val = Number(val);
    if (isNaN(_val)) {
      throw new mongoose.SchemaType.CastError('Double',
        val + ' is not a valid double');
    }
    return new DoubleType(_val);
  }
}

mongoose.Schema.Types.Double = Double;
mongoose.Types.Double = DoubleType;

module.exports = Double;
<|endoftext|>


<commit_before>module.exports = MaintainEl;

function MaintainEl() {
  this.list = [];
  this.map = {};

  this.create = function create($el, key) {
    this.list.push($el);
    if(key) this.map[key] = $el;
  }.bind(this);

  this.destroy = function destroy($el, key) {
    _.remove(this.list, $el);
    if(key) delete this.map[key];
  }.bind(this);
}
<commit_msg>Fix input key possible to evaluate to false<commit_after>module.exports = MaintainEl;

function MaintainEl() {
  this.list = [];
  this.map = {};

  this.create = function create($el, key) {
    this.list.push($el);
    if(typeof key !== undefined) this.map[key] = $el;
  }.bind(this);

  this.destroy = function destroy($el, key) {
    _.remove(this.list, $el);
    if(typeof key !== undefined) delete this.map[key];
  }.bind(this);
}
<|endoftext|>


<commit_before>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var assert = require('assert-plus');

var clone = require('clone');

var bunyan = require('./bunyan_helper');
var clients = require('./clients');
var errors = require('./errors');
var httpDate = require('./http_date');
var plugins = require('./plugins');
var Router = require('./router');

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

///--- Globals

var HttpClient = clients.HttpClient;
var JsonClient = clients.JsonClient;
var StringClient = clients.StringClient;

///--- Helpers

function createRouter(opts) {
        return (new Router(opts));
}

function onUncaughtException(req, res, route, e) {
        if (this.listeners('uncaughtException').length > 1)
                return (false);

        res.send(new errors.InternalError(e.message || 'unexpected error'));
        return (true);
}

///--- Exported API

module.exports = {
        bunyan: bunyan,

        createServer: function createServer(options) {
                var Server = require('./server');

                var opts = clone(options || {});
                var server;

                opts.name = opts.name || 'restify';
                // clone can't clone something with prototypes so we need to
                // manually set opts.log and opts.router to the right objects:
                opts.log =
                        opts.log ? options.log : bunyan.createLogger(opts.name);
                opts.router = opts.router ? options.router : createRouter(opts);

                server = new Server(opts);
                server.on('uncaughtException', onUncaughtException);

                return (server);
        },

        createClient: function createClient(options) {
                assert.object(options, 'options');

                var client;
                var opts = clone(options);
                opts.agent = options.agent;
                opts.name = opts.name || 'restify';
                opts.type = opts.type || 'application/octet-stream';
                opts.log = options.log || bunyan.createLogger(opts.name);

                switch (opts.type) {
                case 'json':
                        client = new JsonClient(opts);
                        break;

                case 'string':
                        client = new StringClient(opts);
                        break;

                case 'http':
                default:
                        client = new HttpClient(opts);
                        break;
                }

                return (client);
        },

        createJsonClient: function createJsonClient(options) {
                assert.object(options, 'options');

                var opts = clone(options);
                opts.agent = options.agent;
                opts.log = options.log;
                opts.type = 'json';
                return (module.exports.createClient(opts));
        },

        createStringClient: function createStringClient(options) {
                assert.object(options, 'options');

                var opts = clone(options);
                opts.agent = options.agent;
                opts.log = options.log;
                opts.type = 'string';
                return (module.exports.createClient(opts));
        },

        HttpClient: HttpClient,
        JsonClient: JsonClient,
        StringClient: StringClient,

        plugins: {},
        httpDate: httpDate,

        /**
         * Returns a string representation of a URL pattern , with its
         * parameters filled in by the passed hash.
         *
         * If a key is not found in the hash for a param, it is left alone.
         *
         * @param {Object} a hash of parameter names to values for substitution.
         */
        realizeUrl: function realizeUrl(pattern, params) {
                var p = pattern.replace(/\/:([^/]+)/g, function (match, k) {
                        return (params.hasOwnProperty(k) ?
                                '/' + params[k] :
                                match);
                });
                return (utils.sanitizePath(p));
        }
};

Object.keys(errors).forEach(function (k) {
        module.exports[k] = errors[k];
});

Object.keys(plugins).forEach(function (k) {
        module.exports.plugins[k] = plugins[k];
        module.exports[k] = plugins[k];
});

// restify 1.0 backwards compatibility.  You probably don't want to use this.
module.exports.__defineSetter__('defaultResponseHeaders', function (f) {
        if (f === false || f === null || f === undefined) {
                f = function stub() {};
        } else if (f === true) {
                return;
        } else if (typeof (f) !== 'function') {
                var msg = 'defaultResponseHeaders must be a function';
                throw new TypeError(msg);
        }

        require('http').ServerResponse.prototype.defaultResponseHeaders = f;
});
<commit_msg>Don't clone crypto buffers<commit_after>// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var assert = require('assert-plus');

var clone = require('clone');

var bunyan = require('./bunyan_helper');
var clients = require('./clients');
var errors = require('./errors');
var httpDate = require('./http_date');
var plugins = require('./plugins');
var Router = require('./router');

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

///--- Globals

var HttpClient = clients.HttpClient;
var JsonClient = clients.JsonClient;
var StringClient = clients.StringClient;

///--- Helpers

function createRouter(opts) {
        return (new Router(opts));
}

function onUncaughtException(req, res, route, e) {
        if (this.listeners('uncaughtException').length > 1)
                return (false);

        res.send(new errors.InternalError(e.message || 'unexpected error'));
        return (true);
}

///--- Exported API

module.exports = {
        bunyan: bunyan,

        createServer: function createServer(options) {
                var Server = require('./server');

                var opts = clone(options || {});
                var server;

                opts.name = opts.name || 'restify';
                // clone can't clone something with prototypes so we need to
                // manually set opts.log and opts.router to the right objects:
                opts.log =
                        opts.log ? options.log : bunyan.createLogger(opts.name);
                opts.router = opts.router ? options.router : createRouter(opts);

                // crypto components are suffer the same malady
                if(options.key && Buffer.isBuffer(options.key))
                    opts.key = options.key;
                if(options.ca && Buffer.isBuffer(options.ca))
                    opts.ca = options.ca;
                if(options.certificate && Buffer.isBuffer(options.certificate))
                    opts.certificate = options.certificate;

                server = new Server(opts);
                server.on('uncaughtException', onUncaughtException);

                return (server);
        },

        createClient: function createClient(options) {
                assert.object(options, 'options');

                var client;
                var opts = clone(options);
                opts.agent = options.agent;
                opts.name = opts.name || 'restify';
                opts.type = opts.type || 'application/octet-stream';
                opts.log = options.log || bunyan.createLogger(opts.name);

                switch (opts.type) {
                case 'json':
                        client = new JsonClient(opts);
                        break;

                case 'string':
                        client = new StringClient(opts);
                        break;

                case 'http':
                default:
                        client = new HttpClient(opts);
                        break;
                }

                return (client);
        },

        createJsonClient: function createJsonClient(options) {
                assert.object(options, 'options');

                var opts = clone(options);
                opts.agent = options.agent;
                opts.log = options.log;
                opts.type = 'json';
                return (module.exports.createClient(opts));
        },

        createStringClient: function createStringClient(options) {
                assert.object(options, 'options');

                var opts = clone(options);
                opts.agent = options.agent;
                opts.log = options.log;
                opts.type = 'string';
                return (module.exports.createClient(opts));
        },

        HttpClient: HttpClient,
        JsonClient: JsonClient,
        StringClient: StringClient,

        plugins: {},
        httpDate: httpDate,

        /**
         * Returns a string representation of a URL pattern , with its
         * parameters filled in by the passed hash.
         *
         * If a key is not found in the hash for a param, it is left alone.
         *
         * @param {Object} a hash of parameter names to values for substitution.
         */
        realizeUrl: function realizeUrl(pattern, params) {
                var p = pattern.replace(/\/:([^/]+)/g, function (match, k) {
                        return (params.hasOwnProperty(k) ?
                                '/' + params[k] :
                                match);
                });
                return (utils.sanitizePath(p));
        }
};

Object.keys(errors).forEach(function (k) {
        module.exports[k] = errors[k];
});

Object.keys(plugins).forEach(function (k) {
        module.exports.plugins[k] = plugins[k];
        module.exports[k] = plugins[k];
});

// restify 1.0 backwards compatibility.  You probably don't want to use this.
module.exports.__defineSetter__('defaultResponseHeaders', function (f) {
        if (f === false || f === null || f === undefined) {
                f = function stub() {};
        } else if (f === true) {
                return;
        } else if (typeof (f) !== 'function') {
                var msg = 'defaultResponseHeaders must be a function';
                throw new TypeError(msg);
        }

        require('http').ServerResponse.prototype.defaultResponseHeaders = f;
});
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('events').EventEmitter;
var https = require('https');
var qs = require('querystring');
var util = require('util');

var _ = require('lodash');
var WebSocket = require('ws');

var errors = {
    invalid_token: 'Error invalid access token, please provide a valid token.',
    missing_options_arg: 'Error missing required argument object options'

}

var SmartSlack = function (options) {

  if (!options){
    throw new Error(errors.missing_options_arg);
  }

  var accessToken = options.token;

  if (!accessToken || typeof accessToken !== 'string' ||
    !accessToken.match(/^([a-z]{4})\-([0-9]{11})\-([0-9a-zA-Z]{24})$/)) {
    throw new Error(errors.invalid_token);
  }

  this.options = _.defaults(options, this.options);
  this.authenticated = false;
  this.connected = false;
  this.messageId = 0;

  this.user = null;
  this.team = null;
}

util.inherits(SmartSlack, EventEmitter)

SmartSlack.prototype.authTest = function () {
  this._apiCall('auth.test', null, function test(data) {
    if (data) {
      if (data.ok) {
        console.log(data);
        return true;
      } else {
        return false;
      }
    }
  })
}

SmartSlack.prototype.apiTest = function (args, error) {
  var params = _.merge({}, args, error);
  this._apiCall('api.test', params, function test(data) {
    if (data) {
      if (data.ok) {
        console.log(data);
      } else {
        throw new Error(data.error);
      }
    }
  })
}

SmartSlack.prototype.getUserByName = function (name) {
 return _.find(this.users, {name: name} );
}

SmartSlack.prototype.login = function () {

  var _this = this;
  this._apiCall('rtm.start', null, function (data) {

    if (data) {

      if (!data.ok) {
        _this.emit('error', data.error);

      } else {

        //console.log(data);

        _this.authenticated = true;

        // Stash the Slack session data
        _this.users = data.users;
        _this.channels = data.channels;
        _this.groups = data.groups;
        _this.ims = data.ims;
        _this.user = data.self
        _this.team = data.team;

        // Connect
        _this.socketUrl = data.url;
        _this.connect();
      }
    }
  });
}

SmartSlack.prototype.connect = function () {
  this.ws = new WebSocket(this.socketUrl);

  this.ws.on('open', function (data) {
    this.emit('open', data);
  }.bind(this));

  this.ws.on('close', function (data) {
    this.emit('close', data);
  }.bind(this));

  this.ws.on('error', function (data) {
    this.emit('error', data);
  }.bind(this));

  this.ws.on('message', function (data) {
    try {
      this.onRtmEvent(JSON.parse(data));
    } catch (e) {
      console.log(e);
    }
  }.bind(this));
}

SmartSlack.prototype.onRtmEvent = function (message) {

  this.emit('rawmessage', message);
  console.log('RAW MESSAGE:');
  console.log(message);

  switch (message.type) {

    case 'hello':
      this.connected = true;
      this.emit('connected');
      break;

    case 'message':
      this.emit('message', message);
      break;

    case 'pong':
    this._lastPong = _.now();
    console.log('LATENCY = ' + (this._lastPong - message.time) + 'ms');
    break;
  }

}

SmartSlack.prototype.postMessage = function (id, text, params) {
  params = _.extend({
    text: text,
    channel: id,
    username: this.name,
    as_user: true
  }, params || {});

  return this._apiCall('chat.postMessage', params);
};

SmartSlack.prototype._ping = function () {
  var data;
  var ping = { "type": "ping" };
  ping.id = this.messageId;
  ping.time = _.now();
  data = JSON.stringify(ping);
  this.ws.send(data);
  this.messageId += 1;
}

SmartSlack.prototype._sendSocket = function (data) {
  if (typeof data !== 'undefined') {
    data.id = this.messageId;
    data = JSON.stringify(data);
    this.ws.send(data);
    this.messageId += 1;
  }
}

SmartSlack.prototype._apiCall = function (method, params, callback) {

  params = _.merge(params || {}, { token: this.options.token });

  var postData = qs.stringify(params);

  var options = {
    hostname: 'slack.com',
    port: 443,
    path: '/api/' + method,
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': postData.length
    }
  };

  var req = https.request(options, function (res) {
    var output = '';
    var value;

    res.setEncoding('utf8');

    res.on('data', function (chunk) {
      output += chunk;
    });

    res.on('end', function () {
      if (callback) {
        if (res.statusCode === 200) {
          value = JSON.parse(output)
          callback(value);
        } else {
          callback({ 'ok': false, 'error': 'API response: ' + res.statusCode })
        }
      }

    })
  });

  req.on('error', function (e) {
    console.log('problem with request: ' + e.message);
  });

  req.write(postData);
  req.end();
}

module.exports = SmartSlack<commit_msg>Added method getChannelByName<commit_after>'use strict';

var EventEmitter = require('events').EventEmitter;
var https = require('https');
var qs = require('querystring');
var util = require('util');

var _ = require('lodash');
var WebSocket = require('ws');

var errors = {
    invalid_token: 'Error invalid access token, please provide a valid token.',
    missing_options_arg: 'Error missing required argument object options'

}

var SmartSlack = function (options) {

  if (!options){
    throw new Error(errors.missing_options_arg);
  }

  var accessToken = options.token;

  if (!accessToken || typeof accessToken !== 'string' ||
    !accessToken.match(/^([a-z]{4})\-([0-9]{11})\-([0-9a-zA-Z]{24})$/)) {
    throw new Error(errors.invalid_token);
  }

  this.options = _.defaults(options, this.options);
  this.authenticated = false;
  this.connected = false;
  this.messageId = 0;

  this.user = null;
  this.team = null;
}

util.inherits(SmartSlack, EventEmitter)

SmartSlack.prototype.authTest = function () {
  this._apiCall('auth.test', null, function test(data) {
    if (data) {
      if (data.ok) {
        console.log(data);
        return true;
      } else {
        return false;
      }
    }
  })
}

SmartSlack.prototype.apiTest = function (args, error) {
  var params = _.merge({}, args, error);
  this._apiCall('api.test', params, function test(data) {
    if (data) {
      if (data.ok) {
        console.log(data);
      } else {
        throw new Error(data.error);
      }
    }
  })
}

SmartSlack.prototype.getChannelByName = function (name) {
 return _.find(this.channels, {name: name} );
}

SmartSlack.prototype.getUserByName = function (name) {
 return _.find(this.users, {name: name} );
}

SmartSlack.prototype.login = function () {

  var _this = this;
  this._apiCall('rtm.start', null, function (data) {

    if (data) {

      if (!data.ok) {
        _this.emit('error', data.error);

      } else {

        //console.log(data);

        _this.authenticated = true;

        // Stash the Slack session data
        _this.users = data.users;
        _this.channels = data.channels;
        _this.groups = data.groups;
        _this.ims = data.ims;
        _this.user = data.self
        _this.team = data.team;

        // Connect
        _this.socketUrl = data.url;
        _this.connect();
      }
    }
  });
}

SmartSlack.prototype.connect = function () {
  this.ws = new WebSocket(this.socketUrl);

  this.ws.on('open', function (data) {
    this.emit('open', data);
  }.bind(this));

  this.ws.on('close', function (data) {
    this.emit('close', data);
  }.bind(this));

  this.ws.on('error', function (data) {
    this.emit('error', data);
  }.bind(this));

  this.ws.on('message', function (data) {
    try {
      this.onRtmEvent(JSON.parse(data));
    } catch (e) {
      console.log(e);
    }
  }.bind(this));
}

SmartSlack.prototype.onRtmEvent = function (message) {

  this.emit('rawmessage', message);
  console.log('RAW MESSAGE:');
  console.log(message);

  switch (message.type) {

    case 'hello':
      this.connected = true;
      this.emit('connected');
      break;

    case 'message':
      this.emit('message', message);
      break;

    case 'pong':
    this._lastPong = _.now();
    console.log('LATENCY = ' + (this._lastPong - message.time) + 'ms');
    break;
  }

}

SmartSlack.prototype.postMessage = function (id, text, params) {
  params = _.extend({
    text: text,
    channel: id,
    username: this.name,
    as_user: true
  }, params || {});

  return this._apiCall('chat.postMessage', params);
};

SmartSlack.prototype._ping = function () {
  var data;
  var ping = { "type": "ping" };
  ping.id = this.messageId;
  ping.time = _.now();
  data = JSON.stringify(ping);
  this.ws.send(data);
  this.messageId += 1;
}

SmartSlack.prototype._sendSocket = function (data) {
  if (typeof data !== 'undefined') {
    data.id = this.messageId;
    data = JSON.stringify(data);
    this.ws.send(data);
    this.messageId += 1;
  }
}

SmartSlack.prototype._apiCall = function (method, params, callback) {

  params = _.merge(params || {}, { token: this.options.token });

  var postData = qs.stringify(params);

  var options = {
    hostname: 'slack.com',
    port: 443,
    path: '/api/' + method,
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': postData.length
    }
  };

  var req = https.request(options, function (res) {
    var output = '';
    var value;

    res.setEncoding('utf8');

    res.on('data', function (chunk) {
      output += chunk;
    });

    res.on('end', function () {
      if (callback) {
        if (res.statusCode === 200) {
          value = JSON.parse(output)
          callback(value);
        } else {
          callback({ 'ok': false, 'error': 'API response: ' + res.statusCode })
        }
      }

    })
  });

  req.on('error', function (e) {
    console.log('problem with request: ' + e.message);
  });

  req.write(postData);
  req.end();
}

module.exports = SmartSlack<|endoftext|>


<commit_before>var _ = require('lodash'),
  fs = require('fs'),
  Model = require('./model'),
  Schema = require('./schema'),
  Store = require('./store');

var Database = module.exports = function Database(source){
  this._store = new Store();
  if (source){
    this.load(source);
  }
};

Database.prototype.load = function(source, callback){
  if (!_.isFunction(callback)) callback = function(){};
  if (_.isObject(source)){
    this._store = source;
    callback();
  } else {
    this._source = source;
    fs.exists(source, function(exist){
      if (!exist) return callback();
      fs.readFile(source, 'utf8', function(err, content){
        if (err) throw new Error('Database load error');
        this._store = new Store(JSON.parse(content));
        callback();
      });
    });
  }
};

Database.prototype.save = function(source, callback){
  if (typeof callback === 'undefined'){
    if (_.isFunction(source)){
      callback = source;
      source = this._source;
    } else {
      callback = function(){};
    }
  }

  var result = {},
    store = this._store;

  for (var i in store){
    result[i] = store[i].list();
  }

  fs.writeFile(source, JSON.stringify(result), callback);
};

Database.prototype.model = function(name, schema){
  var store = this._store,
    data = store.get(name);

  if (data){
    var index = _.without(Object.keys(store.list()), '_primary');
  } else {
    var index = [];
    store.set(name, new Store({_primary: 1}));
  }

  return new Model(name, this, schema, index);
};

Database.prototype.Model = Model;
Database.prototype.Schema = Schema;
Database.prototype.Store = Store;<commit_msg>Fixed database load<commit_after>var _ = require('lodash'),
  fs = require('fs'),
  Model = require('./model'),
  Schema = require('./schema'),
  Store = require('./store');

var Database = module.exports = function Database(source){
  this._store = new Store();
  if (source){
    this.load(source);
  }
};

Database.prototype.load = function(source, callback){
  if (_.isObject(source)){
    if (_.isFunction(callback)) callback();
  } else {
    var _this = this;
    this._source = source;
    if (_.isFunction(callback)){
      fs.exists(source, function(exist){
        if (!exist) return callback();
        fs.readFile(source, 'utf8', function(err, content){
          if (err) throw new Error('Database load error');
          _this._store = new Store(JSON.parse(content));
          callback();
        });
      });
    } else {
      var exist = fs.existsSync(source);
      if (exist){
        var content = fs.readFileSync(source, 'utf8');
        _this._store = new Store(JSON.parse(content));
      }
    }
  }
};

Database.prototype.save = function(source, callback){
  if (typeof callback === 'undefined'){
    if (_.isFunction(source)){
      callback = source;
      source = this._source;
    } else {
      callback = function(){};
    }
  }

  var result = {},
    store = this._store.list();

  for (var i in store){
    result[i] = store[i].list();
  }

  fs.writeFile(source, JSON.stringify(result), callback);
};

Database.prototype.model = function(name, schema){
  var store = this._store,
    data = store.get(name);

  if (data){
    var index = _.without(Object.keys(store.list()), '_primary');
  } else {
    var index = [];
    store.set(name, new Store({_primary: 1}));
  }

  return new Model(name, this, schema, index);
};

Database.prototype.Model = Model;
Database.prototype.Schema = Schema;
Database.prototype.Store = Store;<|endoftext|>


<commit_before>/**
 * extenion of ui-select from ui-angular
 * to support infinity list of items
 *
 */

angular
    .module('ui-select-infinity', [])
    .directive('reachInfinity', function($parse, $timeout) {
        function height(elem) {
            elem = elem[0] || elem;
            if (isNaN(elem.offsetHeight)) {
                return elem.document.documentElement.clientHeight;
            } else {
                return elem.offsetHeight;
            }
        }

        function offsetTop(elem) {
            if (!elem[0].getBoundingClientRect || elem.css('none')) {
                return;
            }
            return elem[0].getBoundingClientRect().top + pageYOffset(elem);
        }

        function pageYOffset(elem) {
            elem = elem[0] || elem;
            if (isNaN(window.pageYOffset)) {
                return elem.document.documentElement.scrollTop;
            } else {
                return elem.ownerDocument.defaultView.pageYOffset;
            }
        }

        /**
         * Since scroll events can fire at a high rate, the event handler
         * shouldn't execute computationally expensive operations such as DOM modifications.
         * based on https://developer.mozilla.org/en-US/docs/Web/Events/scroll#requestAnimationFrame_.2B_customEvent
         *
         * @param type
         * @param name
         * @param (obj)
         * @returns {Function}
         */
        function throttle(type, name, obj) {
            var obj = obj || window;
            var running = false;
            var func = function() {
                if (running) { return; }
                running = true;
                requestAnimationFrame(function() {
                    obj.dispatchEvent(new CustomEvent(name));
                    running = false;
                });
            };

            obj.addEventListener(type, func);

            return function() {
                obj.removeEventListener(type, func);
            };
        }

        return {
            link: function(scope, elem, attrs) {
                var container = elem,
                    scrollDistance = 0.3,
                    removeThrottle;

                function tryToSetupInfinityScroll() {
                    var rows = angular.element('.ui-select-choices-row');

                    if (rows.length === 0) {
                        setupLater();
                        return false;
                    }

                    container = angular.element(document.querySelector('.ui-select-choices'));
                    elem = angular.element(rows[rows.length - 1]);
                    var handler = function() {
                        var containerBottom = height(container),
                            containerTopOffset = 0,
                            elementBottom;

                        if (offsetTop(container) !== void 0) {
                            containerTopOffset = offsetTop(container);
                        }

                        elementBottom = offsetTop(elem) - containerTopOffset + height(elem);

                        var remaining = elementBottom - containerBottom,
                            shouldScroll = remaining <= height(container) * scrollDistance + 1;

                        if (shouldScroll) {
                            $parse(attrs['reachInfinity'])(scope);
                        }
                    };

                    removeThrottle = throttle('scroll', 'optimizedScroll', container[0]);
                    container.on('optimizedScroll', handler);

                    scope.$on('$destroy', function() {
                        removeThrottle();
                        container.off('optimizedScroll', handler);
                    });

                    return true;
                }

                function setupLater() {
                    $timeout(tryToSetupInfinityScroll, 2000);
                }

                setupLater();
            }
        }
    });<commit_msg>decoupled from jquery<commit_after>/**
 * extenion of ui-select from ui-angular
 * to support infinity list of items
 *
 */

angular
    .module('ui-select-infinity', [])
    .directive('reachInfinity', function($parse, $timeout) {
        function height(elem) {
            elem = elem[0] || elem;
            if (isNaN(elem.offsetHeight)) {
                return elem.document.documentElement.clientHeight;
            } else {
                return elem.offsetHeight;
            }
        }

        function offsetTop(elem) {
            if (!elem[0].getBoundingClientRect || elem.css('none')) {
                return;
            }
            return elem[0].getBoundingClientRect().top + pageYOffset(elem);
        }

        function pageYOffset(elem) {
            elem = elem[0] || elem;
            if (isNaN(window.pageYOffset)) {
                return elem.document.documentElement.scrollTop;
            } else {
                return elem.ownerDocument.defaultView.pageYOffset;
            }
        }

        /**
         * Since scroll events can fire at a high rate, the event handler
         * shouldn't execute computationally expensive operations such as DOM modifications.
         * based on https://developer.mozilla.org/en-US/docs/Web/Events/scroll#requestAnimationFrame_.2B_customEvent
         *
         * @param type
         * @param name
         * @param (obj)
         * @returns {Function}
         */
        function throttle(type, name, obj) {
            var obj = obj || window;
            var running = false;
            var func = function() {
                if (running) { return; }
                running = true;
                requestAnimationFrame(function() {
                    obj.dispatchEvent(new CustomEvent(name));
                    running = false;
                });
            };

            obj.addEventListener(type, func);

            return function() {
                obj.removeEventListener(type, func);
            };
        }

        return {
            link: function(scope, elem, attrs) {
                var container = elem,
                    scrollDistance = 0.3,
                    removeThrottle;

                function tryToSetupInfinityScroll() {
                    var rows = document.querySelectorAll('.ui-select-choices-row');

                    if (rows.length === 0) {
                        setupLater();
                        return false;
                    }

                    container = angular.element(document.querySelector('.ui-select-choices'));
                    elem = angular.element(rows[rows.length - 1]);
                    var handler = function() {
                        var containerBottom = height(container),
                            containerTopOffset = 0,
                            elementBottom;

                        if (offsetTop(container) !== void 0) {
                            containerTopOffset = offsetTop(container);
                        }

                        elementBottom = offsetTop(elem) - containerTopOffset + height(elem);

                        var remaining = elementBottom - containerBottom,
                            shouldScroll = remaining <= height(container) * scrollDistance + 1;

                        if (shouldScroll) {
                            $parse(attrs['reachInfinity'])(scope);
                        }
                    };

                    removeThrottle = throttle('scroll', 'optimizedScroll', container[0]);
                    container.on('optimizedScroll', handler);

                    scope.$on('$destroy', function() {
                        removeThrottle();
                        container.off('optimizedScroll', handler);
                    });

                    return true;
                }

                function setupLater() {
                    $timeout(tryToSetupInfinityScroll, 2000);
                }

                setupLater();
            }
        }
    });<|endoftext|>


<commit_before>// es6 runtime requirements
require('babel/polyfill');
import request from 'request';
import htmlparser from 'htmlparser';
import soupselect from 'soupselect';

export default function gpai({
  id = null
}) {
  if(id == null)
    throw new Error("Package name cannot be null!");

  if(!/([a-z_]{1}[a-z0-9_]*(\.[a-z_]{1}[a-z0-9_]*)*)$/.test(id))
    throw new Error("Invalid package name!");

  let url = "https://play.google.com/store/apps/details";
  let qs  = {id:id}
  let select = soupselect.select;

  return new Promise((resolve, reject) => {
    request.get({url:url, qs:qs}, (err, response, body) => {
      if(err) reject(error);
      if(response.statusCode != 200) reject(body);
      let handler = new htmlparser.DefaultHandler(function (error, dom) {
        if (error) reject(error);
        else {
          let info = {
            url : url + "?id="+id,
            pkg : id
          };
          try {
            let containers = select(dom, 'div.info-container');
            if(!containers.length) reject(new Error("Information container not found"));

            let container = containers[0];
            let title = select(container, 'div.document-title');
            if(!title.length) reject(new Error("Application title not found"));
            info.name = title[0].children[1].children[0].raw;

            let links = select(dom, 'a.document-subtitle');
            let company = links[0].attribs.href.replace("/store/apps/developer?id=","");
            info.company = company;

            let stars = select(dom, 'div.stars-container');
            stars = stars[0].children[1].attribs['aria-label'];
            stars = stars.match(/\d[\,\.]\d/)[0];
            info.stars = stars;

            let count = select(dom, 'div.stars-count');
            count = count[0].children[2].raw.replace(")","");
            info.stars_count = count.trim();

            let img = select(dom, 'div.cover-container');
            img = select(img, 'img.cover-image');
            img = img[0].attribs.src;
            info.logo = img;

            resolve(info);
          }catch(e) {
            reject(e);
          }
        }
      });
      let parser = new htmlparser.Parser(handler);
      parser.parseComplete(body);
    });
  });
}
<commit_msg>remove babel polyfill<commit_after>import request from 'request';
import htmlparser from 'htmlparser';
import soupselect from 'soupselect';

export default function gpai({
  id = null
}) {
  if(id == null)
    throw new Error("Package name cannot be null!");

  if(!/([a-z_]{1}[a-z0-9_]*(\.[a-z_]{1}[a-z0-9_]*)*)$/.test(id))
    throw new Error("Invalid package name!");

  let url = "https://play.google.com/store/apps/details";
  let qs  = {id:id}
  let select = soupselect.select;

  return new Promise((resolve, reject) => {
    request.get({url:url, qs:qs}, (err, response, body) => {
      if(err) reject(error);
      if(response.statusCode != 200) reject(body);
      let handler = new htmlparser.DefaultHandler(function (error, dom) {
        if (error) reject(error);
        else {
          let info = {
            url : url + "?id="+id,
            pkg : id
          };
          try {
            let containers = select(dom, 'div.info-container');
            if(!containers.length) reject(new Error("Information container not found"));

            let container = containers[0];
            let title = select(container, 'div.document-title');
            if(!title.length) reject(new Error("Application title not found"));
            info.name = title[0].children[1].children[0].raw;

            let links = select(dom, 'a.document-subtitle');
            let company = links[0].attribs.href.replace("/store/apps/developer?id=","");
            info.company = company;

            let stars = select(dom, 'div.stars-container');
            stars = stars[0].children[1].attribs['aria-label'];
            stars = stars.match(/\d[\,\.]\d/)[0];
            info.stars = stars;

            let count = select(dom, 'div.stars-count');
            count = count[0].children[2].raw.replace(")","");
            info.stars_count = count.trim();

            let img = select(dom, 'div.cover-container');
            img = select(img, 'img.cover-image');
            img = img[0].attribs.src;
            info.logo = img;

            resolve(info);
          }catch(e) {
            reject(e);
          }
        }
      });
      let parser = new htmlparser.Parser(handler);
      parser.parseComplete(body);
    });
  });
}
<|endoftext|>


<commit_before>'use strict';
/**
 *  index.js - Shawn Rapp 2014-10-10
 *  Party Line subsystem interface library file.
 *  @author Shawn Rapp
 *  @version 1.0.0
 *  @license MIT. Read LICENSE for more information.
 *  @fileOverview Main library file.
 */

/**
 * Module dependencies.
 */

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

    self.worker_id = "";
    self.bus_id = "";
    self.listen_context = [];
    self.packet_handlers = [];
    self.input_stream = require('JSONStream').parse();
    process.stdin.pipe(self.input_stream);
    self.outbound_packets = [];
    self.sending_state = false;

    self.logger = require('winston');
    self.logger.add(self.logger.transports.File, {filename: __dirname+'/../../../pl-sub.log'});
    self.logger.remove(self.logger.transports.Console);

    /**
     *  Outputs a single packet to stdout stream.
     *  Defined inside of block because function is needed immediately.
     */
    self.send = function(transmit_packet) {
        self.outbound_packets.push(transmit_packet);

        //already running send in a different thread.
        if (self.sending_state) return;

        //set state high this thread is going to send.
        self.sending_state = true;

        //keep sending till we run out of packets
        while(self.outbound_packets.length > 0) {
            var packet = self.outbound_packets.pop();
            console.log(JSON.stringify(packet));
        }

        //set state low this thread is finished.
        self.sending_state = false;
    };
    self.logger.info("Initialization complete.");

}

var partylinesub = module.exports = exports = new PartyLineSub;
partylinesub.send({context:"bus", type:"whoAmI"})

/**
 * Sends to the bus what contexts this subsystem wants to listen to.
 * Accepts no parameters because the context should be set to
 * self.listen_context array.
 */
PartyLineSub.prototype.sendSetListenerContext = function(){
    var self = this;
    var setContextPacket = {
        context: "bus",
        type: "setListenContext",
        listen_context: self.listen_context
    };
    self.send(setContextPacket);
    self.logger.info("Setting listener to "+self.listen_context.toString());
};

/**
 * Adds a context this sub wants to listen on in the stack and sends the stack
 * to the bus.
 */
PartyLineSub.prototype.addListeningContext = function(new_context) {
    var self = this;

    self.listen_context.push(new_context);
    self.sendSetListenerContext();
};

/**
 * Removes the specified listening context from the stack of listening and sends
 * the results to the bus.
 */
PartyLineSub.prototype.removeListeningContext = function(delete_context) {
    var self = this;

    var new_context_stack = [];

    self.listen_context.forEach(function(context){
       if (context != delete_context) {
           new_context_stack.push(context);
       }
    });

    self.listen_context = new_context_stack;
    self.sendSetListenerContext();
};

/**
 * used to transmit large files accross the bus.
 *  !!! Killed because it was too unstable !!!
 */
// PartyLineSub.prototype.sendFile = function(fd, packet, stats) {
//     var self = this;
//     var fs = require('fs');
//     //size of each block
//     var block_size = 1024;
//     //total number of blocks including ending partial
//     var total_blocks = Math.floor(stats.size / block_size) + (block_size%stats.size?1:0);
//     var resend_blocks = [];
//     var quit_xfer = false;

//     function sendBlock(block_number) {
//         if (quit_xfer) return;  //abort if flag is high

//         var block_position = block_number * block_size;
//         var read_buffer = new Buffer(block_size);
//         var bytesRead = fs.readSync(fd, read_buffer, 0, block_size, block_position);
//         var file_packet = {
//             context: packet.from,
//             type: "blockLongTransfer",
//             block_number: current_block,
//             block_size: bytesRead,
//             data:read_buffer.toString('base64')
//         };
//         self.send(file_packet);
//     }

//     function resendBlocks() {
//         if (quit_xfer) {
//             //clear resend_blocks stack to try to prevent logic that would come back
//             resend_blocks = [];
//             return;
//         }
//         while (resend_blocks.length > 0) {
//             var block_number = resend_blocks.pop();
//             sendBlock(block_number);
//         }
//     }

//     //setup a listener for packets to be resent
//     self.on("resendBlock", function(resend_packet){
//         //if it doesn't belong to us, just ignore it
//         if (resend_packet.request_id != packet.request_id) return;

//         resend_blocks.push(resend_packet.resend_block);
//     });

//     //event that only the client should send on a transfer abort or
//     //file has been sent successfully
//     self.on("endLongTransfer", function(end_packet){
//         fs.close(fd);
//         quit_xfer = true;
//     });

//     var ack_packet = {
//         context: packet.from,
//         type: "startLongTransfer",
//         request_id: packet.request_id,
//         block_size: block_size,
//         total_blocks: total_blocks,
//         header: {
//             "Content-Type": "" //@todo
//         }
//     };
//     self.send(ack_packet);

//     for (var current_block=0; current_block<total_blocks; current_block++) {
//         sendBlock(current_block);

//         //every 8 blocks lets do some resends.
//         //We don't want to go past 8k so our client handler won't have to pause streaming to user.
//         if (current_block%8 === 0) {
//             resendBlocks();
//         }
//     }

//     resendBlocks();
// };

// /**
//  * used to receive large files accross the bus.
//  */
// PartyLineSub.prototype.receiveFile = function(file_buffer, init_packet){
//     var self = this;
//     //chunks being processed
//     var chunks = [];
//     //chunks written
//     var last_chunk_written = -1;
//     var request_id = init_packet.request_id;

//     /**
//      * Object for managing transfered blocks into chunks.
//      */
//     function ReceiveChunk(chunk_pos){
//         var rchunk = this;
//         // buffer is 8 blocks long
//         var outgoing_buffer = new Buffer(8*init_packet.block_size);
//         var received_blocks = [];
//         this.completed = false;
//         this.chunk_pos = chunk_pos;

//         function incomingBlock(packet) {
//             //check to see if some how we ended up in the wrong chunk
//             if (Math.floor(packet.block_position/8) != chunk_pos) return;
//             //calculate the offset in buffer based on block_position
//             var buffer_pos = packet.block_position % 8;

//             //check to see if we have already received this block
//             if (received_blocks.indexOf(packet.block_position) != -1) return;
//             //check to see if we missed a packet
//             if (received_blocks[received_blocks.length-1]+1 < packet.block_position) {
//                 var resend_packet = {
//                     context: packet.from,
//                     type: "resendBlock",
//                     resend_block: received_blocks[received_blocks.length-1]+1
//                 };
//                 self.send(resend_packet);
//             }

//             outgoing_buffer[buffer_pos] = (new Buffer(packet.data, "base64")).toString();
//             //mark this block as successful
//             received_blocks.push(packet.block_position);

//             //check to see if chunk has been completed.
//             if (received_blocks.length > 7) {
//                 if (last_chunk_written+1 == chunk_pos) {
//                     file_buffer.write(outgoing_buffer);
//                 }
//                 rchunk.completed = true;
//             }
//         }

//         self.on("blockLongTransfer", function(packet) {
//             //check to see if packet belongs to us
//             if (packet.request_id != request_id) return;

//             var chunk_position = Math.floor(packet.block_position/8);
//             if (chunk_position == rchunk.chunk_pos) {
//                 var buffer_offset = packet.block_position%8;
//                 outgoing_buffer[buffer_offset] = (new Buffer(packet.data, "base64")).toString();
//                 received_blocks.push(packet.block_position);

//                 if (received_blocks.length > 7) {
//                     rchunk.completed = true;
//                 }
//             }
//         });
//     }

//     //watches incoming blocks and decides whether or not to start a new chunk
//     //to handle the blocks.
//     self.on("blockLongTransfer", function(packet){
//         if (packet.request_id != request_id) return;

//         var chunk_position = Math.floor(packet.block_position/8);
//         if (chunks.indexOf(chunk_position)==-1) {
//             new ReceiveChunk(chunk_position);
//             chunks.push(chunk_position);
//         }
//     });
// };

/**
 * allows developers to attach functions to packets based on packet
 * type.
 * More than one function can be attached to the same "event"
 */
PartyLineSub.prototype.on = function(packet_type, cb_packet_handler) {
    var self = this;

    var new_handler = {
        packet_type: packet_type,
        cb_packet_handler: cb_packet_handler
    };
    self.packet_handlers.push(new_handler);
};

/**
 * Process incoming JSON data looking for packets.
 */
partylinesub.input_stream.on("data",function(packet){
    var self = partylinesub;

    //check if packet has context and if its for this sub
    if (typeof(packet.context) == 'undefined' || !packet.context.match(self.listen_context)) {
        return; //packet is not for this service
    }

    //messages coming down from the bus
    if (packet.from == "bus") {
        switch(packet.type) {
            case "youAre":
                self.bus_id = packet.bus_id;
                self.worker_id = packet.worker_id;
                break;
        }
    }

    //send this packet to calling application
    self.packet_handlers.forEach(function(packet_handler){
       if (packet.type == packet_handler.packet_type) {
           packet_handler.cb_packet_handler(packet);
       }
    });
    self.logger.info("From:"+packet.from+"  Context:"+packet.context+"  Type:"+packet.type);
});

/**
 * A general catch for when something goes wrong in the down stream and
 * sends a message to the upstream.
 */
partylinesub.input_stream.on("error", function(err){
    // Do we really want to send the error as a broadcast on the bus?
    // var error_packet = {
    //     type: 'error',
    //     data: err
    // };
    // partylinesub.send(error_packet);
    partylinesub.logger.error(err);
});
<commit_msg>Hooking up the SAP services.<commit_after>'use strict';
/**
 *  index.js - Shawn Rapp 2014-10-10
 *  Party Line subsystem interface library file.
 *  @author Shawn Rapp
 *  @version 1.0.0
 *  @license MIT. Read LICENSE for more information.
 *  @fileOverview Main library file.
 */

/**
 * Module dependencies.
 */

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

    self.worker_id = "";
    self.bus_id = "";
    self.listen_context = [];
    self.packet_handlers = [];
    self.input_stream = require('JSONStream').parse();
    process.stdin.pipe(self.input_stream);
    self.outbound_packets = [];
    self.sending_state = false;

    self.logger = require('winston');
    self.logger.add(self.logger.transports.File, {filename: __dirname+'/../../../pl-sub.log'});
    self.logger.remove(self.logger.transports.Console);

    /**
     *  Outputs a single packet to stdout stream.
     *  Defined inside of block because function is needed immediately.
     */
    self.send = function(transmit_packet) {
        self.outbound_packets.push(transmit_packet);

        //already running send in a different thread.
        if (self.sending_state) return;

        //set state high this thread is going to send.
        self.sending_state = true;

        //keep sending till we run out of packets
        while(self.outbound_packets.length > 0) {
            var packet = self.outbound_packets.pop();
            console.log(JSON.stringify(packet));
        }

        //set state low this thread is finished.
        self.sending_state = false;
    };
    self.logger.info("Initialization complete.");

}

var partylinesub = module.exports = exports = new PartyLineSub;
partylinesub.send({context:"bus", type:"whoAmI"})

/**
 * Sends to the bus what contexts this subsystem wants to listen to.
 * Accepts no parameters because the context should be set to
 * self.listen_context array.
 */
PartyLineSub.prototype.sendSetListenerContext = function(){
    var self = this;
    var setContextPacket = {
        context: "bus",
        type: "setListenContext",
        listen_context: self.listen_context
    };
    self.send(setContextPacket);
    self.logger.info("Setting listener to "+self.listen_context.toString());
};

/**
 * Adds a context this sub wants to listen on in the stack and sends the stack
 * to the bus.
 */
PartyLineSub.prototype.addListeningContext = function(new_context) {
    var self = this;

    self.listen_context.push(new_context);
    self.sendSetListenerContext();
};

/**
 * Removes the specified listening context from the stack of listening and sends
 * the results to the bus.
 */
PartyLineSub.prototype.removeListeningContext = function(delete_context) {
    var self = this;

    var new_context_stack = [];

    self.listen_context.forEach(function(context){
       if (context != delete_context) {
           new_context_stack.push(context);
       }
    });

    self.listen_context = new_context_stack;
    self.sendSetListenerContext();
};

PartyLineSub.prototype.queryService = function(query_context, cb_Results) {
    var self = this;

    var sap_packet = {
        context: "bus",
        type: "sapQuery",
        service_context: "web.html",
    };

    self.send(sap_packet);

    self.on("serviceList", function(packet){
        self.logger.info("Recieved Service List");
        cb_Results(packet.serviceList);
    });
};

/**
 * used to transmit large files accross the bus.
 *  !!! Killed because it was too unstable !!!
 */
// PartyLineSub.prototype.sendFile = function(fd, packet, stats) {
//     var self = this;
//     var fs = require('fs');
//     //size of each block
//     var block_size = 1024;
//     //total number of blocks including ending partial
//     var total_blocks = Math.floor(stats.size / block_size) + (block_size%stats.size?1:0);
//     var resend_blocks = [];
//     var quit_xfer = false;

//     function sendBlock(block_number) {
//         if (quit_xfer) return;  //abort if flag is high

//         var block_position = block_number * block_size;
//         var read_buffer = new Buffer(block_size);
//         var bytesRead = fs.readSync(fd, read_buffer, 0, block_size, block_position);
//         var file_packet = {
//             context: packet.from,
//             type: "blockLongTransfer",
//             block_number: current_block,
//             block_size: bytesRead,
//             data:read_buffer.toString('base64')
//         };
//         self.send(file_packet);
//     }

//     function resendBlocks() {
//         if (quit_xfer) {
//             //clear resend_blocks stack to try to prevent logic that would come back
//             resend_blocks = [];
//             return;
//         }
//         while (resend_blocks.length > 0) {
//             var block_number = resend_blocks.pop();
//             sendBlock(block_number);
//         }
//     }

//     //setup a listener for packets to be resent
//     self.on("resendBlock", function(resend_packet){
//         //if it doesn't belong to us, just ignore it
//         if (resend_packet.request_id != packet.request_id) return;

//         resend_blocks.push(resend_packet.resend_block);
//     });

//     //event that only the client should send on a transfer abort or
//     //file has been sent successfully
//     self.on("endLongTransfer", function(end_packet){
//         fs.close(fd);
//         quit_xfer = true;
//     });

//     var ack_packet = {
//         context: packet.from,
//         type: "startLongTransfer",
//         request_id: packet.request_id,
//         block_size: block_size,
//         total_blocks: total_blocks,
//         header: {
//             "Content-Type": "" //@todo
//         }
//     };
//     self.send(ack_packet);

//     for (var current_block=0; current_block<total_blocks; current_block++) {
//         sendBlock(current_block);

//         //every 8 blocks lets do some resends.
//         //We don't want to go past 8k so our client handler won't have to pause streaming to user.
//         if (current_block%8 === 0) {
//             resendBlocks();
//         }
//     }

//     resendBlocks();
// };

// /**
//  * used to receive large files accross the bus.
//  */
// PartyLineSub.prototype.receiveFile = function(file_buffer, init_packet){
//     var self = this;
//     //chunks being processed
//     var chunks = [];
//     //chunks written
//     var last_chunk_written = -1;
//     var request_id = init_packet.request_id;

//     /**
//      * Object for managing transfered blocks into chunks.
//      */
//     function ReceiveChunk(chunk_pos){
//         var rchunk = this;
//         // buffer is 8 blocks long
//         var outgoing_buffer = new Buffer(8*init_packet.block_size);
//         var received_blocks = [];
//         this.completed = false;
//         this.chunk_pos = chunk_pos;

//         function incomingBlock(packet) {
//             //check to see if some how we ended up in the wrong chunk
//             if (Math.floor(packet.block_position/8) != chunk_pos) return;
//             //calculate the offset in buffer based on block_position
//             var buffer_pos = packet.block_position % 8;

//             //check to see if we have already received this block
//             if (received_blocks.indexOf(packet.block_position) != -1) return;
//             //check to see if we missed a packet
//             if (received_blocks[received_blocks.length-1]+1 < packet.block_position) {
//                 var resend_packet = {
//                     context: packet.from,
//                     type: "resendBlock",
//                     resend_block: received_blocks[received_blocks.length-1]+1
//                 };
//                 self.send(resend_packet);
//             }

//             outgoing_buffer[buffer_pos] = (new Buffer(packet.data, "base64")).toString();
//             //mark this block as successful
//             received_blocks.push(packet.block_position);

//             //check to see if chunk has been completed.
//             if (received_blocks.length > 7) {
//                 if (last_chunk_written+1 == chunk_pos) {
//                     file_buffer.write(outgoing_buffer);
//                 }
//                 rchunk.completed = true;
//             }
//         }

//         self.on("blockLongTransfer", function(packet) {
//             //check to see if packet belongs to us
//             if (packet.request_id != request_id) return;

//             var chunk_position = Math.floor(packet.block_position/8);
//             if (chunk_position == rchunk.chunk_pos) {
//                 var buffer_offset = packet.block_position%8;
//                 outgoing_buffer[buffer_offset] = (new Buffer(packet.data, "base64")).toString();
//                 received_blocks.push(packet.block_position);

//                 if (received_blocks.length > 7) {
//                     rchunk.completed = true;
//                 }
//             }
//         });
//     }

//     //watches incoming blocks and decides whether or not to start a new chunk
//     //to handle the blocks.
//     self.on("blockLongTransfer", function(packet){
//         if (packet.request_id != request_id) return;

//         var chunk_position = Math.floor(packet.block_position/8);
//         if (chunks.indexOf(chunk_position)==-1) {
//             new ReceiveChunk(chunk_position);
//             chunks.push(chunk_position);
//         }
//     });
// };

/**
 * allows developers to attach functions to packets based on packet
 * type.
 * More than one function can be attached to the same "event"
 */
PartyLineSub.prototype.on = function(packet_type, cb_packet_handler) {
    var self = this;

    var new_handler = {
        packet_type: packet_type,
        cb_packet_handler: cb_packet_handler
    };
    self.packet_handlers.push(new_handler);
};

/**
 * Process incoming JSON data looking for packets.
 */
partylinesub.input_stream.on("data",function(packet){
    var self = partylinesub;

    //check if packet has context and if its for this sub
    if (typeof(packet.context) == 'undefined' || !packet.context.match(self.listen_context)) {
        return; //packet is not for this service
    }

    //messages coming down from the bus
    if (packet.from == "bus") {
        switch(packet.type) {
            case "youAre":
                self.bus_id = packet.bus_id;
                self.worker_id = packet.worker_id;
                break;
        }
    }

    //send this packet to calling application
    self.packet_handlers.forEach(function(packet_handler){
       if (packet.type == packet_handler.packet_type) {
           packet_handler.cb_packet_handler(packet);
       }
    });
    self.logger.info("From:"+packet.from+"  Context:"+packet.context+"  Type:"+packet.type);
});

/**
 * A general catch for when something goes wrong in the down stream and
 * sends a message to the upstream.
 */
partylinesub.input_stream.on("error", function(err){
    // Do we really want to send the error as a broadcast on the bus?
    // var error_packet = {
    //     type: 'error',
    //     data: err
    // };
    // partylinesub.send(error_packet);
    partylinesub.logger.error(err);
});
<|endoftext|>