<commit_before>module.exports = {
  /* eslint-disable quotes */

  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },

  "parser": "babel-eslint",

  "plugins": [
    "babel"
  ],

  "ecmaFeatures": {
    "arrowFunctions": true, // enable arrow functions
    "binaryLiterals": true, // enable binary literals
    "blockBindings": true, // enable let and const (aka block bindings)
    "classes": true, // enable classes
    "defaultParams": true, // enable default function parameters
    "destructuring": true, // enable destructuring
    "forOf": true, // enable for-of loops
    "generators": true, // enable generators
    "modules": true, // enable modules and global strict mode
    "objectLiteralComputedProperties": true, // enable computed object literal property names
    "objectLiteralDuplicateProperties": false, // enable duplicate object literal properties
    "objectLiteralShorthandMethods": false, // enable object literal shorthand methods
    "objectLiteralShorthandProperties": true, // enable object literal shorthand properties
    "octalLiterals": true, // enable octal literals
    "regexUFlag": true, // enable the regular expression u flag
    "regexYFlag": true, // enable the regular expression y flag
    "restParams": true, // enable the rest parameters
    "spread": true, // enable the spread operator for arrays
    "superInFunctions": true, // enable super references inside of functions
    "templateStrings": true, // enable template strings
    "unicodeCodePointEscapes": true, // enable code point escapes
    "globalReturn": false, // allow return statements in the global scope
    "jsx": true, // enable JSX
    "experimentalObjectRestSpread": false // experimental object rest/spread properties
  },

  "rules": {

/**
 * eslint-plugin-babel rule toggles
 */
    "babel/generator-star-spacing": [2, "after"],
    "babel/new-cap": 0,
    "babel/array-bracket-spacing": 0,
    "babel/object-curly-spacing": [2, "never"],
    "babel/object-shorthand": 0,
    "babel/arrow-parens": 0,
    "babel/no-await-in-loop": 2,

/**
 * ES6+
 */
    "arrow-body-style": 0,
    "arrow-spacing": 2,
    "constructor-super": 2,
    "no-confusing-arrow": 2,
    "no-class-assign": 2,
    "no-const-assign": 2,
    "no-dupe-class-members": 2,
    "no-this-before-super": 2,
    "no-var": 2,
    "prefer-arrow-callback": 0,
    "prefer-const": 2,
    "prefer-reflect": 0,
    "prefer-spread": 2,
    "prefer-template": 2,
    "require-yield": 0,

/**
 * Variables
 */
    "no-shadow": 0,
    "no-shadow-restricted-names": 2,
    "no-unused-vars": [2, {
      "vars": "local",
      "args": "none"
    }],
    "no-use-before-define": 0,
    "no-undef": 2,
    "no-delete-var": 2,

/**
 * Possible errors
 */
    "comma-dangle": [2, "never"],
    "no-cond-assign": [2, "always"],
    "no-console": 1,
    "no-constant-condition": 2,
    "no-control-regex": 2,
    "no-debugger": 2,
    "no-dupe-args": 2,
    "no-dupe-keys": 2,
    "no-duplicate-case": 2,
    "no-empty-character-class": 2,
    "no-empty": 2,
    "no-ex-assign": 2,
    "no-extra-semi": 2,
    "no-func-assign": 2,
    "no-inner-declarations": 2,
    "no-invalid-regexp": 2,
    "no-irregular-whitespace": 2,
    "no-negated-in-lhs": 2,
    "no-obj-calls": 2,
    "no-regex-spaces": 2,
    "no-sparse-arrays": 2,
    "no-unreachable": 2,
    "use-isnan": 2,
    "valid-jsdoc": 0,
    "valid-typeof": 2,
    "no-unexpected-multiline": 2,
    "strict": [2, "never"],

    // consistent-return had a bug and in eslint@2.x.x it is more strict, disabling for now
    "consistent-return": 0,
/**
 * Best practices
 */
    "no-extra-boolean-cast": 2,
    "curly": [2, "multi-line"],
    "default-case": 2,
    "dot-notation": [2, {
      "allowKeywords": true
    }],
    "eqeqeq": 2,
    "guard-for-in": 0,
    "no-caller": 2,
    "no-eq-null": 2,
    "no-eval": 2,
    "no-extend-native": 2,
    "no-extra-bind": 2,
    "no-fallthrough": 2,
    "no-floating-decimal": 2,
    "no-implied-eval": 2,
    "no-lone-blocks": 2,
    "no-loop-func": 2,
    "no-multi-str": 2,
    "no-native-reassign": 2,
    "no-new": 2,
    "no-new-func": 2,
    "no-new-wrappers": 2,
    "no-octal": 2,
    "no-octal-escape": 2,
    "no-proto": 2,
    "no-redeclare": 2,
    "no-return-assign": 2,
    "no-script-url": 2,
    "no-self-compare": 2,
    "no-sequences": 2,
    "no-throw-literal": 2,
    "no-with": 2,
    "radix": 2,
    "wrap-iife": [2, "any"],
    "yoda": 2,

/**
 * Style
 */
    "no-mixed-spaces-and-tabs": 2,
    "no-lonely-if": 2,
    "no-array-constructor": 2,
    "no-new-object": 2,
    "new-parens": 2,
    "consistent-this": [2, "self"],
    "space-unary-ops": [1, {"words": true, "nonwords": false}],
    "space-in-parens": [2, "never"],
    "space-before-blocks": [2, "always"],
    "array-bracket-spacing": [2, "never"],
    "indent": [2, 2, {"SwitchCase": 1}],
    "brace-style": [2, "1tbs", {
      "allowSingleLine": true
    }],
    "quotes": [
      2, "single", "avoid-escape"
    ],
    "camelcase": [2, {
      "properties": "never"
    }],
    "comma-spacing": [2, {
      "before": false,
      "after": true
    }],
    "comma-style": [2, "last"],
    "eol-last": 2,
    "key-spacing": [0, {
      "beforeColon": false,
      "afterColon": true
    }],
    "no-multiple-empty-lines": [2, {
      "max": 2
    }],
    "no-unneeded-ternary": 2,
    "no-nested-ternary": 2,
    "no-spaced-func": 2,
    "no-trailing-spaces": 2,
    "no-extra-parens": 0,
    "no-underscore-dangle": 0,
    "one-var": [2, "never"],
    "padded-blocks": [2, "never"],
    "semi": [2, "always"],
    "semi-spacing": [2, {
      "before": false,
      "after": true
    }],
    "keyword-spacing": 2,
    "space-before-function-paren": [2, {
      "anonymous": "always",
      "named": "never"
    }],
    "space-infix-ops": 2,
    "spaced-comment": 2,
    "no-multi-spaces": 0,
    "max-len": [2, 100, 2, {
      "ignoreComments": false,
      "ignoreUrls": true
    }]
  }
};
<commit_msg>Change object-curly-spacing per #16<commit_after>module.exports = {
  /* eslint-disable quotes */

  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },

  "parser": "babel-eslint",

  "plugins": [
    "babel"
  ],

  "ecmaFeatures": {
    "arrowFunctions": true, // enable arrow functions
    "binaryLiterals": true, // enable binary literals
    "blockBindings": true, // enable let and const (aka block bindings)
    "classes": true, // enable classes
    "defaultParams": true, // enable default function parameters
    "destructuring": true, // enable destructuring
    "forOf": true, // enable for-of loops
    "generators": true, // enable generators
    "modules": true, // enable modules and global strict mode
    "objectLiteralComputedProperties": true, // enable computed object literal property names
    "objectLiteralDuplicateProperties": false, // enable duplicate object literal properties
    "objectLiteralShorthandMethods": false, // enable object literal shorthand methods
    "objectLiteralShorthandProperties": true, // enable object literal shorthand properties
    "octalLiterals": true, // enable octal literals
    "regexUFlag": true, // enable the regular expression u flag
    "regexYFlag": true, // enable the regular expression y flag
    "restParams": true, // enable the rest parameters
    "spread": true, // enable the spread operator for arrays
    "superInFunctions": true, // enable super references inside of functions
    "templateStrings": true, // enable template strings
    "unicodeCodePointEscapes": true, // enable code point escapes
    "globalReturn": false, // allow return statements in the global scope
    "jsx": true, // enable JSX
    "experimentalObjectRestSpread": false // experimental object rest/spread properties
  },

  "rules": {

/**
 * eslint-plugin-babel rule toggles
 */
    "babel/generator-star-spacing": [2, "after"],
    "babel/new-cap": 0,
    "babel/array-bracket-spacing": 0,
    "babel/object-curly-spacing": 0,
    "babel/object-shorthand": 0,
    "babel/arrow-parens": 0,
    "babel/no-await-in-loop": 2,

/**
 * ES6+
 */
    "arrow-body-style": 0,
    "arrow-spacing": 2,
    "constructor-super": 2,
    "no-confusing-arrow": 2,
    "no-class-assign": 2,
    "no-const-assign": 2,
    "no-dupe-class-members": 2,
    "no-this-before-super": 2,
    "no-var": 2,
    "prefer-arrow-callback": 0,
    "prefer-const": 2,
    "prefer-reflect": 0,
    "prefer-spread": 2,
    "prefer-template": 2,
    "require-yield": 0,

/**
 * Variables
 */
    "no-shadow": 0,
    "no-shadow-restricted-names": 2,
    "no-unused-vars": [2, {
      "vars": "local",
      "args": "none"
    }],
    "no-use-before-define": 0,
    "no-undef": 2,
    "no-delete-var": 2,

/**
 * Possible errors
 */
    "comma-dangle": [2, "never"],
    "no-cond-assign": [2, "always"],
    "no-console": 1,
    "no-constant-condition": 2,
    "no-control-regex": 2,
    "no-debugger": 2,
    "no-dupe-args": 2,
    "no-dupe-keys": 2,
    "no-duplicate-case": 2,
    "no-empty-character-class": 2,
    "no-empty": 2,
    "no-ex-assign": 2,
    "no-extra-semi": 2,
    "no-func-assign": 2,
    "no-inner-declarations": 2,
    "no-invalid-regexp": 2,
    "no-irregular-whitespace": 2,
    "no-negated-in-lhs": 2,
    "no-obj-calls": 2,
    "no-regex-spaces": 2,
    "no-sparse-arrays": 2,
    "no-unreachable": 2,
    "use-isnan": 2,
    "valid-jsdoc": 0,
    "valid-typeof": 2,
    "no-unexpected-multiline": 2,
    "strict": [2, "never"],

    // consistent-return had a bug and in eslint@2.x.x it is more strict, disabling for now
    "consistent-return": 0,
/**
 * Best practices
 */
    "no-extra-boolean-cast": 2,
    "curly": [2, "multi-line"],
    "default-case": 2,
    "dot-notation": [2, {
      "allowKeywords": true
    }],
    "eqeqeq": 2,
    "guard-for-in": 0,
    "no-caller": 2,
    "no-eq-null": 2,
    "no-eval": 2,
    "no-extend-native": 2,
    "no-extra-bind": 2,
    "no-fallthrough": 2,
    "no-floating-decimal": 2,
    "no-implied-eval": 2,
    "no-lone-blocks": 2,
    "no-loop-func": 2,
    "no-multi-str": 2,
    "no-native-reassign": 2,
    "no-new": 2,
    "no-new-func": 2,
    "no-new-wrappers": 2,
    "no-octal": 2,
    "no-octal-escape": 2,
    "no-proto": 2,
    "no-redeclare": 2,
    "no-return-assign": 2,
    "no-script-url": 2,
    "no-self-compare": 2,
    "no-sequences": 2,
    "no-throw-literal": 2,
    "no-with": 2,
    "radix": 2,
    "wrap-iife": [2, "any"],
    "yoda": 2,

/**
 * Style
 */
    "no-mixed-spaces-and-tabs": 2,
    "no-lonely-if": 2,
    "no-array-constructor": 2,
    "no-new-object": 2,
    "new-parens": 2,
    "consistent-this": [2, "self"],
    "space-unary-ops": [1, {"words": true, "nonwords": false}],
    "space-in-parens": [2, "never"],
    "space-before-blocks": [2, "always"],
    "array-bracket-spacing": [2, "never"],
    "indent": [2, 2, {"SwitchCase": 1}],
    "brace-style": [2, "1tbs", {
      "allowSingleLine": true
    }],
    "quotes": [
      2, "single", "avoid-escape"
    ],
    "camelcase": [2, {
      "properties": "never"
    }],
    "comma-spacing": [2, {
      "before": false,
      "after": true
    }],
    "comma-style": [2, "last"],
    "eol-last": 2,
    "key-spacing": [0, {
      "beforeColon": false,
      "afterColon": true
    }],
    "no-multiple-empty-lines": [2, {
      "max": 2
    }],
    "no-unneeded-ternary": 2,
    "no-nested-ternary": 2,
    "no-spaced-func": 2,
    "no-trailing-spaces": 2,
    "no-extra-parens": 0,
    "no-underscore-dangle": 0,
    "one-var": [2, "never"],
    "padded-blocks": [2, "never"],
    "semi": [2, "always"],
    "semi-spacing": [2, {
      "before": false,
      "after": true
    }],
    "keyword-spacing": 2,
    "space-before-function-paren": [2, {
      "anonymous": "always",
      "named": "never"
    }],
    "space-infix-ops": 2,
    "spaced-comment": 2,
    "no-multi-spaces": 0,
    "max-len": [2, 100, 2, {
      "ignoreComments": false,
      "ignoreUrls": true
    }]
  }
};
<|endoftext|>


