text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  
  var _promise = require('babel-runtime/core-js/promise');
  
  var _promise2 = _interopRequireDefault(_promise);
  
  var _apply = require('babel-runtime/core-js/reflect/apply');
  
  var _apply2 = _interopRequireDefault(_apply);
  
  var _assign = require('babel-runtime/core-js/object/assign');
  
  var _assign2 = _interopRequireDefault(_assign);
  
  var _wrap2 = require('lodash/wrap');
  
  var _wrap3 = _interopRequireDefault(_wrap2);
  
  var _isFunction2 = require('lodash/isFunction');
  
  var _isFunction3 = _interopRequireDefault(_isFunction2);
  
  var _defaults2 = require('lodash/defaults');
  
  var _defaults3 = _interopRequireDefault(_defaults2);
  
  exports.default = retry;
  
  var _events = require('events');
  
  var _backoff = require('backoff');
  
  var _backoff2 = _interopRequireDefault(_backoff);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  /* eslint max-nested-callbacks: [0] */
  
  /**
   * Makes a promise-returning method retryable according to the specified backoff
   * pattern
   * @param {Object} options
   * @param {boolean} options.backoff
   * @param {number} options.delay
   * @param {number} options.initialDelay
   * @param {number} options.maxAttempts
   * @param {number} options.maxDelay
   *
   * @returns {Function}
   */
  /**!
   *
   * Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
   */
  
  function retry() {
    for (var _len = arguments.length, params = Array(_len), _key = 0; _key < _len; _key++) {
      params[_key] = arguments[_key];
    }
  
    var options = params[0] || {};
  
    options = (0, _assign2.default)({}, options);
    (0, _defaults3.default)(options, {
      backoff: true,
      delay: 1,
      maxAttempts: 3
    });
  
    var strategyOptions = void 0;
    if (options.backoff) {
      strategyOptions = {
        initialDelay: options.delay,
        maxDelay: options.maxDelay
      };
    } else {
      strategyOptions = {
        initialDelay: 1,
        maxDelay: 1
      };
    }
  
    if (params.length === 3) {
      return (0, _apply2.default)(retryDecorator, null, params);
    }
  
    return retryDecorator;
  
    /**
     * @param {Object} target
     * @param {string} prop
     * @param {Object} descriptor
     * @private
     * @returns {Object}
     */
    function retryDecorator(target, prop, descriptor) {
      descriptor.value = (0, _wrap3.default)(descriptor.value, function retryExecutor(fn) {
        var _this = this;
  
        for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
          args[_key2 - 1] = arguments[_key2];
        }
  
        var emitter = new _events.EventEmitter();
        var promise = new _promise2.default(function (resolve, reject) {
          // backoff.call is not Function.prototype.call; it's an unfortunate naming
          // collision.
          /* eslint prefer-reflect: [0] */
          var call = _backoff2.default.call(function (cb) {
            /* eslint no-invalid-this: [0] */
            var innerPromise = (0, _apply2.default)(fn, _this, args);
  
            if ((0, _isFunction3.default)(innerPromise.on)) {
              innerPromise.on('progress', emitter.emit.bind(emitter, 'progress'));
              innerPromise.on('upload-progress', emitter.emit.bind(emitter, 'upload-progress'));
              innerPromise.on('download-progress', emitter.emit.bind(emitter, 'download-progress'));
            }
  
            return innerPromise.then(function (res) {
              cb(null, res);
            }).catch(function (reason) {
              if (!reason) {
                reason = new Error('retryable method failed without providing an error object');
              }
              cb(reason);
            });
          }, function (err, res) {
            if (err) {
              return reject(err);
            }
  
            return resolve(res);
          });
  
          call.setStrategy(new _backoff2.default.ExponentialStrategy(strategyOptions));
          if (options.maxAttempts) {
            call.failAfter(options.maxAttempts - 1);
          }
  
          call.start();
        });
  
        promise.on = function on(key, callback) {
          emitter.on(key, callback);
          return promise;
        };
  
        return promise;
      });
  
      // This *should* make decorators compatible with AmpersandState class
      // definitions
      if (typeof target === 'object' && !target.prototype) {
        target[prop] = descriptor.value;
      }
  
      return descriptor;
    }
  }