text: 'use strict';
  
  /* We need to tell jshint what variables are being exported */
  /* global angular: true,
      msie: true,
      jqLite: true,
      jQuery: true,
      slice: true,
      push: true,
      toString: true,
      ngMinErr: true,
      angularModule: true,
      nodeName_: true,
      uid: true,
      VALIDITY_STATE_PROPERTY: true,
  
      lowercase: true,
      uppercase: true,
      manualLowercase: true,
      manualUppercase: true,
      nodeName_: true,
      isArrayLike: true,
      forEach: true,
      sortedKeys: true,
      forEachSorted: true,
      reverseParams: true,
      nextUid: true,
      setHashKey: true,
      extend: true,
      int: true,
      inherit: true,
      noop: true,
      identity: true,
      valueFn: true,
      isUndefined: true,
      isDefined: true,
      isObject: true,
      isString: true,
      isNumber: true,
      isDate: true,
      isArray: true,
      isFunction: true,
      isRegExp: true,
      isWindow: true,
      isScope: true,
      isFile: true,
      isBlob: true,
      isBoolean: true,
      isPromiseLike: true,
      trim: true,
      isElement: true,
      makeMap: true,
      map: true,
      size: true,
      includes: true,
      indexOf: true,
      arrayRemove: true,
      isLeafNode: true,
      copy: true,
      shallowCopy: true,
      equals: true,
      csp: true,
      concat: true,
      sliceArgs: true,
      bind: true,
      toJsonReplacer: true,
      toJson: true,
      fromJson: true,
      toBoolean: true,
      startingTag: true,
      tryDecodeURIComponent: true,
      parseKeyValue: true,
      toKeyValue: true,
      encodeUriSegment: true,
      encodeUriQuery: true,
      angularInit: true,
      bootstrap: true,
      snake_case: true,
      bindJQuery: true,
      assertArg: true,
      assertArgFn: true,
      assertNotHasOwnProperty: true,
      getter: true,
      getBlockElements: true,
      hasOwnProperty: true,
  */
  
  ////////////////////////////////////
  
  /**
   * @ngdoc module
   * @name ng
   * @module ng
   * @description
   *
   * # ng (core module)
   * The ng module is loaded by default when an AngularJS application is started. The module itself
   * contains the essential components for an AngularJS application to function. The table below
   * lists a high level breakdown of each of the services/factories, filters, directives and testing
   * components available within this core module.
   *
   * <div doc-module-components="ng"></div>
   */
  
  // The name of a form control's ValidityState property.
  // This is used so that it's possible for internal tests to create mock ValidityStates.
  var VALIDITY_STATE_PROPERTY = 'validity';
  
  /**
   * @ngdoc function
   * @name angular.lowercase
   * @module ng
   * @kind function
   *
   * @description Converts the specified string to lowercase.
   * @param {string} string String to be converted to lowercase.
   * @returns {string} Lowercased string.
   */
  var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
  var hasOwnProperty = Object.prototype.hasOwnProperty;
  
  /**
   * @ngdoc function
   * @name angular.uppercase
   * @module ng
   * @kind function
   *
   * @description Converts the specified string to uppercase.
   * @param {string} string String to be converted to uppercase.
   * @returns {string} Uppercased string.
   */
  var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
  
  
  var manualLowercase = function(s) {
    /* jshint bitwise: false */
    return isString(s)
        ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
        : s;
  };
  var manualUppercase = function(s) {
    /* jshint bitwise: false */
    return isString(s)
        ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
        : s;
  };
  
  
  // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
  // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
  // with correct but slower alternatives.
  if ('i' !== 'I'.toLowerCase()) {
    lowercase = manualLowercase;
    uppercase = manualUppercase;
  }
  
  
  var
      msie,             // holds major version number for IE, or NaN if UA is not IE.
      jqLite,           // delay binding since jQuery could be loaded after us.
      jQuery,           // delay binding
      slice             = [].slice,
      push              = [].push,
      toString          = Object.prototype.toString,
      ngMinErr          = minErr('ng'),
  
      /** @name angular */
      angular           = window.angular || (window.angular = {}),
      angularModule,
      nodeName_,
      uid               = ['0', '0', '0'];
  
  /**
   * IE 11 changed the format of the UserAgent string.
   * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
   */
  msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
  if (isNaN(msie)) {
    msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
  }
  
  
  /**
   * @private
   * @param {*} obj
   * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
   *                   String ...)
   */
  function isArrayLike(obj) {
    if (obj == null || isWindow(obj)) {
      return false;
    }
  
    var length = obj.length;
  
    if (obj.nodeType === 1 && length) {
      return true;
    }
  
    return isString(obj) || isArray(obj) || length === 0 ||
           typeof length === 'number' && length > 0 && (length - 1) in obj;
  }
  
  /**
   * @ngdoc function
   * @name angular.forEach
   * @module ng
   * @kind function
   *
   * @description
   * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
   * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
   * is the value of an object property or an array element and `key` is the object property key or
   * array element index. Specifying a `context` for the function is optional.
   *
   * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
   * using the `hasOwnProperty` method.
   *
     ```js
       var values = {name: 'misko', gender: 'male'};
       var log = [];
       angular.forEach(values, function(value, key) {
         this.push(key + ': ' + value);
       }, log);
       expect(log).toEqual(['name: misko', 'gender: male']);
     ```
   *
   * @param {Object|Array} obj Object to iterate over.
   * @param {Function} iterator Iterator function.
   * @param {Object=} context Object to become context (`this`) for the iterator function.
   * @returns {Object|Array} Reference to `obj`.
   */
  function forEach(obj, iterator, context) {
    var key;
    if (obj) {
      if (isFunction(obj)) {
        for (key in obj) {
          // Need to check if hasOwnProperty exists,
          // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
          if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
            iterator.call(context, obj[key], key);
          }
        }
      } else if (isArray(obj) || isArrayLike(obj)) {
        for (key = 0; key < obj.length; key++) {
          iterator.call(context, obj[key], key);
        }
      } else if (obj.forEach && obj.forEach !== forEach) {
          obj.forEach(iterator, context);
      } else {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            iterator.call(context, obj[key], key);
          }
        }
      }
    }
    return obj;
  }
  
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }
  
  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
  
  
  /**
   * when using forEach the params are value, key, but it is often useful to have key, value.
   * @param {function(string, *)} iteratorFn
   * @returns {function(*, string)}
   */
  function reverseParams(iteratorFn) {
    return function(value, key) { iteratorFn(key, value); };
  }
  
  /**
   * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
   * characters such as '012ABC'. The reason why we are not using simply a number counter is that
   * the number string gets longer over time, and it can also overflow, where as the nextId
   * will grow much slower, it is a string, and it will never overflow.
   *
   * @returns {string} an unique alpha-numeric string
   */
  function nextUid() {
    var index = uid.length;
    var digit;
  
    while(index) {
      index--;
      digit = uid[index].charCodeAt(0);
      if (digit == 57 /*'9'*/) {
        uid[index] = 'A';
        return uid.join('');
      }
      if (digit == 90  /*'Z'*/) {
        uid[index] = '0';
      } else {
        uid[index] = String.fromCharCode(digit + 1);
        return uid.join('');
      }
    }
    uid.unshift('0');
    return uid.join('');
  }
  
  
  /**
   * Set or clear the hashkey for an object.
   * @param obj object
   * @param h the hashkey (!truthy to delete the hashkey)
   */
  function setHashKey(obj, h) {
    if (h) {
      obj.$$hashKey = h;
    }
    else {
      delete obj.$$hashKey;
    }
  }
  
  /**
   * @ngdoc function
   * @name angular.extend
   * @module ng
   * @kind function
   *
   * @description
   * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
   * to `dst`. You can specify multiple `src` objects.
   *
   * @param {Object} dst Destination object.
   * @param {...Object} src Source object(s).
   * @returns {Object} Reference to `dst`.
   */
  function extend(dst) {
    var h = dst.$$hashKey;
    forEach(arguments, function(obj) {
      if (obj !== dst) {
        forEach(obj, function(value, key) {
          dst[key] = value;
        });
      }
    });
  
    setHashKey(dst,h);
    return dst;
  }
  
  function int(str) {
    return parseInt(str, 10);
  }
  
  
  function inherit(parent, extra) {
    return extend(new (extend(function() {}, {prototype:parent}))(), extra);
  }
  
  /**
   * @ngdoc function
   * @name angular.noop
   * @module ng
   * @kind function
   *
   * @description
   * A function that performs no operations. This function can be useful when writing code in the
   * functional style.
     ```js
       function foo(callback) {
         var result = calculateResult();
         (callback || angular.noop)(result);
       }
     ```
   */
  function noop() {}
  noop.$inject = [];
  
  
  /**
   * @ngdoc function
   * @name angular.identity
   * @module ng
   * @kind function
   *
   * @description
   * A function that returns its first argument. This function is useful when writing code in the
   * functional style.
   *
     ```js
       function transformer(transformationFn, value) {
         return (transformationFn || angular.identity)(value);
       };
     ```
    * @param {*} value to be returned.
    * @returns {*} the value passed in.
   */
  function identity($) {return $;}
  identity.$inject = [];
  
  
  function valueFn(value) {return function() {return value;};}
  
  /**
   * @ngdoc function
   * @name angular.isUndefined
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is undefined.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is undefined.
   */
  function isUndefined(value){return typeof value === 'undefined';}
  
  
  /**
   * @ngdoc function
   * @name angular.isDefined
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is defined.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is defined.
   */
  function isDefined(value){return typeof value !== 'undefined';}
  
  
  /**
   * @ngdoc function
   * @name angular.isObject
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
   * considered to be objects. Note that JavaScript arrays are objects.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is an `Object` but not `null`.
   */
  function isObject(value){return value != null && typeof value === 'object';}
  
  
  /**
   * @ngdoc function
   * @name angular.isString
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is a `String`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `String`.
   */
  function isString(value){return typeof value === 'string';}
  
  
  /**
   * @ngdoc function
   * @name angular.isNumber
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is a `Number`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Number`.
   */
  function isNumber(value){return typeof value === 'number';}
  
  
  /**
   * @ngdoc function
   * @name angular.isDate
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a value is a date.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Date`.
   */
  function isDate(value) {
    return toString.call(value) === '[object Date]';
  }
  
  
  /**
   * @ngdoc function
   * @name angular.isArray
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is an `Array`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is an `Array`.
   */
  var isArray = (function() {
    if (!isFunction(Array.isArray)) {
      return function(value) {
        return toString.call(value) === '[object Array]';
      };
    }
    return Array.isArray;
  })();
  
  /**
   * @ngdoc function
   * @name angular.isFunction
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is a `Function`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Function`.
   */
  function isFunction(value){return typeof value === 'function';}
  
  
  /**
   * Determines if a value is a regular expression object.
   *
   * @private
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `RegExp`.
   */
  function isRegExp(value) {
    return toString.call(value) === '[object RegExp]';
  }
  
  
  /**
   * Checks if `obj` is a window object.
   *
   * @private
   * @param {*} obj Object to check
   * @returns {boolean} True if `obj` is a window obj.
   */
  function isWindow(obj) {
    return obj && obj.document && obj.location && obj.alert && obj.setInterval;
  }
  
  
  function isScope(obj) {
    return obj && obj.$evalAsync && obj.$watch;
  }
  
  
  function isFile(obj) {
    return toString.call(obj) === '[object File]';
  }
  
  
  function isBlob(obj) {
    return toString.call(obj) === '[object Blob]';
  }
  
  
  function isBoolean(value) {
    return typeof value === 'boolean';
  }
  
  
  function isPromiseLike(obj) {
    return obj && isFunction(obj.then);
  }
  
  
  var trim = (function() {
    // native trim is way faster: http://jsperf.com/angular-trim-test
    // but IE doesn't have it... :-(
    // TODO: we should move this into IE/ES5 polyfill
    if (!String.prototype.trim) {
      return function(value) {
        return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
      };
    }
    return function(value) {
      return isString(value) ? value.trim() : value;
    };
  })();
  
  
  /**
   * @ngdoc function
   * @name angular.isElement
   * @module ng
   * @kind function
   *
   * @description
   * Determines if a reference is a DOM element (or wrapped jQuery element).
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
   */
  function isElement(node) {
    return !!(node &&
      (node.nodeName  // we are a direct element
      || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
  }
  
  /**
   * @param str 'key1,key2,...'
   * @returns {object} in the form of {key1:true, key2:true, ...}
   */
  function makeMap(str) {
    var obj = {}, items = str.split(","), i;
    for ( i = 0; i < items.length; i++ )
      obj[ items[i] ] = true;
    return obj;
  }
  
  
  if (msie < 9) {
    nodeName_ = function(element) {
      element = element.nodeName ? element : element[0];
      return (element.scopeName && element.scopeName != 'HTML')
        ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
    };
  } else {
    nodeName_ = function(element) {
      return element.nodeName ? element.nodeName : element[0].nodeName;
    };
  }
  
  
  function map(obj, iterator, context) {
    var results = [];
    forEach(obj, function(value, index, list) {
      results.push(iterator.call(context, value, index, list));
    });
    return results;
  }
  
  
  /**
   * @description
   * Determines the number of elements in an array, the number of properties an object has, or
   * the length of a string.
   *
   * Note: This function is used to augment the Object type in Angular expressions. See
   * {@link angular.Object} for more information about Angular arrays.
   *
   * @param {Object|Array|string} obj Object, array, or string to inspect.
   * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
   * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
   */
  function size(obj, ownPropsOnly) {
    var count = 0, key;
  
    if (isArray(obj) || isString(obj)) {
      return obj.length;
    } else if (isObject(obj)) {
      for (key in obj)
        if (!ownPropsOnly || obj.hasOwnProperty(key))
          count++;
    }
  
    return count;
  }
  
  
  function includes(array, obj) {
    return indexOf(array, obj) != -1;
  }
  
  function indexOf(array, obj) {
    if (array.indexOf) return array.indexOf(obj);
  
    for (var i = 0; i < array.length; i++) {
      if (obj === array[i]) return i;
    }
    return -1;
  }
  
  function arrayRemove(array, value) {
    var index = indexOf(array, value);
    if (index >=0)
      array.splice(index, 1);
    return value;
  }
  
  function isLeafNode (node) {
    if (node) {
      switch (node.nodeName) {
      case "OPTION":
      case "PRE":
      case "TITLE":
        return true;
      }
    }
    return false;
  }
  
  /**
   * @ngdoc function
   * @name angular.copy
   * @module ng
   * @kind function
   *
   * @description
   * Creates a deep copy of `source`, which should be an object or an array.
   *
   * * If no destination is supplied, a copy of the object or array is created.
   * * If a destination is provided, all of its elements (for array) or properties (for objects)
   *   are deleted and then all elements/properties from the source are copied to it.
   * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
   * * If `source` is identical to 'destination' an exception will be thrown.
   *
   * @param {*} source The source that will be used to make a copy.
   *                   Can be any type, including primitives, `null`, and `undefined`.
   * @param {(Object|Array)=} destination Destination into which the source is copied. If
   *     provided, must be of the same type as `source`.
   * @returns {*} The copy or updated `destination`, if `destination` was specified.
   *
   * @example
   <example module="copyExample">
   <file name="index.html">
   <div ng-controller="ExampleController">
   <form novalidate class="simple-form">
   Name: <input type="text" ng-model="user.name" /><br />
   E-mail: <input type="email" ng-model="user.email" /><br />
   Gender: <input type="radio" ng-model="user.gender" value="male" />male
   <input type="radio" ng-model="user.gender" value="female" />female<br />
   <button ng-click="reset()">RESET</button>
   <button ng-click="update(user)">SAVE</button>
   </form>
   <pre>form = {{user | json}}</pre>
   <pre>master = {{master | json}}</pre>
   </div>
  
   <script>
    angular.module('copyExample', [])
      .controller('ExampleController', ['$scope', function($scope) {
        $scope.master= {};
  
        $scope.update = function(user) {
          // Example with 1 argument
          $scope.master= angular.copy(user);
        };
  
        $scope.reset = function() {
          // Example with 2 arguments
          angular.copy($scope.master, $scope.user);
        };
  
        $scope.reset();
      }]);
   </script>
   </file>
   </example>
   */
  function copy(source, destination, stackSource, stackDest) {
    if (isWindow(source) || isScope(source)) {
      throw ngMinErr('cpws',
        "Can't copy! Making copies of Window or Scope instances is not supported.");
    }
  
    if (!destination) {
      destination = source;
      if (source) {
        if (isArray(source)) {
          destination = copy(source, [], stackSource, stackDest);
        } else if (isDate(source)) {
          destination = new Date(source.getTime());
        } else if (isRegExp(source)) {
          destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
          destination.lastIndex = source.lastIndex;
        } else if (isObject(source)) {
          destination = copy(source, {}, stackSource, stackDest);
        }
      }
    } else {
      if (source === destination) throw ngMinErr('cpi',
        "Can't copy! Source and destination are identical.");
  
      stackSource = stackSource || [];
      stackDest = stackDest || [];
  
      if (isObject(source)) {
        var index = indexOf(stackSource, source);
        if (index !== -1) return stackDest[index];
  
        stackSource.push(source);
        stackDest.push(destination);
      }
  
      var result;
      if (isArray(source)) {
        destination.length = 0;
        for ( var i = 0; i < source.length; i++) {
          result = copy(source[i], null, stackSource, stackDest);
          if (isObject(source[i])) {
            stackSource.push(source[i]);
            stackDest.push(result);
          }
          destination.push(result);
        }
      } else {
        var h = destination.$$hashKey;
        if (isArray(destination)) {
          destination.length = 0;
        } else {
          forEach(destination, function(value, key) {
            delete destination[key];
          });
        }
        for ( var key in source) {
          result = copy(source[key], null, stackSource, stackDest);
          if (isObject(source[key])) {
            stackSource.push(source[key]);
            stackDest.push(result);
          }
          destination[key] = result;
        }
        setHashKey(destination,h);
      }
  
    }
    return destination;
  }
  
  /**
   * Creates a shallow copy of an object, an array or a primitive
   */
  function shallowCopy(src, dst) {
    if (isArray(src)) {
      dst = dst || [];
  
      for ( var i = 0; i < src.length; i++) {
        dst[i] = src[i];
      }
    } else if (isObject(src)) {
      dst = dst || {};
  
      for (var key in src) {
        if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
          dst[key] = src[key];
        }
      }
    }
  
    return dst || src;
  }
  
  
  /**
   * @ngdoc function
   * @name angular.equals
   * @module ng
   * @kind function
   *
   * @description
   * Determines if two objects or two values are equivalent. Supports value types, regular
   * expressions, arrays and objects.
   *
   * Two objects or values are considered equivalent if at least one of the following is true:
   *
   * * Both objects or values pass `===` comparison.
   * * Both objects or values are of the same type and all of their properties are equal by
   *   comparing them with `angular.equals`.
   * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
   * * Both values represent the same regular expression (In JavaScript,
   *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
   *   representation matches).
   *
   * During a property comparison, properties of `function` type and properties with names
   * that begin with `$` are ignored.
   *
   * Scope and DOMWindow objects are being compared only by identify (`===`).
   *
   * @param {*} o1 Object or value to compare.
   * @param {*} o2 Object or value to compare.
   * @returns {boolean} True if arguments are equal.
   */
  function equals(o1, o2) {
    if (o1 === o2) return true;
    if (o1 === null || o2 === null) return false;
    if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
    var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
    if (t1 == t2) {
      if (t1 == 'object') {
        if (isArray(o1)) {
          if (!isArray(o2)) return false;
          if ((length = o1.length) == o2.length) {
            for(key=0; key<length; key++) {
              if (!equals(o1[key], o2[key])) return false;
            }
            return true;
          }
        } else if (isDate(o1)) {
          if (!isDate(o2)) return false;
          return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
        } else if (isRegExp(o1) && isRegExp(o2)) {
          return o1.toString() == o2.toString();
        } else {
          if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
          keySet = {};
          for(key in o1) {
            if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
            if (!equals(o1[key], o2[key])) return false;
            keySet[key] = true;
          }
          for(key in o2) {
            if (!keySet.hasOwnProperty(key) &&
                key.charAt(0) !== '$' &&
                o2[key] !== undefined &&
                !isFunction(o2[key])) return false;
          }
          return true;
        }
      }
    }
    return false;
  }
  
  var csp = function() {
    if (isDefined(csp.isActive_)) return csp.isActive_;
  
    var active = !!(document.querySelector('[ng-csp]') ||
                    document.querySelector('[data-ng-csp]'));
  
    if (!active) {
      try {
        /* jshint -W031, -W054 */
        new Function('');
        /* jshint +W031, +W054 */
      } catch (e) {
        active = true;
      }
    }
  
    return (csp.isActive_ = active);
  };
  
  
  
  function concat(array1, array2, index) {
    return array1.concat(slice.call(array2, index));
  }
  
  function sliceArgs(args, startIndex) {
    return slice.call(args, startIndex || 0);
  }
  
  
  /* jshint -W101 */
  /**
   * @ngdoc function
   * @name angular.bind
   * @module ng
   * @kind function
   *
   * @description
   * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
   * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
   * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
   * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
   *
   * @param {Object} self Context which `fn` should be evaluated in.
   * @param {function()} fn Function to be bound.
   * @param {...*} args Optional arguments to be prebound to the `fn` function call.
   * @returns {function()} Function that wraps the `fn` with all the specified bindings.
   */
  /* jshint +W101 */
  function bind(self, fn) {
    var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
    if (isFunction(fn) && !(fn instanceof RegExp)) {
      return curryArgs.length
        ? function() {
            return arguments.length
              ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
              : fn.apply(self, curryArgs);
          }
        : function() {
            return arguments.length
              ? fn.apply(self, arguments)
              : fn.call(self);
          };
    } else {
      // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
      return fn;
    }
  }
  
  
  function toJsonReplacer(key, value) {
    var val = value;
  
    if (typeof key === 'string' && key.charAt(0) === '$') {
      val = undefined;
    } else if (isWindow(value)) {
      val = '$WINDOW';
    } else if (value &&  document === value) {
      val = '$DOCUMENT';
    } else if (isScope(value)) {
      val = '$SCOPE';
    }
  
    return val;
  }
  
  
  /**
   * @ngdoc function
   * @name angular.toJson
   * @module ng
   * @kind function
   *
   * @description
   * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
   * stripped since angular uses this notation internally.
   *
   * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
   * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
   * @returns {string|undefined} JSON-ified string representing `obj`.
   */
  function toJson(obj, pretty) {
    if (typeof obj === 'undefined') return undefined;
    return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
  }
  
  
  /**
   * @ngdoc function
   * @name angular.fromJson
   * @module ng
   * @kind function
   *
   * @description
   * Deserializes a JSON string.
   *
   * @param {string} json JSON string to deserialize.
   * @returns {Object|Array|string|number} Deserialized thingy.
   */
  function fromJson(json) {
    return isString(json)
        ? JSON.parse(json)
        : json;
  }
  
  
  function toBoolean(value) {
    if (typeof value === 'function') {
      value = true;
    } else if (value && value.length !== 0) {
      var v = lowercase("" + value);
      value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
    } else {
      value = false;
    }
    return value;
  }
  
  /**
   * @returns {string} Returns the string representation of the element.
   */
  function startingTag(element) {
    element = jqLite(element).clone();
    try {
      // turns out IE does not let you set .html() on elements which
      // are not allowed to have children. So we just ignore it.
      element.empty();
    } catch(e) {}
    // As Per DOM Standards
    var TEXT_NODE = 3;
    var elemHtml = jqLite('<div>').append(element).html();
    try {
      return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
          elemHtml.
            match(/^(<[^>]+>)/)[1].
            replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
    } catch(e) {
      return lowercase(elemHtml);
    }
  
  }
  
  
  /////////////////////////////////////////////////
  
  /**
   * Tries to decode the URI component without throwing an exception.
   *
   * @private
   * @param str value potential URI component to check.
   * @returns {boolean} True if `value` can be decoded
   * with the decodeURIComponent function.
   */
  function tryDecodeURIComponent(value) {
    try {
      return decodeURIComponent(value);
    } catch(e) {
      // Ignore any invalid uri component
    }
  }
  
  
  /**
   * Parses an escaped url query string into key-value pairs.
   * @returns {Object.<string,boolean|Array>}
   */
  function parseKeyValue(/**string*/keyValue) {
    var obj = {}, key_value, key;
    forEach((keyValue || "").split('&'), function(keyValue) {
      if ( keyValue ) {
        key_value = keyValue.replace(/\+/g,'%20').split('=');
        key = tryDecodeURIComponent(key_value[0]);
        if ( isDefined(key) ) {
          var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
          if (!hasOwnProperty.call(obj, key)) {
            obj[key] = val;
          } else if(isArray(obj[key])) {
            obj[key].push(val);
          } else {
            obj[key] = [obj[key],val];
          }
        }
      }
    });
    return obj;
  }
  
  function toKeyValue(obj) {
    var parts = [];
    forEach(obj, function(value, key) {
      if (isArray(value)) {
        forEach(value, function(arrayValue) {
          parts.push(encodeUriQuery(key, true) +
                     (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
        });
      } else {
      parts.push(encodeUriQuery(key, true) +
                 (value === true ? '' : '=' + encodeUriQuery(value, true)));
      }
    });
    return parts.length ? parts.join('&') : '';
  }
  
  
  /**
   * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
   * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
   * segments:
   *    segment       = *pchar
   *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
   *    pct-encoded   = "%" HEXDIG HEXDIG
   *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
   *                     / "*" / "+" / "," / ";" / "="
   */
  function encodeUriSegment(val) {
    return encodeUriQuery(val, true).
               replace(/%26/gi, '&').
               replace(/%3D/gi, '=').
               replace(/%2B/gi, '+');
  }
  
  
  /**
   * This method is intended for encoding *key* or *value* parts of query component. We need a custom
   * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
   * encoded per http://tools.ietf.org/html/rfc3986:
   *    query       = *( pchar / "/" / "?" )
   *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
   *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   *    pct-encoded   = "%" HEXDIG HEXDIG
   *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
   *                     / "*" / "+" / "," / ";" / "="
   */
  function encodeUriQuery(val, pctEncodeSpaces) {
    return encodeURIComponent(val).
               replace(/%40/gi, '@').
               replace(/%3A/gi, ':').
               replace(/%24/g, '$').
               replace(/%2C/gi, ',').
               replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
  }
  
  
  /**
   * @ngdoc directive
   * @name ngApp
   * @module ng
   *
   * @element ANY
   * @param {angular.Module} ngApp an optional application
   *   {@link angular.module module} name to load.
   *
   * @description
   *
   * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
   * designates the **root element** of the application and is typically placed near the root element
   * of the page - e.g. on the `<body>` or `<html>` tags.
   *
   * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
   * found in the document will be used to define the root element to auto-bootstrap as an
   * application. To run multiple applications in an HTML document you must manually bootstrap them using
   * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
   *
   * You can specify an **AngularJS module** to be used as the root module for the application.  This
   * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
   * should contain the application code needed or have dependencies on other modules that will
   * contain the code. See {@link angular.module} for more information.
   *
   * In the example below if the `ngApp` directive were not placed on the `html` element then the
   * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
   * would not be resolved to `3`.
   *
   * `ngApp` is the easiest, and most common, way to bootstrap an application.
   *
   <example module="ngAppDemo">
     <file name="index.html">
     <div ng-controller="ngAppDemoController">
       I can add: {{a}} + {{b}} =  {{ a+b }}
     </div>
     </file>
     <file name="script.js">
     angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
       $scope.a = 1;
       $scope.b = 2;
     });
     </file>
   </example>
   *
   */
  function angularInit(element, bootstrap) {
    var elements = [element],
        appElement,
        module,
        names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
        NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
  
    function append(element) {
      element && elements.push(element);
    }
  
    forEach(names, function(name) {
      names[name] = true;
      append(document.getElementById(name));
      name = name.replace(':', '\\:');
      if (element.querySelectorAll) {
        forEach(element.querySelectorAll('.' + name), append);
        forEach(element.querySelectorAll('.' + name + '\\:'), append);
        forEach(element.querySelectorAll('[' + name + ']'), append);
      }
    });
  
    forEach(elements, function(element) {
      if (!appElement) {
        var className = ' ' + element.className + ' ';
        var match = NG_APP_CLASS_REGEXP.exec(className);
        if (match) {
          appElement = element;
          module = (match[2] || '').replace(/\s+/g, ',');
        } else {
          forEach(element.attributes, function(attr) {
            if (!appElement && names[attr.name]) {
              appElement = element;
              module = attr.value;
            }
          });
        }
      }
    });
    if (appElement) {
      bootstrap(appElement, module ? [module] : []);
    }
  }
  
  /**
   * @ngdoc function
   * @name angular.bootstrap
   * @module ng
   * @description
   * Use this function to manually start up angular application.
   *
   * See: {@link guide/bootstrap Bootstrap}
   *
   * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
   * They must use {@link ng.directive:ngApp ngApp}.
   *
   * Angular will detect if it has been loaded into the browser more than once and only allow the
   * first loaded script to be bootstrapped and will report a warning to the browser console for
   * each of the subsequent scripts. This prevents strange results in applications, where otherwise
   * multiple instances of Angular try to work on the DOM.
   *
   * <example name="multi-bootstrap" module="multi-bootstrap">
   * <file name="index.html">
   * <script src="../../../angular.js"></script>
   * <div ng-controller="BrokenTable">
   *   <table>
   *   <tr>
   *     <th ng-repeat="heading in headings">{{heading}}</th>
   *   </tr>
   *   <tr ng-repeat="filling in fillings">
   *     <td ng-repeat="fill in filling">{{fill}}</td>
   *   </tr>
   * </table>
   * </div>
   * </file>
   * <file name="controller.js">
   * var app = angular.module('multi-bootstrap', [])
   *
   * .controller('BrokenTable', function($scope) {
   *     $scope.headings = ['One', 'Two', 'Three'];
   *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
   * });
   * </file>
   * <file name="protractor.js" type="protractor">
   * it('should only insert one table cell for each item in $scope.fillings', function() {
   *  expect(element.all(by.css('td')).count())
   *      .toBe(9);
   * });
   * </file>
   * </example>
   *
   * @param {DOMElement} element DOM element which is the root of angular application.
   * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
   *     Each item in the array should be the name of a predefined module or a (DI annotated)
   *     function that will be invoked by the injector as a run block.
   *     See: {@link angular.module modules}
   * @returns {auto.$injector} Returns the newly created injector for this app.
   */
  function bootstrap(element, modules) {
    var doBootstrap = function() {
      element = jqLite(element);
  
      if (element.injector()) {
        var tag = (element[0] === document) ? 'document' : startingTag(element);
        //Encode angle brackets to prevent input from being sanitized to empty string #8683
        throw ngMinErr(
            'btstrpd',
            "App Already Bootstrapped with this Element '{0}'",
            tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
      }
  
      modules = modules || [];
      modules.unshift(['$provide', function($provide) {
        $provide.value('$rootElement', element);
      }]);
      modules.unshift('ng');
      var injector = createInjector(modules);
      injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
         function(scope, element, compile, injector, animate) {
          scope.$apply(function() {
            element.data('$injector', injector);
            compile(element)(scope);
          });
        }]
      );
      return injector;
    };
  
    var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
  
    if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
      return doBootstrap();
    }
  
    window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
    angular.resumeBootstrap = function(extraModules) {
      forEach(extraModules, function(module) {
        modules.push(module);
      });
      doBootstrap();
    };
  }
  
  var SNAKE_CASE_REGEXP = /[A-Z]/g;
  function snake_case(name, separator) {
    separator = separator || '_';
    return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
      return (pos ? separator : '') + letter.toLowerCase();
    });
  }
  
  function bindJQuery() {
    // bind to jQuery if present;
    jQuery = window.jQuery;
    // Use jQuery if it exists with proper functionality, otherwise default to us.
    // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
    if (jQuery && jQuery.fn.on) {
      jqLite = jQuery;
      extend(jQuery.fn, {
        scope: JQLitePrototype.scope,
        isolateScope: JQLitePrototype.isolateScope,
        controller: JQLitePrototype.controller,
        injector: JQLitePrototype.injector,
        inheritedData: JQLitePrototype.inheritedData
      });
      // Method signature:
      //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
      jqLitePatchJQueryRemove('remove', true, true, false);
      jqLitePatchJQueryRemove('empty', false, false, false);
      jqLitePatchJQueryRemove('html', false, false, true);
    } else {
      jqLite = JQLite;
    }
    angular.element = jqLite;
  }
  
  /**
   * throw error if the argument is falsy.
   */
  function assertArg(arg, name, reason) {
    if (!arg) {
      throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
    }
    return arg;
  }
  
  function assertArgFn(arg, name, acceptArrayAnnotation) {
    if (acceptArrayAnnotation && isArray(arg)) {
        arg = arg[arg.length - 1];
    }
  
    assertArg(isFunction(arg), name, 'not a function, got ' +
        (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
    return arg;
  }
  
  /**
   * throw error if the name given is hasOwnProperty
   * @param  {String} name    the name to test
   * @param  {String} context the context in which the name is used, such as module or directive
   */
  function assertNotHasOwnProperty(name, context) {
    if (name === 'hasOwnProperty') {
      throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
    }
  }
  
  /**
   * Return the value accessible from the object by path. Any undefined traversals are ignored
   * @param {Object} obj starting object
   * @param {String} path path to traverse
   * @param {boolean} [bindFnToScope=true]
   * @returns {Object} value as accessible by path
   */
  //TODO(misko): this function needs to be removed
  function getter(obj, path, bindFnToScope) {
    if (!path) return obj;
    var keys = path.split('.');
    var key;
    var lastInstance = obj;
    var len = keys.length;
  
    for (var i = 0; i < len; i++) {
      key = keys[i];
      if (obj) {
        obj = (lastInstance = obj)[key];
      }
    }
    if (!bindFnToScope && isFunction(obj)) {
      return bind(lastInstance, obj);
    }
    return obj;
  }
  
  /**
   * Return the DOM siblings between the first and last node in the given array.
   * @param {Array} array like object
   * @returns {DOMElement} object containing the elements
   */
  function getBlockElements(nodes) {
    var startNode = nodes[0],
        endNode = nodes[nodes.length - 1];
    if (startNode === endNode) {
      return jqLite(startNode);
    }
  
    var element = startNode;
    var elements = [element];
  
    do {
      element = element.nextSibling;
      if (!element) break;
      elements.push(element);
    } while (element !== endNode);
  
    return jqLite(elements);
  }
  