<commit_before>var request = require('request');
var JSONStream = require('JSONStream');
var through2 = require('through2');
var zlib = require('zlib');

var RateLimiter = require('limiter').RateLimiter;
var limiter = new RateLimiter(120, 'minute');
limiter.tokenBucket.bucketSize = 30;

var panlex = module.exports = {
  setUserAgent: setUserAgent,
  query: query,
  queryAll: queryAll,
  queryStream: queryStream,
  queryStreamAll: queryStreamAll,
  limit: true,
  endpoint: process.env.PANLEX_API || 'https://api.panlex.org'
};

setUserAgent('Unknown application', '?');

function setUserAgent(appName, version) {
  panlex.userAgent = appName + '/' + version
    + ' (Language=node.js/' + process.version
    + '; Client=panlex/' + require('./package.json').version
    + '; Platform=' + process.platform + ')';
}

function query(url, body, cb) {
  if (body instanceof Function) {
    cb = body;
    body = {};
  }

  callWhenReady(_query, [url, body, cb]);
}

function _query(url, body, cb) {
  var req = createRequest(url, 'application/json')
  .on('error', cb)
  .on('response', function (res) {
    var err = getError(res);
    res = decode(res);

    var body = '';

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

    res.on('end', function () {
      try {
        body = JSON.parse(body);
      } catch (e) {
        return cb(new Error('PanLex API returned invalid JSON'), body);
      }

      cb(err, body);
    });
  });

  writeBody(req, body);
}

function queryAll(url, body, method, cb) {
  if (body instanceof Function) {
    cb = body;
    body = {};
  }

  if (method instanceof Function) {
    cb = method;
    method = 'offset';
  }

  body = copyBody(body);

  var loop;
  var result;

  if (method === 'offset') {
    body.offset = 0;

    loop = function loop() {
      query(url, body, function (err, thisResult) {
        if (err) return cb(err, thisResult);

        if (result) {
          Array.prototype.push.apply(result.result, thisResult.result);
          result.resultNum += thisResult.resultNum;
        }
        else result = thisResult;

        if (thisResult.resultNum < thisResult.resultMax) cb(null, result);
        else {
          body.offset += thisResult.resultNum;
          loop();
        }
      });
    };
  }
  else if (method === 'after') {
    var afterParams = getAfterParams(url, body);

    loop = function loop() {
      query(url, body, function (err, thisResult) {
        if (err) return cb(err, thisResult);

        if (result) {
          Array.prototype.push.apply(result.result, thisResult.result);
          result.resultNum += thisResult.resultNum;
        }
        else result = thisResult;

        if (thisResult.resultNum < thisResult.resultMax) cb(null, result);
        else {
          body.after = getAfterValue(thisResult.result[thisResult.result.length - 1], afterParams);
          loop();
        }
      });
    };
  }
  else {
    throw 'unknown method: valid values are "offset" and "after"';
  }

  loop();
}

function queryStream(url, body) {
  var stream = through2.obj();

  callWhenReady(_queryStream, [url, body, stream]);

  return stream;
}

function _queryStream(url, body, stream) {
  var req = createRequest(url, 'application/x-json-stream,application/json')
  .on('error', function (err) {
    stream.emit('error', err);
  })
  .on('response', function (res) {
    var err = getError(res);
    res = decode(res);

    if (err) {
      res.pipe(JSONStream.parse())
      .once('data', function (data) {
        stream.emit('error', err, data);
        stream.end();
      });
    }
    else {
      res.pipe(JSONStream.parse('result.*'))
      .on('root', function (root, count) {
        stream.emit('root', root, count);
      })
      .pipe(stream);
    }
  });

  writeBody(req, body);
}

function queryStreamAll(url, body, method) {
  var stream = through2.obj();

  body = copyBody(body);

  var loop;

  if (method === undefined || method === 'offset') {
    body.offset = 0;

    loop = function loop() {
      var gotErr;

      queryStream(url, body)
      .on('error', function (err, data) {
        stream.emit('error', err, data);
        gotErr = true;
      })
      .on('end', function () {
        if (gotErr) stream.end();
      })
      .on('root', function (root, count) {
        if (count < root.resultMax) stream.end();
        else {
          body.offset += count;
          loop();
        }
      })
      .pipe(stream, { end: false });
    };
  }
  else if (method === 'after') {
    var afterParams = getAfterParams(url, body);

    loop = function loop() {
      var gotErr;
      var last;

      queryStream(url, body)
      .on('data', function (data) {
        last = data;
      })
      .on('error', function (err, data) {
        stream.emit('error', err, data);
        gotErr = true;
      })
      .on('end', function () {
        if (gotErr) stream.end();
      })
      .on('root', function (root, count) {
        if (count < root.resultMax) stream.end();
        else {
          body.after = getAfterValue(last, afterParams);
          loop();
        }
      })
      .pipe(stream, { end: false });
    };
  }
  else {
    throw 'unknown method: valid values are "offset" and "after"';
  }

  loop();

  return stream;
}

function callWhenReady(f, args) {
  if (panlex.limit) {
    limiter.removeTokens(1, function (err) {
      if (err) args[args.length - 1](err);
      else f.apply(null, args);
    });
  }
  else f.apply(null, args);
}

