text: 'use strict';
  
  var APPLICATION_JSON = 'application/json';
  var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
  var JSON_START = /^\[|^\{(?!\{)/;
  var JSON_ENDS = {
    '[': /]$/,
    '{': /}$/
  };
  var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/;
  var $httpMinErr = minErr('$http');
  
  function serializeValue(v) {
    if (isObject(v)) {
      return isDate(v) ? v.toISOString() : toJson(v);
    }
    return v;
  }
  
  
  /** @this */
  function $HttpParamSerializerProvider() {
    /**
     * @ngdoc service
     * @name $httpParamSerializer
     * @description
     *
     * Default {@link $http `$http`} params serializer that converts objects to strings
     * according to the following rules:
     *
     * * `{'foo': 'bar'}` results in `foo=bar`
     * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
     * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
     * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
     *
     * Note that serializer will sort the request parameters alphabetically.
     */
  
    this.$get = function() {
      return function ngParamSerializer(params) {
        if (!params) return '';
        var parts = [];
        forEachSorted(params, function(value, key) {
          if (value === null || isUndefined(value) || isFunction(value)) return;
          if (isArray(value)) {
            forEach(value, function(v) {
              parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
            });
          } else {
            parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
          }
        });
  
        return parts.join('&');
      };
    };
  }
  
  /** @this */
  function $HttpParamSerializerJQLikeProvider() {
    /**
     * @ngdoc service
     * @name $httpParamSerializerJQLike
     *
     * @description
     *
     * Alternative {@link $http `$http`} params serializer that follows
     * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
     * The serializer will also sort the params alphabetically.
     *
     * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
     *
     * ```js
     * $http({
     *   url: myUrl,
     *   method: 'GET',
     *   params: myParams,
     *   paramSerializer: '$httpParamSerializerJQLike'
     * });
     * ```
     *
     * It is also possible to set it as the default `paramSerializer` in the
     * {@link $httpProvider#defaults `$httpProvider`}.
     *
     * Additionally, you can inject the serializer and use it explicitly, for example to serialize
     * form data for submission:
     *
     * ```js
     * .controller(function($http, $httpParamSerializerJQLike) {
     *   //...
     *
     *   $http({
     *     url: myUrl,
     *     method: 'POST',
     *     data: $httpParamSerializerJQLike(myData),
     *     headers: {
     *       'Content-Type': 'application/x-www-form-urlencoded'
     *     }
     *   });
     *
     * });
     * ```
     *
     */
    this.$get = function() {
      return function jQueryLikeParamSerializer(params) {
        if (!params) return '';
        var parts = [];
        serialize(params, '', true);
        return parts.join('&');
  
        function serialize(toSerialize, prefix, topLevel) {
          if (isArray(toSerialize)) {
            forEach(toSerialize, function(value, index) {
              serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
            });
          } else if (isObject(toSerialize) && !isDate(toSerialize)) {
            forEachSorted(toSerialize, function(value, key) {
              serialize(value, prefix +
                  (topLevel ? '' : '[') +
                  key +
                  (topLevel ? '' : ']'));
            });
          } else {
            if (isFunction(toSerialize)) {
              toSerialize = toSerialize();
            }
            parts.push(encodeUriQuery(prefix) + '=' +
                (toSerialize == null ? '' : encodeUriQuery(serializeValue(toSerialize))));
          }
        }
      };
    };
  }
  
  function defaultHttpResponseTransform(data, headers) {
    if (isString(data)) {
      // Strip json vulnerability protection prefix and trim whitespace
      var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
  
      if (tempData) {
        var contentType = headers('Content-Type');
        var hasJsonContentType = contentType && (contentType.indexOf(APPLICATION_JSON) === 0);
  
        if (hasJsonContentType || isJsonLike(tempData)) {
          try {
            data = fromJson(tempData);
          } catch (e) {
            if (!hasJsonContentType) {
              return data;
            }
            throw $httpMinErr('baddata', 'Data must be a valid JSON object. Received: "{0}". ' +
            'Parse error: "{1}"', data, e);
          }
        }
      }
    }
  
    return data;
  }
  
  function isJsonLike(str) {
      var jsonStart = str.match(JSON_START);
      return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
  }
  
  /**
   * Parse headers into key value object
   *
   * @param {string} headers Raw headers as a string
   * @returns {Object} Parsed headers as key value object
   */
  function parseHeaders(headers) {
    var parsed = createMap(), i;
  
    function fillInParsed(key, val) {
      if (key) {
        parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
      }
    }
  
    if (isString(headers)) {
      forEach(headers.split('\n'), function(line) {
        i = line.indexOf(':');
        fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
      });
    } else if (isObject(headers)) {
      forEach(headers, function(headerVal, headerKey) {
        fillInParsed(lowercase(headerKey), trim(headerVal));
      });
    }
  
    return parsed;
  }
  
  
  /**
   * Returns a function that provides access to parsed headers.
   *
   * Headers are lazy parsed when first requested.
   * @see parseHeaders
   *
   * @param {(string|Object)} headers Headers to provide access to.
   * @returns {function(string=)} Returns a getter function which if called with:
   *
   *   - if called with an argument returns a single header value or null
   *   - if called with no arguments returns an object containing all headers.
   */
  function headersGetter(headers) {
    var headersObj;
  
    return function(name) {
      if (!headersObj) headersObj =  parseHeaders(headers);
  
      if (name) {
        var value = headersObj[lowercase(name)];
        if (value === undefined) {
          value = null;
        }
        return value;
      }
  
      return headersObj;
    };
  }
  
  
  /**
   * Chain all given functions
   *
   * This function is used for both request and response transforming
   *
   * @param {*} data Data to transform.
   * @param {function(string=)} headers HTTP headers getter fn.
   * @param {number} status HTTP status code of the response.
   * @param {(Function|Array.<Function>)} fns Function or an array of functions.
   * @returns {*} Transformed data.
   */
  function transformData(data, headers, status, fns) {
    if (isFunction(fns)) {
      return fns(data, headers, status);
    }
  
    forEach(fns, function(fn) {
      data = fn(data, headers, status);
    });
  
    return data;
  }
  
  
  function isSuccess(status) {
    return 200 <= status && status < 300;
  }
  
  
  /**
   * @ngdoc provider
   * @name $httpProvider
   * @this
   *
   * @description
   * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
   */
  function $HttpProvider() {
    /**
     * @ngdoc property
     * @name $httpProvider#defaults
     * @description
     *
     * Object containing default values for all {@link ng.$http $http} requests.
     *
     * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
     * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
     * setting default headers.
     *     - **`defaults.headers.common`**
     *     - **`defaults.headers.post`**
     *     - **`defaults.headers.put`**
     *     - **`defaults.headers.patch`**
     *
     * - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
     * callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
     * {@link $jsonpCallbacks} service. Defaults to `'callback'`.
     *
     * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
     *  used to the prepare string representation of request parameters (specified as an object).
     *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
     *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
     *
     * - **`defaults.transformRequest`** -
     * `{Array<function(data, headersGetter)>|function(data, headersGetter)}` -
     * An array of functions (or a single function) which are applied to the request data.
     * By default, this is an array with one request transformation function:
     *
     *   - If the `data` property of the request configuration object contains an object, serialize it
     *     into JSON format.
     *
     * - **`defaults.transformResponse`** -
     * `{Array<function(data, headersGetter, status)>|function(data, headersGetter, status)}` -
     * An array of functions (or a single function) which are applied to the response data. By default,
     * this is an array which applies one response transformation function that does two things:
     *
     *  - If XSRF prefix is detected, strip it
     *    (see {@link ng.$http#security-considerations Security Considerations in the $http docs}).
     *  - If the `Content-Type` is `application/json` or the response looks like JSON,
     *    deserialize it using a JSON parser.
     *
     */
    var defaults = this.defaults = {
      // transform incoming response data
      transformResponse: [defaultHttpResponseTransform],
  
      // transform outgoing request data
      transformRequest: [function(d) {
        return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
      }],
  
      // default headers
      headers: {
        common: {
          'Accept': 'application/json, text/plain, */*'
        },
        post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
        put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
        patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
      },
  
      paramSerializer: '$httpParamSerializer',
  
      jsonpCallbackParam: 'callback'
    };
  
    var useApplyAsync = false;
    /**
     * @ngdoc method
     * @name $httpProvider#useApplyAsync
     * @description
     *
     * Configure $http service to combine processing of multiple http responses received at around
     * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
     * significant performance improvement for bigger applications that make many HTTP requests
     * concurrently (common during application bootstrap).
     *
     * Defaults to false. If no value is specified, returns the current configured value.
     *
     * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
     *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
     *    to load and share the same digest cycle.
     *
     * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
     *    otherwise, returns the current configured value.
     */
    this.useApplyAsync = function(value) {
      if (isDefined(value)) {
        useApplyAsync = !!value;
        return this;
      }
      return useApplyAsync;
    };
  
    /**
     * @ngdoc property
     * @name $httpProvider#interceptors
     * @description
     *
     * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
     * pre-processing of request or postprocessing of responses.
     *
     * These service factories are ordered by request, i.e. they are applied in the same order as the
     * array, on request, but reverse order, on response.
     *
     * {@link ng.$http#interceptors Interceptors detailed info}
     */
    var interceptorFactories = this.interceptors = [];
  
    this.$get = ['$browser', '$httpBackend', '$rootScope', '$q', '$injector', '$sce',
        function($browser, $httpBackend, $rootScope, $q, $injector, $sce) {
  
      /**
       * Make sure that default param serializer is exposed as a function
       */
      defaults.paramSerializer = isString(defaults.paramSerializer) ?
        $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
  
      /**
       * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
       * The reversal is needed so that we can build up the interception chain around the
       * server request.
       */
      var reversedInterceptors = [];
  
      forEach(interceptorFactories, function(interceptorFactory) {
        reversedInterceptors.unshift(isString(interceptorFactory)
            ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
      });
  
      /**
       * @ngdoc service
       * @kind function
       * @name $http
       * @requires ng.$httpBackend
       * @requires $rootScope
       * @requires $q
       * @requires $injector
       *
       * @description
       * The `$http` service is a core AngularJS service that facilitates communication with the remote
       * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
       * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
       *
       * For unit testing applications that use `$http` service, see
       * {@link ngMock.$httpBackend $httpBackend mock}.
       *
       * For a higher level of abstraction, please check out the {@link ngResource.$resource
       * $resource} service.
       *
       * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
       * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
       * it is important to familiarize yourself with these APIs and the guarantees they provide.
       *
       *
       * ## General usage
       * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
       * that is used to generate an HTTP request and returns  a {@link ng.$q promise} that is
       * resolved (request success) or rejected (request failure) with a
       * {@link ng.$http#$http-returns response} object.
       *
       * ```js
       *   // Simple GET request example:
       *   $http({
       *     method: 'GET',
       *     url: '/someUrl'
       *   }).then(function successCallback(response) {
       *       // this callback will be called asynchronously
       *       // when the response is available
       *     }, function errorCallback(response) {
       *       // called asynchronously if an error occurs
       *       // or server returns response with an error status.
       *     });
       * ```
       *
       *
       * ## Shortcut methods
       *
       * Shortcut methods are also available. All shortcut methods require passing in the URL, and
       * request data must be passed in for POST/PUT requests. An optional config can be passed as the
       * last argument.
       *
       * ```js
       *   $http.get('/someUrl', config).then(successCallback, errorCallback);
       *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
       * ```
       *
       * Complete list of shortcut methods:
       *
       * - {@link ng.$http#get $http.get}
       * - {@link ng.$http#head $http.head}
       * - {@link ng.$http#post $http.post}
       * - {@link ng.$http#put $http.put}
       * - {@link ng.$http#delete $http.delete}
       * - {@link ng.$http#jsonp $http.jsonp}
       * - {@link ng.$http#patch $http.patch}
       *
       *
       * ## Writing Unit Tests that use $http
       * When unit testing (using {@link ngMock ngMock}), it is necessary to call
       * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
       * request using trained responses.
       *
       * ```
       * $httpBackend.expectGET(...);
       * $http.get(...);
       * $httpBackend.flush();
       * ```
       *
       * ## Setting HTTP Headers
       *
       * The $http service will automatically add certain HTTP headers to all requests. These defaults
       * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
       * object, which currently contains this default configuration:
       *
       * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
       *   - <code>Accept: application/json, text/plain, \*&#65279;/&#65279;\*</code>
       * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
       *   - `Content-Type: application/json`
       * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
       *   - `Content-Type: application/json`
       *
       * To add or overwrite these defaults, simply add or remove a property from these configuration
       * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
       * with the lowercased HTTP method name as the key, e.g.
       * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
       *
       * The defaults can also be set at runtime via the `$http.defaults` object in the same
       * fashion. For example:
       *
       * ```
       * module.run(function($http) {
       *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
       * });
       * ```
       *
       * In addition, you can supply a `headers` property in the config object passed when
       * calling `$http(config)`, which overrides the defaults without changing them globally.
       *
       * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
       * Use the `headers` property, setting the desired header to `undefined`. For example:
       *
       * ```js
       * var req = {
       *  method: 'POST',
       *  url: 'http://example.com',
       *  headers: {
       *    'Content-Type': undefined
       *  },
       *  data: { test: 'test' }
       * }
       *
       * $http(req).then(function(){...}, function(){...});
       * ```
       *
       * ## Transforming Requests and Responses
       *
       * Both requests and responses can be transformed using transformation functions: `transformRequest`
       * and `transformResponse`. These properties can be a single function that returns
       * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
       * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
       *
       * <div class="alert alert-warning">
       * **Note:** AngularJS does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
       * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
       * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
       * function will be reflected on the scope and in any templates where the object is data-bound.
       * To prevent this, transform functions should have no side-effects.
       * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
       * </div>
       *
       * ### Default Transformations
       *
       * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
       * `defaults.transformResponse` properties. If a request does not provide its own transformations
       * then these will be applied.
       *
       * You can augment or replace the default transformations by modifying these properties by adding to or
       * replacing the array.
       *
       * AngularJS provides the following default transformations:
       *
       * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is
       * an array with one function that does the following:
       *
       * - If the `data` property of the request configuration object contains an object, serialize it
       *   into JSON format.
       *
       * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`) is
       * an array with one function that does the following:
       *
       *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
       *  - If the `Content-Type` is `application/json` or the response looks like JSON,
     *      deserialize it using a JSON parser.
       *
       *
       * ### Overriding the Default Transformations Per Request
       *
       * If you wish to override the request/response transformations only for a single request then provide
       * `transformRequest` and/or `transformResponse` properties on the configuration object passed
       * into `$http`.
       *
       * Note that if you provide these properties on the config object the default transformations will be
       * overwritten. If you wish to augment the default transformations then you must include them in your
       * local transformation array.
       *
       * The following code demonstrates adding a new response transformation to be run after the default response
       * transformations have been run.
       *
       * ```js
       * function appendTransform(defaults, transform) {
       *
       *   // We can't guarantee that the default transformation is an array
       *   defaults = angular.isArray(defaults) ? defaults : [defaults];
       *
       *   // Append the new transformation to the defaults
       *   return defaults.concat(transform);
       * }
       *
       * $http({
       *   url: '...',
       *   method: 'GET',
       *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
       *     return doTransform(value);
       *   })
       * });
       * ```
       *
       * ## Interceptors
       *
       * Before you start creating interceptors, be sure to understand the
       * {@link ng.$q $q and deferred/promise APIs}.
       *
       * For purposes of global error handling, authentication, or any kind of synchronous or
       * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
       * able to intercept requests before they are handed to the server and
       * responses before they are handed over to the application code that
       * initiated these requests. The interceptors leverage the {@link ng.$q
       * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
       *
       * The interceptors are service factories that are registered with the `$httpProvider` by
       * adding them to the `$httpProvider.interceptors` array. The factory is called and
       * injected with dependencies (if specified) and returns the interceptor.
       *
       * There are two kinds of interceptors (and two kinds of rejection interceptors):
       *
       *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
       *     modify the `config` object or create a new one. The function needs to return the `config`
       *     object directly, or a promise containing the `config` or a new `config` object.
       *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
       *     resolved with a rejection.
       *   * `response`: interceptors get called with http `response` object. The function is free to
       *     modify the `response` object or create a new one. The function needs to return the `response`
       *     object directly, or as a promise containing the `response` or a new `response` object.
       *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
       *     resolved with a rejection.
       *
       *
       * ```js
       *   // register the interceptor as a service
       *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
       *     return {
       *       // optional method
       *       'request': function(config) {
       *         // do something on success
       *         return config;
       *       },
       *
       *       // optional method
       *      'requestError': function(rejection) {
       *         // do something on error
       *         if (canRecover(rejection)) {
       *           return responseOrNewPromise
       *         }
       *         return $q.reject(rejection);
       *       },
       *
       *
       *
       *       // optional method
       *       'response': function(response) {
       *         // do something on success
       *         return response;
       *       },
       *
       *       // optional method
       *      'responseError': function(rejection) {
       *         // do something on error
       *         if (canRecover(rejection)) {
       *           return responseOrNewPromise
       *         }
       *         return $q.reject(rejection);
       *       }
       *     };
       *   });
       *
       *   $httpProvider.interceptors.push('myHttpInterceptor');
       *
       *
       *   // alternatively, register the interceptor via an anonymous factory
       *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
       *     return {
       *      'request': function(config) {
       *          // same as above
       *       },
       *
       *       'response': function(response) {
       *          // same as above
       *       }
       *     };
       *   });
       * ```
       *
       * ## Security Considerations
       *
       * When designing web applications, consider security threats from:
       *
       * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
       * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
       *
       * Both server and the client must cooperate in order to eliminate these threats. AngularJS comes
       * pre-configured with strategies that address these issues, but for this to work backend server
       * cooperation is required.
       *
       * ### JSON Vulnerability Protection
       *
       * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
       * allows third party website to turn your JSON resource URL into
       * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
       * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
       * AngularJS will automatically strip the prefix before processing it as JSON.
       *
       * For example if your server needs to return:
       * ```js
       * ['one','two']
       * ```
       *
       * which is vulnerable to attack, your server can return:
       * ```js
       * )]}',
       * ['one','two']
       * ```
       *
       * AngularJS will strip the prefix, before processing the JSON.
       *
       *
       * ### Cross Site Request Forgery (XSRF) Protection
       *
       * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
       * which the attacker can trick an authenticated user into unknowingly executing actions on your
       * website. AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the
       * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
       * header (by default `X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read
       * the cookie, your server can be assured that the XHR came from JavaScript running on your
       * domain.
       *
       * To take advantage of this, your server needs to set a token in a JavaScript readable session
       * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
       * server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be
       * sure that only JavaScript running on your domain could have sent the request. The token must
       * be unique for each user and must be verifiable by the server (to prevent the JavaScript from
       * making up its own tokens). We recommend that the token is a digest of your site's
       * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
       * for added security.
       *
       * <div class="alert alert-danger">
       *   **Warning**<br />
       *   Only whitelist origins that you have control over and make sure you understand the
       *   implications of doing so.
       * </div>
       *
       * @param {object} config Object describing the request to be made and how it should be
       *    processed. The object has following properties:
       *
       *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
       *    - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested;
       *      or an object created by a call to `$sce.trustAsResourceUrl(url)`.
       *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
       *      with the `paramSerializer` and appended as GET parameters.
       *    - **data** – `{string|Object}` – Data to be sent as the request message data.
       *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
       *      HTTP headers to send to the server. If the return value of a function is null, the
       *      header will not be sent. Functions accept a config object as an argument.
       *    - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
       *      To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
       *      The handler will be called in the context of a `$apply` block.
       *    - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
       *      object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
       *    - **transformRequest** –
       *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
       *      transform function or an array of such functions. The transform function takes the http
       *      request body and headers and returns its transformed (typically serialized) version.
       *      See {@link ng.$http#overriding-the-default-transformations-per-request
       *      Overriding the Default Transformations}
       *    - **transformResponse** –
       *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
       *      transform function or an array of such functions. The transform function takes the http
       *      response body, headers and status and returns its transformed (typically deserialized) version.
       *      See {@link ng.$http#overriding-the-default-transformations-per-request
       *      Overriding the Default Transformations}
       *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
       *      prepare the string representation of request parameters (specified as an object).
       *      If specified as string, it is interpreted as function registered with the
       *      {@link $injector $injector}, which means you can create your own serializer
       *      by registering it as a {@link auto.$provide#service service}.
       *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
       *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
       *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
       *      that should abort the request when resolved.
       *
       *      A numerical timeout or a promise returned from {@link ng.$timeout $timeout}, will set
       *      the `xhrStatus` in the {@link $http#$http-returns response} to "timeout", and any other
       *      resolved promise will set it to "abort", following standard XMLHttpRequest behavior.
       *
       *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
       *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
       *      for more information.
       *    - **responseType** - `{string}` - see
       *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
       *
       * @returns {HttpPromise} A {@link ng.$q `Promise}` that will be resolved (request success)
       *   or rejected (request failure) with a response object.
       *
       *   The response object has these properties:
       *
       *   - **data** – `{string|Object}` – The response body transformed with
       *     the transform functions.
       *   - **status** – `{number}` – HTTP status code of the response.
       *   - **headers** – `{function([headerName])}` – Header getter function.
       *   - **config** – `{Object}` – The configuration object that was used
       *     to generate the request.
       *   - **statusText** – `{string}` – HTTP status text of the response.
       *   - **xhrStatus** – `{string}` – Status of the XMLHttpRequest
       *     (`complete`, `error`, `timeout` or `abort`).
       *
       *
       *   A response status code between 200 and 299 is considered a success status
       *   and will result in the success callback being called. Any response status
       *   code outside of that range is considered an error status and will result
       *   in the error callback being called.
       *   Also, status codes less than -1 are normalized to zero. -1 usually means
       *   the request was aborted, e.g. using a `config.timeout`. More information
       *   about the status might be available in the `xhrStatus` property.
       *
       *   Note that if the response is a redirect, XMLHttpRequest will transparently
       *   follow it, meaning that the outcome (success or error) will be determined
       *   by the final response status code.
       *
       *
       * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
       *   requests. This is primarily meant to be used for debugging purposes.
       *
       *
       * @example
  <example module="httpExample" name="http-service">
  <file name="index.html">
    <div ng-controller="FetchController">
      <select ng-model="method" aria-label="Request method">
        <option>GET</option>
        <option>JSONP</option>
      </select>
      <input type="text" ng-model="url" size="80" aria-label="URL" />
      <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
      <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
      <button id="samplejsonpbtn"
        ng-click="updateModel('JSONP',
                      'https://angularjs.org/greet.php?name=Super%20Hero')">
        Sample JSONP
      </button>
      <button id="invalidjsonpbtn"
        ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist')">
          Invalid JSONP
        </button>
      <pre>http status code: {{status}}</pre>
      <pre>http response data: {{data}}</pre>
    </div>
  </file>
  <file name="script.js">
    angular.module('httpExample', [])
      .config(['$sceDelegateProvider', function($sceDelegateProvider) {
        // We must whitelist the JSONP endpoint that we are using to show that we trust it
        $sceDelegateProvider.resourceUrlWhitelist([
          'self',
          'https://angularjs.org/**'
        ]);
      }])
      .controller('FetchController', ['$scope', '$http', '$templateCache',
        function($scope, $http, $templateCache) {
          $scope.method = 'GET';
          $scope.url = 'http-hello.html';
  
          $scope.fetch = function() {
            $scope.code = null;
            $scope.response = null;
  
            $http({method: $scope.method, url: $scope.url}).
              then(function(response) {
                $scope.status = response.status;
                $scope.data = response.data;
              }, function(response) {
                $scope.data = response.data || 'Request failed';
                $scope.status = response.status;
            });
          };
  
          $scope.updateModel = function(method, url) {
            $scope.method = method;
            $scope.url = url;
          };
        }]);
  </file>
  <file name="http-hello.html">
    Hello, $http!
  </file>
  <file name="protractor.js" type="protractor">
    var status = element(by.binding('status'));
    var data = element(by.binding('data'));
    var fetchBtn = element(by.id('fetchbtn'));
    var sampleGetBtn = element(by.id('samplegetbtn'));
    var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
  
    it('should make an xhr GET request', function() {
      sampleGetBtn.click();
      fetchBtn.click();
      expect(status.getText()).toMatch('200');
      expect(data.getText()).toMatch(/Hello, \$http!/);
    });
  
  // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
  // it('should make a JSONP request to angularjs.org', function() {
  //   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
  //   sampleJsonpBtn.click();
  //   fetchBtn.click();
  //   expect(status.getText()).toMatch('200');
  //   expect(data.getText()).toMatch(/Super Hero!/);
  // });
  
    it('should make JSONP request to invalid URL and invoke the error handler',
        function() {
      invalidJsonpBtn.click();
      fetchBtn.click();
      expect(status.getText()).toMatch('0');
      expect(data.getText()).toMatch('Request failed');
    });
  </file>
  </example>
       */
      function $http(requestConfig) {
  
        if (!isObject(requestConfig)) {
          throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
        }
  
        if (!isString($sce.valueOf(requestConfig.url))) {
          throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object.  Received: {0}', requestConfig.url);
        }
  
        if (requestConfig.cache) {
          throw new Error('$http does not support cache anymore! (https://github.com/Crowd9/angular.js)');
        }
  
        var config = extend({
          method: 'get',
          transformRequest: defaults.transformRequest,
          transformResponse: defaults.transformResponse,
          paramSerializer: defaults.paramSerializer,
          jsonpCallbackParam: defaults.jsonpCallbackParam
        }, requestConfig);
  
        config.headers = mergeHeaders(requestConfig);
        config.method = uppercase(config.method);
        config.paramSerializer = isString(config.paramSerializer) ?
            $injector.get(config.paramSerializer) : config.paramSerializer;
  
        $browser.$$incOutstandingRequestCount('$http');
  
        var requestInterceptors = [];
        var responseInterceptors = [];
        var promise = $q.resolve(config);
  
        // apply interceptors
        forEach(reversedInterceptors, function(interceptor) {
          if (interceptor.request || interceptor.requestError) {
            requestInterceptors.unshift(interceptor.request, interceptor.requestError);
          }
          if (interceptor.response || interceptor.responseError) {
            responseInterceptors.push(interceptor.response, interceptor.responseError);
          }
        });
  
        promise = chainInterceptors(promise, requestInterceptors);
        promise = promise.then(serverRequest);
        promise = chainInterceptors(promise, responseInterceptors);
        promise = promise.finally(completeOutstandingRequest);
  
        return promise;
  
  
        function chainInterceptors(promise, interceptors) {
          for (var i = 0, ii = interceptors.length; i < ii;) {
            var thenFn = interceptors[i++];
            var rejectFn = interceptors[i++];
  
            promise = promise.then(thenFn, rejectFn);
          }
  
          interceptors.length = 0;
  
          return promise;
        }
  
        function completeOutstandingRequest() {
          $browser.$$completeOutstandingRequest(noop, '$http');
        }
  
        function executeHeaderFns(headers, config) {
          var headerContent, processedHeaders = {};
  
          forEach(headers, function(headerFn, header) {
            if (isFunction(headerFn)) {
              headerContent = headerFn(config);
              if (headerContent != null) {
                processedHeaders[header] = headerContent;
              }
            } else {
              processedHeaders[header] = headerFn;
            }
          });
  
          return processedHeaders;
        }
  
        function mergeHeaders(config) {
          var defHeaders = defaults.headers,
              reqHeaders = extend({}, config.headers),
              defHeaderName, lowercaseDefHeaderName, reqHeaderName;
  
          defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
  
          // using for-in instead of forEach to avoid unnecessary iteration after header has been found
          defaultHeadersIteration:
          for (defHeaderName in defHeaders) {
            lowercaseDefHeaderName = lowercase(defHeaderName);
  
            for (reqHeaderName in reqHeaders) {
              if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
                continue defaultHeadersIteration;
              }
            }
  
            reqHeaders[defHeaderName] = defHeaders[defHeaderName];
          }
  
          // execute if header value is a function for merged headers
          return executeHeaderFns(reqHeaders, shallowCopy(config));
        }
  
        function serverRequest(config) {
          var headers = config.headers;
          var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
  
          // strip content-type if data is undefined
          if (isUndefined(reqData)) {
            forEach(headers, function(value, header) {
              if (lowercase(header) === 'content-type') {
                delete headers[header];
              }
            });
          }
  
          if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
            config.withCredentials = defaults.withCredentials;
          }
  
          // send request
          return sendReq(config, reqData).then(transformResponse, transformResponse);
        }
  
        function transformResponse(response) {
          // make a copy since the response must be cacheable
          var resp = extend({}, response);
          resp.data = transformData(response.data, response.headers, response.status,
                                    config.transformResponse);
          return (isSuccess(response.status))
            ? resp
            : $q.reject(resp);
        }
      }
  
      $http.pendingRequests = [];
  
      /**
       * @ngdoc method
       * @name $http#get
       *
       * @description
       * Shortcut method to perform `GET` request.
       *
       * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
       *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
  
      /**
       * @ngdoc method
       * @name $http#delete
       *
       * @description
       * Shortcut method to perform `DELETE` request.
       *
       * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
       *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
  
      /**
       * @ngdoc method
       * @name $http#head
       *
       * @description
       * Shortcut method to perform `HEAD` request.
       *
       * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
       *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
  
      /**
       * @ngdoc method
       * @name $http#jsonp
       *
       * @description
       * Shortcut method to perform `JSONP` request.
       *
       * Note that, since JSONP requests are sensitive because the response is given full access to the browser,
       * the url must be declared, via {@link $sce} as a trusted resource URL.
       * You can trust a URL by adding it to the whitelist via
       * {@link $sceDelegateProvider#resourceUrlWhitelist  `$sceDelegateProvider.resourceUrlWhitelist`} or
       * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
       *
       * You should avoid generating the URL for the JSONP request from user provided data.
       * Provide additional query parameters via `params` property of the `config` parameter, rather than
       * modifying the URL itself.
       *
       * JSONP requests must specify a callback to be used in the response from the server. This callback
       * is passed as a query parameter in the request. You must specify the name of this parameter by
       * setting the `jsonpCallbackParam` property on the request config object.
       *
       * ```
       * $http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
       * ```
       *
       * You can also specify a default callback parameter name in `$http.defaults.jsonpCallbackParam`.
       * Initially this is set to `'callback'`.
       *
       * <div class="alert alert-danger">
       * You can no longer use the `JSON_CALLBACK` string as a placeholder for specifying where the callback
       * parameter value should go.
       * </div>
       *
       * If you would like to customise where and how the callbacks are stored then try overriding
       * or decorating the {@link $jsonpCallbacks} service.
       *
       * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
       *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
      createShortMethods('get', 'delete', 'head', 'jsonp');
  
      /**
       * @ngdoc method
       * @name $http#post
       *
       * @description
       * Shortcut method to perform `POST` request.
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {*} data Request content
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
  
      /**
       * @ngdoc method
       * @name $http#put
       *
       * @description
       * Shortcut method to perform `PUT` request.
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {*} data Request content
       * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
       * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
       * See {@link ng.$http#$http-returns `$http()` return value}.
       */
  
       /**
        * @ngdoc method
        * @name $http#patch
        *
        * @description
        * Shortcut method to perform `PATCH` request.
        *
        * @param {string} url Relative or absolute URL specifying the destination of the request
        * @param {*} data Request content
        * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
        * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
        * See {@link ng.$http#$http-returns `$http()` return value}.
        */
      createShortMethodsWithData('post', 'put', 'patch');
  
          /**
           * @ngdoc property
           * @name $http#defaults
           *
           * @description
           * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
           * default headers, withCredentials as well as request and response transformations.
           *
           * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
           */
      $http.defaults = defaults;
  
  
      return $http;
  
  
      function createShortMethods(names) {
        forEach(arguments, function(name) {
          $http[name] = function(url, config) {
            return $http(extend({}, config || {}, {
              method: name,
              url: url
            }));
          };
        });
      }
  
  
      function createShortMethodsWithData(name) {
        forEach(arguments, function(name) {
          $http[name] = function(url, data, config) {
            return $http(extend({}, config || {}, {
              method: name,
              url: url,
              data: data
            }));
          };
        });
      }
  
  
      /**
       * Makes the request.
       *
       * !!! ACCESSES CLOSURE VARS:
       * $httpBackend, defaults, $log, $rootScope, $http.pendingRequests
       */
      function sendReq(config, reqData) {
        var deferred = $q.defer(),
            promise = deferred.promise,
            reqHeaders = config.headers,
            isJsonp = lowercase(config.method) === 'jsonp',
            url = config.url;
  
        if (isJsonp) {
          // JSONP is a pretty sensitive operation where we're allowing a script to have full access to
          // our DOM and JS space.  So we require that the URL satisfies SCE.RESOURCE_URL.
          url = $sce.getTrustedResourceUrl(url);
        } else if (!isString(url)) {
          // If it is not a string then the URL must be a $sce trusted object
          url = $sce.valueOf(url);
        }
  
        url = buildUrl(url, config.paramSerializer(config.params));
  
        if (isJsonp) {
          // Check the url and add the JSONP callback placeholder
          url = sanitizeJsonpCallbackParam(url, config.jsonpCallbackParam);
        }
  
        $http.pendingRequests.push(config);
        promise.then(removePendingReq, removePendingReq);
  
        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
            config.withCredentials, config.responseType,
            createApplyHandlers(config.eventHandlers),
            createApplyHandlers(config.uploadEventHandlers));
  
        return promise;
  
        function createApplyHandlers(eventHandlers) {
          if (eventHandlers) {
            var applyHandlers = {};
            forEach(eventHandlers, function(eventHandler, key) {
              applyHandlers[key] = function(event) {
                if (useApplyAsync) {
                  $rootScope.$applyAsync(callEventHandler);
                } else if ($rootScope.$$phase) {
                  callEventHandler();
                } else {
                  $rootScope.$apply(callEventHandler);
                }
  
                function callEventHandler() {
                  eventHandler(event);
                }
              };
            });
            return applyHandlers;
          }
        }
  
  
        /**
         * Callback registered to $httpBackend():
         *  - resolves the raw $http promise
         *  - calls $apply
         */
        function done(status, response, headersString, statusText, xhrStatus) {
          function resolveHttpPromise() {
            resolvePromise(response, status, headersString, statusText, xhrStatus);
          }
  
          if (useApplyAsync) {
            $rootScope.$applyAsync(resolveHttpPromise);
          } else {
            resolveHttpPromise();
            if (!$rootScope.$$phase) $rootScope.$apply();
          }
        }
  
  
        /**
         * Resolves the raw $http promise.
         */
        function resolvePromise(response, status, headers, statusText, xhrStatus) {
          //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
          status = status >= -1 ? status : 0;
  
          (isSuccess(status) ? deferred.resolve : deferred.reject)({
            data: response,
            status: status,
            headers: headersGetter(headers),
            config: config,
            statusText: statusText,
            xhrStatus: xhrStatus
          });
        }
  
        function resolvePromiseWithResult(result) {
          resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText, result.xhrStatus);
        }
  
        function removePendingReq() {
          var idx = $http.pendingRequests.indexOf(config);
          if (idx !== -1) $http.pendingRequests.splice(idx, 1);
        }
      }
  
  
      function buildUrl(url, serializedParams) {
        if (serializedParams.length > 0) {
          url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams;
        }
        return url;
      }
  
      function sanitizeJsonpCallbackParam(url, cbKey) {
        var parts = url.split('?');
        if (parts.length > 2) {
          // Throw if the url contains more than one `?` query indicator
          throw $httpMinErr('badjsonp', 'Illegal use more than one "?", in url, "{1}"', url);
        }
        var params = parseKeyValue(parts[1]);
        forEach(params, function(value, key) {
          if (value === 'JSON_CALLBACK') {
            // Throw if the url already contains a reference to JSON_CALLBACK
            throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url);
          }
          if (key === cbKey) {
            // Throw if the callback param was already provided
            throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', cbKey, url);
          }
        });
  
        // Add in the JSON_CALLBACK callback param value
        url += ((url.indexOf('?') === -1) ? '?' : '&') + cbKey + '=JSON_CALLBACK';
  
        return url;
      }
    }];
  }
  