text: var AWS = require('./core');
  var AcceptorStateMachine = require('./state_machine');
  var inherit = AWS.util.inherit;
  var domain = AWS.util.domain;
  var jmespath = require('jmespath');
  
  /**
   * @api private
   */
  var hardErrorStates = {success: 1, error: 1, complete: 1};
  
  function isTerminalState(machine) {
    return Object.prototype.hasOwnProperty.call(hardErrorStates, machine._asm.currentState);
  }
  
  var fsm = new AcceptorStateMachine();
  fsm.setupStates = function() {
    var transition = function(_, done) {
      var self = this;
      self._haltHandlersOnError = false;
  
      self.emit(self._asm.currentState, function(err) {
        if (err) {
          if (isTerminalState(self)) {
            if (domain && self.domain instanceof domain.Domain) {
              err.domainEmitter = self;
              err.domain = self.domain;
              err.domainThrown = false;
              self.domain.emit('error', err);
            } else {
              throw err;
            }
          } else {
            self.response.error = err;
            done(err);
          }
        } else {
          done(self.response.error);
        }
      });
  
    };
  
    this.addState('validate', 'build', 'error', transition);
    this.addState('build', 'afterBuild', 'restart', transition);
    this.addState('afterBuild', 'sign', 'restart', transition);
    this.addState('sign', 'send', 'retry', transition);
    this.addState('retry', 'afterRetry', 'afterRetry', transition);
    this.addState('afterRetry', 'sign', 'error', transition);
    this.addState('send', 'validateResponse', 'retry', transition);
    this.addState('validateResponse', 'extractData', 'extractError', transition);
    this.addState('extractError', 'extractData', 'retry', transition);
    this.addState('extractData', 'success', 'retry', transition);
    this.addState('restart', 'build', 'error', transition);
    this.addState('success', 'complete', 'complete', transition);
    this.addState('error', 'complete', 'complete', transition);
    this.addState('complete', null, null, transition);
  };
  fsm.setupStates();
  
  /**
   * ## Asynchronous Requests
   *
   * All requests made through the SDK are asynchronous and use a
   * callback interface. Each service method that kicks off a request
   * returns an `AWS.Request` object that you can use to register
   * callbacks.
   *
   * For example, the following service method returns the request
   * object as "request", which can be used to register callbacks:
   *
   * ```javascript
   * // request is an AWS.Request object
   * var request = ec2.describeInstances();
   *
   * // register callbacks on request to retrieve response data
   * request.on('success', function(response) {
   *   console.log(response.data);
   * });
   * ```
   *
   * When a request is ready to be sent, the {send} method should
   * be called:
   *
   * ```javascript
   * request.send();
   * ```
   *
   * Since registered callbacks may or may not be idempotent, requests should only
   * be sent once. To perform the same operation multiple times, you will need to
   * create multiple request objects, each with its own registered callbacks.
   *
   * ## Removing Default Listeners for Events
   *
   * Request objects are built with default listeners for the various events,
   * depending on the service type. In some cases, you may want to remove
   * some built-in listeners to customize behaviour. Doing this requires
   * access to the built-in listener functions, which are exposed through
   * the {AWS.EventListeners.Core} namespace. For instance, you may
   * want to customize the HTTP handler used when sending a request. In this
   * case, you can remove the built-in listener associated with the 'send'
   * event, the {AWS.EventListeners.Core.SEND} listener and add your own.
   *
   * ## Multiple Callbacks and Chaining
   *
   * You can register multiple callbacks on any request object. The
   * callbacks can be registered for different events, or all for the
   * same event. In addition, you can chain callback registration, for
   * example:
   *
   * ```javascript
   * request.
   *   on('success', function(response) {
   *     console.log("Success!");
   *   }).
   *   on('error', function(error, response) {
   *     console.log("Error!");
   *   }).
   *   on('complete', function(response) {
   *     console.log("Always!");
   *   }).
   *   send();
   * ```
   *
   * The above example will print either "Success! Always!", or "Error! Always!",
   * depending on whether the request succeeded or not.
   *
   * @!attribute httpRequest
   *   @readonly
   *   @!group HTTP Properties
   *   @return [AWS.HttpRequest] the raw HTTP request object
   *     containing request headers and body information
   *     sent by the service.
   *
   * @!attribute startTime
   *   @readonly
   *   @!group Operation Properties
   *   @return [Date] the time that the request started
   *
   * @!group Request Building Events
   *
   * @!event validate(request)
   *   Triggered when a request is being validated. Listeners
   *   should throw an error if the request should not be sent.
   *   @param request [Request] the request object being sent
   *   @see AWS.EventListeners.Core.VALIDATE_CREDENTIALS
   *   @see AWS.EventListeners.Core.VALIDATE_REGION
   *   @example Ensuring that a certain parameter is set before sending a request
   *     var req = s3.putObject(params);
   *     req.on('validate', function() {
   *       if (!req.params.Body.match(/^Hello\s/)) {
   *         throw new Error('Body must start with "Hello "');
   *       }
   *     });
   *     req.send(function(err, data) { ... });
   *
   * @!event build(request)
   *   Triggered when the request payload is being built. Listeners
   *   should fill the necessary information to send the request
   *   over HTTP.
   *   @param (see AWS.Request~validate)
   *   @example Add a custom HTTP header to a request
   *     var req = s3.putObject(params);
   *     req.on('build', function() {
   *       req.httpRequest.headers['Custom-Header'] = 'value';
   *     });
   *     req.send(function(err, data) { ... });
   *
   * @!event sign(request)
   *   Triggered when the request is being signed. Listeners should
   *   add the correct authentication headers and/or adjust the body,
   *   depending on the authentication mechanism being used.
   *   @param (see AWS.Request~validate)
   *
   * @!group Request Sending Events
   *
   * @!event send(response)
   *   Triggered when the request is ready to be sent. Listeners
   *   should call the underlying transport layer to initiate
   *   the sending of the request.
   *   @param response [Response] the response object
   *   @context [Request] the request object that was sent
   *   @see AWS.EventListeners.Core.SEND
   *
   * @!event retry(response)
   *   Triggered when a request failed and might need to be retried or redirected.
   *   If the response is retryable, the listener should set the
   *   `response.error.retryable` property to `true`, and optionally set
   *   `response.error.retryDelay` to the millisecond delay for the next attempt.
   *   In the case of a redirect, `response.error.redirect` should be set to
   *   `true` with `retryDelay` set to an optional delay on the next request.
   *
   *   If a listener decides that a request should not be retried,
   *   it should set both `retryable` and `redirect` to false.
   *
   *   Note that a retryable error will be retried at most
   *   {AWS.Config.maxRetries} times (based on the service object's config).
   *   Similarly, a request that is redirected will only redirect at most
   *   {AWS.Config.maxRedirects} times.
   *
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *   @example Adding a custom retry for a 404 response
   *     request.on('retry', function(response) {
   *       // this resource is not yet available, wait 10 seconds to get it again
   *       if (response.httpResponse.statusCode === 404 && response.error) {
   *         response.error.retryable = true;   // retry this error
   *         response.error.retryDelay = 10000; // wait 10 seconds
   *       }
   *     });
   *
   * @!group Data Parsing Events
   *
   * @!event extractError(response)
   *   Triggered on all non-2xx requests so that listeners can extract
   *   error details from the response body. Listeners to this event
   *   should set the `response.error` property.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!event extractData(response)
   *   Triggered in successful requests to allow listeners to
   *   de-serialize the response body into `response.data`.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!group Completion Events
   *
   * @!event success(response)
   *   Triggered when the request completed successfully.
   *   `response.data` will contain the response data and
   *   `response.error` will be null.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!event error(error, response)
   *   Triggered when an error occurs at any point during the
   *   request. `response.error` will contain details about the error
   *   that occurred. `response.data` will be null.
   *   @param error [Error] the error object containing details about
   *     the error that occurred.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!event complete(response)
   *   Triggered whenever a request cycle completes. `response.error`
   *   should be checked, since the request may have failed.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!group HTTP Events
   *
   * @!event httpHeaders(statusCode, headers, response, statusMessage)
   *   Triggered when headers are sent by the remote server
   *   @param statusCode [Integer] the HTTP response code
   *   @param headers [map<String,String>] the response headers
   *   @param (see AWS.Request~send)
   *   @param statusMessage [String] A status message corresponding to the HTTP
   *                                 response code
   *   @context (see AWS.Request~send)
   *
   * @!event httpData(chunk, response)
   *   Triggered when data is sent by the remote server
   *   @param chunk [Buffer] the buffer data containing the next data chunk
   *     from the server
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *   @see AWS.EventListeners.Core.HTTP_DATA
   *
   * @!event httpUploadProgress(progress, response)
   *   Triggered when the HTTP request has uploaded more data
   *   @param progress [map] An object containing the `loaded` and `total` bytes
   *     of the request.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *   @note This event will not be emitted in Node.js 0.8.x.
   *
   * @!event httpDownloadProgress(progress, response)
   *   Triggered when the HTTP request has downloaded more data
   *   @param progress [map] An object containing the `loaded` and `total` bytes
   *     of the request.
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *   @note This event will not be emitted in Node.js 0.8.x.
   *
   * @!event httpError(error, response)
   *   Triggered when the HTTP request failed
   *   @param error [Error] the error object that was thrown
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @!event httpDone(response)
   *   Triggered when the server is finished sending data
   *   @param (see AWS.Request~send)
   *   @context (see AWS.Request~send)
   *
   * @see AWS.Response
   */
  AWS.Request = inherit({
  
    /**
     * Creates a request for an operation on a given service with
     * a set of input parameters.
     *
     * @param service [AWS.Service] the service to perform the operation on
     * @param operation [String] the operation to perform on the service
     * @param params [Object] parameters to send to the operation.
     *   See the operation's documentation for the format of the
     *   parameters.
     */
    constructor: function Request(service, operation, params) {
      var endpoint = service.endpoint;
      var region = service.config.region;
      var customUserAgent = service.config.customUserAgent;
  
      if (service.isGlobalEndpoint) {
        if (service.signingRegion) {
          region = service.signingRegion;
        } else {
          region = 'us-east-1';
        }
      }
  
      this.domain = domain && domain.active;
      this.service = service;
      this.operation = operation;
      this.params = params || {};
      this.httpRequest = new AWS.HttpRequest(endpoint, region);
      this.httpRequest.appendToUserAgent(customUserAgent);
      this.startTime = service.getSkewCorrectedDate();
  
      this.response = new AWS.Response(this);
      this._asm = new AcceptorStateMachine(fsm.states, 'validate');
      this._haltHandlersOnError = false;
  
      AWS.SequentialExecutor.call(this);
      this.emit = this.emitEvent;
    },
  
    /**
     * @!group Sending a Request
     */
  
    /**
     * @overload send(callback = null)
     *   Sends the request object.
     *
     *   @callback callback function(err, data)
     *     If a callback is supplied, it is called when a response is returned
     *     from the service.
     *     @context [AWS.Request] the request object being sent.
     *     @param err [Error] the error object returned from the request.
     *       Set to `null` if the request is successful.
     *     @param data [Object] the de-serialized data returned from
     *       the request. Set to `null` if a request error occurs.
     *   @example Sending a request with a callback
     *     request = s3.putObject({Bucket: 'bucket', Key: 'key'});
     *     request.send(function(err, data) { console.log(err, data); });
     *   @example Sending a request with no callback (using event handlers)
     *     request = s3.putObject({Bucket: 'bucket', Key: 'key'});
     *     request.on('complete', function(response) { ... }); // register a callback
     *     request.send();
     */
    send: function send(callback) {
      if (callback) {
        // append to user agent
        this.httpRequest.appendToUserAgent('callback');
        this.on('complete', function (resp) {
          callback.call(resp, resp.error, resp.data);
        });
      }
      this.runTo();
  
      return this.response;
    },
  
    /**
     * @!method  promise()
     *   Sends the request and returns a 'thenable' promise.
     *
     *   Two callbacks can be provided to the `then` method on the returned promise.
     *   The first callback will be called if the promise is fulfilled, and the second
     *   callback will be called if the promise is rejected.
     *   @callback fulfilledCallback function(data)
     *     Called if the promise is fulfilled.
     *     @param data [Object] the de-serialized data returned from the request.
     *   @callback rejectedCallback function(error)
     *     Called if the promise is rejected.
     *     @param error [Error] the error object returned from the request.
     *   @return [Promise] A promise that represents the state of the request.
     *   @example Sending a request using promises.
     *     var request = s3.putObject({Bucket: 'bucket', Key: 'key'});
     *     var result = request.promise();
     *     result.then(function(data) { ... }, function(error) { ... });
     */
  
    /**
     * @api private
     */
    build: function build(callback) {
      return this.runTo('send', callback);
    },
  
    /**
     * @api private
     */
    runTo: function runTo(state, done) {
      this._asm.runTo(state, done, this);
      return this;
    },
  
    /**
     * Aborts a request, emitting the error and complete events.
     *
     * @!macro nobrowser
     * @example Aborting a request after sending
     *   var params = {
     *     Bucket: 'bucket', Key: 'key',
     *     Body: Buffer.alloc(1024 * 1024 * 5) // 5MB payload
     *   };
     *   var request = s3.putObject(params);
     *   request.send(function (err, data) {
     *     if (err) console.log("Error:", err.code, err.message);
     *     else console.log(data);
     *   });
     *
     *   // abort request in 1 second
     *   setTimeout(request.abort.bind(request), 1000);
     *
     *   // prints "Error: RequestAbortedError Request aborted by user"
     * @return [AWS.Request] the same request object, for chaining.
     * @since v1.4.0
     */
    abort: function abort() {
      this.removeAllListeners('validateResponse');
      this.removeAllListeners('extractError');
      this.on('validateResponse', function addAbortedError(resp) {
        resp.error = AWS.util.error(new Error('Request aborted by user'), {
           code: 'RequestAbortedError', retryable: false
        });
      });
  
      if (this.httpRequest.stream && !this.httpRequest.stream.didCallback) { // abort HTTP stream
        this.httpRequest.stream.abort();
        if (this.httpRequest._abortCallback) {
           this.httpRequest._abortCallback();
        } else {
          this.removeAllListeners('send'); // haven't sent yet, so let's not
        }
      }
  
      return this;
    },
  
    /**
     * Iterates over each page of results given a pageable request, calling
     * the provided callback with each page of data. After all pages have been
     * retrieved, the callback is called with `null` data.
     *
     * @note This operation can generate multiple requests to a service.
     * @example Iterating over multiple pages of objects in an S3 bucket
     *   var pages = 1;
     *   s3.listObjects().eachPage(function(err, data) {
     *     if (err) return;
     *     console.log("Page", pages++);
     *     console.log(data);
     *   });
     * @example Iterating over multiple pages with an asynchronous callback
     *   s3.listObjects(params).eachPage(function(err, data, done) {
     *     doSomethingAsyncAndOrExpensive(function() {
     *       // The next page of results isn't fetched until done is called
     *       done();
     *     });
     *   });
     * @callback callback function(err, data, [doneCallback])
     *   Called with each page of resulting data from the request. If the
     *   optional `doneCallback` is provided in the function, it must be called
     *   when the callback is complete.
     *
     *   @param err [Error] an error object, if an error occurred.
     *   @param data [Object] a single page of response data. If there is no
     *     more data, this object will be `null`.
     *   @param doneCallback [Function] an optional done callback. If this
     *     argument is defined in the function declaration, it should be called
     *     when the next page is ready to be retrieved. This is useful for
     *     controlling serial pagination across asynchronous operations.
     *   @return [Boolean] if the callback returns `false`, pagination will
     *     stop.
     *
     * @see AWS.Request.eachItem
     * @see AWS.Response.nextPage
     * @since v1.4.0
     */
    eachPage: function eachPage(callback) {
      // Make all callbacks async-ish
      callback = AWS.util.fn.makeAsync(callback, 3);
  
      function wrappedCallback(response) {
        callback.call(response, response.error, response.data, function (result) {
          if (result === false) return;
  
          if (response.hasNextPage()) {
            response.nextPage().on('complete', wrappedCallback).send();
          } else {
            callback.call(response, null, null, AWS.util.fn.noop);
          }
        });
      }
  
      this.on('complete', wrappedCallback).send();
    },
  
    /**
     * Enumerates over individual items of a request, paging the responses if
     * necessary.
     *
     * @api experimental
     * @since v1.4.0
     */
    eachItem: function eachItem(callback) {
      var self = this;
      function wrappedCallback(err, data) {
        if (err) return callback(err, null);
        if (data === null) return callback(null, null);
  
        var config = self.service.paginationConfig(self.operation);
        var resultKey = config.resultKey;
        if (Array.isArray(resultKey)) resultKey = resultKey[0];
        var items = jmespath.search(data, resultKey);
        var continueIteration = true;
        AWS.util.arrayEach(items, function(item) {
          continueIteration = callback(null, item);
          if (continueIteration === false) {
            return AWS.util.abort;
          }
        });
        return continueIteration;
      }
  
      this.eachPage(wrappedCallback);
    },
  
    /**
     * @return [Boolean] whether the operation can return multiple pages of
     *   response data.
     * @see AWS.Response.eachPage
     * @since v1.4.0
     */
    isPageable: function isPageable() {
      return this.service.paginationConfig(this.operation) ? true : false;
    },
  
    /**
     * Sends the request and converts the request object into a readable stream
     * that can be read from or piped into a writable stream.
     *
     * @note The data read from a readable stream contains only
     *   the raw HTTP body contents.
     * @example Manually reading from a stream
     *   request.createReadStream().on('data', function(data) {
     *     console.log("Got data:", data.toString());
     *   });
     * @example Piping a request body into a file
     *   var out = fs.createWriteStream('/path/to/outfile.jpg');
     *   s3.service.getObject(params).createReadStream().pipe(out);
     * @return [Stream] the readable stream object that can be piped
     *   or read from (by registering 'data' event listeners).
     * @!macro nobrowser
     */
    createReadStream: function createReadStream() {
      var streams = AWS.util.stream;
      var req = this;
      var stream = null;
  
      if (AWS.HttpClient.streamsApiVersion === 2) {
        stream = new streams.PassThrough();
        process.nextTick(function() { req.send(); });
      } else {
        stream = new streams.Stream();
        stream.readable = true;
  
        stream.sent = false;
        stream.on('newListener', function(event) {
          if (!stream.sent && event === 'data') {
            stream.sent = true;
            process.nextTick(function() { req.send(); });
          }
        });
      }
  
      this.on('error', function(err) {
        stream.emit('error', err);
      });
  
      this.on('httpHeaders', function streamHeaders(statusCode, headers, resp) {
        if (statusCode < 300) {
          req.removeListener('httpData', AWS.EventListeners.Core.HTTP_DATA);
          req.removeListener('httpError', AWS.EventListeners.Core.HTTP_ERROR);
          req.on('httpError', function streamHttpError(error) {
            resp.error = error;
            resp.error.retryable = false;
          });
  
          var shouldCheckContentLength = false;
          var expectedLen;
          if (req.httpRequest.method !== 'HEAD') {
            expectedLen = parseInt(headers['content-length'], 10);
          }
          if (expectedLen !== undefined && !isNaN(expectedLen) && expectedLen >= 0) {
            shouldCheckContentLength = true;
            var receivedLen = 0;
          }
  
          var checkContentLengthAndEmit = function checkContentLengthAndEmit() {
            if (shouldCheckContentLength && receivedLen !== expectedLen) {
              stream.emit('error', AWS.util.error(
                new Error('Stream content length mismatch. Received ' +
                  receivedLen + ' of ' + expectedLen + ' bytes.'),
                { code: 'StreamContentLengthMismatch' }
              ));
            } else if (AWS.HttpClient.streamsApiVersion === 2) {
              stream.end();
            } else {
              stream.emit('end');
            }
          };
  
          var httpStream = resp.httpResponse.createUnbufferedStream();
  
          if (AWS.HttpClient.streamsApiVersion === 2) {
            if (shouldCheckContentLength) {
              var lengthAccumulator = new streams.PassThrough();
              lengthAccumulator._write = function(chunk) {
                if (chunk && chunk.length) {
                  receivedLen += chunk.length;
                }
                return streams.PassThrough.prototype._write.apply(this, arguments);
              };
  
              lengthAccumulator.on('end', checkContentLengthAndEmit);
              stream.on('error', function(err) {
                shouldCheckContentLength = false;
                httpStream.unpipe(lengthAccumulator);
                lengthAccumulator.emit('end');
                lengthAccumulator.end();
              });
              httpStream.pipe(lengthAccumulator).pipe(stream, { end: false });
            } else {
              httpStream.pipe(stream);
            }
          } else {
  
            if (shouldCheckContentLength) {
              httpStream.on('data', function(arg) {
                if (arg && arg.length) {
                  receivedLen += arg.length;
                }
              });
            }
  
            httpStream.on('data', function(arg) {
              stream.emit('data', arg);
            });
            httpStream.on('end', checkContentLengthAndEmit);
          }
  
          httpStream.on('error', function(err) {
            shouldCheckContentLength = false;
            stream.emit('error', err);
          });
        }
      });
  
      return stream;
    },
  
    /**
     * @param [Array,Response] args This should be the response object,
     *   or an array of args to send to the event.
     * @api private
     */
    emitEvent: function emit(eventName, args, done) {
      if (typeof args === 'function') { done = args; args = null; }
      if (!done) done = function() { };
      if (!args) args = this.eventParameters(eventName, this.response);
  
      var origEmit = AWS.SequentialExecutor.prototype.emit;
      origEmit.call(this, eventName, args, function (err) {
        if (err) this.response.error = err;
        done.call(this, err);
      });
    },
  
    /**
     * @api private
     */
    eventParameters: function eventParameters(eventName) {
      switch (eventName) {
        case 'restart':
        case 'validate':
        case 'sign':
        case 'build':
        case 'afterValidate':
        case 'afterBuild':
          return [this];
        case 'error':
          return [this.response.error, this.response];
        default:
          return [this.response];
      }
    },
  
    /**
     * @api private
     */
    presign: function presign(expires, callback) {
      if (!callback && typeof expires === 'function') {
        callback = expires;
        expires = null;
      }
      return new AWS.Signers.Presign().sign(this.toGet(), expires, callback);
    },
  
    /**
     * @api private
     */
    isPresigned: function isPresigned() {
      return Object.prototype.hasOwnProperty.call(this.httpRequest.headers, 'presigned-expires');
    },
  
    /**
     * @api private
     */
    toUnauthenticated: function toUnauthenticated() {
      this._unAuthenticated = true;
      this.removeListener('validate', AWS.EventListeners.Core.VALIDATE_CREDENTIALS);
      this.removeListener('sign', AWS.EventListeners.Core.SIGN);
      return this;
    },
  
    /**
     * @api private
     */
    toGet: function toGet() {
      if (this.service.api.protocol === 'query' ||
          this.service.api.protocol === 'ec2') {
        this.removeListener('build', this.buildAsGet);
        this.addListener('build', this.buildAsGet);
      }
      return this;
    },
  
    /**
     * @api private
     */
    buildAsGet: function buildAsGet(request) {
      request.httpRequest.method = 'GET';
      request.httpRequest.path = request.service.endpoint.path +
                                 '?' + request.httpRequest.body;
      request.httpRequest.body = '';
  
      // don't need these headers on a GET request
      delete request.httpRequest.headers['Content-Length'];
      delete request.httpRequest.headers['Content-Type'];
    },
  
    /**
     * @api private
     */
    haltHandlersOnError: function haltHandlersOnError() {
      this._haltHandlersOnError = true;
    }
  });
  
  /**
   * @api private
   */
  AWS.Request.addPromisesToClass = function addPromisesToClass(PromiseDependency) {
    this.prototype.promise = function promise() {
      var self = this;
      // append to user agent
      this.httpRequest.appendToUserAgent('promise');
      return new PromiseDependency(function(resolve, reject) {
        self.on('complete', function(resp) {
          if (resp.error) {
            reject(resp.error);
          } else {
            // define $response property so that it is not enumerable
            // this prevents circular reference errors when stringifying the JSON object
            resolve(Object.defineProperty(
              resp.data || {},
              '$response',
              {value: resp}
            ));
          }
        });
        self.runTo();
      });
    };
  };
  
  /**
   * @api private
   */
  AWS.Request.deletePromisesFromClass = function deletePromisesFromClass() {
    delete this.prototype.promise;
  };
  
  AWS.util.addPromises(AWS.Request);
  
  AWS.util.mixin(AWS.Request, AWS.SequentialExecutor);
  