function createRequest(url, accept) {
  url = url.match(/^\//) ? panlex.endpoint + url : url;

  var headers = {
    'content-type': 'application/json',
    'accept-encoding': 'gzip',
    'user-agent': panlex.userAgent
  };

  if (accept) headers.accept = accept;

  return request.post({ uri: url, headers: headers });
}

function writeBody(req, body) {
  req.write(JSON.stringify(body || {}));
  req.end();
}

function getError(res) {
  return res.statusCode === 200
    ? null
    : new Error('PanLex API returned HTTP status code ' + res.statusCode);
}

function decode(res) {
  return res.headers['content-encoding'] === 'gzip'
    ? res.pipe(zlib.createGunzip())
    : res;
}

function copyBody(body) {
  var copy = {};
  for (var i in body) copy[i] = body[i];
  delete copy.limit;
  delete copy.offset;
  delete copy.after;
  return copy;
}

function getAfterParams(url, body) {
  if (body.sort !== undefined) {
    var sort = body.sort;
    if (!(sort instanceof Array)) sort = [sort];

    return sort.map(function (item) { return item.replace(/ +(?:asc|desc)/gi, '') });
  }
  else {
    var match = url.match(/\/([a-z]+)$/);

    if (match) return [match[1]];

    throw 'could not automatically guess "after" field from ' + url;
  }
}

function getAfterValue(last, afterParams) {
  return afterParams.map(function (item) { return last[item] });
}
<commit_msg>minor cleanup of last commit<commit_after>var request = require('request');
var JSONStream = require('JSONStream');
var through2 = require('through2');
var zlib = require('zlib');

var RateLimiter = require('limiter').RateLimiter;
var limiter = new RateLimiter(120, 'minute');
limiter.tokenBucket.bucketSize = 30;

var panlex = module.exports = {
  setUserAgent: setUserAgent,
  query: query,
  queryAll: queryAll,
  queryStream: queryStream,
  queryStreamAll: queryStreamAll,
  limit: true,
  endpoint: process.env.PANLEX_API || 'https://api.panlex.org'
};

setUserAgent('Unknown application', '?');

function setUserAgent(appName, version) {
  panlex.userAgent = appName + '/' + version
    + ' (Language=node.js/' + process.version
    + '; Client=panlex/' + require('./package.json').version
    + '; Platform=' + process.platform + ')';
}

function query(url, body, cb) {
  if (body instanceof Function) {
    cb = body;
    body = {};
  }

  callWhenReady(_query, [url, body, cb]);
}

function _query(url, body, cb) {
  var req = createRequest(url, 'application/json')
  .on('error', cb)
  .on('response', function (res) {
    var err = getError(res);
    res = decode(res);

    var body = '';

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

    res.on('end', function () {
      try {
        body = JSON.parse(body);
      } catch (e) {
        return cb(new Error('PanLex API returned invalid JSON'), body);
      }

      cb(err, body);
    });
  });

  writeBody(req, body);
}

function queryAll(url, body, method, cb) {
  if (body instanceof Function) {
    cb = body;
    body = {};
    method = 'offset';
  }

  if (method instanceof Function) {
    cb = method;
    method = 'offset';
  }

  body = copyBody(body);

  var loop, result;

  if (method === 'offset') {
    body.offset = body.offset || 0;

    loop = function loop() {
      query(url, body, function (err, thisResult) {
        if (err) return cb(err, thisResult);

        if (result) {
          Array.prototype.push.apply(result.result, thisResult.result);
          result.resultNum += thisResult.resultNum;
        }
        else result = thisResult;

        if (thisResult.resultNum < thisResult.resultMax) cb(null, result);
        else {
          body.offset += thisResult.resultNum;
          loop();
        }
      });
    };
  }
  else if (method === 'after') {
    var afterParams = getAfterParams(url, body);
    delete body.offset;

    loop = function loop() {
      query(url, body, function (err, thisResult) {
        if (err) return cb(err, thisResult);

        if (result) {
          Array.prototype.push.apply(result.result, thisResult.result);
          result.resultNum += thisResult.resultNum;
        }
        else result = thisResult;

        if (thisResult.resultNum < thisResult.resultMax) cb(null, result);
        else {
          body.after = getAfterValues(thisResult.result[thisResult.result.length - 1], afterParams);
          loop();
        }
      });
    };
  }
  else unknownMethodError();

  loop();
}

function queryStream(url, body) {
  var stream = through2.obj();

  callWhenReady(_queryStream, [url, body, stream]);

  return stream;
}

function _queryStream(url, body, stream) {
  var req = createRequest(url, 'application/x-json-stream,application/json')
  .on('error', function (err) {
    stream.emit('error', err);
  })
  .on('response', function (res) {
    var err = getError(res);
    res = decode(res);

    if (err) {
      res.pipe(JSONStream.parse())
      .once('data', function (data) {
        stream.emit('error', err, data);
        stream.end();
      });
    }
    else {
      res.pipe(JSONStream.parse('result.*'))
      .on('root', function (root, count) {
        stream.emit('root', root, count);
      })
      .pipe(stream);
    }
  });

  writeBody(req, body);
}

function queryStreamAll(url, body, method) {
  var stream = through2.obj();

  body = copyBody(body);

  var loop;

  if (method === undefined || method === 'offset') {
    body.offset = body.offset || 0;

    loop = function loop() {
      var gotErr;

      queryStream(url, body)
      .on('error', function (err, data) {
        stream.emit('error', err, data);
        gotErr = true;
      })
      .on('end', function () {
        if (gotErr) stream.end();
      })
      .on('root', function (root, count) {
        if (count < root.resultMax) stream.end();
        else {
          body.offset += count;
          loop();
        }
      })
      .pipe(stream, { end: false });
    };
  }
  else if (method === 'after') {
    var afterParams = getAfterParams(url, body);
    delete body.offset;

    loop = function loop() {
      var gotErr, last;

      queryStream(url, body)
      .on('data', function (data) { // save latest result
        last = data;
      })
      .on('error', function (err, data) {
        stream.emit('error', err, data);
        gotErr = true;
      })
      .on('end', function () {
        if (gotErr) stream.end();
      })
      .on('root', function (root, count) {
        if (count < root.resultMax) stream.end();
        else {
          body.after = getAfterValues(last, afterParams);
          loop();
        }
      })
      .pipe(stream, { end: false });
    };
  }
  else unknownMethodError();

  loop();

  return stream;
}

function callWhenReady(f, args) {
  if (panlex.limit) {
    limiter.removeTokens(1, function (err) {
      if (err) args[args.length - 1](err);
      else f.apply(null, args);
    });
  }
  else f.apply(null, args);
}

function createRequest(url, accept) {
  url = url.match(/^\//) ? panlex.endpoint + url : url;

  var headers = {
    'content-type': 'application/json',
    'accept-encoding': 'gzip',
    'user-agent': panlex.userAgent
  };

  if (accept) headers.accept = accept;

  return request.post({ uri: url, headers: headers });
}

function writeBody(req, body) {
  req.write(JSON.stringify(body || {}));
  req.end();
}

function getError(res) {
  return res.statusCode === 200
    ? null
    : new Error('PanLex API returned HTTP status code ' + res.statusCode);
}

function decode(res) {
  return res.headers['content-encoding'] === 'gzip'
    ? res.pipe(zlib.createGunzip())
    : res;
}

function copyBody(body) {
  var copy = {};

  for (var i in body) {
    if (i !== 'limit') copy[i] = body[i];
  }

  return copy;
}

function getAfterParams(url, body) {
  if (body.sort !== undefined) {
    var sort = body.sort;
    if (!(sort instanceof Array)) sort = [sort];

    return sort.map(function (item) { return item.replace(/ (?:asc|desc)$/gi, '') });
  }
  else {
    var match = url.match(/\/([a-z]+)$/);

    if (match) return [match[1]];

    throw 'could not automatically guess "after" field from URL: ' + url;
  }
}

function getAfterValues(last, afterParams) {
  return afterParams.map(function (item) { return last[item] });
}

function unknownMethodError() {
  throw 'unknown method: valid values are "offset" and "after"';
}
<|endoftext|>


<commit_before>'use strict';

if ( typeof module !== 'undefined' && typeof require !== 'undefined') {
  var debug   = require('mini-debug');
  var WebapiMediaStream = require('webapi-mediastream');
}

/**
 *
 * @constructor
 * @extends WebapiMediaStream
 * @param {MediaStream} stream
 * @returns {WrtcMediaStream}
 */
var WrtcMediaStream = function(stream) {
  var self = WebapiMediaStream(stream);
  //var self = this;

  self.muted        = false;
  self.videoEnabled = true;
  self.audioEnabled = true;

  self.stop = function() {
    debug.log('WebapiMediaStream.stop()');
    self.emit('stop');
    stream.stop();
  };

  self.hasAudio = function() {
    return self.stream.getAudioTracks().length > 0;
  };

  self.setAudioEnabled = function(value) {
    debug.debug('WebapiMediaStream.setAudioEnabled('+value+')');
    self.audioEnabled = value;
    var audioTracks = self.stream.getAudioTracks();
    for ( var i = 0, l = audioTracks.length; i < l; i++ ) {
      audioTracks[i].enabled = value;
    }
  };

  self.toggleAudioEnabled = function() {
    debug.debug('WebapiMediaStream.toggleAudioEnabled()');
    self.setAudioEnabled( ! self.audioEnabled );
  };

  self.hasVideo = function() {
    return self.stream.getVideoTracks().length > 0;
  };

  self.setVideoEnabled = function(value) {
    // Muting for screencast is disabled
    // https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc&q=Disable%20muting%20for%20screencast.&sq=package:chromium&type=cs&l=3232
    //
    debug.debug('WebapiMediaStream.setVideoEnabled('+value+')');
    self.videoEnabled = value;
    var tracks = self.stream.getVideoTracks();
    for ( var i = 0, l = tracks.length; i < l; i++ ) {
      tracks[i].enabled = value;
    }
  };

  self.toggleVideoEnabled = function() {
    // Muting for screencast is disabled
    // https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc&q=Disable%20muting%20for%20screencast.&sq=package:chromium&type=cs&l=3232
    debug.debug('WebapiMediaStream.toggleVideoEnabled()');
    self.setVideoEnabled( ! self.videoEnabled );
  };

  self.setAudioEnabled(self.audioEnabled);

  self.setVideoEnabled(self.videoEnabled);

  return self;
};

//

if (typeof module !== 'undefined') {
  module.exports = WrtcMediaStream;
}

if (typeof window !== 'undefined') {
  window.WrtcMediaStream = WrtcMediaStream;
}
<commit_msg>extended by Attachable<commit_after>'use strict';

if ( typeof module !== 'undefined' && typeof require !== 'undefined') {
  var debug   = require('mini-debug');
  var WebapiMediaStream = require('webapi-mediastream');
}

/**
 *
 * @constructor
 * @extends WebapiMediaStream
 * @param {MediaStream} stream
 * @param {"local"|"remote"} kind
 * @returns {WrtcMediaStream}
 */
var WrtcMediaStream = function(stream, kind) {
  var self = new WebapiMediaStream(stream);
  Attachable(self);
  //var self = this;

  self.muted        = false;
  self.videoEnabled = true;
  self.audioEnabled = true;

  function setObjectEventDebug(object, prop, debugMethod) {
    object[prop] = function(event) { debug[debugMethod]('WrtcMediaStream: mediaTrack.'+prop+': kind: '+object.kind+', event:', event); };
  }
  function setTracksDebug(tracks) {
    var i, len;
    for (len=tracks.length, i=0; i<len; ++i) {
      setObjectEventDebug(tracks[i], 'onended',  'warn');
      setObjectEventDebug(tracks[i], 'onmute',   'log');
      setObjectEventDebug(tracks[i], 'onoverconstrained', 'warn');
      setObjectEventDebug(tracks[i], 'onunmute', 'log');
    }
  }
  // Assign event handlers to stream tracks
  setTracksDebug(stream.getTracks());

  self.stop = function() {
    debug.log('WebapiMediaStream.stop()');
    self.emit('stop');
    self.detachAll();
    stream.stop();
  };

  self.hasAudio = function() {
    return self.stream.getAudioTracks().length > 0;
  };

  self.setAudioEnabled = function(value) {
    debug.debug('WebapiMediaStream.setAudioEnabled('+value+')');
    self.audioEnabled = value;
    var audioTracks = self.stream.getAudioTracks();
    for ( var i = 0, l = audioTracks.length; i < l; i++ ) {
      audioTracks[i].enabled = value;
    }
  };

  self.toggleAudioEnabled = function() {
    debug.debug('WebapiMediaStream.toggleAudioEnabled()');
    self.setAudioEnabled( ! self.audioEnabled );
  };

  self.hasVideo = function() {
    return self.stream.getVideoTracks().length > 0;
  };

  self.setVideoEnabled = function(value) {
    // Muting for screencast is disabled
    // https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc&q=Disable%20muting%20for%20screencast.&sq=package:chromium&type=cs&l=3232
    //
    debug.debug('WebapiMediaStream.setVideoEnabled('+value+')');
    self.videoEnabled = value;
    var tracks = self.stream.getVideoTracks();
    for ( var i = 0, l = tracks.length; i < l; i++ ) {
      tracks[i].enabled = value;
    }
  };

  self.toggleVideoEnabled = function() {
    // Muting for screencast is disabled
    // https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc&q=Disable%20muting%20for%20screencast.&sq=package:chromium&type=cs&l=3232
    debug.debug('WebapiMediaStream.toggleVideoEnabled()');
    self.setVideoEnabled( ! self.videoEnabled );
  };

  self.setAudioEnabled(self.audioEnabled);

  self.setVideoEnabled(self.videoEnabled);

  /**
   * Print information on devices used for the stream
   */
  self._printInfo = function() {
    var i, msg, prefix = 'WrtcMediaStream._printInfo(): ';
    var audioTracks = self.stream.getAudioTracks();
    if (audioTracks.length > 0) {
      if (kind==='local' && audioTracks.length > 1) {
        debug.warn(prefix+'Expected 1 audio track for local stream.');
      }
      for (i = 0; i<audioTracks.length; i++) {
        debug.info(prefix+'Using Audio device (audioTracks[i].label): \'' + audioTracks[ i ].label + '\'');

        msg = prefix+'audioTracks[i].readyState: \'' + audioTracks[ i ].readyState + '\'';
        (audioTracks[ i ].readyState === 'ended') ? debug.warn(msg) : debug.log(msg);
      }
    } else {
      debug.warn(prefix+'stream does not contains audioTracks');
    }

    var videoTracks = self.stream.getVideoTracks();
    if (videoTracks.length > 0) {
      if (kind==='local' && videoTracks.length > 1) {
        debug.warn(prefix+'Expected 1 video track for local stream.');
      }
      for (i = 0; i<audioTracks.length; i++) {
        debug.info(prefix+'Using Video device (videoTracks[i].label): \'' + videoTracks[ i ].label + '\'');

        msg = prefix+'videoTracks[i].readyState: \'' + videoTracks[ i ].readyState + '\'';
        (videoTracks[ i ].readyState === 'ended') ? debug.warn(msg) : debug.log(msg);
      }
    } else {
      debug.warn(prefix+'stream does not contains videoTracks');
    }
  };

  return self;
};

//

if (typeof module !== 'undefined') {
  module.exports = WrtcMediaStream;
}

if (typeof window !== 'undefined') {
  window.WrtcMediaStream = WrtcMediaStream;
}
<|endoftext|>


<commit_before>/*globals __dirname:false,JSON:false */

// web part
var express = require('express');
var app = express();
var pouchdb = require('pouchdb');
var http = require('http').Server(app);
var port = process.env.PORT || 3000;

app.use(express.static('client'));

http.listen(port, function(){
	console.log("http server listening on *:" + port);
	console.log("please browse: http://localhost:" + port);
});

const pdb = new pouchdb("test_pdb");

//const cdb = new pouchdb('http://localhost:5984/test_cdb');
//const cdb = new pouchdb('http://192.168.1.13:5984/test_cdb');

// local and remote db synchronization
// socket part
var PORT = 5000;
var ws = require("nodejs-websocket");
var connections = [];
var syncHandler;

var server = ws.createServer(function (conn) {
	connections.push(conn);
	conn.on("text", function (str) {
		var data = JSON.parse(str);

		var message, style;
		var user = data.user;
		switch (data.type) {
			case "open":
				// array for more users on one connection (tested on localhost multiple client)
				if (this.currentUser) {
					~this.currentUser.indexOf(user) || this.currentUser.push(user);
				} else {
					this.currentUser = [user];
				}
				_hDbReplication(data.ip || "localhost");
				message = "has been connected";
				style = "info";
				break;
			case "message":
				message = data.message;
				break;
			case "close":
				message =  "has beed disconnected";
				style = "info";
				break;
			case "logout":
				syncHandler.cancel();
				message =  "logged off";
				style = "info";
				break;
			case "clear":
				clearDb();
				break;
			case "typing":
				message = "is typing";
				style = "info";
				break;
		}

		message && broadcast(user, message, style);
	}.bind(this));
	conn.on("error", function() {
		console.log(arguments);
	});
	conn.on("close", function (/*code, reason*/) {
		var idx = connections.indexOf(conn);
		~idx && connections.splice(idx, 1);
		console.log("Connection closed");
		broadcast(null, "Client closed connection", "info");
		syncHandler.cancel();
	});
}).listen(PORT);
console.log('websocket server listening on ' + PORT);

function broadcast(user, message, style) {
	~["info", "sync"].indexOf(style) || pdb.put({
		_id : new Date().getTime() + "",
		message : message,
		user : user,
		style : style
	});
	connections.forEach(function(c) {
		c.sendText(JSON.stringify({
			message : message,
			user : user,
			style : style
		}));
	});
}

function clearDb() {
	pdb.allDocs()//
	.then(r => {
		var docs = r.rows.map(function(row){
			return {
				_id: row.id,
				_rev: row._rev || row.value.rev,
				_deleted: true
			};
		});
		return (docs && docs.length) && pdb.bulkDocs(docs)//
		.then(() => {
			console.log("Documents deleted Successfully");
		});
	})//
	.catch(e => {
		console.log('error: ' + e);
	});
}

function _hDbReplication(ipAddress) {
	const cdb = "http://" + ipAddress + ":5984/test_cdb";
	let opts = {
		live: true,
	  	retry: true
	};
	syncHandler = pdb.sync(cdb, opts);

	console.log("Replication to remote DB: ", cdb);

	syncHandler.on("change", evt => {
		let docs = evt.change && evt.change.docs;
		if (!docs || !docs.length) {
			return;
		}
		docs.forEach(doc => {
			if (doc._deleted || ~server.currentUser.indexOf(doc.user)) {
				return;
			}
			broadcast(doc.user, doc.message, "sync");
			//console.log("Changes from repl:", doc);
		});
	});

	syncHandler.on('error', e => {
		console.log("error: ", e);
	});

	syncHandler.on('complete', i => {
		console.log("Replication was canceled!");
	});
}<commit_msg>pdb to localcdb<commit_after>/*globals __dirname:false,JSON:false */

// web part
var express = require('express');
var app = express();
var pouchdb = require('pouchdb');
var http = require('http').Server(app);
var port = process.env.PORT || 3000;

app.use(express.static('client'));

http.listen(port, function(){
	console.log("http server listening on *:" + port);
	console.log("please browse: http://localhost:" + port);
});

var localCDB = new pouchdb("http://localhost:5984/test_cdb"); //const pdb

//const cdb = new pouchdb('http://localhost:5984/test_cdb');
//const cdb = new pouchdb('http://192.168.1.13:5984/test_cdb');

// local and remote db synchronization
// socket part
var PORT = 5000;
var ws = require("nodejs-websocket");
var connections = [];
var syncHandler;

var server = ws.createServer(function (conn) {
	connections.push(conn);
	conn.on("text", function (str) {
		var data = JSON.parse(str);

		var message, style;
		var user = data.user;
		switch (data.type) {
			case "open":
				// array for more users on one connection (tested on localhost multiple client)
				if (this.currentUser) {
					~this.currentUser.indexOf(user) || this.currentUser.push(user);
				} else {
					this.currentUser = [user];
				}
				_hDbReplication(data.ip || "localhost");
				message = "has been connected";
				style = "info";
				break;
			case "message":
				message = data.message;
				break;
			case "close":
				message =  "has beed disconnected";
				style = "info";
				break;
			case "logout":
				syncHandler.cancel();
				message =  "logged off";
				style = "info";
				break;
			case "clear":
				clearDb();
				break;
			case "typing":
				message = "is typing";
				style = "info";
				break;
		}

		message && broadcast(user, message, style);
	}.bind(this));
	conn.on("error", function() {
		console.log(arguments);
	});
	conn.on("close", function (/*code, reason*/) {
		var idx = connections.indexOf(conn);
		~idx && connections.splice(idx, 1);
		console.log("Connection closed");
		broadcast(null, "Client closed connection", "info");
		syncHandler.cancel();
	});
}).listen(PORT);
console.log('websocket server listening on ' + PORT);

function broadcast(user, message, style) {
	~["info", "sync"].indexOf(style) || localCDB.put({
		_id : new Date().getTime() + "",
		message : message,
		user : user,
		style : style
	});
	connections.forEach(function(c) {
		c.sendText(JSON.stringify({
			message : message,
			user : user,
			style : style
		}));
	});
}

function clearDb() {
	localCDB.allDocs()//
	.then(r => {
		var docs = r.rows.map(function(row){
			return {
				_id: row.id,
				_rev: row._rev || row.value.rev,
				_deleted: true
			};
		});
		return (docs && docs.length) && localCDB.bulkDocs(docs)//
		.then(() => {
			console.log("Documents deleted Successfully");
		});
	})//
	.catch(e => {
		console.log('error: ' + e);
	});
}

function _hDbReplication(ipAddress) {
	var remoteCDB = new PouchDB("http://" + ipAddress + ":5984/test_cdb"); //const cdb
	let opts = {
		live: true,
	  	retry: true
	};
	syncHandler = localCDB.sync(remoteCDB, opts);

	console.log("Replication to remote DB: ", remoteCDB);

	syncHandler.on("change", evt => {
		let docs = evt.change && evt.change.docs;
		if (!docs || !docs.length) {
			return;
		}
		docs.forEach(doc => {
			if (doc._deleted || ~server.currentUser.indexOf(doc.user)) {
				return;
			}
			broadcast(doc.user, doc.message, "sync");
			//console.log("Changes from repl:", doc);
		});
	});

	syncHandler.on('error', e => {
		console.log("error: ", e);
	});

	syncHandler.on('complete', i => {
		console.log("Replication was canceled!");
	});
}<|endoftext|>


<commit_before>// Load the node-ffi extensions
require('./ffi-extend')

// The main exports is the casting function
module.exports = $
$._ = $ // legacy. TODO: remove by 0.1.0

// export the exports from the 'import' module
var Import = require('./import')
$.import  = Import.import
$.resolve = Import.resolve

// This function accepts native JS types (String, Number, Date) and converts them
// to the proper Objective-C type (NSString, NSNumber, NSDate).
//   Syntax Sugar...
function $ (str) {
  $.import('Foundation')
  return module.exports.NSString('stringWithUTF8String', String(str))
}
<commit_msg>Add support for converting Numbers to NSNumbers and Dates to NSDates in the $ function.<commit_after>// Load the node-ffi extensions
require('./ffi-extend')

// The main exports is the casting function
module.exports = $
$._ = $ // legacy. TODO: remove by 0.1.0

// export the exports from the 'import' module
var Import = require('./import')
$.import  = Import.import
$.resolve = Import.resolve

// This function accepts native JS types (String, Number, Date) and converts them
// to the proper Objective-C type (NSString, NSNumber, NSDate).
//   Syntax Sugar...
function $ (o) {
  var t = typeof o
  if (t == 'string') {
    return $.NSString('stringWithUTF8String', String(o))
  } else if (t == 'number') {
    return $.NSNumber('numberWithDouble', Number(o))
  } else if (isDate(o)) {
    return $.NSDate('dateWithTimeIntervalSince1970', o / 1000)
  }
  throw new Error('Unsupported object passed in to convert')
}

function isDate (d) {
  return d instanceof Date
      || Object.prototype.toString.call(d) == '[object Date]'
}
<|endoftext|>


<commit_before>'use strict';

var hashKey = '__EV_STORE_KEY@4';

module.exports = EvStore;

function EvStore(elem) {
    var hash = elem[hashKey];

    if (!hash) {
        hash = elem[hashKey] = {};
    }

    return hash;
}
<commit_msg>update key<commit_after>'use strict';

var hashKey = '__EV_STORE_KEY@6';

module.exports = EvStore;

function EvStore(elem) {
    var hash = elem[hashKey];

    if (!hash) {
        hash = elem[hashKey] = {};
    }

    return hash;
}
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var through = require('through2');
var duplexer = require('duplexer2');
var util = require('./lib/util');
var rename = require('./lib/rename');
var cache = require('./lib/cache');
var common = require('./lib/common');
var include = require('./lib/include');
var concat = require('./lib/concat');

function main(options){
  var input = through.obj({ objectMode: true });
  var output = through.obj({ objectMode: true });

  var monitor = function (stream){
    stream.on('error', function (e){
      output.emit('error', e);
    });

    return stream;
  };

  monitor(input)
    .pipe(monitor(include(options)))
    .pipe(monitor(concat()))
    .pipe(output);

  return duplexer(input, output);
}

/**
 * Exports module.
 */

main.cache = {};
main.cache.clean = cache.clean;
main.createParser = common.createParser;
main.cwd = util.cwd;
main.debug = util.debug;
main.colors = util.colors;
main.isAbsolute = util.isAbsolute;
main.isRelative = util.isRelative;
main.isLocal = util.isLocal;
main.parseVars = util.parseVars;
main.parsePaths = util.parsePaths;
main.parseAlias = util.parseAlias;
main.throwError = util.throwError;
main.addExt = util.addExt;
main.hideExt = util.hideExt;
main.extend = util.extend;
main.normalize = util.normalize;
main.rename = rename;
main.pathFormCwd = util.pathFormCwd;
module.exports = main;
<commit_msg>add source files<commit_after>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var through = require('through2');
var duplexer = require('duplexer2');
var util = require('./lib/util');
var rename = require('./lib/rename');
var cache = require('./lib/cache');
var common = require('./lib/common');
var include = require('./lib/include');
var concat = require('./lib/concat');

function main(options){
  var input = through.obj({ objectMode: true });
  var output = through.obj({ objectMode: true });

  var monitor = function (stream){
    stream.on('error', function (e){
      output.emit('error', e);
    });

    return stream;
  };

  monitor(input)
    .pipe(monitor(include(options)))
    .pipe(monitor(concat()))
    .pipe(output);

  return duplexer(input, output);
}

/**
 * Exports module.
 */

main.cache = {};
main.cache.clean = cache.clean;
main.createParser = common.createParser;
main.cwd = util.cwd;
main.debug = util.debug;
main.colors = util.colors;
main.parseVars = util.parseVars;
main.parsePaths = util.parsePaths;
main.parseAlias = util.parseAlias;
main.throwError = util.throwError;
main.addExt = util.addExt;
main.hideExt = util.hideExt;
main.isLocal = util.isLocal;
main.isAbsolute = util.isAbsolute;
main.isRelative = util.isRelative;
main.rename = rename;
main.extend = util.extend;
main.normalize = util.normalize;
main.pathFormCwd = util.pathFormCwd;
module.exports = main;
<|endoftext|>


<commit_before>/**
 * Created by cfiloteo on 11/17/15.
 */
var express = require('express');
var app = express();
app.set('view engine', 'jade');
app.use(express.static('build'));

app.get('/', function (req, res) {
	res.render('index');
});

var server = app.listen(3000, function () {
	var host = server.address().address;
	var port = server.address().port;

	console.log('Example app listening at http://%s:%s', host, port);
});<commit_msg>Changed static location for easy access to all project files (dist and src).<commit_after>/**
 * Created by cfiloteo on 11/17/15.
 */
var express = require('express'),
		app = express();

app.set('view engine', 'jade');
app.use(express.static(__dirname + '/'));

app.get('/', function (req, res) {
	res.render('index');
});

var server = app.listen(3000, function () {
	var host = server.address().address;
	var port = server.address().port;

	console.log('Example app listening at http://%s:%s', host, port);
});<|endoftext|>


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

'use strict';

module.exports = function (FAT_REMOTE, SKIM_REMOTE, port, logger) {
  FAT_REMOTE = FAT_REMOTE || 'https://registry.npmjs.org';
  SKIM_REMOTE =  SKIM_REMOTE || 'https://skimdb.npmjs.com/registry';
  port = port  || 5080;
  logger =  logger || 'dev';
  var startingTimeout = 1000;
  function log(msgs) {
    if (logger !== 'off') {
      console.log.apply(console, arguments);
    }
  }
  log('\nWelcome!');
  log('To start using local-npm, just run: ');
  log('\n  $ npm set registry http://127.0.0.1:' + port);
  log('\nTo switch back, you can run: ');
  log('\n  $ npm set registry ' + FAT_REMOTE);
  var backoff = 1.1;
  var request = require('request');
  var Promise = require('bluebird');
  var express = require('express');
  var app = express();
  var PouchDB = require('./pouchdb-server-lite').PouchDB;
  var skimRemote = new PouchDB(SKIM_REMOTE);
  var skimLocal = new PouchDB('skimdb');
  var base = 'http://localhost:' + port + '/tarballs';
  var level = require('level');
  var db = level('./binarydb');
  var through = require('through2');
  if (logger !== 'off') {
    app.use(require('morgan')(logger));
  }
  app.use(require('compression')());
  app.use(require('serve-favicon')(__dirname + '/favicon.ico'));
  app.get('/:name', function (req, res) {
    skimLocal.get(req.params.name).catch(function () {
      return skimRemote.get(req.params.name);
    }).then(function (doc) {
      var docs = changeTarballs(base, doc);
      res.json(docs);
    }).catch(function (e) {
      request.get(FAT_REMOTE + req.url).pipe(res);
    });
  });
  app.get('/:name/:version', function (req, res) {
    skimLocal.get(req.params.name).catch(function () {
      return skimRemote.get(req.params.name);
    }).then(function (doc) {
      res.json(changeTarballs(base, doc).versions[req.params.version]);
    }).catch(function (e) {
      request.get(FAT_REMOTE + req.url).pipe(res);
    });
  });
  app.get('/tarballs/:name/:version.tgz', function (req, res) {
    var id = req.params.name + '-' + req.params.version;
    db.get(id, function (err, resp) {
      if (!err) {
        res.set('content-type', 'application/octet-stream');
        res.set('content-length', resp.length);
        return res.send(resp);
      }
      var buffs = [];
      var get = request.get(FAT_REMOTE + '/' + req.params.name + '/-/' + id + '.tgz');
      get.on('error', function () {
        res.send(500, 'you are offline and this package isn\'t cached');
        restartReplication();
      });
      get.pipe(res);
      get.pipe(through(function (chunk, _, next) {
        buffs.push(chunk);
        next();
      }, function (next) {
        next();
        var buff = Buffer.concat(buffs);
        db.put(id, buff, function (err) {
          if (err) {
            log(err);
          }
        });
      }));
    });
  });
  function changeTarballs(base, doc) {
    Object.keys(doc.versions).forEach(function (key) {
      doc.versions[key].dist.tarball = base + '/' + doc.name + '/' + key + '.tgz';
    });
    return doc;
  }
  app.all('/*', function (req, res) {
    res.send(500);
  });
  var sync;
  function replicateSkim() {
    skimRemote.info().then(function (info) {
      sync = skimLocal.replicate.from(skimRemote, {
        live: true,
        batch_size: 2000
      }).on('change', function (change) {
        var percent = Math.min(100,
          (Math.floor(change.last_seq / info.update_seq * 10000) / 100).toFixed(2));
        log('Replicating skimdb, last_seq is: ' + change.last_seq + ' (' + percent + '%)');
      }).on('uptodate', function () {
        log('local skimdb is up to date');
      }).on('error', function (err) {
        console.error('error during replication with skimdb');
        console.error(err);
        restartReplication();
      });
    }).catch(function (err) {
      console.error('error doing info() on ' + SKIM_REMOTE);
      console.error(err);
      restartReplication();
    });
  }
  function restartReplication() {
    // just keep going
    startingTimeout *= backoff;
    setTimeout(replicateSkim, Math.round(startingTimeout));
  }
  replicateSkim();

  app.listen(port);

  process.on('SIGINT', function () {
    // close gracefully
    sync.cancel();
    db.close(function () {
      skimLocal.close().then(function () {
        process.exit();
      }, function () {
        process.exit();
      });
    });
  });
};
<commit_msg>don't need to restart replication here<commit_after>#!/usr/bin/env node

'use strict';

module.exports = function (FAT_REMOTE, SKIM_REMOTE, port, logger) {
  FAT_REMOTE = FAT_REMOTE || 'https://registry.npmjs.org';
  SKIM_REMOTE =  SKIM_REMOTE || 'https://skimdb.npmjs.com/registry';
  port = port  || 5080;
  logger =  logger || 'dev';
  var startingTimeout = 1000;
  function log(msgs) {
    if (logger !== 'off') {
      console.log.apply(console, arguments);
    }
  }
  log('\nWelcome!');
  log('To start using local-npm, just run: ');
  log('\n  $ npm set registry http://127.0.0.1:' + port);
  log('\nTo switch back, you can run: ');
  log('\n  $ npm set registry ' + FAT_REMOTE);
  var backoff = 1.1;
  var request = require('request');
  var Promise = require('bluebird');
  var express = require('express');
  var app = express();
  var PouchDB = require('./pouchdb-server-lite').PouchDB;
  var skimRemote = new PouchDB(SKIM_REMOTE);
  var skimLocal = new PouchDB('skimdb');
  var base = 'http://localhost:' + port + '/tarballs';
  var level = require('level');
  var db = level('./binarydb');
  var through = require('through2');
  if (logger !== 'off') {
    app.use(require('morgan')(logger));
  }
  app.use(require('compression')());
  app.use(require('serve-favicon')(__dirname + '/favicon.ico'));
  app.get('/:name', function (req, res) {
    skimLocal.get(req.params.name).catch(function () {
      return skimRemote.get(req.params.name);
    }).then(function (doc) {
      var docs = changeTarballs(base, doc);
      res.json(docs);
    }).catch(function (e) {
      request.get(FAT_REMOTE + req.url).pipe(res);
    });
  });
  app.get('/:name/:version', function (req, res) {
    skimLocal.get(req.params.name).catch(function () {
      return skimRemote.get(req.params.name);
    }).then(function (doc) {
      res.json(changeTarballs(base, doc).versions[req.params.version]);
    }).catch(function (e) {
      request.get(FAT_REMOTE + req.url).pipe(res);
    });
  });
  app.get('/tarballs/:name/:version.tgz', function (req, res) {
    var id = req.params.name + '-' + req.params.version;
    db.get(id, function (err, resp) {
      if (!err) {
        res.set('content-type', 'application/octet-stream');
        res.set('content-length', resp.length);
        return res.send(resp);
      }
      var buffs = [];
      var get = request.get(FAT_REMOTE + '/' + req.params.name + '/-/' + id + '.tgz');
      get.on('error', function () {
        res.send(500, 'you are offline and this package isn\'t cached');
      });
      get.pipe(res);
      get.pipe(through(function (chunk, _, next) {
        buffs.push(chunk);
        next();
      }, function (next) {
        next();
        var buff = Buffer.concat(buffs);
        db.put(id, buff, function (err) {
          if (err) {
            log(err);
          }
        });
      }));
    });
  });
  function changeTarballs(base, doc) {
    Object.keys(doc.versions).forEach(function (key) {
      doc.versions[key].dist.tarball = base + '/' + doc.name + '/' + key + '.tgz';
    });
    return doc;
  }
  app.all('/*', function (req, res) {
    res.send(500);
  });
  var sync;
  function replicateSkim() {
    skimRemote.info().then(function (info) {
      sync = skimLocal.replicate.from(skimRemote, {
        live: true,
        batch_size: 2000
      }).on('change', function (change) {
        var percent = Math.min(100,
          (Math.floor(change.last_seq / info.update_seq * 10000) / 100).toFixed(2));
        log('Replicating skimdb, last_seq is: ' + change.last_seq + ' (' + percent + '%)');
      }).on('uptodate', function () {
        log('local skimdb is up to date');
      }).on('error', function (err) {
        console.error('error during replication with skimdb');
        console.error(err);
        restartReplication();
      });
    }).catch(function (err) {
      console.error('error doing info() on ' + SKIM_REMOTE);
      console.error(err);
      restartReplication();
    });
  }
  function restartReplication() {
    // just keep going
    startingTimeout *= backoff;
    setTimeout(replicateSkim, Math.round(startingTimeout));
  }
  replicateSkim();

  app.listen(port);

  process.on('SIGINT', function () {
    // close gracefully
    sync.cancel();
    db.close(function () {
      skimLocal.close().then(function () {
        process.exit();
      }, function () {
        process.exit();
      });
    });
  });
};
<|endoftext|>


<commit_before>
(function ($) {
    'use strict';

    var defaultWidth = 200;
    var defaultHeight = 100;
    var defaultColor = '#9BA3AB';
    var defaultChipHeight = 12;
    var defaultPartitionX = 5;
    var defaultPartitionY = 3;
    var defaultDistance = 25;

    function SpeechBubble($parent, $content, x, y, w, h, color, chipHeight, partitionX, partitionY, distance) {
        this.$parent = $parent;
        this.$content = $content.css({position: 'absolute', opacity: 0});
        this.x = x;
        this.y = y;
        this.w = w || defaultWidth;
        this.h = h || defaultHeight;
        this.color = color || defaultColor;
        this.chipHeight = chipHeight || defaultChipHeight;
        this.partitionX = partitionX || defaultPartitionX;
        this.partitionY = partitionY || defaultPartitionY;
        this.distance = distance || defaultDistance;

    }

    var sbPt = SpeechBubble.prototype;

    sbPt.createInfoPane = function () {
        this.$dom = $('<div />')
            .css({
                position: 'absolute',
                left: (this.x - this.w / 2) + 'px',
                top: (this.y - this.h - this.chipHeight - this.distance) + 'px'
            })
            .width(this.w).height(this.h).append(this.$content).appendTo(this.$parent);

        this.$chip = $('<div />')
            .css({
                position: 'absolute',
                bottom: '-' + this.chipHeight * 2 + 'px',
                left: this.w / 2 - Math.floor(this.chipHeight / 1.5),
                width: 0,
                height: 0,
                borderWidth: this.chipHeight + 'px ' + Math.floor(this.chipHeight / 1.5) + 'px',
                borderColor: 'transparent',
                borderStyle: 'solid',
                borderTop: 'solid ' + this.chipHeight + 'px ' + this.color,
                borderTopColor: this.color,
                opacity: 0
            }).appendTo(this.$dom);

        console.log((this.x - this.w / 2) + 'px');
        console.log((this.y - this.h - this.chipHeight) + 'px');

        this.ip = this.$dom.infoPane(this.partitionX, this.partitionY, {
            bgcolor: this.color,
        });

        return this.ip;
    };

    sbPt.show = function () {
        var that = this;

        return this.createInfoPane().show().then(function () {
            return that;
        });
    };

    sbPt.hide = function () {
        var that = this;

        return this.ip.hide().then(function () {
            that.$dom.remove();
        });
    };

    $.fn.speechBubble = function ($content, opts) {
        opts = opts || {};

        var pos = this.position();

        return new SpeechBubble(this.parent(), $content, pos.left + this.width() / 2, pos.top, opts.width, opts.height, opts.color, opts.chipHeight, opts.partitionX, opts.partitionY, opts.distance);
    };

}(window.jQuery));
<commit_msg>Add cssClass option<commit_after>
(function ($) {
    'use strict';

    var defaultWidth = 200;
    var defaultHeight = 100;
    var defaultColor = '#9BA3AB';
    var defaultChipHeight = 12;
    var defaultPartitionX = 5;
    var defaultPartitionY = 3;
    var defaultDistance = 25;

    function SpeechBubble($parent, $content, x, y, w, h, color, chipHeight, partitionX, partitionY, distance, cssClass) {
        this.$parent = $parent;
        this.$content = $content.css({position: 'absolute', opacity: 0});
        this.x = x;
        this.y = y;
        this.w = w || defaultWidth;
        this.h = h || defaultHeight;
        this.color = color || defaultColor;
        this.chipHeight = chipHeight || defaultChipHeight;
        this.partitionX = partitionX || defaultPartitionX;
        this.partitionY = partitionY || defaultPartitionY;
        this.distance = distance || defaultDistance;
        this.cssClass = cssClass || '';

    }

    var sbPt = SpeechBubble.prototype;

    sbPt.createInfoPane = function () {
        this.$dom = $('<div />')
            .css({
                position: 'absolute',
                left: (this.x - this.w / 2) + 'px',
                top: (this.y - this.h - this.chipHeight - this.distance) + 'px'
            })
            .addClass(this.cssClass)
            .width(this.w).height(this.h).append(this.$content).appendTo(this.$parent);

        this.$chip = $('<div />')
            .css({
                position: 'absolute',
                bottom: '-' + this.chipHeight * 2 + 'px',
                left: this.w / 2 - Math.floor(this.chipHeight / 1.5),
                width: 0,
                height: 0,
                borderWidth: this.chipHeight + 'px ' + Math.floor(this.chipHeight / 1.5) + 'px',
                borderColor: 'transparent',
                borderStyle: 'solid',
                borderTop: 'solid ' + this.chipHeight + 'px ' + this.color,
                borderTopColor: this.color,
                opacity: 0
            }).appendTo(this.$dom);

        this.ip = this.$dom.infoPane(this.partitionX, this.partitionY, {
            bgcolor: this.color,
        });

        return this.ip;
    };

    sbPt.show = function () {
        var that = this;

        return this.createInfoPane().show().then(function () {
            return that;
        });
    };

    sbPt.hide = function () {
        var that = this;

        return this.ip.hide().then(function () {
            that.$dom.remove();
        });
    };

    $.fn.speechBubble = function ($content, opts) {
        opts = opts || {};

        var pos = this.position();

        return new SpeechBubble(this.parent(), $content, pos.left + this.width() / 2, pos.top, opts.width, opts.height, opts.color, opts.chipHeight, opts.partitionX, opts.partitionY, opts.distance, opts.cssClass);
    };

}(window.jQuery));
<|endoftext|>


<commit_before>module.exports = createTorrent
module.exports.parseInput = parseInput

module.exports.announceList = [
  [ 'udp://tracker.openbittorrent.com:80' ],
  [ 'udp://tracker.internetwarriors.net:1337' ],
  [ 'udp://tracker.leechers-paradise.org:6969' ],
  [ 'udp://tracker.coppersurfer.tk:6969' ],
  [ 'udp://exodus.desync.com:6969' ],
  [ 'wss://tracker.btorrent.xyz' ],
  [ 'wss://tracker.openwebtorrent.com' ],
  [ 'wss://tracker.fastcast.nz' ]
]

var bencode = require('bencode')
var BlockStream = require('block-stream2')
var calcPieceLength = require('piece-length')
var corePath = require('path')
var extend = require('xtend')
var FileReadStream = require('filestream/read')
var flatten = require('flatten')
var fs = require('fs')
var isFile = require('is-file')
var junk = require('junk')
var MultiStream = require('multistream')
var once = require('once')
var parallel = require('run-parallel')
var sha1 = require('simple-sha1')
var stream = require('readable-stream')

/**
 * Create a torrent.
 * @param  {string|File|FileList|Buffer|Stream|Array.<string|File|Buffer|Stream>} input
 * @param  {Object} opts
 * @param  {string=} opts.name
 * @param  {Date=} opts.creationDate
 * @param  {string=} opts.comment
 * @param  {string=} opts.createdBy
 * @param  {boolean|number=} opts.private
 * @param  {number=} opts.pieceLength
 * @param  {Array.<Array.<string>>=} opts.announceList
 * @param  {Array.<string>=} opts.urlList
 * @param  {function} cb
 * @return {Buffer} buffer of .torrent file data
 */
function createTorrent (input, opts, cb) {
  if (typeof opts === 'function') return createTorrent(input, null, opts)
  opts = opts ? extend(opts) : {}

  _parseInput(input, opts, function (err, files, singleFileTorrent) {
    if (err) return cb(err)
    opts.singleFileTorrent = singleFileTorrent
    onFiles(files, opts, cb)
  })
}

function parseInput (input, opts, cb) {
  if (typeof opts === 'function') return parseInput(input, null, opts)
  opts = opts ? extend(opts) : {}
  _parseInput(input, opts, cb)
}

/**
 * Parse input file and return file information.
 */
function _parseInput (input, opts, cb) {
  if (Array.isArray(input) && input.length === 0) throw new Error('invalid input type')

  if (isFileList(input)) input = Array.prototype.slice.call(input)
  if (!Array.isArray(input)) input = [ input ]

  // In Electron, use the true file path
  input = input.map(function (item) {
    if (isBlob(item) && typeof item.path === 'string' && typeof fs.stat === 'function') return item.path
    return item
  })

  // If there's just one file, allow the name to be set by `opts.name`
  if (input.length === 1 && typeof input[0] !== 'string' && !input[0].name) input[0].name = opts.name

  var commonPrefix = null
  input.forEach(function (item, i) {
    if (typeof item === 'string') {
      return
    }

    var path = item.fullPath || item.name
    if (!path) {
      path = 'Unknown File ' + (i + 1)
      item.unknownName = true
    }

    item.path = path.split('/')

    // Remove initial slash
    if (!item.path[0]) {
      item.path.shift()
    }

    if (item.path.length < 2) { // No real prefix
      commonPrefix = null
    } else if (i === 0 && input.length > 1) { // The first file has a prefix
      commonPrefix = item.path[0]
    } else if (item.path[0] !== commonPrefix) { // The prefix doesn't match
      commonPrefix = null
    }
  })

  // remove junk files
  input = input.filter(function (item) {
    if (typeof item === 'string') {
      return true
    }
    var filename = item.path[item.path.length - 1]
    return notHidden(filename) && junk.not(filename)
  })

  if (commonPrefix) {
    input.forEach(function (item) {
      var pathless = (Buffer.isBuffer(item) || isReadable(item)) && !item.path
      if (typeof item === 'string' || pathless) return
      item.path.shift()
    })
  }

  if (!opts.name && commonPrefix) {
    opts.name = commonPrefix
  }

  if (!opts.name) {
    // use first user-set file name
    input.some(function (item) {
      if (typeof item === 'string') {
        opts.name = corePath.basename(item)
        return true
      } else if (!item.unknownName) {
        opts.name = item.path[item.path.length - 1]
        return true
      }
    })
  }

  if (!opts.name) {
    opts.name = 'Unnamed Torrent ' + Date.now()
  }

  var numPaths = input.reduce(function (sum, item) {
    return sum + Number(typeof item === 'string')
  }, 0)

  var isSingleFileTorrent = (input.length === 1)

  if (input.length === 1 && typeof input[0] === 'string') {
    if (typeof fs.stat !== 'function') {
      throw new Error('filesystem paths do not work in the browser')
    }
    // If there's a single path, verify it's a file before deciding this is a single
    // file torrent
    isFile(input[0], function (err, pathIsFile) {
      if (err) return cb(err)
      isSingleFileTorrent = pathIsFile
      processInput()
    })
  } else {
    process.nextTick(function () {
      processInput()
    })
  }

  function processInput () {
    parallel(input.map(function (item) {
      return function (cb) {
        var file = {}

        if (isBlob(item)) {
          file.getStream = getBlobStream(item)
          file.length = item.size
        } else if (Buffer.isBuffer(item)) {
          file.getStream = getBufferStream(item)
          file.length = item.length
        } else if (isReadable(item)) {
          file.getStream = getStreamStream(item, file)
          file.length = 0
        } else if (typeof item === 'string') {
          if (typeof fs.stat !== 'function') {
            throw new Error('filesystem paths do not work in the browser')
          }
          var keepRoot = numPaths > 1 || isSingleFileTorrent
          getFiles(item, keepRoot, cb)
          return // early return!
        } else {
          throw new Error('invalid input type')
        }
        file.path = item.path
        cb(null, file)
      }
    }), function (err, files) {
      if (err) return cb(err)
      files = flatten(files)
      cb(null, files, isSingleFileTorrent)
    })
  }
}

function getFiles (path, keepRoot, cb) {
  traversePath(path, getFileInfo, function (err, files) {
    if (err) return cb(err)

    if (Array.isArray(files)) files = flatten(files)
    else files = [ files ]

    path = corePath.normalize(path)
    if (keepRoot) {
      path = path.slice(0, path.lastIndexOf(corePath.sep) + 1)
    }
    if (path[path.length - 1] !== corePath.sep) path += corePath.sep

    files.forEach(function (file) {
      file.getStream = getFilePathStream(file.path)
      file.path = file.path.replace(path, '').split(corePath.sep)
    })
    cb(null, files)
  })
}

function getFileInfo (path, cb) {
  cb = once(cb)
  fs.stat(path, function (err, stat) {
    if (err) return cb(err)
    var info = {
      length: stat.size,
      path: path
    }
    cb(null, info)
  })
}

function traversePath (path, fn, cb) {
  fs.stat(path, function (err, stats) {
    if (err) return cb(err)
    if (stats.isDirectory()) {
      fs.readdir(path, function (err, entries) {
        if (err) return cb(err)
        parallel(entries.filter(notHidden).filter(junk.not).map(function (entry) {
          return function (cb) {
            traversePath(corePath.join(path, entry), fn, cb)
          }
        }), cb)
      })
    } else if (stats.isFile()) {
      fn(path, cb)
    }
    // Ignore other types (not a file or directory)
  })
}

function notHidden (file) {
  return file[0] !== '.'
}

function getPieceList (files, pieceLength, cb) {
  cb = once(cb)
  var pieces = []
  var length = 0

  var streams = files.map(function (file) {
    return file.getStream
  })

  var remainingHashes = 0
  var pieceNum = 0
  var ended = false

  var multistream = new MultiStream(streams)
  var blockstream = new BlockStream(pieceLength, { zeroPadding: false })

  multistream.on('error', onError)

  multistream
    .pipe(blockstream)
    .on('data', onData)
    .on('end', onEnd)
    .on('error', onError)

  function onData (chunk) {
    length += chunk.length

    var i = pieceNum
    sha1(chunk, function (hash) {
      pieces[i] = hash
      remainingHashes -= 1
      maybeDone()
    })
    remainingHashes += 1
    pieceNum += 1
  }

  function onEnd () {
    ended = true
    maybeDone()
  }

  function onError (err) {
    cleanup()
    cb(err)
  }

  function cleanup () {
    multistream.removeListener('error', onError)
    blockstream.removeListener('data', onData)
    blockstream.removeListener('end', onEnd)
    blockstream.removeListener('error', onError)
  }

  function maybeDone () {
    if (ended && remainingHashes === 0) {
      cleanup()
      cb(null, new Buffer(pieces.join(''), 'hex'), length)
    }
  }
}

function onFiles (files, opts, cb) {
  var announceList = opts.announceList

  if (!announceList) {
    if (typeof opts.announce === 'string') announceList = [ [ opts.announce ] ]
    else if (Array.isArray(opts.announce)) {
      announceList = opts.announce.map(function (u) { return [ u ] })
    }
  }

  if (!announceList) announceList = []

  if (global.WEBTORRENT_ANNOUNCE) {
    if (typeof global.WEBTORRENT_ANNOUNCE === 'string') {
      announceList.push([ [ global.WEBTORRENT_ANNOUNCE ] ])
    } else if (Array.isArray(global.WEBTORRENT_ANNOUNCE)) {
      announceList = announceList.concat(global.WEBTORRENT_ANNOUNCE.map(function (u) {
        return [ u ]
      }))
    }
  }

  // When no trackers specified, use some reasonable defaults
  if (opts.announce === undefined && opts.announceList === undefined) {
    announceList = announceList.concat(module.exports.announceList)
  }

  if (typeof opts.urlList === 'string') opts.urlList = [ opts.urlList ]

  var torrent = {
    info: {
      name: opts.name
    },
    'creation date': Math.ceil((Number(opts.creationDate) || Date.now()) / 1000),
    encoding: 'UTF-8'
  }

  if (announceList.length !== 0) {
    torrent.announce = announceList[0][0]
    torrent['announce-list'] = announceList
  }

  if (opts.comment !== undefined) torrent.comment = opts.comment

  if (opts.createdBy !== undefined) torrent['created by'] = opts.createdBy

  if (opts.private !== undefined) torrent.info.private = Number(opts.private)

  // "ssl-cert" key is for SSL torrents, see:
  //   - http://blog.libtorrent.org/2012/01/bittorrent-over-ssl/
  //   - http://www.libtorrent.org/manual-ref.html#ssl-torrents
  //   - http://www.libtorrent.org/reference-Create_Torrents.html
  if (opts.sslCert !== undefined) torrent.info['ssl-cert'] = opts.sslCert

  if (opts.urlList !== undefined) torrent['url-list'] = opts.urlList

  var pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0))
  torrent.info['piece length'] = pieceLength

  getPieceList(files, pieceLength, function (err, pieces, torrentLength) {
    if (err) return cb(err)
    torrent.info.pieces = pieces

    files.forEach(function (file) {
      delete file.getStream
    })

    if (opts.singleFileTorrent) {
      torrent.info.length = torrentLength
    } else {
      torrent.info.files = files
    }

    cb(null, bencode.encode(torrent))
  })
}

