docs: function handleEventually(fn, { maxRetries=30, ms=1000 } = {}, context = null) { // jshint ignore:line
    /**
     * Retry loop
     *
     * @param fn
     * @param retries
     * @returns {*}
     */
    function loop(fn, retries) {
      /**
       * Retries fn through the loop after the delay (ms).
       * If all retries have been exhausted the err is returned
       * as the reason for rejection of the promise.
       *
       * @param err
       *
       * @returns {Promise}
       */
      function retry (err) {
        if (retries < maxRetries) {
          return Bluebird
            .delay(ms)
            .then(function() {
              return loop(fn, retries + 1);
            });
        }
  
        return Bluebird.reject(err);
      }
  
      // Resolve non-promise and promise returns of fn()
      // Retry on any caught errors.
      return Bluebird.resolve(fn()).catch(retry);
    }
  
    /**
     * The returned "then" handler for wherever you called handleEventually.
     * The handler binds it's arguments to the underlying fn, and kicks
     * off the retry loop.
     *
     * Binding arguments ensures all calls to fn() from within the loop will
     * be applied with the arguments to the handler.
     *
     * goGetData()
     *  .then(handleEventually(doSomethingWithData))
     *
     * The wrapped function expects a signature of (data).
     * fn.bind.apply and the argument trickery below ensures all calls to it will
     * have that argument.
     */
    return function handler(...args) {
      return loop(fn.bind.apply(fn, [context, ...args]), 0);
    };
  }