Index: node_modules/retry/.npmignore
===================================================================
--- node_modules/retry/.npmignore	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/.npmignore	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,3 @@
+/node_modules/*
+npm-debug.log
+coverage
Index: node_modules/retry/.travis.yml
===================================================================
--- node_modules/retry/.travis.yml	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/.travis.yml	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,15 @@
+language: node_js
+node_js:
+  - "4"
+before_install:
+  - pip install --user codecov
+after_success:
+  - codecov --file coverage/lcov.info --disable search
+# travis encrypt [subdomain]:[api token]@[room id]
+# notifications:
+#   email: false
+#   campfire:
+#     rooms:
+#       secure: xyz
+#     on_failure: always
+#     on_success: always
Index: node_modules/retry/License
===================================================================
--- node_modules/retry/License	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/License	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,21 @@
+Copyright (c) 2011:
+Tim Koschützki (tim@debuggable.com)
+Felix Geisendörfer (felix@debuggable.com)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
Index: node_modules/retry/Makefile
===================================================================
--- node_modules/retry/Makefile	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/Makefile	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,18 @@
+SHELL := /bin/bash
+
+release-major: test
+	npm version major -m "Release %s"
+	git push
+	npm publish
+
+release-minor: test
+	npm version minor -m "Release %s"
+	git push
+	npm publish
+
+release-patch: test
+	npm version patch -m "Release %s"
+	git push
+	npm publish
+
+.PHONY: test release-major release-minor release-patch
Index: node_modules/retry/README.md
===================================================================
--- node_modules/retry/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,227 @@
+<!-- badges/ -->
+[![Build Status](https://secure.travis-ci.org/tim-kos/node-retry.png?branch=master)](http://travis-ci.org/tim-kos/node-retry "Check this project's build status on TravisCI")
+[![codecov](https://codecov.io/gh/tim-kos/node-retry/branch/master/graph/badge.svg)](https://codecov.io/gh/tim-kos/node-retry)
+<!-- /badges -->
+
+# retry
+
+Abstraction for exponential and custom retry strategies for failed operations.
+
+## Installation
+
+    npm install retry
+
+## Current Status
+
+This module has been tested and is ready to be used.
+
+## Tutorial
+
+The example below will retry a potentially failing `dns.resolve` operation
+`10` times using an exponential backoff strategy. With the default settings, this
+means the last attempt is made after `17 minutes and 3 seconds`.
+
+``` javascript
+var dns = require('dns');
+var retry = require('retry');
+
+function faultTolerantResolve(address, cb) {
+  var operation = retry.operation();
+
+  operation.attempt(function(currentAttempt) {
+    dns.resolve(address, function(err, addresses) {
+      if (operation.retry(err)) {
+        return;
+      }
+
+      cb(err ? operation.mainError() : null, addresses);
+    });
+  });
+}
+
+faultTolerantResolve('nodejs.org', function(err, addresses) {
+  console.log(err, addresses);
+});
+```
+
+Of course you can also configure the factors that go into the exponential
+backoff. See the API documentation below for all available settings.
+currentAttempt is an int representing the number of attempts so far.
+
+``` javascript
+var operation = retry.operation({
+  retries: 5,
+  factor: 3,
+  minTimeout: 1 * 1000,
+  maxTimeout: 60 * 1000,
+  randomize: true,
+});
+```
+
+## API
+
+### retry.operation([options])
+
+Creates a new `RetryOperation` object. `options` is the same as `retry.timeouts()`'s `options`, with two additions:
+
+* `forever`: Whether to retry forever, defaults to `false`.
+* `unref`: Whether to [unref](https://nodejs.org/api/timers.html#timers_unref) the setTimeout's, defaults to `false`.
+* `maxRetryTime`: The maximum time (in milliseconds) that the retried operation is allowed to run. Default is `Infinity`.  
+
+### retry.timeouts([options])
+
+Returns an array of timeouts. All time `options` and return values are in
+milliseconds. If `options` is an array, a copy of that array is returned.
+
+`options` is a JS object that can contain any of the following keys:
+
+* `retries`: The maximum amount of times to retry the operation. Default is `10`. Seting this to `1` means `do it once, then retry it once`.
+* `factor`: The exponential factor to use. Default is `2`.
+* `minTimeout`: The number of milliseconds before starting the first retry. Default is `1000`.
+* `maxTimeout`: The maximum number of milliseconds between two retries. Default is `Infinity`.
+* `randomize`: Randomizes the timeouts by multiplying with a factor between `1` to `2`. Default is `false`.
+
+The formula used to calculate the individual timeouts is:
+
+```
+Math.min(random * minTimeout * Math.pow(factor, attempt), maxTimeout)
+```
+
+Have a look at [this article][article] for a better explanation of approach.
+
+If you want to tune your `factor` / `times` settings to attempt the last retry
+after a certain amount of time, you can use wolfram alpha. For example in order
+to tune for `10` attempts in `5 minutes`, you can use this equation:
+
+![screenshot](https://github.com/tim-kos/node-retry/raw/master/equation.gif)
+
+Explaining the various values from left to right:
+
+* `k = 0 ... 9`:  The `retries` value (10)
+* `1000`: The `minTimeout` value in ms (1000)
+* `x^k`: No need to change this, `x` will be your resulting factor
+* `5 * 60 * 1000`: The desired total amount of time for retrying in ms (5 minutes)
+
+To make this a little easier for you, use wolfram alpha to do the calculations:
+
+<http://www.wolframalpha.com/input/?i=Sum%5B1000*x^k%2C+{k%2C+0%2C+9}%5D+%3D+5+*+60+*+1000>
+
+[article]: http://dthain.blogspot.com/2009/02/exponential-backoff-in-distributed.html
+
+### retry.createTimeout(attempt, opts)
+
+Returns a new `timeout` (integer in milliseconds) based on the given parameters.
+
+`attempt` is an integer representing for which retry the timeout should be calculated. If your retry operation was executed 4 times you had one attempt and 3 retries. If you then want to calculate a new timeout, you should set `attempt` to 4 (attempts are zero-indexed).
+
+`opts` can include `factor`, `minTimeout`, `randomize` (boolean) and `maxTimeout`. They are documented above.
+
+`retry.createTimeout()` is used internally by `retry.timeouts()` and is public for you to be able to create your own timeouts for reinserting an item, see [issue #13](https://github.com/tim-kos/node-retry/issues/13).
+
+### retry.wrap(obj, [options], [methodNames])
+
+Wrap all functions of the `obj` with retry. Optionally you can pass operation options and
+an array of method names which need to be wrapped.
+
+```
+retry.wrap(obj)
+
+retry.wrap(obj, ['method1', 'method2'])
+
+retry.wrap(obj, {retries: 3})
+
+retry.wrap(obj, {retries: 3}, ['method1', 'method2'])
+```
+The `options` object can take any options that the usual call to `retry.operation` can take.
+
+### new RetryOperation(timeouts, [options])
+
+Creates a new `RetryOperation` where `timeouts` is an array where each value is
+a timeout given in milliseconds.
+
+Available options:
+* `forever`: Whether to retry forever, defaults to `false`.
+* `unref`: Wether to [unref](https://nodejs.org/api/timers.html#timers_unref) the setTimeout's, defaults to `false`.
+
+If `forever` is true, the following changes happen:
+* `RetryOperation.errors()` will only output an array of one item: the last error.
+* `RetryOperation` will repeatedly use the `timeouts` array. Once all of its timeouts have been used up, it restarts with the first timeout, then uses the second and so on.
+
+#### retryOperation.errors()
+
+Returns an array of all errors that have been passed to `retryOperation.retry()` so far. The
+returning array has the errors ordered chronologically based on when they were passed to
+`retryOperation.retry()`, which means the first passed error is at index zero and the last is
+at the last index.
+
+#### retryOperation.mainError()
+
+A reference to the error object that occured most frequently. Errors are
+compared using the `error.message` property.
+
+If multiple error messages occured the same amount of time, the last error
+object with that message is returned.
+
+If no errors occured so far, the value is `null`.
+
+#### retryOperation.attempt(fn, timeoutOps)
+
+Defines the function `fn` that is to be retried and executes it for the first
+time right away. The `fn` function can receive an optional `currentAttempt` callback that represents the number of attempts to execute `fn` so far.
+
+Optionally defines `timeoutOps` which is an object having a property `timeout` in miliseconds and a property `cb` callback function.
+Whenever your retry operation takes longer than `timeout` to execute, the timeout callback function `cb` is called.
+
+
+#### retryOperation.try(fn)
+
+This is an alias for `retryOperation.attempt(fn)`. This is deprecated. Please use `retryOperation.attempt(fn)` instead.
+
+#### retryOperation.start(fn)
+
+This is an alias for `retryOperation.attempt(fn)`. This is deprecated. Please use `retryOperation.attempt(fn)` instead.
+
+#### retryOperation.retry(error)
+
+Returns `false` when no `error` value is given, or the maximum amount of retries
+has been reached.
+
+Otherwise it returns `true`, and retries the operation after the timeout for
+the current attempt number.
+
+#### retryOperation.stop()
+
+Allows you to stop the operation being retried. Useful for aborting the operation on a fatal error etc.
+
+#### retryOperation.reset()
+
+Resets the internal state of the operation object, so that you can call `attempt()` again as if this was a new operation object.
+
+#### retryOperation.attempts()
+
+Returns an int representing the number of attempts it took to call `fn` before it was successful.
+
+## License
+
+retry is licensed under the MIT license.
+
+
+# Changelog
+
+0.10.0 Adding `stop` functionality, thanks to @maxnachlinger.
+
+0.9.0 Adding `unref` functionality, thanks to @satazor.
+
+0.8.0 Implementing retry.wrap.
+
+0.7.0 Some bug fixes and made retry.createTimeout() public. Fixed issues [#10](https://github.com/tim-kos/node-retry/issues/10), [#12](https://github.com/tim-kos/node-retry/issues/12), and [#13](https://github.com/tim-kos/node-retry/issues/13).
+
+0.6.0 Introduced optional timeOps parameter for the attempt() function which is an object having a property timeout in milliseconds and a property cb callback function. Whenever your retry operation takes longer than timeout to execute, the timeout callback function cb is called.
+
+0.5.0 Some minor refactoring.
+
+0.4.0 Changed retryOperation.try() to retryOperation.attempt(). Deprecated the aliases start() and try() for it.
+
+0.3.0 Added retryOperation.start() which is an alias for retryOperation.try().
+
+0.2.0 Added attempts() function and parameter to retryOperation.try() representing the number of attempts it took to call fn().
Index: node_modules/retry/example/dns.js
===================================================================
--- node_modules/retry/example/dns.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/example/dns.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,31 @@
+var dns = require('dns');
+var retry = require('../lib/retry');
+
+function faultTolerantResolve(address, cb) {
+  var opts = {
+    retries: 2,
+    factor: 2,
+    minTimeout: 1 * 1000,
+    maxTimeout: 2 * 1000,
+    randomize: true
+  };
+  var operation = retry.operation(opts);
+
+  operation.attempt(function(currentAttempt) {
+    dns.resolve(address, function(err, addresses) {
+      if (operation.retry(err)) {
+        return;
+      }
+
+      cb(operation.mainError(), operation.errors(), addresses);
+    });
+  });
+}
+
+faultTolerantResolve('nodejs.org', function(err, errors, addresses) {
+  console.warn('err:');
+  console.log(err);
+
+  console.warn('addresses:');
+  console.log(addresses);
+});
Index: node_modules/retry/example/stop.js
===================================================================
--- node_modules/retry/example/stop.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/example/stop.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,40 @@
+var retry = require('../lib/retry');
+
+function attemptAsyncOperation(someInput, cb) {
+  var opts = {
+    retries: 2,
+    factor: 2,
+    minTimeout: 1 * 1000,
+    maxTimeout: 2 * 1000,
+    randomize: true
+  };
+  var operation = retry.operation(opts);
+
+  operation.attempt(function(currentAttempt) {
+    failingAsyncOperation(someInput, function(err, result) {
+
+      if (err && err.message === 'A fatal error') {
+        operation.stop();
+        return cb(err);
+      }
+
+      if (operation.retry(err)) {
+        return;
+      }
+
+      cb(operation.mainError(), operation.errors(), result);
+    });
+  });
+}
+
+attemptAsyncOperation('test input', function(err, errors, result) {
+  console.warn('err:');
+  console.log(err);
+
+  console.warn('result:');
+  console.log(result);
+});
+
+function failingAsyncOperation(input, cb) {
+  return setImmediate(cb.bind(null, new Error('A fatal error')));
+}
Index: node_modules/retry/index.js
===================================================================
--- node_modules/retry/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,1 @@
+module.exports = require('./lib/retry');
Index: node_modules/retry/lib/retry.js
===================================================================
--- node_modules/retry/lib/retry.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/lib/retry.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,100 @@
+var RetryOperation = require('./retry_operation');
+
+exports.operation = function(options) {
+  var timeouts = exports.timeouts(options);
+  return new RetryOperation(timeouts, {
+      forever: options && options.forever,
+      unref: options && options.unref,
+      maxRetryTime: options && options.maxRetryTime
+  });
+};
+
+exports.timeouts = function(options) {
+  if (options instanceof Array) {
+    return [].concat(options);
+  }
+
+  var opts = {
+    retries: 10,
+    factor: 2,
+    minTimeout: 1 * 1000,
+    maxTimeout: Infinity,
+    randomize: false
+  };
+  for (var key in options) {
+    opts[key] = options[key];
+  }
+
+  if (opts.minTimeout > opts.maxTimeout) {
+    throw new Error('minTimeout is greater than maxTimeout');
+  }
+
+  var timeouts = [];
+  for (var i = 0; i < opts.retries; i++) {
+    timeouts.push(this.createTimeout(i, opts));
+  }
+
+  if (options && options.forever && !timeouts.length) {
+    timeouts.push(this.createTimeout(i, opts));
+  }
+
+  // sort the array numerically ascending
+  timeouts.sort(function(a,b) {
+    return a - b;
+  });
+
+  return timeouts;
+};
+
+exports.createTimeout = function(attempt, opts) {
+  var random = (opts.randomize)
+    ? (Math.random() + 1)
+    : 1;
+
+  var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
+  timeout = Math.min(timeout, opts.maxTimeout);
+
+  return timeout;
+};
+
+exports.wrap = function(obj, options, methods) {
+  if (options instanceof Array) {
+    methods = options;
+    options = null;
+  }
+
+  if (!methods) {
+    methods = [];
+    for (var key in obj) {
+      if (typeof obj[key] === 'function') {
+        methods.push(key);
+      }
+    }
+  }
+
+  for (var i = 0; i < methods.length; i++) {
+    var method   = methods[i];
+    var original = obj[method];
+
+    obj[method] = function retryWrapper(original) {
+      var op       = exports.operation(options);
+      var args     = Array.prototype.slice.call(arguments, 1);
+      var callback = args.pop();
+
+      args.push(function(err) {
+        if (op.retry(err)) {
+          return;
+        }
+        if (err) {
+          arguments[0] = op.mainError();
+        }
+        callback.apply(this, arguments);
+      });
+
+      op.attempt(function() {
+        original.apply(obj, args);
+      });
+    }.bind(obj, original);
+    obj[method].options = options;
+  }
+};
Index: node_modules/retry/lib/retry_operation.js
===================================================================
--- node_modules/retry/lib/retry_operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/lib/retry_operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,158 @@
+function RetryOperation(timeouts, options) {
+  // Compatibility for the old (timeouts, retryForever) signature
+  if (typeof options === 'boolean') {
+    options = { forever: options };
+  }
+
+  this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
+  this._timeouts = timeouts;
+  this._options = options || {};
+  this._maxRetryTime = options && options.maxRetryTime || Infinity;
+  this._fn = null;
+  this._errors = [];
+  this._attempts = 1;
+  this._operationTimeout = null;
+  this._operationTimeoutCb = null;
+  this._timeout = null;
+  this._operationStart = null;
+
+  if (this._options.forever) {
+    this._cachedTimeouts = this._timeouts.slice(0);
+  }
+}
+module.exports = RetryOperation;
+
+RetryOperation.prototype.reset = function() {
+  this._attempts = 1;
+  this._timeouts = this._originalTimeouts;
+}
+
+RetryOperation.prototype.stop = function() {
+  if (this._timeout) {
+    clearTimeout(this._timeout);
+  }
+
+  this._timeouts       = [];
+  this._cachedTimeouts = null;
+};
+
+RetryOperation.prototype.retry = function(err) {
+  if (this._timeout) {
+    clearTimeout(this._timeout);
+  }
+
+  if (!err) {
+    return false;
+  }
+  var currentTime = new Date().getTime();
+  if (err && currentTime - this._operationStart >= this._maxRetryTime) {
+    this._errors.unshift(new Error('RetryOperation timeout occurred'));
+    return false;
+  }
+
+  this._errors.push(err);
+
+  var timeout = this._timeouts.shift();
+  if (timeout === undefined) {
+    if (this._cachedTimeouts) {
+      // retry forever, only keep last error
+      this._errors.splice(this._errors.length - 1, this._errors.length);
+      this._timeouts = this._cachedTimeouts.slice(0);
+      timeout = this._timeouts.shift();
+    } else {
+      return false;
+    }
+  }
+
+  var self = this;
+  var timer = setTimeout(function() {
+    self._attempts++;
+
+    if (self._operationTimeoutCb) {
+      self._timeout = setTimeout(function() {
+        self._operationTimeoutCb(self._attempts);
+      }, self._operationTimeout);
+
+      if (self._options.unref) {
+          self._timeout.unref();
+      }
+    }
+
+    self._fn(self._attempts);
+  }, timeout);
+
+  if (this._options.unref) {
+      timer.unref();
+  }
+
+  return true;
+};
+
+RetryOperation.prototype.attempt = function(fn, timeoutOps) {
+  this._fn = fn;
+
+  if (timeoutOps) {
+    if (timeoutOps.timeout) {
+      this._operationTimeout = timeoutOps.timeout;
+    }
+    if (timeoutOps.cb) {
+      this._operationTimeoutCb = timeoutOps.cb;
+    }
+  }
+
+  var self = this;
+  if (this._operationTimeoutCb) {
+    this._timeout = setTimeout(function() {
+      self._operationTimeoutCb();
+    }, self._operationTimeout);
+  }
+
+  this._operationStart = new Date().getTime();
+
+  this._fn(this._attempts);
+};
+
+RetryOperation.prototype.try = function(fn) {
+  console.log('Using RetryOperation.try() is deprecated');
+  this.attempt(fn);
+};
+
+RetryOperation.prototype.start = function(fn) {
+  console.log('Using RetryOperation.start() is deprecated');
+  this.attempt(fn);
+};
+
+RetryOperation.prototype.start = RetryOperation.prototype.try;
+
+RetryOperation.prototype.errors = function() {
+  return this._errors;
+};
+
+RetryOperation.prototype.attempts = function() {
+  return this._attempts;
+};
+
+RetryOperation.prototype.mainError = function() {
+  if (this._errors.length === 0) {
+    return null;
+  }
+
+  var counts = {};
+  var mainError = null;
+  var mainErrorCount = 0;
+
+  for (var i = 0; i < this._errors.length; i++) {
+    var error = this._errors[i];
+    var message = error.message;
+    var count = (counts[message] || 0) + 1;
+
+    counts[message] = count;
+
+    if (count >= mainErrorCount) {
+      mainError = error;
+      mainErrorCount = count;
+    }
+  }
+
+  return mainError;
+};
Index: node_modules/retry/package.json
===================================================================
--- node_modules/retry/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,32 @@
+{
+  "author": "Tim Koschützki <tim@debuggable.com> (http://debuggable.com/)",
+  "name": "retry",
+  "description": "Abstraction for exponential and custom retry strategies for failed operations.",
+  "license": "MIT",
+  "version": "0.12.0",
+  "homepage": "https://github.com/tim-kos/node-retry",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/tim-kos/node-retry.git"
+  },
+  "directories": {
+    "lib": "./lib"
+  },
+  "main": "index",
+  "engines": {
+    "node": ">= 4"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "fake": "0.2.0",
+    "istanbul": "^0.4.5",
+    "tape": "^4.8.0"
+  },
+  "scripts": {
+    "test": "./node_modules/.bin/istanbul cover ./node_modules/tape/bin/tape ./test/integration/*.js",
+    "release:major": "env SEMANTIC=major npm run release",
+    "release:minor": "env SEMANTIC=minor npm run release",
+    "release:patch": "env SEMANTIC=patch npm run release",
+    "release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && git push && git push --tags && npm publish"
+  }
+}
Index: node_modules/retry/test/common.js
===================================================================
--- node_modules/retry/test/common.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/common.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,10 @@
+var common = module.exports;
+var path = require('path');
+
+var rootDir = path.join(__dirname, '..');
+common.dir = {
+  lib: rootDir + '/lib'
+};
+
+common.assert = require('assert');
+common.fake = require('fake');
Index: node_modules/retry/test/integration/test-forever.js
===================================================================
--- node_modules/retry/test/integration/test-forever.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-forever.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,24 @@
+var common = require('../common');
+var assert = common.assert;
+var retry = require(common.dir.lib + '/retry');
+
+(function testForeverUsesFirstTimeout() {
+  var operation = retry.operation({
+    retries: 0,
+    minTimeout: 100,
+    maxTimeout: 100,
+    forever: true
+  });
+
+  operation.attempt(function(numAttempt) {
+    console.log('>numAttempt', numAttempt);
+    var err = new Error("foo");
+    if (numAttempt == 10) {
+      operation.stop();
+    }
+
+    if (operation.retry(err)) {
+      return;
+    }
+  });
+})();
Index: node_modules/retry/test/integration/test-retry-operation.js
===================================================================
--- node_modules/retry/test/integration/test-retry-operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-retry-operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,258 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var retry = require(common.dir.lib + '/retry');
+
+(function testReset() {
+  var error = new Error('some error');
+  var operation = retry.operation([1, 2, 3]);
+  var attempts = 0;
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var expectedFinishes = 1;
+  var finishes         = 0;
+
+  var fn = function() {
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+      if (operation.retry(error)) {
+        return;
+      }
+
+      finishes++
+      assert.equal(expectedFinishes, finishes);
+      assert.strictEqual(attempts, 4);
+      assert.strictEqual(operation.attempts(), attempts);
+      assert.strictEqual(operation.mainError(), error);
+
+      if (finishes < 2) {
+        attempts = 0;
+        expectedFinishes++;
+        operation.reset();
+        fn()
+      } else {
+        finalCallback();
+      }
+    });
+  };
+
+  fn();
+})();
+
+(function testErrors() {
+  var operation = retry.operation();
+
+  var error = new Error('some error');
+  var error2 = new Error('some other error');
+  operation._errors.push(error);
+  operation._errors.push(error2);
+
+  assert.deepEqual(operation.errors(), [error, error2]);
+})();
+
+(function testMainErrorReturnsMostFrequentError() {
+  var operation = retry.operation();
+  var error = new Error('some error');
+  var error2 = new Error('some other error');
+
+  operation._errors.push(error);
+  operation._errors.push(error2);
+  operation._errors.push(error);
+
+  assert.strictEqual(operation.mainError(), error);
+})();
+
+(function testMainErrorReturnsLastErrorOnEqualCount() {
+  var operation = retry.operation();
+  var error = new Error('some error');
+  var error2 = new Error('some other error');
+
+  operation._errors.push(error);
+  operation._errors.push(error2);
+
+  assert.strictEqual(operation.mainError(), error2);
+})();
+
+(function testAttempt() {
+  var operation = retry.operation();
+  var fn = new Function();
+
+  var timeoutOpts = {
+    timeout: 1,
+    cb: function() {}
+  };
+  operation.attempt(fn, timeoutOpts);
+
+  assert.strictEqual(fn, operation._fn);
+  assert.strictEqual(timeoutOpts.timeout, operation._operationTimeout);
+  assert.strictEqual(timeoutOpts.cb, operation._operationTimeoutCb);
+})();
+
+(function testRetry() {
+  var error = new Error('some error');
+  var operation = retry.operation([1, 2, 3]);
+  var attempts = 0;
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var fn = function() {
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+      if (operation.retry(error)) {
+        return;
+      }
+
+      assert.strictEqual(attempts, 4);
+      assert.strictEqual(operation.attempts(), attempts);
+      assert.strictEqual(operation.mainError(), error);
+      finalCallback();
+    });
+  };
+
+  fn();
+})();
+
+(function testRetryForever() {
+  var error = new Error('some error');
+  var operation = retry.operation({ retries: 3, forever: true });
+  var attempts = 0;
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var fn = function() {
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+      if (attempts !== 6 && operation.retry(error)) {
+        return;
+      }
+
+      assert.strictEqual(attempts, 6);
+      assert.strictEqual(operation.attempts(), attempts);
+      assert.strictEqual(operation.mainError(), error);
+      finalCallback();
+    });
+  };
+
+  fn();
+})();
+
+(function testRetryForeverNoRetries() {
+  var error = new Error('some error');
+  var delay = 50
+  var operation = retry.operation({
+    retries: null,
+    forever: true,
+    minTimeout: delay,
+    maxTimeout: delay
+  });
+
+  var attempts = 0;
+  var startTime = new Date().getTime();
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var fn = function() {
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+      if (attempts !== 4 && operation.retry(error)) {
+        return;
+      }
+
+      var endTime = new Date().getTime();
+      var minTime = startTime + (delay * 3);
+      var maxTime = minTime + 20 // add a little headroom for code execution time
+      assert(endTime >= minTime)
+      assert(endTime < maxTime)
+      assert.strictEqual(attempts, 4);
+      assert.strictEqual(operation.attempts(), attempts);
+      assert.strictEqual(operation.mainError(), error);
+      finalCallback();
+    });
+  };
+
+  fn();
+})();
+
+(function testStop() {
+  var error = new Error('some error');
+  var operation = retry.operation([1, 2, 3]);
+  var attempts = 0;
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var fn = function() {
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+
+      if (attempts === 2) {
+        operation.stop();
+
+        assert.strictEqual(attempts, 2);
+        assert.strictEqual(operation.attempts(), attempts);
+        assert.strictEqual(operation.mainError(), error);
+        finalCallback();
+      }
+
+      if (operation.retry(error)) {
+        return;
+      }
+    });
+  };
+
+  fn();
+})();
+
+(function testMaxRetryTime() {
+  var error = new Error('some error');
+  var maxRetryTime = 30;
+  var operation = retry.operation({
+      minTimeout: 1,
+      maxRetryTime: maxRetryTime
+  });
+  var attempts = 0;
+
+  var finalCallback = fake.callback('finalCallback');
+  fake.expectAnytime(finalCallback);
+
+  var longAsyncFunction = function (wait, callback){
+    setTimeout(callback, wait);
+  };
+
+  var fn = function() {
+    var startTime = new Date().getTime();
+    operation.attempt(function(currentAttempt) {
+      attempts++;
+      assert.equal(currentAttempt, attempts);
+
+      if (attempts !== 2) {
+        if (operation.retry(error)) {
+            return;
+        }
+      } else {
+        var curTime = new Date().getTime();
+        longAsyncFunction(maxRetryTime - (curTime - startTime - 1), function(){
+          if (operation.retry(error)) {
+            assert.fail('timeout should be occurred');
+            return;
+          }
+
+          assert.strictEqual(operation.mainError(), error);
+          finalCallback();
+        });
+      }
+    });
+  };
+
+  fn();
+})();
Index: node_modules/retry/test/integration/test-retry-wrap.js
===================================================================
--- node_modules/retry/test/integration/test-retry-wrap.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-retry-wrap.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,101 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var retry = require(common.dir.lib + '/retry');
+
+function getLib() {
+  return {
+    fn1: function() {},
+    fn2: function() {},
+    fn3: function() {}
+  };
+}
+
+(function wrapAll() {
+  var lib = getLib();
+  retry.wrap(lib);
+  assert.equal(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+}());
+
+(function wrapAllPassOptions() {
+  var lib = getLib();
+  retry.wrap(lib, {retries: 2});
+  assert.equal(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+  assert.equal(lib.fn1.options.retries, 2);
+  assert.equal(lib.fn2.options.retries, 2);
+  assert.equal(lib.fn3.options.retries, 2);
+}());
+
+(function wrapDefined() {
+  var lib = getLib();
+  retry.wrap(lib, ['fn2', 'fn3']);
+  assert.notEqual(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+}());
+
+(function wrapDefinedAndPassOptions() {
+  var lib = getLib();
+  retry.wrap(lib, {retries: 2}, ['fn2', 'fn3']);
+  assert.notEqual(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.options.retries, 2);
+  assert.equal(lib.fn3.options.retries, 2);
+}());
+
+(function runWrappedWithoutError() {
+  var callbackCalled;
+  var lib = {method: function(a, b, callback) {
+    assert.equal(a, 1);
+    assert.equal(b, 2);
+    assert.equal(typeof callback, 'function');
+    callback();
+  }};
+  retry.wrap(lib);
+  lib.method(1, 2, function() {
+    callbackCalled = true;
+  });
+  assert.ok(callbackCalled);
+}());
+
+(function runWrappedSeveralWithoutError() {
+  var callbacksCalled = 0;
+  var lib = {
+    fn1: function (a, callback) {
+      assert.equal(a, 1);
+      assert.equal(typeof callback, 'function');
+      callback();
+    },
+    fn2: function (a, callback) {
+      assert.equal(a, 2);
+      assert.equal(typeof callback, 'function');
+      callback();
+    }
+  };
+  retry.wrap(lib, {}, ['fn1', 'fn2']);
+  lib.fn1(1, function() {
+    callbacksCalled++;
+  });
+  lib.fn2(2, function() {
+    callbacksCalled++;
+  });
+  assert.equal(callbacksCalled, 2);
+}());
+
+(function runWrappedWithError() {
+  var callbackCalled;
+  var lib = {method: function(callback) {
+    callback(new Error('Some error'));
+  }};
+  retry.wrap(lib, {retries: 1});
+  lib.method(function(err) {
+    callbackCalled = true;
+    assert.ok(err instanceof Error);
+  });
+  assert.ok(!callbackCalled);
+}());
Index: node_modules/retry/test/integration/test-timeouts.js
===================================================================
--- node_modules/retry/test/integration/test-timeouts.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-timeouts.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,69 @@
+var common = require('../common');
+var assert = common.assert;
+var retry = require(common.dir.lib + '/retry');
+
+(function testDefaultValues() {
+  var timeouts = retry.timeouts();
+
+  assert.equal(timeouts.length, 10);
+  assert.equal(timeouts[0], 1000);
+  assert.equal(timeouts[1], 2000);
+  assert.equal(timeouts[2], 4000);
+})();
+
+(function testDefaultValuesWithRandomize() {
+  var minTimeout = 5000;
+  var timeouts = retry.timeouts({
+    minTimeout: minTimeout,
+    randomize: true
+  });
+
+  assert.equal(timeouts.length, 10);
+  assert.ok(timeouts[0] > minTimeout);
+  assert.ok(timeouts[1] > timeouts[0]);
+  assert.ok(timeouts[2] > timeouts[1]);
+})();
+
+(function testPassedTimeoutsAreUsed() {
+  var timeoutsArray = [1000, 2000, 3000];
+  var timeouts = retry.timeouts(timeoutsArray);
+  assert.deepEqual(timeouts, timeoutsArray);
+  assert.notStrictEqual(timeouts, timeoutsArray);
+})();
+
+(function testTimeoutsAreWithinBoundaries() {
+  var minTimeout = 1000;
+  var maxTimeout = 10000;
+  var timeouts = retry.timeouts({
+    minTimeout: minTimeout,
+    maxTimeout: maxTimeout
+  });
+  for (var i = 0; i < timeouts; i++) {
+    assert.ok(timeouts[i] >= minTimeout);
+    assert.ok(timeouts[i] <= maxTimeout);
+  }
+})();
+
+(function testTimeoutsAreIncremental() {
+  var timeouts = retry.timeouts();
+  var lastTimeout = timeouts[0];
+  for (var i = 0; i < timeouts; i++) {
+    assert.ok(timeouts[i] > lastTimeout);
+    lastTimeout = timeouts[i];
+  }
+})();
+
+(function testTimeoutsAreIncrementalForFactorsLessThanOne() {
+  var timeouts = retry.timeouts({
+    retries: 3,
+    factor: 0.5
+  });
+
+  var expected = [250, 500, 1000];
+  assert.deepEqual(expected, timeouts);
+})();
+
+(function testRetries() {
+  var timeouts = retry.timeouts({retries: 2});
+  assert.strictEqual(timeouts.length, 2);
+})();