/**
 * Accumulator to sum file lengths
 * @param  {number} sum
 * @param  {Object} file
 * @return {number}
 */
function sumLength (sum, file) {
  return sum + file.length
}

/**
 * Check if `obj` is a W3C `Blob` object (which `File` inherits from)
 * @param  {*} obj
 * @return {boolean}
 */
function isBlob (obj) {
  return typeof Blob !== 'undefined' && obj instanceof Blob
}

/**
 * Check if `obj` is a W3C `FileList` object
 * @param  {*} obj
 * @return {boolean}
 */
function isFileList (obj) {
  return typeof FileList !== 'undefined' && obj instanceof FileList
}

/**
 * Check if `obj` is a node Readable stream
 * @param  {*} obj
 * @return {boolean}
 */
function isReadable (obj) {
  return typeof obj === 'object' && obj != null && typeof obj.pipe === 'function'
}

/**
 * Convert a `File` to a lazy readable stream.
 * @param  {File|Blob} file
 * @return {function}
 */
function getBlobStream (file) {
  return function () {
    return new FileReadStream(file)
  }
}

/**
 * Convert a `Buffer` to a lazy readable stream.
 * @param  {Buffer} buffer
 * @return {function}
 */
function getBufferStream (buffer) {
  return function () {
    var s = new stream.PassThrough()
    s.end(buffer)
    return s
  }
}

/**
 * Convert a file path to a lazy readable stream.
 * @param  {string} path
 * @return {function}
 */
function getFilePathStream (path) {
  return function () {
    return fs.createReadStream(path)
  }
}

/**
 * Convert a readable stream to a lazy readable stream. Adds instrumentation to track
 * the number of bytes in the stream and set `file.length`.
 *
 * @param  {Stream} stream
 * @param  {Object} file
 * @return {function}
 */
function getStreamStream (readable, file) {
  return function () {
    var counter = new stream.Transform()
    counter._transform = function (buf, enc, done) {
      file.length += buf.length
      this.push(buf)
      done()
    }
    readable.pipe(counter)
    return counter
  }
}
<commit_msg>Replace dead trackers<commit_after>module.exports = createTorrent
module.exports.parseInput = parseInput

module.exports.announceList = [
  [ 'udp://tracker.openbittorrent.com:80' ],
  [ 'udp://tracker.leechers-paradise.org:6969' ],
  [ 'udp://tracker.coppersurfer.tk:6969' ],
  [ 'udp://tracker.opentrackr.org:1337' ],
  [ 'udp://explodie.org:6969' ],
  [ 'udp://zer0day.ch:1337' ],
  [ 'wss://tracker.btorrent.xyz' ],
  [ 'wss://tracker.openwebtorrent.com' ],
  [ 'wss://tracker.fastcast.nz' ]
]

var bencode = require('bencode')
var BlockStream = require('block-stream2')
var calcPieceLength = require('piece-length')
var corePath = require('path')
var extend = require('xtend')
var FileReadStream = require('filestream/read')
var flatten = require('flatten')
var fs = require('fs')
var isFile = require('is-file')
var junk = require('junk')
var MultiStream = require('multistream')
var once = require('once')
var parallel = require('run-parallel')
var sha1 = require('simple-sha1')
var stream = require('readable-stream')

/**
 * Create a torrent.
 * @param  {string|File|FileList|Buffer|Stream|Array.<string|File|Buffer|Stream>} input
 * @param  {Object} opts
 * @param  {string=} opts.name
 * @param  {Date=} opts.creationDate
 * @param  {string=} opts.comment
 * @param  {string=} opts.createdBy
 * @param  {boolean|number=} opts.private
 * @param  {number=} opts.pieceLength
 * @param  {Array.<Array.<string>>=} opts.announceList
 * @param  {Array.<string>=} opts.urlList
 * @param  {function} cb
 * @return {Buffer} buffer of .torrent file data
 */
function createTorrent (input, opts, cb) {
  if (typeof opts === 'function') return createTorrent(input, null, opts)
  opts = opts ? extend(opts) : {}

  _parseInput(input, opts, function (err, files, singleFileTorrent) {
    if (err) return cb(err)
    opts.singleFileTorrent = singleFileTorrent
    onFiles(files, opts, cb)
  })
}

function parseInput (input, opts, cb) {
  if (typeof opts === 'function') return parseInput(input, null, opts)
  opts = opts ? extend(opts) : {}
  _parseInput(input, opts, cb)
}

/**
 * Parse input file and return file information.
 */
function _parseInput (input, opts, cb) {
  if (Array.isArray(input) && input.length === 0) throw new Error('invalid input type')

  if (isFileList(input)) input = Array.prototype.slice.call(input)
  if (!Array.isArray(input)) input = [ input ]

  // In Electron, use the true file path
  input = input.map(function (item) {
    if (isBlob(item) && typeof item.path === 'string' && typeof fs.stat === 'function') return item.path
    return item
  })

  // If there's just one file, allow the name to be set by `opts.name`
  if (input.length === 1 && typeof input[0] !== 'string' && !input[0].name) input[0].name = opts.name

  var commonPrefix = null
  input.forEach(function (item, i) {
    if (typeof item === 'string') {
      return
    }

    var path = item.fullPath || item.name
    if (!path) {
      path = 'Unknown File ' + (i + 1)
      item.unknownName = true
    }

    item.path = path.split('/')

    // Remove initial slash
    if (!item.path[0]) {
      item.path.shift()
    }

    if (item.path.length < 2) { // No real prefix
      commonPrefix = null
    } else if (i === 0 && input.length > 1) { // The first file has a prefix
      commonPrefix = item.path[0]
    } else if (item.path[0] !== commonPrefix) { // The prefix doesn't match
      commonPrefix = null
    }
  })

  // remove junk files
  input = input.filter(function (item) {
    if (typeof item === 'string') {
      return true
    }
    var filename = item.path[item.path.length - 1]
    return notHidden(filename) && junk.not(filename)
  })

  if (commonPrefix) {
    input.forEach(function (item) {
      var pathless = (Buffer.isBuffer(item) || isReadable(item)) && !item.path
      if (typeof item === 'string' || pathless) return
      item.path.shift()
    })
  }

  if (!opts.name && commonPrefix) {
    opts.name = commonPrefix
  }

  if (!opts.name) {
    // use first user-set file name
    input.some(function (item) {
      if (typeof item === 'string') {
        opts.name = corePath.basename(item)
        return true
      } else if (!item.unknownName) {
        opts.name = item.path[item.path.length - 1]
        return true
      }
    })
  }

  if (!opts.name) {
    opts.name = 'Unnamed Torrent ' + Date.now()
  }

  var numPaths = input.reduce(function (sum, item) {
    return sum + Number(typeof item === 'string')
  }, 0)

  var isSingleFileTorrent = (input.length === 1)

  if (input.length === 1 && typeof input[0] === 'string') {
    if (typeof fs.stat !== 'function') {
      throw new Error('filesystem paths do not work in the browser')
    }
    // If there's a single path, verify it's a file before deciding this is a single
    // file torrent
    isFile(input[0], function (err, pathIsFile) {
      if (err) return cb(err)
      isSingleFileTorrent = pathIsFile
      processInput()
    })
  } else {
    process.nextTick(function () {
      processInput()
    })
  }

  function processInput () {
    parallel(input.map(function (item) {
      return function (cb) {
        var file = {}

        if (isBlob(item)) {
          file.getStream = getBlobStream(item)
          file.length = item.size
        } else if (Buffer.isBuffer(item)) {
          file.getStream = getBufferStream(item)
          file.length = item.length
        } else if (isReadable(item)) {
          file.getStream = getStreamStream(item, file)
          file.length = 0
        } else if (typeof item === 'string') {
          if (typeof fs.stat !== 'function') {
            throw new Error('filesystem paths do not work in the browser')
          }
          var keepRoot = numPaths > 1 || isSingleFileTorrent
          getFiles(item, keepRoot, cb)
          return // early return!
        } else {
          throw new Error('invalid input type')
        }
        file.path = item.path
        cb(null, file)
      }
    }), function (err, files) {
      if (err) return cb(err)
      files = flatten(files)
      cb(null, files, isSingleFileTorrent)
    })
  }
}

function getFiles (path, keepRoot, cb) {
  traversePath(path, getFileInfo, function (err, files) {
    if (err) return cb(err)

    if (Array.isArray(files)) files = flatten(files)
    else files = [ files ]

    path = corePath.normalize(path)
    if (keepRoot) {
      path = path.slice(0, path.lastIndexOf(corePath.sep) + 1)
    }
    if (path[path.length - 1] !== corePath.sep) path += corePath.sep

    files.forEach(function (file) {
      file.getStream = getFilePathStream(file.path)
      file.path = file.path.replace(path, '').split(corePath.sep)
    })
    cb(null, files)
  })
}

function getFileInfo (path, cb) {
  cb = once(cb)
  fs.stat(path, function (err, stat) {
    if (err) return cb(err)
    var info = {
      length: stat.size,
      path: path
    }
    cb(null, info)
  })
}

function traversePath (path, fn, cb) {
  fs.stat(path, function (err, stats) {
    if (err) return cb(err)
    if (stats.isDirectory()) {
      fs.readdir(path, function (err, entries) {
        if (err) return cb(err)
        parallel(entries.filter(notHidden).filter(junk.not).map(function (entry) {
          return function (cb) {
            traversePath(corePath.join(path, entry), fn, cb)
          }
        }), cb)
      })
    } else if (stats.isFile()) {
      fn(path, cb)
    }
    // Ignore other types (not a file or directory)
  })
}

function notHidden (file) {
  return file[0] !== '.'
}

function getPieceList (files, pieceLength, cb) {
  cb = once(cb)
  var pieces = []
  var length = 0

  var streams = files.map(function (file) {
    return file.getStream
  })

  var remainingHashes = 0
  var pieceNum = 0
  var ended = false

  var multistream = new MultiStream(streams)
  var blockstream = new BlockStream(pieceLength, { zeroPadding: false })

  multistream.on('error', onError)

  multistream
    .pipe(blockstream)
    .on('data', onData)
    .on('end', onEnd)
    .on('error', onError)

  function onData (chunk) {
    length += chunk.length

    var i = pieceNum
    sha1(chunk, function (hash) {
      pieces[i] = hash
      remainingHashes -= 1
      maybeDone()
    })
    remainingHashes += 1
    pieceNum += 1
  }

  function onEnd () {
    ended = true
    maybeDone()
  }

  function onError (err) {
    cleanup()
    cb(err)
  }

  function cleanup () {
    multistream.removeListener('error', onError)
    blockstream.removeListener('data', onData)
    blockstream.removeListener('end', onEnd)
    blockstream.removeListener('error', onError)
  }

  function maybeDone () {
    if (ended && remainingHashes === 0) {
      cleanup()
      cb(null, new Buffer(pieces.join(''), 'hex'), length)
    }
  }
}

function onFiles (files, opts, cb) {
  var announceList = opts.announceList

  if (!announceList) {
    if (typeof opts.announce === 'string') announceList = [ [ opts.announce ] ]
    else if (Array.isArray(opts.announce)) {
      announceList = opts.announce.map(function (u) { return [ u ] })
    }
  }

  if (!announceList) announceList = []

  if (global.WEBTORRENT_ANNOUNCE) {
    if (typeof global.WEBTORRENT_ANNOUNCE === 'string') {
      announceList.push([ [ global.WEBTORRENT_ANNOUNCE ] ])
    } else if (Array.isArray(global.WEBTORRENT_ANNOUNCE)) {
      announceList = announceList.concat(global.WEBTORRENT_ANNOUNCE.map(function (u) {
        return [ u ]
      }))
    }
  }

  // When no trackers specified, use some reasonable defaults
  if (opts.announce === undefined && opts.announceList === undefined) {
    announceList = announceList.concat(module.exports.announceList)
  }

  if (typeof opts.urlList === 'string') opts.urlList = [ opts.urlList ]

  var torrent = {
    info: {
      name: opts.name
    },
    'creation date': Math.ceil((Number(opts.creationDate) || Date.now()) / 1000),
    encoding: 'UTF-8'
  }

  if (announceList.length !== 0) {
    torrent.announce = announceList[0][0]
    torrent['announce-list'] = announceList
  }

  if (opts.comment !== undefined) torrent.comment = opts.comment

  if (opts.createdBy !== undefined) torrent['created by'] = opts.createdBy

  if (opts.private !== undefined) torrent.info.private = Number(opts.private)

  // "ssl-cert" key is for SSL torrents, see:
  //   - http://blog.libtorrent.org/2012/01/bittorrent-over-ssl/
  //   - http://www.libtorrent.org/manual-ref.html#ssl-torrents
  //   - http://www.libtorrent.org/reference-Create_Torrents.html
  if (opts.sslCert !== undefined) torrent.info['ssl-cert'] = opts.sslCert

  if (opts.urlList !== undefined) torrent['url-list'] = opts.urlList

  var pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0))
  torrent.info['piece length'] = pieceLength

  getPieceList(files, pieceLength, function (err, pieces, torrentLength) {
    if (err) return cb(err)
    torrent.info.pieces = pieces

    files.forEach(function (file) {
      delete file.getStream
    })

    if (opts.singleFileTorrent) {
      torrent.info.length = torrentLength
    } else {
      torrent.info.files = files
    }

    cb(null, bencode.encode(torrent))
  })
}

/**
 * Accumulator to sum file lengths
 * @param  {number} sum
 * @param  {Object} file
 * @return {number}
 */
function sumLength (sum, file) {
  return sum + file.length
}

/**
 * Check if `obj` is a W3C `Blob` object (which `File` inherits from)
 * @param  {*} obj
 * @return {boolean}
 */
function isBlob (obj) {
  return typeof Blob !== 'undefined' && obj instanceof Blob
}

/**
 * Check if `obj` is a W3C `FileList` object
 * @param  {*} obj
 * @return {boolean}
 */
function isFileList (obj) {
  return typeof FileList !== 'undefined' && obj instanceof FileList
}

/**
 * Check if `obj` is a node Readable stream
 * @param  {*} obj
 * @return {boolean}
 */
function isReadable (obj) {
  return typeof obj === 'object' && obj != null && typeof obj.pipe === 'function'
}

/**
 * Convert a `File` to a lazy readable stream.
 * @param  {File|Blob} file
 * @return {function}
 */
function getBlobStream (file) {
  return function () {
    return new FileReadStream(file)
  }
}

/**
 * Convert a `Buffer` to a lazy readable stream.
 * @param  {Buffer} buffer
 * @return {function}
 */
function getBufferStream (buffer) {
  return function () {
    var s = new stream.PassThrough()
    s.end(buffer)
    return s
  }
}

/**
 * Convert a file path to a lazy readable stream.
 * @param  {string} path
 * @return {function}
 */
function getFilePathStream (path) {
  return function () {
    return fs.createReadStream(path)
  }
}

/**
 * Convert a readable stream to a lazy readable stream. Adds instrumentation to track
 * the number of bytes in the stream and set `file.length`.
 *
 * @param  {Stream} stream
 * @param  {Object} file
 * @return {function}
 */
function getStreamStream (readable, file) {
  return function () {
    var counter = new stream.Transform()
    counter._transform = function (buf, enc, done) {
      file.length += buf.length
      this.push(buf)
      done()
    }
    readable.pipe(counter)
    return counter
  }
}
<|endoftext|>


<commit_before>// var allowCrossDomain = function(req, res, next) {
//     res.header('Access-Control-Allow-Origin', '*');
//     res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
//     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

//     // intercept OPTIONS method
//     if ('OPTIONS' == req.method) {
//       res.send(200);
//     }
//     else {
//       next();
//     }
// };

var app = require('express')();
var http = require('http').Server(app);
// var cors = require('cors');
var io = require('socket.io')(http);

io.set('transports', [
        	'websocket',
        	'flashsocket',
        	'htmlfile',
        	'xhr-polling',
        	'jsonp-polling'
		    ]);

// io.configure( function(){
    io.set('origin', '*:*');
    // io.set('origins', "http://yaps.herokuapp.com" );
// });
// io.set("origins", "https://yaps.herokuapp.com");
// io.set("origins","*:*");

// Enables CORS
// var enableCORS = function(req, res, next) {
//     res.header('Access-Control-Allow-Origin', '*');
//     res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
//     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

//     // intercept OPTIONS method
//     if ('OPTIONS' == req.method) {
//       res.send(200);
//     }
//     else {
//       next();
//     }
// };

// // enable CORS!
// app.use(enableCORS);
// app.use(cors({credentials: true}));

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*:*');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
    // debugger;
    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
};

// app.use(allowCrossDomain);

app.use(allowCrossDomain);

// app.configure(function () {
//   app.use(express.bodyParser());
//   app.use(express.methodOverride());
//   app.use(allowCrossDomain);
//   app.use(app.router);
//   app.use(express.static(path.join(application_root, "public")));
//   app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
// });
// io.configure(function () {
//   io.set("transports", ["xhr-polling"]);
//   io.set("polling duration", 10);
// });

// var cors = require('cors'); app.use(cors());

// io.set('transports', [            // all transports (optional if you want flashsocket)
//         'websocket'
//         , 'flashsocket'
//         , 'htmlfile'
//         , 'xhr-polling'
//         , 'jsonp-polling'
//     ]);
// io.set('origins', '*:*');

// app.configure(function () {
//   app.use(allowCrossDomain);
//   app.use(express.bodyParser());
//   app.use(express.methodOverride());
//   app.use(app.router);
//   app.use(express.static(path.join(application_root, "public")));
//   app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
// });

// var username = confirm("Username?");
var url = "http://yaps.herokuapp.com/"

// app.use(allowCrossDomain);

app.get(url, function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('chat message', function(msg){
  	console.log('message: ' + msg);
  });
});

// // broadcast to all
// io.emit('some event', { for: 'everyone' });

// // broadcast to everyone except for certain socket
// io.on('connection', function(socket){
// 	socket.broadcast.emit('hi');
// });

io.on('connection', function(socket){
	socket.on('chat message', function(msg){
		io.emit('chat message', msg);
	});
});

// http.listen(3001, function(){
//   console.log('listening on *:3001');
// });

http.listen(url, function(){
  console.log('listening to' + url);
});

io.connect('http://yaps.herokuapp.com');<commit_msg>alknslkasn<commit_after>// var allowCrossDomain = function(req, res, next) {
//     res.header('Access-Control-Allow-Origin', '*');
//     res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
//     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

//     // intercept OPTIONS method
//     if ('OPTIONS' == req.method) {
//       res.send(200);
//     }
//     else {
//       next();
//     }
// };

var app = require('express')();
var http = require('http').Server(app);
// var cors = require('cors');
var io = require('socket.io')(http);

io.set('transports', [
        	'websocket',
        	'flashsocket',
        	'htmlfile',
        	'xhr-polling',
        	'jsonp-polling'
		    ]);

// io.configure( function(){
    io.set('origin', '*:*');
    // io.set('origins', "http://yaps.herokuapp.com" );
// });
// io.set("origins", "https://yaps.herokuapp.com");
// io.set("origins","*:*");

// Enables CORS
// var enableCORS = function(req, res, next) {
//     res.header('Access-Control-Allow-Origin', '*');
//     res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
//     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

//     // intercept OPTIONS method
//     if ('OPTIONS' == req.method) {
//       res.send(200);
//     }
//     else {
//       next();
//     }
// };

// // enable CORS!
// app.use(enableCORS);
// app.use(cors({credentials: true}));

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*:*');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
    // debugger;
    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
};

// app.use(allowCrossDomain);

app.use(allowCrossDomain);

// app.configure(function () {
//   app.use(express.bodyParser());
//   app.use(express.methodOverride());
//   app.use(allowCrossDomain);
//   app.use(app.router);
//   app.use(express.static(path.join(application_root, "public")));
//   app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
// });
// io.configure(function () {
//   io.set("transports", ["xhr-polling"]);
//   io.set("polling duration", 10);
// });

// var cors = require('cors'); app.use(cors());

// io.set('transports', [            // all transports (optional if you want flashsocket)
//         'websocket'
//         , 'flashsocket'
//         , 'htmlfile'
//         , 'xhr-polling'
//         , 'jsonp-polling'
//     ]);
// io.set('origins', '*:*');

// app.configure(function () {
//   app.use(allowCrossDomain);
//   app.use(express.bodyParser());
//   app.use(express.methodOverride());
//   app.use(app.router);
//   app.use(express.static(path.join(application_root, "public")));
//   app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
// });

// var username = confirm("Username?");
var url = "http://yaps.herokuapp.com/"

// app.use(allowCrossDomain);

app.get(url, function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('chat message', function(msg){
  	console.log('message: ' + msg);
  });
});

// // broadcast to all
// io.emit('some event', { for: 'everyone' });

// // broadcast to everyone except for certain socket
// io.on('connection', function(socket){
// 	socket.broadcast.emit('hi');
// });

io.on('connection', function(socket){
	socket.on('chat message', function(msg){
		io.emit('chat message', msg);
	});
});

// http.listen(3001, function(){
//   console.log('listening on *:3001');
// });

http.listen(url, function(){
  console.log('listening to' + url);
});

// io.connect('http://yaps.herokuapp.com');<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    extend = require('extend');

function load() {
    // Recursively load one or more directories passed as arguments.

    var dir, result = {};

    function processFilename(fn) {
        var fp = path.join(dir, fn),
            // If the given filename is a directory, recursively load it.
            extra = fs.statSync(fp).isDirectory() ? load(fp) : require(fp);

        // The JSON data is independent of the actual file
        // hierarchy, so it is essential to extend "deeply".
        result = extend(true, result, extra);
    }

    for (dir of arguments) {
        dir = path.resolve(__dirname, dir);
        fs.readdirSync(dir).forEach(processFilename);
    }

    return result;
}

module.exports = load(
    // 'api',
    'css',
    // 'http',
    // 'javascript',
    'webextensions'
);
<commit_msg>Add 'api' folder to exports<commit_after>var fs = require('fs'),
    path = require('path'),
    extend = require('extend');

function load() {
    // Recursively load one or more directories passed as arguments.

    var dir, result = {};

    function processFilename(fn) {
        var fp = path.join(dir, fn),
            // If the given filename is a directory, recursively load it.
            extra = fs.statSync(fp).isDirectory() ? load(fp) : require(fp);

        // The JSON data is independent of the actual file
        // hierarchy, so it is essential to extend "deeply".
        result = extend(true, result, extra);
    }

    for (dir of arguments) {
        dir = path.resolve(__dirname, dir);
        fs.readdirSync(dir).forEach(processFilename);
    }

    return result;
}

module.exports = load(
    'api',
    'css',
    // 'http',
    // 'javascript',
    'webextensions'
);
<|endoftext|>