Full Code of alferov/angular-file-saver for AI

master bdba5fab87f5 cached
31 files
1.3 MB
329.1k tokens
305 symbols
1 requests
Download .txt
Showing preview only (1,370K chars total). Download the full file or copy to clipboard to get everything.
Repository: alferov/angular-file-saver
Branch: master
Commit: bdba5fab87f5
Files: 31
Total size: 1.3 MB

Directory structure:
gitextract_n7x54ki7/

├── .babelrc
├── .eslintrc
├── .gitignore
├── .travis.yml
├── bower.json
├── dist/
│   ├── angular-file-saver.bundle.js
│   └── angular-file-saver.js
├── docs/
│   ├── assets/
│   │   ├── js/
│   │   │   └── custom.js
│   │   └── stylesheets/
│   │       ├── github-light.css
│   │       ├── normalize.css
│   │       └── stylesheet.css
│   ├── dist/
│   │   ├── examples.css
│   │   └── examples.js
│   ├── index.html
│   └── params.json
├── gulpfile.babel.js
├── karma.conf.js
├── license.md
├── package.json
├── readme.md
├── src/
│   ├── angular-file-saver-bundle.module.js
│   ├── angular-file-saver.module.js
│   ├── angular-file-saver.service.js
│   ├── dependencies/
│   │   ├── blob-bundle.service.js
│   │   ├── blob.service.js
│   │   ├── file-saver-bundle.service.js
│   │   └── file-saver.service.js
│   └── utils/
│       └── utils.service.js
└── test/
    ├── angular-file-saver-bundle.spec.js
    ├── blob-bundle.spec.js
    └── file-saver-bundle.spec.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "presets": ["es2015"]
}


================================================
FILE: .eslintrc
================================================
root: true

env:
  node: true
  browser: true
  jasmine: true
  es6: true

extends:
  "eslint:recommended"

rules:
  indent: [2, 2, { "SwitchCase": 1 }]
  quotes: [2, "single"]
  semi: [2, "always"]
  space-before-function-paren: [2, "never"]

ecmaFeatures:
  modules: true

globals:
  angular: true


================================================
FILE: .gitignore
================================================
node_modules
bower_components
.publish


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - 0.12
  - stable
git:
  depth: 10
before_script:
  - export DISPLAY=:99.0
  - sh -e /etc/init.d/xvfb start


================================================
FILE: bower.json
================================================
{
  "name": "angular-file-saver",
  "version": "1.1.3",
  "main": "dist/angular-file-saver.bundle.js",
  "authors": [
    "Philipp Alferov <philipp.alferov@gmail.com>"
  ],
  "description": "An AngularJS service that implements the HTML5 W3C saveAs() in browsers that do not natively support it",
  "keywords": [
    "filesaver",
    "angular",
    "saveas",
    "blob",
    "save",
    "file"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "blob-polyfill": "~1.0.20150320",
    "file-saver.js": "~1.20150507.2"
  }
}


================================================
FILE: dist/angular-file-saver.bundle.js
================================================
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
		var a = factory();
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';
	/*
	*
	* A AngularJS module that implements the HTML5 W3C saveAs() in browsers that
	* do not natively support it
	*
	* (c) 2015 Philipp Alferov
	* License: MIT
	*
	*/

	module.exports = 'ngFileSaver';

	angular.module('ngFileSaver', [])
	  .factory('FileSaver', ['Blob', 'SaveAs', 'FileSaverUtils', __webpack_require__(1)])
	  .factory('FileSaverUtils', [__webpack_require__(2)])
	  .factory('Blob', ['$window', __webpack_require__(3)])
	  .factory('SaveAs', [__webpack_require__(5)]);


/***/ },
/* 1 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function FileSaver(Blob, SaveAs, FileSaverUtils) {

	  function save(blob, filename, disableAutoBOM) {
	    try {
	      SaveAs(blob, filename, disableAutoBOM);
	    } catch(err) {
	      FileSaverUtils.handleErrors(err.message);
	    }
	  }

	  return {

	    /**
	    * saveAs
	    * Immediately starts saving a file, returns undefined.
	    *
	    * @name saveAs
	    * @function
	    * @param {Blob} data A Blob instance
	    * @param {Object} filename Custom filename (extension is optional)
	    * @param {Boolean} disableAutoBOM Disable automatically provided Unicode
	    * text encoding hints
	    *
	    * @return {Undefined}
	    */

	    saveAs: function(data, filename, disableAutoBOM) {

	      if (!FileSaverUtils.isBlobInstance(data)) {
	        FileSaverUtils.handleErrors('Data argument should be a blob instance');
	      }

	      if (!FileSaverUtils.isString(filename)) {
	        FileSaverUtils.handleErrors('Filename argument should be a string');
	      }

	      return save(data, filename, disableAutoBOM);
	    }
	  };
	};


/***/ },
/* 2 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function FileSaverUtils() {
	  return {
	    handleErrors: function(msg) {
	      throw new Error(msg);
	    },
	    isString: function(obj) {
	      return typeof obj === 'string' || obj instanceof String;
	    },
	    isUndefined: function(obj) {
	      return typeof obj === 'undefined';
	    },
	    isBlobInstance: function(obj) {
	      return obj instanceof Blob;
	    }
	  };
	};


/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	__webpack_require__(4);

	module.exports = function Blob($window) {
	  return $window.Blob;
	};


/***/ },
/* 4 */
/***/ function(module, exports) {

	/* Blob.js
	 * A Blob implementation.
	 * 2014-07-24
	 *
	 * By Eli Grey, http://eligrey.com
	 * By Devin Samarin, https://github.com/dsamarin
	 * License: MIT
	 *   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
	 */

	/*global self, unescape */
	/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
	  plusplus: true */

	/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */

	(function (view) {
		"use strict";

		view.URL = view.URL || view.webkitURL;

		if (view.Blob && view.URL) {
			try {
				new Blob;
				return;
			} catch (e) {}
		}

		// Internally we use a BlobBuilder implementation to base Blob off of
		// in order to support older browsers that only have BlobBuilder
		var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
			var
				  get_class = function(object) {
					return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
				}
				, FakeBlobBuilder = function BlobBuilder() {
					this.data = [];
				}
				, FakeBlob = function Blob(data, type, encoding) {
					this.data = data;
					this.size = data.length;
					this.type = type;
					this.encoding = encoding;
				}
				, FBB_proto = FakeBlobBuilder.prototype
				, FB_proto = FakeBlob.prototype
				, FileReaderSync = view.FileReaderSync
				, FileException = function(type) {
					this.code = this[this.name = type];
				}
				, file_ex_codes = (
					  "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
					+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
				).split(" ")
				, file_ex_code = file_ex_codes.length
				, real_URL = view.URL || view.webkitURL || view
				, real_create_object_URL = real_URL.createObjectURL
				, real_revoke_object_URL = real_URL.revokeObjectURL
				, URL = real_URL
				, btoa = view.btoa
				, atob = view.atob

				, ArrayBuffer = view.ArrayBuffer
				, Uint8Array = view.Uint8Array

				, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
			;
			FakeBlob.fake = FB_proto.fake = true;
			while (file_ex_code--) {
				FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
			}
			// Polyfill URL
			if (!real_URL.createObjectURL) {
				URL = view.URL = function(uri) {
					var
						  uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
						, uri_origin
					;
					uri_info.href = uri;
					if (!("origin" in uri_info)) {
						if (uri_info.protocol.toLowerCase() === "data:") {
							uri_info.origin = null;
						} else {
							uri_origin = uri.match(origin);
							uri_info.origin = uri_origin && uri_origin[1];
						}
					}
					return uri_info;
				};
			}
			URL.createObjectURL = function(blob) {
				var
					  type = blob.type
					, data_URI_header
				;
				if (type === null) {
					type = "application/octet-stream";
				}
				if (blob instanceof FakeBlob) {
					data_URI_header = "data:" + type;
					if (blob.encoding === "base64") {
						return data_URI_header + ";base64," + blob.data;
					} else if (blob.encoding === "URI") {
						return data_URI_header + "," + decodeURIComponent(blob.data);
					} if (btoa) {
						return data_URI_header + ";base64," + btoa(blob.data);
					} else {
						return data_URI_header + "," + encodeURIComponent(blob.data);
					}
				} else if (real_create_object_URL) {
					return real_create_object_URL.call(real_URL, blob);
				}
			};
			URL.revokeObjectURL = function(object_URL) {
				if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
					real_revoke_object_URL.call(real_URL, object_URL);
				}
			};
			FBB_proto.append = function(data/*, endings*/) {
				var bb = this.data;
				// decode data to a binary string
				if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
					var
						  str = ""
						, buf = new Uint8Array(data)
						, i = 0
						, buf_len = buf.length
					;
					for (; i < buf_len; i++) {
						str += String.fromCharCode(buf[i]);
					}
					bb.push(str);
				} else if (get_class(data) === "Blob" || get_class(data) === "File") {
					if (FileReaderSync) {
						var fr = new FileReaderSync;
						bb.push(fr.readAsBinaryString(data));
					} else {
						// async FileReader won't work as BlobBuilder is sync
						throw new FileException("NOT_READABLE_ERR");
					}
				} else if (data instanceof FakeBlob) {
					if (data.encoding === "base64" && atob) {
						bb.push(atob(data.data));
					} else if (data.encoding === "URI") {
						bb.push(decodeURIComponent(data.data));
					} else if (data.encoding === "raw") {
						bb.push(data.data);
					}
				} else {
					if (typeof data !== "string") {
						data += ""; // convert unsupported types to strings
					}
					// decode UTF-16 to binary string
					bb.push(unescape(encodeURIComponent(data)));
				}
			};
			FBB_proto.getBlob = function(type) {
				if (!arguments.length) {
					type = null;
				}
				return new FakeBlob(this.data.join(""), type, "raw");
			};
			FBB_proto.toString = function() {
				return "[object BlobBuilder]";
			};
			FB_proto.slice = function(start, end, type) {
				var args = arguments.length;
				if (args < 3) {
					type = null;
				}
				return new FakeBlob(
					  this.data.slice(start, args > 1 ? end : this.data.length)
					, type
					, this.encoding
				);
			};
			FB_proto.toString = function() {
				return "[object Blob]";
			};
			FB_proto.close = function() {
				this.size = 0;
				delete this.data;
			};
			return FakeBlobBuilder;
		}(view));

		view.Blob = function(blobParts, options) {
			var type = options ? (options.type || "") : "";
			var builder = new BlobBuilder();
			if (blobParts) {
				for (var i = 0, len = blobParts.length; i < len; i++) {
					if (Uint8Array && blobParts[i] instanceof Uint8Array) {
						builder.append(blobParts[i].buffer);
					}
					else {
						builder.append(blobParts[i]);
					}
				}
			}
			var blob = builder.getBlob(type);
			if (!blob.slice && blob.webkitSlice) {
				blob.slice = blob.webkitSlice;
			}
			return blob;
		};

		var getPrototypeOf = Object.getPrototypeOf || function(object) {
			return object.__proto__;
		};
		view.Blob.prototype = getPrototypeOf(new view.Blob());
	}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));


/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	module.exports = function SaveAs() {
	  return __webpack_require__(6).saveAs || function() {};
	};


/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_RESULT__;/* FileSaver.js
	 * A saveAs() FileSaver implementation.
	 * 1.3.2
	 * 2016-06-16 18:25:19
	 *
	 * By Eli Grey, http://eligrey.com
	 * License: MIT
	 *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
	 */

	/*global self */
	/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

	/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */

	var saveAs = saveAs || (function(view) {
		"use strict";
		// IE <10 is explicitly unsupported
		if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
			return;
		}
		var
			  doc = view.document
			  // only get URL when necessary in case Blob.js hasn't overridden it yet
			, get_URL = function() {
				return view.URL || view.webkitURL || view;
			}
			, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
			, can_use_save_link = "download" in save_link
			, click = function(node) {
				var event = new MouseEvent("click");
				node.dispatchEvent(event);
			}
			, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
			, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
			, throw_outside = function(ex) {
				(view.setImmediate || view.setTimeout)(function() {
					throw ex;
				}, 0);
			}
			, force_saveable_type = "application/octet-stream"
			// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
			, arbitrary_revoke_timeout = 1000 * 40 // in ms
			, revoke = function(file) {
				var revoker = function() {
					if (typeof file === "string") { // file is an object URL
						get_URL().revokeObjectURL(file);
					} else { // file is a File
						file.remove();
					}
				};
				setTimeout(revoker, arbitrary_revoke_timeout);
			}
			, dispatch = function(filesaver, event_types, event) {
				event_types = [].concat(event_types);
				var i = event_types.length;
				while (i--) {
					var listener = filesaver["on" + event_types[i]];
					if (typeof listener === "function") {
						try {
							listener.call(filesaver, event || filesaver);
						} catch (ex) {
							throw_outside(ex);
						}
					}
				}
			}
			, auto_bom = function(blob) {
				// prepend BOM for UTF-8 XML and text/* types (including HTML)
				// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
				if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
					return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
				}
				return blob;
			}
			, FileSaver = function(blob, name, no_auto_bom) {
				if (!no_auto_bom) {
					blob = auto_bom(blob);
				}
				// First try a.download, then web filesystem, then object URLs
				var
					  filesaver = this
					, type = blob.type
					, force = type === force_saveable_type
					, object_url
					, dispatch_all = function() {
						dispatch(filesaver, "writestart progress write writeend".split(" "));
					}
					// on any filesys errors revert to saving with object URLs
					, fs_error = function() {
						if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
							// Safari doesn't allow downloading of blob urls
							var reader = new FileReader();
							reader.onloadend = function() {
								var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
								var popup = view.open(url, '_blank');
								if(!popup) view.location.href = url;
								url=undefined; // release reference before dispatching
								filesaver.readyState = filesaver.DONE;
								dispatch_all();
							};
							reader.readAsDataURL(blob);
							filesaver.readyState = filesaver.INIT;
							return;
						}
						// don't create more object URLs than needed
						if (!object_url) {
							object_url = get_URL().createObjectURL(blob);
						}
						if (force) {
							view.location.href = object_url;
						} else {
							var opened = view.open(object_url, "_blank");
							if (!opened) {
								// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
								view.location.href = object_url;
							}
						}
						filesaver.readyState = filesaver.DONE;
						dispatch_all();
						revoke(object_url);
					}
				;
				filesaver.readyState = filesaver.INIT;

				if (can_use_save_link) {
					object_url = get_URL().createObjectURL(blob);
					setTimeout(function() {
						save_link.href = object_url;
						save_link.download = name;
						click(save_link);
						dispatch_all();
						revoke(object_url);
						filesaver.readyState = filesaver.DONE;
					});
					return;
				}

				fs_error();
			}
			, FS_proto = FileSaver.prototype
			, saveAs = function(blob, name, no_auto_bom) {
				return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
			}
		;
		// IE 10+ (native saveAs)
		if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
			return function(blob, name, no_auto_bom) {
				name = name || blob.name || "download";

				if (!no_auto_bom) {
					blob = auto_bom(blob);
				}
				return navigator.msSaveOrOpenBlob(blob, name);
			};
		}

		FS_proto.abort = function(){};
		FS_proto.readyState = FS_proto.INIT = 0;
		FS_proto.WRITING = 1;
		FS_proto.DONE = 2;

		FS_proto.error =
		FS_proto.onwritestart =
		FS_proto.onprogress =
		FS_proto.onwrite =
		FS_proto.onabort =
		FS_proto.onerror =
		FS_proto.onwriteend =
			null;

		return saveAs;
	}(
		   typeof self !== "undefined" && self
		|| typeof window !== "undefined" && window
		|| this.content
	));
	// `self` is undefined in Firefox for Android content script context
	// while `this` is nsIContentFrameMessageManager
	// with an attribute `content` that corresponds to the window

	if (typeof module !== "undefined" && module.exports) {
	  module.exports.saveAs = saveAs;
	} else if (("function" !== "undefined" && __webpack_require__(7) !== null) && (__webpack_require__(8) !== null)) {
	  !(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
	    return saveAs;
	  }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	}


/***/ },
/* 7 */
/***/ function(module, exports) {

	module.exports = function() { throw new Error("define cannot be used indirect"); };


/***/ },
/* 8 */
/***/ function(module, exports) {

	/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {module.exports = __webpack_amd_options__;

	/* WEBPACK VAR INJECTION */}.call(exports, {}))

/***/ }
/******/ ])
});
;

================================================
FILE: dist/angular-file-saver.js
================================================
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
		var a = factory();
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	/*
	*
	* A AngularJS module that implements the HTML5 W3C saveAs() in browsers that
	* do not natively support it
	*
	* (c) 2015 Philipp Alferov
	* License: MIT
	*
	*/

	module.exports = 'ngFileSaver';

	angular.module('ngFileSaver', [])
	  .factory('FileSaver', ['Blob', 'SaveAs', 'FileSaverUtils', __webpack_require__(1)])
	  .factory('FileSaverUtils', [__webpack_require__(2)])
	  .factory('Blob', ['$window', 'FileSaverUtils', __webpack_require__(3)])
	  .factory('SaveAs', ['$window', 'FileSaverUtils', __webpack_require__(4)]);


/***/ },
/* 1 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function FileSaver(Blob, SaveAs, FileSaverUtils) {

	  function save(blob, filename, disableAutoBOM) {
	    try {
	      SaveAs(blob, filename, disableAutoBOM);
	    } catch(err) {
	      FileSaverUtils.handleErrors(err.message);
	    }
	  }

	  return {

	    /**
	    * saveAs
	    * Immediately starts saving a file, returns undefined.
	    *
	    * @name saveAs
	    * @function
	    * @param {Blob} data A Blob instance
	    * @param {Object} filename Custom filename (extension is optional)
	    * @param {Boolean} disableAutoBOM Disable automatically provided Unicode
	    * text encoding hints
	    *
	    * @return {Undefined}
	    */

	    saveAs: function(data, filename, disableAutoBOM) {

	      if (!FileSaverUtils.isBlobInstance(data)) {
	        FileSaverUtils.handleErrors('Data argument should be a blob instance');
	      }

	      if (!FileSaverUtils.isString(filename)) {
	        FileSaverUtils.handleErrors('Filename argument should be a string');
	      }

	      return save(data, filename, disableAutoBOM);
	    }
	  };
	};


/***/ },
/* 2 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function FileSaverUtils() {
	  return {
	    handleErrors: function(msg) {
	      throw new Error(msg);
	    },
	    isString: function(obj) {
	      return typeof obj === 'string' || obj instanceof String;
	    },
	    isUndefined: function(obj) {
	      return typeof obj === 'undefined';
	    },
	    isBlobInstance: function(obj) {
	      return obj instanceof Blob;
	    }
	  };
	};


/***/ },
/* 3 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function Blob($window, FileSaverUtils) {
	  var blob = $window.Blob;

	  if (FileSaverUtils.isUndefined(blob)) {
	    FileSaverUtils.handleErrors('Blob is not supported. Please include blob polyfilll');
	  }

	  return blob;
	};


/***/ },
/* 4 */
/***/ function(module, exports) {

	'use strict';

	module.exports = function SaveAs($window, FileSaverUtils) {
	  var saveAs = $window.saveAs;

	  if (FileSaverUtils.isUndefined(saveAs)) {
	    FileSaverUtils.handleErrors('saveAs is not supported. Please include saveAs polyfill');
	  }

	  return saveAs;
	};


/***/ }
/******/ ])
});
;

================================================
FILE: docs/assets/js/custom.js
================================================
'use strict';

var angular = require('angular');
require('../../../src/angular-file-saver-bundle.module');

function DownloadText(FileSaver, Blob, $timeout) {
  var vm = this;

  vm.val = {
    text: 'Hey ho lets go!'
  };

  vm.download = function(text) {
    var data = new Blob([text], { type: 'text/plain;charset=utf-8' });
    $timeout(FileSaver.saveAs.bind(FileSaver, data, 'text.txt'), 100);
  };
}

angular
  .module('fileSaverExample', ['ngFileSaver'])
  .controller('DownloadText', ['FileSaver', 'Blob', '$timeout', DownloadText]);


================================================
FILE: docs/assets/stylesheets/github-light.css
================================================
/*
   Copyright 2014 GitHub Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

.pl-c /* comment */ {
  color: #969896;
}

.pl-c1      /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
.pl-s .pl-v /* string variable */ {
  color: #0086b3;
}

.pl-e  /* entity */,
.pl-en /* entity.name */ {
  color: #795da3;
}

.pl-s .pl-s1 /* string source */,
.pl-smi      /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
  color: #333;
}

.pl-ent /* entity.name.tag */ {
  color: #63a35c;
}

.pl-k /* keyword, storage, storage.type */ {
  color: #a71d5d;
}

.pl-pds              /* punctuation.definition.string, string.regexp.character-class */,
.pl-s                /* string */,
.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
.pl-sr               /* string.regexp */,
.pl-sr .pl-cce       /* string.regexp constant.character.escape */,
.pl-sr .pl-sra       /* string.regexp string.regexp.arbitrary-repitition */,
.pl-sr .pl-sre       /* string.regexp source.ruby.embedded */ {
  color: #183691;
}

.pl-v /* variable */ {
  color: #ed6a43;
}

.pl-id /* invalid.deprecated */ {
  color: #b52a1d;
}

.pl-ii /* invalid.illegal */ {
  background-color: #b52a1d;
  color: #f8f8f8;
}

.pl-sr .pl-cce /* string.regexp constant.character.escape */ {
  color: #63a35c;
  font-weight: bold;
}

.pl-ml /* markup.list */ {
  color: #693a17;
}

.pl-mh        /* markup.heading */,
.pl-mh .pl-en /* markup.heading entity.name */,
.pl-ms        /* meta.separator */ {
  color: #1d3e81;
  font-weight: bold;
}

.pl-mq /* markup.quote */ {
  color: #008080;
}

.pl-mi /* markup.italic */ {
  color: #333;
  font-style: italic;
}

.pl-mb /* markup.bold */ {
  color: #333;
  font-weight: bold;
}

.pl-md /* markup.deleted, meta.diff.header.from-file */ {
  background-color: #ffecec;
  color: #bd2c00;
}

.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
  background-color: #eaffea;
  color: #55a532;
}

.pl-mdr /* meta.diff.range */ {
  color: #795da3;
  font-weight: bold;
}

.pl-mo /* meta.output */ {
  color: #1d3e81;
}



================================================
FILE: docs/assets/stylesheets/normalize.css
================================================
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */

/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */

html {
  font-family: sans-serif; /* 1 */
  -ms-text-size-adjust: 100%; /* 2 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/**
 * Remove default margin.
 */

body {
  margin: 0;
}

/* HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined for any HTML5 element in IE 8/9.
 * Correct `block` display not defined for `details` or `summary` in IE 10/11
 * and Firefox.
 * Correct `block` display not defined for `main` in IE 11.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
  display: block;
}

/**
 * 1. Correct `inline-block` display not defined in IE 8/9.
 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 */

audio,
canvas,
progress,
video {
  display: inline-block; /* 1 */
  vertical-align: baseline; /* 2 */
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
  display: none;
  height: 0;
}

/**
 * Address `[hidden]` styling not present in IE 8/9/10.
 * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
 */

[hidden],
template {
  display: none;
}

/* Links
   ========================================================================== */

/**
 * Remove the gray background color from active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */

a:active,
a:hover {
  outline: 0;
}

/* Text-level semantics
   ========================================================================== */

/**
 * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
 */

abbr[title] {
  border-bottom: 1px dotted;
}

/**
 * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
 */

b,
strong {
  font-weight: bold;
}

/**
 * Address styling not present in Safari and Chrome.
 */

dfn {
  font-style: italic;
}

/**
 * Address variable `h1` font-size and margin within `section` and `article`
 * contexts in Firefox 4+, Safari, and Chrome.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/**
 * Address styling not present in IE 8/9.
 */

mark {
  background: #ff0;
  color: #000;
}

/**
 * Address inconsistent and variable font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove border when inside `a` element in IE 8/9/10.
 */

img {
  border: 0;
}

/**
 * Correct overflow not hidden in IE 9/10/11.
 */

svg:not(:root) {
  overflow: hidden;
}

/* Grouping content
   ========================================================================== */

/**
 * Address margin not present in IE 8/9 and Safari.
 */

figure {
  margin: 1em 40px;
}

/**
 * Address differences between Firefox and other browsers.
 */

hr {
  box-sizing: content-box;
  height: 0;
}

/**
 * Contain overflow in all browsers.
 */

pre {
  overflow: auto;
}

/**
 * Address odd `em`-unit font size rendering in all browsers.
 */

code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em;
}

/* Forms
   ========================================================================== */

/**
 * Known limitation: by default, Chrome and Safari on OS X allow very limited
 * styling of `select`, unless a `border` property is set.
 */

/**
 * 1. Correct color not being inherited.
 *    Known issue: affects color of disabled elements.
 * 2. Correct font properties not being inherited.
 * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
 */

button,
input,
optgroup,
select,
textarea {
  color: inherit; /* 1 */
  font: inherit; /* 2 */
  margin: 0; /* 3 */
}

/**
 * Address `overflow` set to `hidden` in IE 8/9/10/11.
 */

button {
  overflow: visible;
}

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
 * Correct `select` style inheritance in Firefox.
 */

button,
select {
  text-transform: none;
}

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */

button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button; /* 2 */
  cursor: pointer; /* 3 */
}

/**
 * Re-set default cursor for disabled elements.
 */

button[disabled],
html input[disabled] {
  cursor: default;
}

/**
 * Remove inner padding and border in Firefox 4+.
 */

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0;
}

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */

input {
  line-height: normal;
}

/**
 * It's recommended that you don't attempt to style these elements.
 * Firefox's implementation doesn't respect box-sizing, padding, or width.
 *
 * 1. Address box sizing set to `content-box` in IE 8/9/10.
 * 2. Remove excess padding in IE 8/9/10.
 */

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Fix the cursor style for Chrome's increment/decrement buttons. For certain
 * `font-size` values of the `input`, it causes the cursor style of the
 * decrement button to change from `default` to `text`.
 */

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
 *    (include `-moz` to future-proof).
 */

input[type="search"] {
  -webkit-appearance: textfield; /* 1 */ /* 2 */
  box-sizing: content-box;
}

/**
 * Remove inner padding and search cancel button in Safari and Chrome on OS X.
 * Safari (but not Chrome) clips the cancel button when the search input has
 * padding (and `textfield` appearance).
 */

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * Define consistent border, margin, and padding.
 */

fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em;
}

/**
 * 1. Correct `color` not being inherited in IE 8/9/10/11.
 * 2. Remove padding so people aren't caught out if they zero out fieldsets.
 */

legend {
  border: 0; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Remove default vertical scrollbar in IE 8/9/10/11.
 */

textarea {
  overflow: auto;
}

/**
 * Don't inherit the `font-weight` (applied by a rule above).
 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
 */

optgroup {
  font-weight: bold;
}

/* Tables
   ========================================================================== */

/**
 * Remove most spacing between table cells.
 */

table {
  border-collapse: collapse;
  border-spacing: 0;
}

td,
th {
  padding: 0;
}


================================================
FILE: docs/assets/stylesheets/stylesheet.css
================================================
* {
  box-sizing: border-box;
}
body {
  padding: 0;
  margin: 0;
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: #606c71;
}
textarea {
  width: 100%;
  font-size: 0.9rem;
  padding: 10px;
}
a {
  color: #1e6bb8;
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
.btn {
  display: inline-block;
  margin-bottom: 1rem;
  color: rgba(255, 255, 255, 0.7);
  background-color: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.2);
  border-style: solid;
  border-width: 1px;
  border-radius: 0.3rem;
  transition: color 0.2s, background-color 0.2s, border-color 0.2s;
}
.btn + .btn {
  margin-left: 1rem;
}
.btn:hover {
  color: rgba(255, 255, 255, 0.8);
  text-decoration: none;
  background-color: rgba(255, 255, 255, 0.2);
  border-color: rgba(255, 255, 255, 0.3);
}
.btn-dark {
  background-color: #2980b9;
}
.btn-dark:hover {
  background-color: #1067A0;
}
@media screen and (min-width: 64em) {
  .btn {
    padding: 0.75rem 1rem;
  }
  .btn-small {
    padding: 0.5rem 0.8rem;
    font-size: 0.9rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .btn {
    padding: 0.6rem 0.9rem;
    font-size: 0.9rem;
  }
}
@media screen and (max-width: 42em) {
  .btn {
    display: block;
    width: 100%;
    padding: 0.75rem;
    font-size: 0.9rem;
  }
  .btn + .btn {
    margin-top: 1rem;
    margin-left: 0;
  }
}
.page-header {
  color: #fff;
  text-align: center;
  background-color: #159957;
  background-image: linear-gradient(120deg, #155799, #159957);
}
@media screen and (min-width: 64em) {
  .page-header {
    padding: 5rem 6rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .page-header {
    padding: 3rem 4rem;
  }
}
@media screen and (max-width: 42em) {
  .page-header {
    padding: 2rem 1rem;
  }
}
.project-name {
  margin-top: 0;
  margin-bottom: 0.1rem;
}
@media screen and (min-width: 64em) {
  .project-name {
    font-size: 3.25rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .project-name {
    font-size: 2.25rem;
  }
}
@media screen and (max-width: 42em) {
  .project-name {
    font-size: 1.75rem;
  }
}
.project-tagline {
  margin-bottom: 2rem;
  font-weight: normal;
  opacity: 0.7;
}
@media screen and (min-width: 64em) {
  .project-tagline {
    font-size: 1.25rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .project-tagline {
    font-size: 1.15rem;
  }
}
@media screen and (max-width: 42em) {
  .project-tagline {
    font-size: 1rem;
  }
}
.main-content:first-child {
  margin-top: 0;
}
.main-content img {
  max-width: 100%;
}
.main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6 {
  margin-top: 2rem;
  margin-bottom: 1rem;
  font-weight: normal;
  color: #159957;
}
.main-content p {
  margin-bottom: 1em;
}
.main-content code {
  padding: 2px 4px;
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
  font-size: 0.9rem;
  color: #383e41;
  background-color: #f3f6fa;
  border-radius: 0.3rem;
}
.main-content pre {
  padding: 0.8rem;
  margin-top: 0;
  margin-bottom: 1rem;
  font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace;
  color: #567482;
  word-wrap: normal;
  background-color: #f3f6fa;
  border: solid 1px #dce6f0;
  border-radius: 0.3rem;
}
.main-content pre > code {
  padding: 0;
  margin: 0;
  font-size: 0.9rem;
  color: #567482;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0;
}
.main-content .highlight {
  margin-bottom: 1rem;
}
.main-content .highlight pre {
  margin-bottom: 0;
  word-break: normal;
}
.main-content .highlight pre, .main-content pre {
  padding: 0.8rem;
  overflow: auto;
  font-size: 0.9rem;
  line-height: 1.45;
  border-radius: 0.3rem;
}
.main-content pre code, .main-content pre tt {
  display: inline;
  max-width: initial;
  padding: 0;
  margin: 0;
  overflow: initial;
  line-height: inherit;
  word-wrap: normal;
  background-color: transparent;
  border: 0;
}
.main-content pre code:before, .main-content pre code:after, .main-content pre tt:before, .main-content pre tt:after {
  content: normal;
}
.main-content ul, .main-content ol {
  margin-top: 0;
}
.main-content blockquote {
  padding: 0 1rem;
  margin-left: 0;
  color: #819198;
  border-left: 0.3rem solid #dce6f0;
}
.main-content blockquote >:first-child {
  margin-top: 0;
}
.main-content blockquote >:last-child {
  margin-bottom: 0;
}
.main-content table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: normal;
  word-break: keep-all;
}
.main-content table th {
  font-weight: bold;
}
.main-content table th, .main-content table td {
  padding: 0.5rem 1rem;
  border: 1px solid #e9ebec;
}
.main-content dl {
  padding: 0;
}
.main-content dl dt {
  padding: 0;
  margin-top: 1rem;
  font-size: 1rem;
  font-weight: bold;
}
.main-content dl dd {
  padding: 0;
  margin-bottom: 1rem;
}
.main-content hr {
  height: 2px;
  padding: 0;
  margin: 1rem 0;
  background-color: #eff0f1;
  border: 0;
}
@media screen and (min-width: 64em) {
  .main-content {
    max-width: 64rem;
    padding: 2rem 6rem;
    margin: 0 auto;
    font-size: 1.1rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .main-content {
    padding: 2rem 4rem;
    font-size: 1.1rem;
  }
}
@media screen and (max-width: 42em) {
  .main-content {
    padding: 2rem 1rem;
    font-size: 1rem;
  }
}
.site-footer {
  padding-top: 2rem;
  margin-top: 2rem;
  border-top: solid 1px #eff0f1;
}
.site-footer-owner {
  display: block;
  font-weight: bold;
}
.site-footer-credits {
  color: #819198;
}
@media screen and (min-width: 64em) {
  .site-footer {
    font-size: 1rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .site-footer {
    font-size: 1rem;
  }
}
@media screen and (max-width: 42em) {
  .site-footer {
    font-size: 0.9rem;
  }
}


================================================
FILE: docs/dist/examples.css
================================================
/*
   Copyright 2014 GitHub Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

.pl-c /* comment */ {
  color: #969896;
}

.pl-c1      /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */,
.pl-s .pl-v /* string variable */ {
  color: #0086b3;
}

.pl-e  /* entity */,
.pl-en /* entity.name */ {
  color: #795da3;
}

.pl-s .pl-s1 /* string source */,
.pl-smi      /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ {
  color: #333;
}

.pl-ent /* entity.name.tag */ {
  color: #63a35c;
}

.pl-k /* keyword, storage, storage.type */ {
  color: #a71d5d;
}

.pl-pds              /* punctuation.definition.string, string.regexp.character-class */,
.pl-s                /* string */,
.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
.pl-sr               /* string.regexp */,
.pl-sr .pl-cce       /* string.regexp constant.character.escape */,
.pl-sr .pl-sra       /* string.regexp string.regexp.arbitrary-repitition */,
.pl-sr .pl-sre       /* string.regexp source.ruby.embedded */ {
  color: #183691;
}

.pl-v /* variable */ {
  color: #ed6a43;
}

.pl-id /* invalid.deprecated */ {
  color: #b52a1d;
}

.pl-ii /* invalid.illegal */ {
  background-color: #b52a1d;
  color: #f8f8f8;
}

.pl-sr .pl-cce /* string.regexp constant.character.escape */ {
  color: #63a35c;
  font-weight: bold;
}

.pl-ml /* markup.list */ {
  color: #693a17;
}

.pl-mh        /* markup.heading */,
.pl-mh .pl-en /* markup.heading entity.name */,
.pl-ms        /* meta.separator */ {
  color: #1d3e81;
  font-weight: bold;
}

.pl-mq /* markup.quote */ {
  color: #008080;
}

.pl-mi /* markup.italic */ {
  color: #333;
  font-style: italic;
}

.pl-mb /* markup.bold */ {
  color: #333;
  font-weight: bold;
}

.pl-md /* markup.deleted, meta.diff.header.from-file */ {
  background-color: #ffecec;
  color: #bd2c00;
}

.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
  background-color: #eaffea;
  color: #55a532;
}

.pl-mdr /* meta.diff.range */ {
  color: #795da3;
  font-weight: bold;
}

.pl-mo /* meta.output */ {
  color: #1d3e81;
}


/*! normalize.css v3.0.2 | MIT License | git.io/normalize */

/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */

html {
  font-family: sans-serif; /* 1 */
  -ms-text-size-adjust: 100%; /* 2 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/**
 * Remove default margin.
 */

body {
  margin: 0;
}

/* HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined for any HTML5 element in IE 8/9.
 * Correct `block` display not defined for `details` or `summary` in IE 10/11
 * and Firefox.
 * Correct `block` display not defined for `main` in IE 11.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
  display: block;
}

/**
 * 1. Correct `inline-block` display not defined in IE 8/9.
 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 */

audio,
canvas,
progress,
video {
  display: inline-block; /* 1 */
  vertical-align: baseline; /* 2 */
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
  display: none;
  height: 0;
}

/**
 * Address `[hidden]` styling not present in IE 8/9/10.
 * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
 */

[hidden],
template {
  display: none;
}

/* Links
   ========================================================================== */

/**
 * Remove the gray background color from active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */

a:active,
a:hover {
  outline: 0;
}

/* Text-level semantics
   ========================================================================== */

/**
 * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
 */

abbr[title] {
  border-bottom: 1px dotted;
}

/**
 * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
 */

b,
strong {
  font-weight: bold;
}

/**
 * Address styling not present in Safari and Chrome.
 */

dfn {
  font-style: italic;
}

/**
 * Address variable `h1` font-size and margin within `section` and `article`
 * contexts in Firefox 4+, Safari, and Chrome.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/**
 * Address styling not present in IE 8/9.
 */

mark {
  background: #ff0;
  color: #000;
}

/**
 * Address inconsistent and variable font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove border when inside `a` element in IE 8/9/10.
 */

img {
  border: 0;
}

/**
 * Correct overflow not hidden in IE 9/10/11.
 */

svg:not(:root) {
  overflow: hidden;
}

/* Grouping content
   ========================================================================== */

/**
 * Address margin not present in IE 8/9 and Safari.
 */

figure {
  margin: 1em 40px;
}

/**
 * Address differences between Firefox and other browsers.
 */

hr {
  box-sizing: content-box;
  height: 0;
}

/**
 * Contain overflow in all browsers.
 */

pre {
  overflow: auto;
}

/**
 * Address odd `em`-unit font size rendering in all browsers.
 */

code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em;
}

/* Forms
   ========================================================================== */

/**
 * Known limitation: by default, Chrome and Safari on OS X allow very limited
 * styling of `select`, unless a `border` property is set.
 */

/**
 * 1. Correct color not being inherited.
 *    Known issue: affects color of disabled elements.
 * 2. Correct font properties not being inherited.
 * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
 */

button,
input,
optgroup,
select,
textarea {
  color: inherit; /* 1 */
  font: inherit; /* 2 */
  margin: 0; /* 3 */
}

/**
 * Address `overflow` set to `hidden` in IE 8/9/10/11.
 */

button {
  overflow: visible;
}

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
 * Correct `select` style inheritance in Firefox.
 */

button,
select {
  text-transform: none;
}

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */

button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button; /* 2 */
  cursor: pointer; /* 3 */
}

/**
 * Re-set default cursor for disabled elements.
 */

button[disabled],
html input[disabled] {
  cursor: default;
}

/**
 * Remove inner padding and border in Firefox 4+.
 */

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0;
}

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */

input {
  line-height: normal;
}

/**
 * It's recommended that you don't attempt to style these elements.
 * Firefox's implementation doesn't respect box-sizing, padding, or width.
 *
 * 1. Address box sizing set to `content-box` in IE 8/9/10.
 * 2. Remove excess padding in IE 8/9/10.
 */

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Fix the cursor style for Chrome's increment/decrement buttons. For certain
 * `font-size` values of the `input`, it causes the cursor style of the
 * decrement button to change from `default` to `text`.
 */

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
 *    (include `-moz` to future-proof).
 */

input[type="search"] {
  -webkit-appearance: textfield; /* 1 */ /* 2 */
  box-sizing: content-box;
}

/**
 * Remove inner padding and search cancel button in Safari and Chrome on OS X.
 * Safari (but not Chrome) clips the cancel button when the search input has
 * padding (and `textfield` appearance).
 */

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * Define consistent border, margin, and padding.
 */

fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em;
}

/**
 * 1. Correct `color` not being inherited in IE 8/9/10/11.
 * 2. Remove padding so people aren't caught out if they zero out fieldsets.
 */

legend {
  border: 0; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Remove default vertical scrollbar in IE 8/9/10/11.
 */

textarea {
  overflow: auto;
}

/**
 * Don't inherit the `font-weight` (applied by a rule above).
 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
 */

optgroup {
  font-weight: bold;
}

/* Tables
   ========================================================================== */

/**
 * Remove most spacing between table cells.
 */

table {
  border-collapse: collapse;
  border-spacing: 0;
}

td,
th {
  padding: 0;
}

* {
  box-sizing: border-box;
}
body {
  padding: 0;
  margin: 0;
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: #606c71;
}
textarea {
  width: 100%;
  font-size: 0.9rem;
  padding: 10px;
}
a {
  color: #1e6bb8;
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
.btn {
  display: inline-block;
  margin-bottom: 1rem;
  color: rgba(255, 255, 255, 0.7);
  background-color: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.2);
  border-style: solid;
  border-width: 1px;
  border-radius: 0.3rem;
  transition: color 0.2s, background-color 0.2s, border-color 0.2s;
}
.btn + .btn {
  margin-left: 1rem;
}
.btn:hover {
  color: rgba(255, 255, 255, 0.8);
  text-decoration: none;
  background-color: rgba(255, 255, 255, 0.2);
  border-color: rgba(255, 255, 255, 0.3);
}
.btn-dark {
  background-color: #2980b9;
}
.btn-dark:hover {
  background-color: #1067A0;
}
@media screen and (min-width: 64em) {
  .btn {
    padding: 0.75rem 1rem;
  }
  .btn-small {
    padding: 0.5rem 0.8rem;
    font-size: 0.9rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .btn {
    padding: 0.6rem 0.9rem;
    font-size: 0.9rem;
  }
}
@media screen and (max-width: 42em) {
  .btn {
    display: block;
    width: 100%;
    padding: 0.75rem;
    font-size: 0.9rem;
  }
  .btn + .btn {
    margin-top: 1rem;
    margin-left: 0;
  }
}
.page-header {
  color: #fff;
  text-align: center;
  background-color: #159957;
  background-image: linear-gradient(120deg, #155799, #159957);
}
@media screen and (min-width: 64em) {
  .page-header {
    padding: 5rem 6rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .page-header {
    padding: 3rem 4rem;
  }
}
@media screen and (max-width: 42em) {
  .page-header {
    padding: 2rem 1rem;
  }
}
.project-name {
  margin-top: 0;
  margin-bottom: 0.1rem;
}
@media screen and (min-width: 64em) {
  .project-name {
    font-size: 3.25rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .project-name {
    font-size: 2.25rem;
  }
}
@media screen and (max-width: 42em) {
  .project-name {
    font-size: 1.75rem;
  }
}
.project-tagline {
  margin-bottom: 2rem;
  font-weight: normal;
  opacity: 0.7;
}
@media screen and (min-width: 64em) {
  .project-tagline {
    font-size: 1.25rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .project-tagline {
    font-size: 1.15rem;
  }
}
@media screen and (max-width: 42em) {
  .project-tagline {
    font-size: 1rem;
  }
}
.main-content:first-child {
  margin-top: 0;
}
.main-content img {
  max-width: 100%;
}
.main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6 {
  margin-top: 2rem;
  margin-bottom: 1rem;
  font-weight: normal;
  color: #159957;
}
.main-content p {
  margin-bottom: 1em;
}
.main-content code {
  padding: 2px 4px;
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
  font-size: 0.9rem;
  color: #383e41;
  background-color: #f3f6fa;
  border-radius: 0.3rem;
}
.main-content pre {
  padding: 0.8rem;
  margin-top: 0;
  margin-bottom: 1rem;
  font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace;
  color: #567482;
  word-wrap: normal;
  background-color: #f3f6fa;
  border: solid 1px #dce6f0;
  border-radius: 0.3rem;
}
.main-content pre > code {
  padding: 0;
  margin: 0;
  font-size: 0.9rem;
  color: #567482;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0;
}
.main-content .highlight {
  margin-bottom: 1rem;
}
.main-content .highlight pre {
  margin-bottom: 0;
  word-break: normal;
}
.main-content .highlight pre, .main-content pre {
  padding: 0.8rem;
  overflow: auto;
  font-size: 0.9rem;
  line-height: 1.45;
  border-radius: 0.3rem;
}
.main-content pre code, .main-content pre tt {
  display: inline;
  max-width: initial;
  padding: 0;
  margin: 0;
  overflow: initial;
  line-height: inherit;
  word-wrap: normal;
  background-color: transparent;
  border: 0;
}
.main-content pre code:before, .main-content pre code:after, .main-content pre tt:before, .main-content pre tt:after {
  content: normal;
}
.main-content ul, .main-content ol {
  margin-top: 0;
}
.main-content blockquote {
  padding: 0 1rem;
  margin-left: 0;
  color: #819198;
  border-left: 0.3rem solid #dce6f0;
}
.main-content blockquote >:first-child {
  margin-top: 0;
}
.main-content blockquote >:last-child {
  margin-bottom: 0;
}
.main-content table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: normal;
  word-break: keep-all;
}
.main-content table th {
  font-weight: bold;
}
.main-content table th, .main-content table td {
  padding: 0.5rem 1rem;
  border: 1px solid #e9ebec;
}
.main-content dl {
  padding: 0;
}
.main-content dl dt {
  padding: 0;
  margin-top: 1rem;
  font-size: 1rem;
  font-weight: bold;
}
.main-content dl dd {
  padding: 0;
  margin-bottom: 1rem;
}
.main-content hr {
  height: 2px;
  padding: 0;
  margin: 1rem 0;
  background-color: #eff0f1;
  border: 0;
}
@media screen and (min-width: 64em) {
  .main-content {
    max-width: 64rem;
    padding: 2rem 6rem;
    margin: 0 auto;
    font-size: 1.1rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .main-content {
    padding: 2rem 4rem;
    font-size: 1.1rem;
  }
}
@media screen and (max-width: 42em) {
  .main-content {
    padding: 2rem 1rem;
    font-size: 1rem;
  }
}
.site-footer {
  padding-top: 2rem;
  margin-top: 2rem;
  border-top: solid 1px #eff0f1;
}
.site-footer-owner {
  display: block;
  font-weight: bold;
}
.site-footer-credits {
  color: #819198;
}
@media screen and (min-width: 64em) {
  .site-footer {
    font-size: 1rem;
  }
}
@media screen and (min-width: 42em) and (max-width: 64em) {
  .site-footer {
    font-size: 1rem;
  }
}
@media screen and (max-width: 42em) {
  .site-footer {
    font-size: 0.9rem;
  }
}


================================================
FILE: docs/dist/examples.js
================================================
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
		var a = factory();
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	var angular = __webpack_require__(1);
	__webpack_require__(3);

	function DownloadText(FileSaver, Blob, $timeout) {
	  var vm = this;

	  vm.val = {
	    text: 'Hey ho lets go!'
	  };

	  vm.download = function(text) {
	    var data = new Blob([text], { type: 'text/plain;charset=utf-8' });
	    $timeout(FileSaver.saveAs.bind(FileSaver, data, 'text.txt'), 100);
	  };
	}

	angular
	  .module('fileSaverExample', ['ngFileSaver'])
	  .controller('DownloadText', ['FileSaver', 'Blob', '$timeout', DownloadText]);


/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	__webpack_require__(2);
	module.exports = angular;


/***/ },
/* 2 */
/***/ function(module, exports) {

	/**
	 * @license AngularJS v1.6.1
	 * (c) 2010-2016 Google, Inc. http://angularjs.org
	 * License: MIT
	 */
	(function(window) {'use strict';

	/**
	 * @description
	 *
	 * This object provides a utility for producing rich Error messages within
	 * Angular. It can be called as follows:
	 *
	 * var exampleMinErr = minErr('example');
	 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
	 *
	 * The above creates an instance of minErr in the example namespace. The
	 * resulting error will have a namespaced error code of example.one.  The
	 * resulting error will replace {0} with the value of foo, and {1} with the
	 * value of bar. The object is not restricted in the number of arguments it can
	 * take.
	 *
	 * If fewer arguments are specified than necessary for interpolation, the extra
	 * interpolation markers will be preserved in the final string.
	 *
	 * Since data will be parsed statically during a build step, some restrictions
	 * are applied with respect to how minErr instances are created and called.
	 * Instances should have names of the form namespaceMinErr for a minErr created
	 * using minErr('namespace') . Error codes, namespaces and template strings
	 * should all be static strings, not variables or general expressions.
	 *
	 * @param {string} module The namespace to use for the new minErr instance.
	 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
	 *   error from returned function, for cases when a particular type of error is useful.
	 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
	 */

	function minErr(module, ErrorConstructor) {
	  ErrorConstructor = ErrorConstructor || Error;
	  return function() {
	    var SKIP_INDEXES = 2;

	    var templateArgs = arguments,
	      code = templateArgs[0],
	      message = '[' + (module ? module + ':' : '') + code + '] ',
	      template = templateArgs[1],
	      paramPrefix, i;

	    message += template.replace(/\{\d+\}/g, function(match) {
	      var index = +match.slice(1, -1),
	        shiftedIndex = index + SKIP_INDEXES;

	      if (shiftedIndex < templateArgs.length) {
	        return toDebugString(templateArgs[shiftedIndex]);
	      }

	      return match;
	    });

	    message += '\nhttp://errors.angularjs.org/1.6.1/' +
	      (module ? module + '/' : '') + code;

	    for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
	      message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
	        encodeURIComponent(toDebugString(templateArgs[i]));
	    }

	    return new ErrorConstructor(message);
	  };
	}

	/* We need to tell ESLint what variables are being exported */
	/* exported
	  angular,
	  msie,
	  jqLite,
	  jQuery,
	  slice,
	  splice,
	  push,
	  toString,
	  ngMinErr,
	  angularModule,
	  uid,
	  REGEX_STRING_REGEXP,
	  VALIDITY_STATE_PROPERTY,

	  lowercase,
	  uppercase,
	  manualLowercase,
	  manualUppercase,
	  nodeName_,
	  isArrayLike,
	  forEach,
	  forEachSorted,
	  reverseParams,
	  nextUid,
	  setHashKey,
	  extend,
	  toInt,
	  inherit,
	  merge,
	  noop,
	  identity,
	  valueFn,
	  isUndefined,
	  isDefined,
	  isObject,
	  isBlankObject,
	  isString,
	  isNumber,
	  isNumberNaN,
	  isDate,
	  isArray,
	  isFunction,
	  isRegExp,
	  isWindow,
	  isScope,
	  isFile,
	  isFormData,
	  isBlob,
	  isBoolean,
	  isPromiseLike,
	  trim,
	  escapeForRegexp,
	  isElement,
	  makeMap,
	  includes,
	  arrayRemove,
	  copy,
	  equals,
	  csp,
	  jq,
	  concat,
	  sliceArgs,
	  bind,
	  toJsonReplacer,
	  toJson,
	  fromJson,
	  convertTimezoneToLocal,
	  timezoneToOffset,
	  startingTag,
	  tryDecodeURIComponent,
	  parseKeyValue,
	  toKeyValue,
	  encodeUriSegment,
	  encodeUriQuery,
	  angularInit,
	  bootstrap,
	  getTestability,
	  snake_case,
	  bindJQuery,
	  assertArg,
	  assertArgFn,
	  assertNotHasOwnProperty,
	  getter,
	  getBlockNodes,
	  hasOwnProperty,
	  createMap,
	  stringify,

	  NODE_TYPE_ELEMENT,
	  NODE_TYPE_ATTRIBUTE,
	  NODE_TYPE_TEXT,
	  NODE_TYPE_COMMENT,
	  NODE_TYPE_DOCUMENT,
	  NODE_TYPE_DOCUMENT_FRAGMENT
	*/

	////////////////////////////////////

	/**
	 * @ngdoc module
	 * @name ng
	 * @module ng
	 * @installation
	 * @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>
	 */

	var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;

	// 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';


	var hasOwnProperty = Object.prototype.hasOwnProperty;

	/**
	 * @ngdoc function
	 * @name angular.lowercase
	 * @module ng
	 * @kind function
	 *
	 * @deprecated
	 * sinceVersion="1.5.0"
	 * removeVersion="1.7.0"
	 * Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
	 *
	 * @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;};

	/**
	 * @ngdoc function
	 * @name angular.uppercase
	 * @module ng
	 * @kind function
	 *
	 * @deprecated
	 * sinceVersion="1.5.0"
	 * removeVersion="1.7.0"
	 * Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
	 *
	 * @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) {
	  /* eslint-disable no-bitwise */
	  return isString(s)
	      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
	      : s;
	  /* eslint-enable */
	};
	var manualUppercase = function(s) {
	  /* eslint-disable no-bitwise */
	  return isString(s)
	      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
	      : s;
	  /* eslint-enable */
	};


	// 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. See https://github.com/angular/angular.js/issues/11387
	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,
	    splice            = [].splice,
	    push              = [].push,
	    toString          = Object.prototype.toString,
	    getPrototypeOf    = Object.getPrototypeOf,
	    ngMinErr          = minErr('ng'),

	    /** @name angular */
	    angular           = window.angular || (window.angular = {}),
	    angularModule,
	    uid               = 0;

	// Support: IE 9-11 only
	/**
	 * documentMode is an IE-only property
	 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
	 */
	msie = window.document.documentMode;


	/**
	 * @private
	 * @param {*} obj
	 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
	 *                   String ...)
	 */
	function isArrayLike(obj) {

	  // `null`, `undefined` and `window` are not array-like
	  if (obj == null || isWindow(obj)) return false;

	  // arrays, strings and jQuery/jqLite objects are array like
	  // * jqLite is either the jQuery or jqLite constructor function
	  // * we have to check the existence of jqLite first as this method is called
	  //   via the forEach method when constructing the jqLite object in the first place
	  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;

	  // Support: iOS 8.2 (not reproducible in simulator)
	  // "length" in obj used to prevent JIT error (gh-11508)
	  var length = 'length' in Object(obj) && obj.length;

	  // NodeList objects (with `item` method) and
	  // other objects with suitable length characteristics are array-like
	  return isNumber(length) &&
	    (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item === 'function');

	}

	/**
	 * @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, obj)`, where `value`
	 * is the value of an object property or an array element, `key` is the object property key or
	 * array element index and obj is the `obj` itself. 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.
	 *
	 * Unlike ES262's
	 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
	 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
	 * return the value provided.
	 *
	   ```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, length;
	  if (obj) {
	    if (isFunction(obj)) {
	      for (key in obj) {
	        if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
	          iterator.call(context, obj[key], key, obj);
	        }
	      }
	    } else if (isArray(obj) || isArrayLike(obj)) {
	      var isPrimitive = typeof obj !== 'object';
	      for (key = 0, length = obj.length; key < length; key++) {
	        if (isPrimitive || key in obj) {
	          iterator.call(context, obj[key], key, obj);
	        }
	      }
	    } else if (obj.forEach && obj.forEach !== forEach) {
	        obj.forEach(iterator, context, obj);
	    } else if (isBlankObject(obj)) {
	      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
	      for (key in obj) {
	        iterator.call(context, obj[key], key, obj);
	      }
	    } else if (typeof obj.hasOwnProperty === 'function') {
	      // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
	      for (key in obj) {
	        if (obj.hasOwnProperty(key)) {
	          iterator.call(context, obj[key], key, obj);
	        }
	      }
	    } else {
	      // Slow path for objects which do not have a method `hasOwnProperty`
	      for (key in obj) {
	        if (hasOwnProperty.call(obj, key)) {
	          iterator.call(context, obj[key], key, obj);
	        }
	      }
	    }
	  }
	  return obj;
	}

	function forEachSorted(obj, iterator, context) {
	  var keys = Object.keys(obj).sort();
	  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.
	 *
	 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
	 * we hit number precision issues in JavaScript.
	 *
	 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
	 *
	 * @returns {number} an unique alpha-numeric string
	 */
	function nextUid() {
	  return ++uid;
	}


	/**
	 * 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;
	  }
	}


	function baseExtend(dst, objs, deep) {
	  var h = dst.$$hashKey;

	  for (var i = 0, ii = objs.length; i < ii; ++i) {
	    var obj = objs[i];
	    if (!isObject(obj) && !isFunction(obj)) continue;
	    var keys = Object.keys(obj);
	    for (var j = 0, jj = keys.length; j < jj; j++) {
	      var key = keys[j];
	      var src = obj[key];

	      if (deep && isObject(src)) {
	        if (isDate(src)) {
	          dst[key] = new Date(src.valueOf());
	        } else if (isRegExp(src)) {
	          dst[key] = new RegExp(src);
	        } else if (src.nodeName) {
	          dst[key] = src.cloneNode(true);
	        } else if (isElement(src)) {
	          dst[key] = src.clone();
	        } else {
	          if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
	          baseExtend(dst[key], [src], true);
	        }
	      } else {
	        dst[key] = src;
	      }
	    }
	  }

	  setHashKey(dst, h);
	  return dst;
	}

	/**
	 * @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. If you want to preserve original objects, you can do so
	 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
	 *
	 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
	 * {@link angular.merge} for this.
	 *
	 * @param {Object} dst Destination object.
	 * @param {...Object} src Source object(s).
	 * @returns {Object} Reference to `dst`.
	 */
	function extend(dst) {
	  return baseExtend(dst, slice.call(arguments, 1), false);
	}


	/**
	* @ngdoc function
	* @name angular.merge
	* @module ng
	* @kind function
	*
	* @description
	* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
	* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
	* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
	*
	* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
	* objects, performing a deep copy.
	*
	* @param {Object} dst Destination object.
	* @param {...Object} src Source object(s).
	* @returns {Object} Reference to `dst`.
	*/
	function merge(dst) {
	  return baseExtend(dst, slice.call(arguments, 1), true);
	}



	function toInt(str) {
	  return parseInt(str, 10);
	}

	var isNumberNaN = Number.isNaN || function isNumberNaN(num) {
	  // eslint-disable-next-line no-self-compare
	  return num !== num;
	};


	function inherit(parent, extra) {
	  return extend(Object.create(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);
	   };

	   // E.g.
	   function getResult(fn, input) {
	     return (fn || angular.identity)(input);
	   };

	   getResult(function(n) { return n * 2; }, 21);   // returns 42
	   getResult(null, 21);                            // returns 21
	   getResult(undefined, 21);                       // returns 21
	   ```
	 *
	 * @param {*} value to be returned.
	 * @returns {*} the value passed in.
	 */
	function identity($) {return $;}
	identity.$inject = [];


	function valueFn(value) {return function valueRef() {return value;};}

	function hasCustomToString(obj) {
	  return isFunction(obj.toString) && obj.toString !== toString;
	}


	/**
	 * @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) {
	  // http://jsperf.com/isobject4
	  return value !== null && typeof value === 'object';
	}


	/**
	 * Determine if a value is an object with a null prototype
	 *
	 * @returns {boolean} True if `value` is an `Object` with a null prototype
	 */
	function isBlankObject(value) {
	  return value !== null && typeof value === 'object' && !getPrototypeOf(value);
	}


	/**
	 * @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`.
	 *
	 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
	 *
	 * If you wish to exclude these then you can use the native
	 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
	 * method.
	 *
	 * @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`. Alias of Array.isArray.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is an `Array`.
	 */
	var isArray = 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.window === obj;
	}


	function isScope(obj) {
	  return obj && obj.$evalAsync && obj.$watch;
	}


	function isFile(obj) {
	  return toString.call(obj) === '[object File]';
	}


	function isFormData(obj) {
	  return toString.call(obj) === '[object FormData]';
	}


	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 TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
	function isTypedArray(value) {
	  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
	}

	function isArrayBuffer(obj) {
	  return toString.call(obj) === '[object ArrayBuffer]';
	}


	var trim = function(value) {
	  return isString(value) ? value.trim() : value;
	};

	// Copied from:
	// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
	// Prereq: s is a string.
	var escapeForRegexp = function(s) {
	  return s
	    .replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
	    // eslint-disable-next-line no-control-regex
	    .replace(/\x08/g, '\\x08');
	};


	/**
	 * @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;
	}


	function nodeName_(element) {
	  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
	}

	function includes(array, obj) {
	  return Array.prototype.indexOf.call(array, obj) !== -1;
	}

	function arrayRemove(array, value) {
	  var index = array.indexOf(value);
	  if (index >= 0) {
	    array.splice(index, 1);
	  }
	  return index;
	}

	/**
	 * @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 arrays) 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.
	 *
	 * <br />
	 * <div class="alert alert-warning">
	 *   Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
	 *   and on `destination`) will be ignored.
	 * </div>
	 *
	 * @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" name="angular-copy">
	    <file name="index.html">
	      <div ng-controller="ExampleController">
	        <form novalidate class="simple-form">
	          <label>Name: <input type="text" ng-model="user.name" /></label><br />
	          <label>Age:  <input type="number" ng-model="user.age" /></label><br />
	          Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
	                  <label><input type="radio" ng-model="user.gender" value="female" />female</label><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>
	    </file>
	    <file name="script.js">
	      // Module: copyExample
	      angular.
	        module('copyExample', []).
	        controller('ExampleController', ['$scope', function($scope) {
	          $scope.master = {};

	          $scope.reset = function() {
	            // Example with 1 argument
	            $scope.user = angular.copy($scope.master);
	          };

	          $scope.update = function(user) {
	            // Example with 2 arguments
	            angular.copy(user, $scope.master);
	          };

	          $scope.reset();
	        }]);
	    </file>
	  </example>
	 */
	function copy(source, destination) {
	  var stackSource = [];
	  var stackDest = [];

	  if (destination) {
	    if (isTypedArray(destination) || isArrayBuffer(destination)) {
	      throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.');
	    }
	    if (source === destination) {
	      throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.');
	    }

	    // Empty the destination object
	    if (isArray(destination)) {
	      destination.length = 0;
	    } else {
	      forEach(destination, function(value, key) {
	        if (key !== '$$hashKey') {
	          delete destination[key];
	        }
	      });
	    }

	    stackSource.push(source);
	    stackDest.push(destination);
	    return copyRecurse(source, destination);
	  }

	  return copyElement(source);

	  function copyRecurse(source, destination) {
	    var h = destination.$$hashKey;
	    var key;
	    if (isArray(source)) {
	      for (var i = 0, ii = source.length; i < ii; i++) {
	        destination.push(copyElement(source[i]));
	      }
	    } else if (isBlankObject(source)) {
	      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
	      for (key in source) {
	        destination[key] = copyElement(source[key]);
	      }
	    } else if (source && typeof source.hasOwnProperty === 'function') {
	      // Slow path, which must rely on hasOwnProperty
	      for (key in source) {
	        if (source.hasOwnProperty(key)) {
	          destination[key] = copyElement(source[key]);
	        }
	      }
	    } else {
	      // Slowest path --- hasOwnProperty can't be called as a method
	      for (key in source) {
	        if (hasOwnProperty.call(source, key)) {
	          destination[key] = copyElement(source[key]);
	        }
	      }
	    }
	    setHashKey(destination, h);
	    return destination;
	  }

	  function copyElement(source) {
	    // Simple values
	    if (!isObject(source)) {
	      return source;
	    }

	    // Already copied values
	    var index = stackSource.indexOf(source);
	    if (index !== -1) {
	      return stackDest[index];
	    }

	    if (isWindow(source) || isScope(source)) {
	      throw ngMinErr('cpws',
	        'Can\'t copy! Making copies of Window or Scope instances is not supported.');
	    }

	    var needsRecurse = false;
	    var destination = copyType(source);

	    if (destination === undefined) {
	      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
	      needsRecurse = true;
	    }

	    stackSource.push(source);
	    stackDest.push(destination);

	    return needsRecurse
	      ? copyRecurse(source, destination)
	      : destination;
	  }

	  function copyType(source) {
	    switch (toString.call(source)) {
	      case '[object Int8Array]':
	      case '[object Int16Array]':
	      case '[object Int32Array]':
	      case '[object Float32Array]':
	      case '[object Float64Array]':
	      case '[object Uint8Array]':
	      case '[object Uint8ClampedArray]':
	      case '[object Uint16Array]':
	      case '[object Uint32Array]':
	        return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);

	      case '[object ArrayBuffer]':
	        // Support: IE10
	        if (!source.slice) {
	          // If we're in this case we know the environment supports ArrayBuffer
	          /* eslint-disable no-undef */
	          var copied = new ArrayBuffer(source.byteLength);
	          new Uint8Array(copied).set(new Uint8Array(source));
	          /* eslint-enable */
	          return copied;
	        }
	        return source.slice(0);

	      case '[object Boolean]':
	      case '[object Number]':
	      case '[object String]':
	      case '[object Date]':
	        return new source.constructor(source.valueOf());

	      case '[object RegExp]':
	        var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
	        re.lastIndex = source.lastIndex;
	        return re;

	      case '[object Blob]':
	        return new source.constructor([source], {type: source.type});
	    }

	    if (isFunction(source.cloneNode)) {
	      return source.cloneNode(true);
	    }
	  }
	}


	/**
	 * @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.
	 *
	 * @example
	   <example module="equalsExample" name="equalsExample">
	     <file name="index.html">
	      <div ng-controller="ExampleController">
	        <form novalidate>
	          <h3>User 1</h3>
	          Name: <input type="text" ng-model="user1.name">
	          Age: <input type="number" ng-model="user1.age">

	          <h3>User 2</h3>
	          Name: <input type="text" ng-model="user2.name">
	          Age: <input type="number" ng-model="user2.age">

	          <div>
	            <br/>
	            <input type="button" value="Compare" ng-click="compare()">
	          </div>
	          User 1: <pre>{{user1 | json}}</pre>
	          User 2: <pre>{{user2 | json}}</pre>
	          Equal: <pre>{{result}}</pre>
	        </form>
	      </div>
	    </file>
	    <file name="script.js">
	        angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
	          $scope.user1 = {};
	          $scope.user2 = {};
	          $scope.compare = function() {
	            $scope.result = angular.equals($scope.user1, $scope.user2);
	          };
	        }]);
	    </file>
	  </example>
	 */
	function equals(o1, o2) {
	  if (o1 === o2) return true;
	  if (o1 === null || o2 === null) return false;
	  // eslint-disable-next-line no-self-compare
	  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
	  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
	  if (t1 === t2 && 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 equals(o1.getTime(), o2.getTime());
	    } else if (isRegExp(o1)) {
	      if (!isRegExp(o2)) return false;
	      return o1.toString() === o2.toString();
	    } else {
	      if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
	        isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
	      keySet = createMap();
	      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 (!(key in keySet) &&
	            key.charAt(0) !== '$' &&
	            isDefined(o2[key]) &&
	            !isFunction(o2[key])) return false;
	      }
	      return true;
	    }
	  }
	  return false;
	}

	var csp = function() {
	  if (!isDefined(csp.rules)) {


	    var ngCspElement = (window.document.querySelector('[ng-csp]') ||
	                    window.document.querySelector('[data-ng-csp]'));

	    if (ngCspElement) {
	      var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
	                    ngCspElement.getAttribute('data-ng-csp');
	      csp.rules = {
	        noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
	        noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
	      };
	    } else {
	      csp.rules = {
	        noUnsafeEval: noUnsafeEval(),
	        noInlineStyle: false
	      };
	    }
	  }

	  return csp.rules;

	  function noUnsafeEval() {
	    try {
	      // eslint-disable-next-line no-new, no-new-func
	      new Function('');
	      return false;
	    } catch (e) {
	      return true;
	    }
	  }
	};

	/**
	 * @ngdoc directive
	 * @module ng
	 * @name ngJq
	 *
	 * @element ANY
	 * @param {string=} ngJq the name of the library available under `window`
	 * to be used for angular.element
	 * @description
	 * Use this directive to force the angular.element library.  This should be
	 * used to force either jqLite by leaving ng-jq blank or setting the name of
	 * the jquery variable under window (eg. jQuery).
	 *
	 * Since angular looks for this directive when it is loaded (doesn't wait for the
	 * DOMContentLoaded event), it must be placed on an element that comes before the script
	 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
	 * others ignored.
	 *
	 * @example
	 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
	 ```html
	 <!doctype html>
	 <html ng-app ng-jq>
	 ...
	 ...
	 </html>
	 ```
	 * @example
	 * This example shows how to use a jQuery based library of a different name.
	 * The library name must be available at the top most 'window'.
	 ```html
	 <!doctype html>
	 <html ng-app ng-jq="jQueryLib">
	 ...
	 ...
	 </html>
	 ```
	 */
	var jq = function() {
	  if (isDefined(jq.name_)) return jq.name_;
	  var el;
	  var i, ii = ngAttrPrefixes.length, prefix, name;
	  for (i = 0; i < ii; ++i) {
	    prefix = ngAttrPrefixes[i];
	    el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]');
	    if (el) {
	      name = el.getAttribute(prefix + 'jq');
	      break;
	    }
	  }

	  return (jq.name_ = name);
	};

	function concat(array1, array2, index) {
	  return array1.concat(slice.call(array2, index));
	}

	function sliceArgs(args, startIndex) {
	  return slice.call(args, startIndex || 0);
	}


	/**
	 * @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.
	 */
	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, concat(curryArgs, 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) === '$' && key.charAt(1) === '$') {
	    val = undefined;
	  } else if (isWindow(value)) {
	    val = '$WINDOW';
	  } else if (value &&  window.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|boolean} obj Input to be serialized into JSON.
	 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
	 *    If set to an integer, the JSON output will contain that many spaces per indentation.
	 * @returns {string|undefined} JSON-ified string representing `obj`.
	 * @knownIssue
	 *
	 * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
	 * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
	 * `Date.prototype.toJSON` method as follows:
	 *
	 * ```
	 * var _DatetoJSON = Date.prototype.toJSON;
	 * Date.prototype.toJSON = function() {
	 *   try {
	 *     return _DatetoJSON.call(this);
	 *   } catch(e) {
	 *     if (e instanceof RangeError) {
	 *       return null;
	 *     }
	 *     throw e;
	 *   }
	 * };
	 * ```
	 *
	 * See https://github.com/angular/angular.js/pull/14221 for more information.
	 */
	function toJson(obj, pretty) {
	  if (isUndefined(obj)) return undefined;
	  if (!isNumber(pretty)) {
	    pretty = pretty ? 2 : null;
	  }
	  return JSON.stringify(obj, toJsonReplacer, pretty);
	}


	/**
	 * @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 JSON string.
	 */
	function fromJson(json) {
	  return isString(json)
	      ? JSON.parse(json)
	      : json;
	}


	var ALL_COLONS = /:/g;
	function timezoneToOffset(timezone, fallback) {
	  // Support: IE 9-11 only, Edge 13-14+
	  // IE/Edge do not "understand" colon (`:`) in timezone
	  timezone = timezone.replace(ALL_COLONS, '');
	  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
	  return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
	}


	function addDateMinutes(date, minutes) {
	  date = new Date(date.getTime());
	  date.setMinutes(date.getMinutes() + minutes);
	  return date;
	}


	function convertTimezoneToLocal(date, timezone, reverse) {
	  reverse = reverse ? -1 : 1;
	  var dateTimezoneOffset = date.getTimezoneOffset();
	  var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
	  return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
	}


	/**
	 * @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) { /* empty */ }
	  var elemHtml = jqLite('<div>').append(element).html();
	  try {
	    return element[0].nodeType === NODE_TYPE_TEXT ? 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 = {};
	  forEach((keyValue || '').split('&'), function(keyValue) {
	    var splitPoint, key, val;
	    if (keyValue) {
	      key = keyValue = keyValue.replace(/\+/g,'%20');
	      splitPoint = keyValue.indexOf('=');
	      if (splitPoint !== -1) {
	        key = keyValue.substring(0, splitPoint);
	        val = keyValue.substring(splitPoint + 1);
	      }
	      key = tryDecodeURIComponent(key);
	      if (isDefined(key)) {
	        val = isDefined(val) ? tryDecodeURIComponent(val) : 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(/%3B/gi, ';').
	             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
	}

	var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];

	function getNgAttribute(element, ngAttr) {
	  var attr, i, ii = ngAttrPrefixes.length;
	  for (i = 0; i < ii; ++i) {
	    attr = ngAttrPrefixes[i] + ngAttr;
	    if (isString(attr = element.getAttribute(attr))) {
	      return attr;
	    }
	  }
	  return null;
	}

	function allowAutoBootstrap(document) {
	  if (!document.currentScript) {
	    return true;
	  }
	  var src = document.currentScript.getAttribute('src');
	  var link = document.createElement('a');
	  link.href = src;
	  if (document.location.origin === link.origin) {
	    // Same-origin resources are always allowed, even for non-whitelisted schemes.
	    return true;
	  }
	  // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
	  // This is to prevent angular.js bundled with browser extensions from being used to bypass the
	  // content security policy in web pages and other browser extensions.
	  switch (link.protocol) {
	    case 'http:':
	    case 'https:':
	    case 'ftp:':
	    case 'blob:':
	    case 'file:':
	    case 'data:':
	      return true;
	    default:
	      return false;
	  }
	}

	// Cached as it has to run during loading so that document.currentScript is available.
	var isAutoBootstrapAllowed = allowAutoBootstrap(window.document);

	/**
	 * @ngdoc directive
	 * @name ngApp
	 * @module ng
	 *
	 * @element ANY
	 * @param {angular.Module} ngApp an optional application
	 *   {@link angular.module module} name to load.
	 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
	 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
	 *   do not use explicit function annotation (and are thus unsuitable for minification), as described
	 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
	 *   tracking down the root of these bugs.
	 *
	 * @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.
	 *
	 * There are a few things to keep in mind when using `ngApp`:
	 * - 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.
	 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
	 *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
	 *   {@link ngRoute.ngView `ngView`}.
	 *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
	 *   causing animations to stop working and making the injector inaccessible from outside the app.
	 *
	 * 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. It
	 * 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" name="ng-app">
	   <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>
	 *
	 * Using `ngStrictDi`, you would see something like this:
	 *
	 <example ng-app-included="true" name="strict-di">
	   <file name="index.html">
	   <div ng-app="ngAppStrictDemo" ng-strict-di>
	       <div ng-controller="GoodController1">
	           I can add: {{a}} + {{b}} =  {{ a+b }}

	           <p>This renders because the controller does not fail to
	              instantiate, by using explicit annotation style (see
	              script.js for details)
	           </p>
	       </div>

	       <div ng-controller="GoodController2">
	           Name: <input ng-model="name"><br />
	           Hello, {{name}}!

	           <p>This renders because the controller does not fail to
	              instantiate, by using explicit annotation style
	              (see script.js for details)
	           </p>
	       </div>

	       <div ng-controller="BadController">
	           I can add: {{a}} + {{b}} =  {{ a+b }}

	           <p>The controller could not be instantiated, due to relying
	              on automatic function annotations (which are disabled in
	              strict mode). As such, the content of this section is not
	              interpolated, and there should be an error in your web console.
	           </p>
	       </div>
	   </div>
	   </file>
	   <file name="script.js">
	   angular.module('ngAppStrictDemo', [])
	     // BadController will fail to instantiate, due to relying on automatic function annotation,
	     // rather than an explicit annotation
	     .controller('BadController', function($scope) {
	       $scope.a = 1;
	       $scope.b = 2;
	     })
	     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
	     // due to using explicit annotations using the array style and $inject property, respectively.
	     .controller('GoodController1', ['$scope', function($scope) {
	       $scope.a = 1;
	       $scope.b = 2;
	     }])
	     .controller('GoodController2', GoodController2);
	     function GoodController2($scope) {
	       $scope.name = 'World';
	     }
	     GoodController2.$inject = ['$scope'];
	   </file>
	   <file name="style.css">
	   div[ng-controller] {
	       margin-bottom: 1em;
	       -webkit-border-radius: 4px;
	       border-radius: 4px;
	       border: 1px solid;
	       padding: .5em;
	   }
	   div[ng-controller^=Good] {
	       border-color: #d6e9c6;
	       background-color: #dff0d8;
	       color: #3c763d;
	   }
	   div[ng-controller^=Bad] {
	       border-color: #ebccd1;
	       background-color: #f2dede;
	       color: #a94442;
	       margin-bottom: 0;
	   }
	   </file>
	 </example>
	 */
	function angularInit(element, bootstrap) {
	  var appElement,
	      module,
	      config = {};

	  // The element `element` has priority over any other element.
	  forEach(ngAttrPrefixes, function(prefix) {
	    var name = prefix + 'app';

	    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
	      appElement = element;
	      module = element.getAttribute(name);
	    }
	  });
	  forEach(ngAttrPrefixes, function(prefix) {
	    var name = prefix + 'app';
	    var candidate;

	    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
	      appElement = candidate;
	      module = candidate.getAttribute(name);
	    }
	  });
	  if (appElement) {
	    if (!isAutoBootstrapAllowed) {
	      window.console.error('Angular: disabling automatic bootstrap. <script> protocol indicates ' +
	          'an extension, document.location.href does not match.');
	      return;
	    }
	    config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
	    bootstrap(appElement, module ? [module] : [], config);
	  }
	}

	/**
	 * @ngdoc function
	 * @name angular.bootstrap
	 * @module ng
	 * @description
	 * Use this function to manually start up angular application.
	 *
	 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
	 *
	 * 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.
	 *
	 * <div class="alert alert-warning">
	 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
	 * They must use {@link ng.directive:ngApp ngApp}.
	 * </div>
	 *
	 * <div class="alert alert-warning">
	 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
	 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
	 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
	 * causing animations to stop working and making the injector inaccessible from outside the app.
	 * </div>
	 *
	 * ```html
	 * <!doctype html>
	 * <html>
	 * <body>
	 * <div ng-controller="WelcomeController">
	 *   {{greeting}}
	 * </div>
	 *
	 * <script src="angular.js"></script>
	 * <script>
	 *   var app = angular.module('demo', [])
	 *   .controller('WelcomeController', function($scope) {
	 *       $scope.greeting = 'Welcome!';
	 *   });
	 *   angular.bootstrap(document, ['demo']);
	 * </script>
	 * </body>
	 * </html>
	 * ```
	 *
	 * @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 `config` block.
	 *     See: {@link angular.module modules}
	 * @param {Object=} config an object for defining configuration options for the application. The
	 *     following keys are supported:
	 *
	 * * `strictDi` - disable automatic function annotation for the application. This is meant to
	 *   assist in finding bugs which break minified code. Defaults to `false`.
	 *
	 * @returns {auto.$injector} Returns the newly created injector for this app.
	 */
	function bootstrap(element, modules, config) {
	  if (!isObject(config)) config = {};
	  var defaultConfig = {
	    strictDi: false
	  };
	  config = extend(defaultConfig, config);
	  var doBootstrap = function() {
	    element = jqLite(element);

	    if (element.injector()) {
	      var tag = (element[0] === window.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);
	    }]);

	    if (config.debugInfoEnabled) {
	      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
	      modules.push(['$compileProvider', function($compileProvider) {
	        $compileProvider.debugInfoEnabled(true);
	      }]);
	    }

	    modules.unshift('ng');
	    var injector = createInjector(modules, config.strictDi);
	    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
	       function bootstrapApply(scope, element, compile, injector) {
	        scope.$apply(function() {
	          element.data('$injector', injector);
	          compile(element)(scope);
	        });
	      }]
	    );
	    return injector;
	  };

	  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
	  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;

	  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
	    config.debugInfoEnabled = true;
	    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
	  }

	  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);
	    });
	    return doBootstrap();
	  };

	  if (isFunction(angular.resumeDeferredBootstrap)) {
	    angular.resumeDeferredBootstrap();
	  }
	}

	/**
	 * @ngdoc function
	 * @name angular.reloadWithDebugInfo
	 * @module ng
	 * @description
	 * Use this function to reload the current application with debug information turned on.
	 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
	 *
	 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
	 */
	function reloadWithDebugInfo() {
	  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
	  window.location.reload();
	}

	/**
	 * @name angular.getTestability
	 * @module ng
	 * @description
	 * Get the testability service for the instance of Angular on the given
	 * element.
	 * @param {DOMElement} element DOM element which is the root of angular application.
	 */
	function getTestability(rootElement) {
	  var injector = angular.element(rootElement).injector();
	  if (!injector) {
	    throw ngMinErr('test',
	      'no injector found for element argument to getTestability');
	  }
	  return injector.get('$$testability');
	}

	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();
	  });
	}

	var bindJQueryFired = false;
	function bindJQuery() {
	  var originalCleanData;

	  if (bindJQueryFired) {
	    return;
	  }

	  // bind to jQuery if present;
	  var jqName = jq();
	  jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
	           !jqName             ? undefined     :   // use jqLite
	                                 window[jqName];   // use jQuery specified by `ngJq`

	  // Use jQuery if it exists with proper functionality, otherwise default to us.
	  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
	  // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
	  // versions. It will not work for sure with jQuery <1.7, though.
	  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
	    });

	    // All nodes removed from the DOM via various jQuery APIs like .remove()
	    // are passed through jQuery.cleanData. Monkey-patch this method to fire
	    // the $destroy event on all removed nodes.
	    originalCleanData = jQuery.cleanData;
	    jQuery.cleanData = function(elems) {
	      var events;
	      for (var i = 0, elem; (elem = elems[i]) != null; i++) {
	        events = jQuery._data(elem, 'events');
	        if (events && events.$destroy) {
	          jQuery(elem).triggerHandler('$destroy');
	        }
	      }
	      originalCleanData(elems);
	    };
	  } else {
	    jqLite = JQLite;
	  }

	  angular.element = jqLite;

	  // Prevent double-proxying.
	  bindJQueryFired = true;
	}

	/**
	 * 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 {Array} the inputted object or a jqLite collection containing the nodes
	 */
	function getBlockNodes(nodes) {
	  // TODO(perf): update `nodes` instead of creating a new object?
	  var node = nodes[0];
	  var endNode = nodes[nodes.length - 1];
	  var blockNodes;

	  for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
	    if (blockNodes || nodes[i] !== node) {
	      if (!blockNodes) {
	        blockNodes = jqLite(slice.call(nodes, 0, i));
	      }
	      blockNodes.push(node);
	    }
	  }

	  return blockNodes || nodes;
	}


	/**
	 * Creates a new object without a prototype. This object is useful for lookup without having to
	 * guard against prototypically inherited properties via hasOwnProperty.
	 *
	 * Related micro-benchmarks:
	 * - http://jsperf.com/object-create2
	 * - http://jsperf.com/proto-map-lookup/2
	 * - http://jsperf.com/for-in-vs-object-keys2
	 *
	 * @returns {Object}
	 */
	function createMap() {
	  return Object.create(null);
	}

	function stringify(value) {
	  if (value == null) { // null || undefined
	    return '';
	  }
	  switch (typeof value) {
	    case 'string':
	      break;
	    case 'number':
	      value = '' + value;
	      break;
	    default:
	      if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
	        value = value.toString();
	      } else {
	        value = toJson(value);
	      }
	  }

	  return value;
	}

	var NODE_TYPE_ELEMENT = 1;
	var NODE_TYPE_ATTRIBUTE = 2;
	var NODE_TYPE_TEXT = 3;
	var NODE_TYPE_COMMENT = 8;
	var NODE_TYPE_DOCUMENT = 9;
	var NODE_TYPE_DOCUMENT_FRAGMENT = 11;

	/**
	 * @ngdoc type
	 * @name angular.Module
	 * @module ng
	 * @description
	 *
	 * Interface for configuring angular {@link angular.module modules}.
	 */

	function setupModuleLoader(window) {

	  var $injectorMinErr = minErr('$injector');
	  var ngMinErr = minErr('ng');

	  function ensure(obj, name, factory) {
	    return obj[name] || (obj[name] = factory());
	  }

	  var angular = ensure(window, 'angular', Object);

	  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
	  angular.$$minErr = angular.$$minErr || minErr;

	  return ensure(angular, 'module', function() {
	    /** @type {Object.<string, angular.Module>} */
	    var modules = {};

	    /**
	     * @ngdoc function
	     * @name angular.module
	     * @module ng
	     * @description
	     *
	     * The `angular.module` is a global place for creating, registering and retrieving Angular
	     * modules.
	     * All modules (angular core or 3rd party) that should be available to an application must be
	     * registered using this mechanism.
	     *
	     * Passing one argument retrieves an existing {@link angular.Module},
	     * whereas passing more than one argument creates a new {@link angular.Module}
	     *
	     *
	     * # Module
	     *
	     * A module is a collection of services, directives, controllers, filters, and configuration information.
	     * `angular.module` is used to configure the {@link auto.$injector $injector}.
	     *
	     * ```js
	     * // Create a new module
	     * var myModule = angular.module('myModule', []);
	     *
	     * // register a new service
	     * myModule.value('appName', 'MyCoolApp');
	     *
	     * // configure existing services inside initialization blocks.
	     * myModule.config(['$locationProvider', function($locationProvider) {
	     *   // Configure existing providers
	     *   $locationProvider.hashPrefix('!');
	     * }]);
	     * ```
	     *
	     * Then you can create an injector and load your modules like this:
	     *
	     * ```js
	     * var injector = angular.injector(['ng', 'myModule'])
	     * ```
	     *
	     * However it's more likely that you'll just use
	     * {@link ng.directive:ngApp ngApp} or
	     * {@link angular.bootstrap} to simplify this process for you.
	     *
	     * @param {!string} name The name of the module to create or retrieve.
	     * @param {!Array.<string>=} requires If specified then new module is being created. If
	     *        unspecified then the module is being retrieved for further configuration.
	     * @param {Function=} configFn Optional configuration function for the module. Same as
	     *        {@link angular.Module#config Module#config()}.
	     * @returns {angular.Module} new module with the {@link angular.Module} api.
	     */
	    return function module(name, requires, configFn) {
	      var assertNotHasOwnProperty = function(name, context) {
	        if (name === 'hasOwnProperty') {
	          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
	        }
	      };

	      assertNotHasOwnProperty(name, 'module');
	      if (requires && modules.hasOwnProperty(name)) {
	        modules[name] = null;
	      }
	      return ensure(modules, name, function() {
	        if (!requires) {
	          throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
	             'the module name or forgot to load it. If registering a module ensure that you ' +
	             'specify the dependencies as the second argument.', name);
	        }

	        /** @type {!Array.<Array.<*>>} */
	        var invokeQueue = [];

	        /** @type {!Array.<Function>} */
	        var configBlocks = [];

	        /** @type {!Array.<Function>} */
	        var runBlocks = [];

	        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);

	        /** @type {angular.Module} */
	        var moduleInstance = {
	          // Private state
	          _invokeQueue: invokeQueue,
	          _configBlocks: configBlocks,
	          _runBlocks: runBlocks,

	          /**
	           * @ngdoc property
	           * @name angular.Module#requires
	           * @module ng
	           *
	           * @description
	           * Holds the list of modules which the injector will load before the current module is
	           * loaded.
	           */
	          requires: requires,

	          /**
	           * @ngdoc property
	           * @name angular.Module#name
	           * @module ng
	           *
	           * @description
	           * Name of the module.
	           */
	          name: name,


	          /**
	           * @ngdoc method
	           * @name angular.Module#provider
	           * @module ng
	           * @param {string} name service name
	           * @param {Function} providerType Construction function for creating new instance of the
	           *                                service.
	           * @description
	           * See {@link auto.$provide#provider $provide.provider()}.
	           */
	          provider: invokeLaterAndSetModuleName('$provide', 'provider'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#factory
	           * @module ng
	           * @param {string} name service name
	           * @param {Function} providerFunction Function for creating new instance of the service.
	           * @description
	           * See {@link auto.$provide#factory $provide.factory()}.
	           */
	          factory: invokeLaterAndSetModuleName('$provide', 'factory'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#service
	           * @module ng
	           * @param {string} name service name
	           * @param {Function} constructor A constructor function that will be instantiated.
	           * @description
	           * See {@link auto.$provide#service $provide.service()}.
	           */
	          service: invokeLaterAndSetModuleName('$provide', 'service'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#value
	           * @module ng
	           * @param {string} name service name
	           * @param {*} object Service instance object.
	           * @description
	           * See {@link auto.$provide#value $provide.value()}.
	           */
	          value: invokeLater('$provide', 'value'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#constant
	           * @module ng
	           * @param {string} name constant name
	           * @param {*} object Constant value.
	           * @description
	           * Because the constants are fixed, they get applied before other provide methods.
	           * See {@link auto.$provide#constant $provide.constant()}.
	           */
	          constant: invokeLater('$provide', 'constant', 'unshift'),

	           /**
	           * @ngdoc method
	           * @name angular.Module#decorator
	           * @module ng
	           * @param {string} name The name of the service to decorate.
	           * @param {Function} decorFn This function will be invoked when the service needs to be
	           *                           instantiated and should return the decorated service instance.
	           * @description
	           * See {@link auto.$provide#decorator $provide.decorator()}.
	           */
	          decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),

	          /**
	           * @ngdoc method
	           * @name angular.Module#animation
	           * @module ng
	           * @param {string} name animation name
	           * @param {Function} animationFactory Factory function for creating new instance of an
	           *                                    animation.
	           * @description
	           *
	           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
	           *
	           *
	           * Defines an animation hook that can be later used with
	           * {@link $animate $animate} service and directives that use this service.
	           *
	           * ```js
	           * module.animation('.animation-name', function($inject1, $inject2) {
	           *   return {
	           *     eventName : function(element, done) {
	           *       //code to run the animation
	           *       //once complete, then run done()
	           *       return function cancellationFunction(element) {
	           *         //code to cancel the animation
	           *       }
	           *     }
	           *   }
	           * })
	           * ```
	           *
	           * See {@link ng.$animateProvider#register $animateProvider.register()} and
	           * {@link ngAnimate ngAnimate module} for more information.
	           */
	          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#filter
	           * @module ng
	           * @param {string} name Filter name - this must be a valid angular expression identifier
	           * @param {Function} filterFactory Factory function for creating new instance of filter.
	           * @description
	           * See {@link ng.$filterProvider#register $filterProvider.register()}.
	           *
	           * <div class="alert alert-warning">
	           * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
	           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
	           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
	           * (`myapp_subsection_filterx`).
	           * </div>
	           */
	          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#controller
	           * @module ng
	           * @param {string|Object} name Controller name, or an object map of controllers where the
	           *    keys are the names and the values are the constructors.
	           * @param {Function} constructor Controller constructor function.
	           * @description
	           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
	           */
	          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#directive
	           * @module ng
	           * @param {string|Object} name Directive name, or an object map of directives where the
	           *    keys are the names and the values are the factories.
	           * @param {Function} directiveFactory Factory function for creating new instance of
	           * directives.
	           * @description
	           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
	           */
	          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#component
	           * @module ng
	           * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
	           * @param {Object} options Component definition object (a simplified
	           *    {@link ng.$compile#directive-definition-object directive definition object})
	           *
	           * @description
	           * See {@link ng.$compileProvider#component $compileProvider.component()}.
	           */
	          component: invokeLaterAndSetModuleName('$compileProvider', 'component'),

	          /**
	           * @ngdoc method
	           * @name angular.Module#config
	           * @module ng
	           * @param {Function} configFn Execute this function on module load. Useful for service
	           *    configuration.
	           * @description
	           * Use this method to register work which needs to be performed on module loading.
	           * For more about how to configure services, see
	           * {@link providers#provider-recipe Provider Recipe}.
	           */
	          config: config,

	          /**
	           * @ngdoc method
	           * @name angular.Module#run
	           * @module ng
	           * @param {Function} initializationFn Execute this function after injector creation.
	           *    Useful for application initialization.
	           * @description
	           * Use this method to register work which should be performed when the injector is done
	           * loading all modules.
	           */
	          run: function(block) {
	            runBlocks.push(block);
	            return this;
	          }
	        };

	        if (configFn) {
	          config(configFn);
	        }

	        return moduleInstance;

	        /**
	         * @param {string} provider
	         * @param {string} method
	         * @param {String=} insertMethod
	         * @returns {angular.Module}
	         */
	        function invokeLater(provider, method, insertMethod, queue) {
	          if (!queue) queue = invokeQueue;
	          return function() {
	            queue[insertMethod || 'push']([provider, method, arguments]);
	            return moduleInstance;
	          };
	        }

	        /**
	         * @param {string} provider
	         * @param {string} method
	         * @returns {angular.Module}
	         */
	        function invokeLaterAndSetModuleName(provider, method, queue) {
	          if (!queue) queue = invokeQueue;
	          return function(recipeName, factoryFunction) {
	            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
	            queue.push([provider, method, arguments]);
	            return moduleInstance;
	          };
	        }
	      });
	    };
	  });

	}

	/* global shallowCopy: true */

	/**
	 * Creates a shallow copy of an object, an array or a primitive.
	 *
	 * Assumes that there are no proto properties for objects.
	 */
	function shallowCopy(src, dst) {
	  if (isArray(src)) {
	    dst = dst || [];

	    for (var i = 0, ii = src.length; i < ii; i++) {
	      dst[i] = src[i];
	    }
	  } else if (isObject(src)) {
	    dst = dst || {};

	    for (var key in src) {
	      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
	        dst[key] = src[key];
	      }
	    }
	  }

	  return dst || src;
	}

	/* global toDebugString: true */

	function serializeObject(obj) {
	  var seen = [];

	  return JSON.stringify(obj, function(key, val) {
	    val = toJsonReplacer(key, val);
	    if (isObject(val)) {

	      if (seen.indexOf(val) >= 0) return '...';

	      seen.push(val);
	    }
	    return val;
	  });
	}

	function toDebugString(obj) {
	  if (typeof obj === 'function') {
	    return obj.toString().replace(/ \{[\s\S]*$/, '');
	  } else if (isUndefined(obj)) {
	    return 'undefined';
	  } else if (typeof obj !== 'string') {
	    return serializeObject(obj);
	  }
	  return obj;
	}

	/* global angularModule: true,
	  version: true,

	  $CompileProvider,

	  htmlAnchorDirective,
	  inputDirective,
	  inputDirective,
	  formDirective,
	  scriptDirective,
	  selectDirective,
	  optionDirective,
	  ngBindDirective,
	  ngBindHtmlDirective,
	  ngBindTemplateDirective,
	  ngClassDirective,
	  ngClassEvenDirective,
	  ngClassOddDirective,
	  ngCloakDirective,
	  ngControllerDirective,
	  ngFormDirective,
	  ngHideDirective,
	  ngIfDirective,
	  ngIncludeDirective,
	  ngIncludeFillContentDirective,
	  ngInitDirective,
	  ngNonBindableDirective,
	  ngPluralizeDirective,
	  ngRepeatDirective,
	  ngShowDirective,
	  ngStyleDirective,
	  ngSwitchDirective,
	  ngSwitchWhenDirective,
	  ngSwitchDefaultDirective,
	  ngOptionsDirective,
	  ngTranscludeDirective,
	  ngModelDirective,
	  ngListDirective,
	  ngChangeDirective,
	  patternDirective,
	  patternDirective,
	  requiredDirective,
	  requiredDirective,
	  minlengthDirective,
	  minlengthDirective,
	  maxlengthDirective,
	  maxlengthDirective,
	  ngValueDirective,
	  ngModelOptionsDirective,
	  ngAttributeAliasDirectives,
	  ngEventDirectives,

	  $AnchorScrollProvider,
	  $AnimateProvider,
	  $CoreAnimateCssProvider,
	  $$CoreAnimateJsProvider,
	  $$CoreAnimateQueueProvider,
	  $$AnimateRunnerFactoryProvider,
	  $$AnimateAsyncRunFactoryProvider,
	  $BrowserProvider,
	  $CacheFactoryProvider,
	  $ControllerProvider,
	  $DateProvider,
	  $DocumentProvider,
	  $$IsDocumentHiddenProvider,
	  $ExceptionHandlerProvider,
	  $FilterProvider,
	  $$ForceReflowProvider,
	  $InterpolateProvider,
	  $IntervalProvider,
	  $$HashMapProvider,
	  $HttpProvider,
	  $HttpParamSerializerProvider,
	  $HttpParamSerializerJQLikeProvider,
	  $HttpBackendProvider,
	  $xhrFactoryProvider,
	  $jsonpCallbacksProvider,
	  $LocationProvider,
	  $LogProvider,
	  $ParseProvider,
	  $RootScopeProvider,
	  $QProvider,
	  $$QProvider,
	  $$SanitizeUriProvider,
	  $SceProvider,
	  $SceDelegateProvider,
	  $SnifferProvider,
	  $TemplateCacheProvider,
	  $TemplateRequestProvider,
	  $$TestabilityProvider,
	  $TimeoutProvider,
	  $$RAFProvider,
	  $WindowProvider,
	  $$jqLiteProvider,
	  $$CookieReaderProvider
	*/


	/**
	 * @ngdoc object
	 * @name angular.version
	 * @module ng
	 * @description
	 * An object that contains information about the current AngularJS version.
	 *
	 * This object has the following properties:
	 *
	 * - `full` – `{string}` – Full version string, such as "0.9.18".
	 * - `major` – `{number}` – Major version number, such as "0".
	 * - `minor` – `{number}` – Minor version number, such as "9".
	 * - `dot` – `{number}` – Dot version number, such as "18".
	 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
	 */
	var version = {
	  // These placeholder strings will be replaced by grunt's `build` task.
	  // They need to be double- or single-quoted.
	  full: '1.6.1',
	  major: 1,
	  minor: 6,
	  dot: 1,
	  codeName: 'promise-rectification'
	};


	function publishExternalAPI(angular) {
	  extend(angular, {
	    'bootstrap': bootstrap,
	    'copy': copy,
	    'extend': extend,
	    'merge': merge,
	    'equals': equals,
	    'element': jqLite,
	    'forEach': forEach,
	    'injector': createInjector,
	    'noop': noop,
	    'bind': bind,
	    'toJson': toJson,
	    'fromJson': fromJson,
	    'identity': identity,
	    'isUndefined': isUndefined,
	    'isDefined': isDefined,
	    'isString': isString,
	    'isFunction': isFunction,
	    'isObject': isObject,
	    'isNumber': isNumber,
	    'isElement': isElement,
	    'isArray': isArray,
	    'version': version,
	    'isDate': isDate,
	    'lowercase': lowercase,
	    'uppercase': uppercase,
	    'callbacks': {$$counter: 0},
	    'getTestability': getTestability,
	    'reloadWithDebugInfo': reloadWithDebugInfo,
	    '$$minErr': minErr,
	    '$$csp': csp,
	    '$$encodeUriSegment': encodeUriSegment,
	    '$$encodeUriQuery': encodeUriQuery,
	    '$$stringify': stringify
	  });

	  angularModule = setupModuleLoader(window);

	  angularModule('ng', ['ngLocale'], ['$provide',
	    function ngModule($provide) {
	      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
	      $provide.provider({
	        $$sanitizeUri: $$SanitizeUriProvider
	      });
	      $provide.provider('$compile', $CompileProvider).
	        directive({
	            a: htmlAnchorDirective,
	            input: inputDirective,
	            textarea: inputDirective,
	            form: formDirective,
	            script: scriptDirective,
	            select: selectDirective,
	            option: optionDirective,
	            ngBind: ngBindDirective,
	            ngBindHtml: ngBindHtmlDirective,
	            ngBindTemplate: ngBindTemplateDirective,
	            ngClass: ngClassDirective,
	            ngClassEven: ngClassEvenDirective,
	            ngClassOdd: ngClassOddDirective,
	            ngCloak: ngCloakDirective,
	            ngController: ngControllerDirective,
	            ngForm: ngFormDirective,
	            ngHide: ngHideDirective,
	            ngIf: ngIfDirective,
	            ngInclude: ngIncludeDirective,
	            ngInit: ngInitDirective,
	            ngNonBindable: ngNonBindableDirective,
	            ngPluralize: ngPluralizeDirective,
	            ngRepeat: ngRepeatDirective,
	            ngShow: ngShowDirective,
	            ngStyle: ngStyleDirective,
	            ngSwitch: ngSwitchDirective,
	            ngSwitchWhen: ngSwitchWhenDirective,
	            ngSwitchDefault: ngSwitchDefaultDirective,
	            ngOptions: ngOptionsDirective,
	            ngTransclude: ngTranscludeDirective,
	            ngModel: ngModelDirective,
	            ngList: ngListDirective,
	            ngChange: ngChangeDirective,
	            pattern: patternDirective,
	            ngPattern: patternDirective,
	            required: requiredDirective,
	            ngRequired: requiredDirective,
	            minlength: minlengthDirective,
	            ngMinlength: minlengthDirective,
	            maxlength: maxlengthDirective,
	            ngMaxlength: maxlengthDirective,
	            ngValue: ngValueDirective,
	            ngModelOptions: ngModelOptionsDirective
	        }).
	        directive({
	          ngInclude: ngIncludeFillContentDirective
	        }).
	        directive(ngAttributeAliasDirectives).
	        directive(ngEventDirectives);
	      $provide.provider({
	        $anchorScroll: $AnchorScrollProvider,
	        $animate: $AnimateProvider,
	        $animateCss: $CoreAnimateCssProvider,
	        $$animateJs: $$CoreAnimateJsProvider,
	        $$animateQueue: $$CoreAnimateQueueProvider,
	        $$AnimateRunner: $$AnimateRunnerFactoryProvider,
	        $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
	        $browser: $BrowserProvider,
	        $cacheFactory: $CacheFactoryProvider,
	        $controller: $ControllerProvider,
	        $document: $DocumentProvider,
	        $$isDocumentHidden: $$IsDocumentHiddenProvider,
	        $exceptionHandler: $ExceptionHandlerProvider,
	        $filter: $FilterProvider,
	        $$forceReflow: $$ForceReflowProvider,
	        $interpolate: $InterpolateProvider,
	        $interval: $IntervalProvider,
	        $http: $HttpProvider,
	        $httpParamSerializer: $HttpParamSerializerProvider,
	        $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
	        $httpBackend: $HttpBackendProvider,
	        $xhrFactory: $xhrFactoryProvider,
	        $jsonpCallbacks: $jsonpCallbacksProvider,
	        $location: $LocationProvider,
	        $log: $LogProvider,
	        $parse: $ParseProvider,
	        $rootScope: $RootScopeProvider,
	        $q: $QProvider,
	        $$q: $$QProvider,
	        $sce: $SceProvider,
	        $sceDelegate: $SceDelegateProvider,
	        $sniffer: $SnifferProvider,
	        $templateCache: $TemplateCacheProvider,
	        $templateRequest: $TemplateRequestProvider,
	        $$testability: $$TestabilityProvider,
	        $timeout: $TimeoutProvider,
	        $window: $WindowProvider,
	        $$rAF: $$RAFProvider,
	        $$jqLite: $$jqLiteProvider,
	        $$HashMap: $$HashMapProvider,
	        $$cookieReader: $$CookieReaderProvider
	      });
	    }
	  ]);
	}

	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 *     Any commits to this file should be reviewed with security in mind.  *
	 *   Changes to this file can potentially create security vulnerabilities. *
	 *          An approval from 2 Core members with history of modifying      *
	 *                         this file is required.                          *
	 *                                                                         *
	 *  Does the change somehow allow for arbitrary javascript to be executed? *
	 *    Or allows for someone to change the prototype of built-in objects?   *
	 *     Or gives undesired access to variables likes document or window?    *
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

	/* global
	  JQLitePrototype: true,
	  BOOLEAN_ATTR: true,
	  ALIASED_ATTR: true
	*/

	//////////////////////////////////
	//JQLite
	//////////////////////////////////

	/**
	 * @ngdoc function
	 * @name angular.element
	 * @module ng
	 * @kind function
	 *
	 * @description
	 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
	 *
	 * If jQuery is available, `angular.element` is an alias for the
	 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
	 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
	 *
	 * jqLite is a tiny, API-compatible subset of jQuery that allows
	 * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
	 * commonly needed functionality with the goal of having a very small footprint.
	 *
	 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
	 * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
	 * specific version of jQuery if multiple versions exist on the page.
	 *
	 * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
	 * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
	 *
	 * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
	 * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
	 * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
	 *
	 * ## Angular's jqLite
	 * jqLite provides only the following jQuery methods:
	 *
	 * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
	 * - [`after()`](http://api.jquery.com/after/)
	 * - [`append()`](http://api.jquery.com/append/)
	 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
	 * - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
	 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
	 * - [`clone()`](http://api.jquery.com/clone/)
	 * - [`contents()`](http://api.jquery.com/contents/)
	 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
	 *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
	 * - [`data()`](http://api.jquery.com/data/)
	 * - [`detach()`](http://api.jquery.com/detach/)
	 * - [`empty()`](http://api.jquery.com/empty/)
	 * - [`eq()`](http://api.jquery.com/eq/)
	 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
	 * - [`hasClass()`](http://api.jquery.com/hasClass/)
	 * - [`html()`](http://api.jquery.com/html/)
	 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
	 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
	 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
	 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
	 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
	 * - [`prepend()`](http://api.jquery.com/prepend/)
	 * - [`prop()`](http://api.jquery.com/prop/)
	 * - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
	 * - [`remove()`](http://api.jquery.com/remove/)
	 * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
	 * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
	 * - [`removeData()`](http://api.jquery.com/removeData/)
	 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
	 * - [`text()`](http://api.jquery.com/text/)
	 * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
	 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
	 * - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
	 * - [`val()`](http://api.jquery.com/val/)
	 * - [`wrap()`](http://api.jquery.com/wrap/)
	 *
	 * ## jQuery/jqLite Extras
	 * Angular also provides the following additional methods and events to both jQuery and jqLite:
	 *
	 * ### Events
	 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
	 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
	 *    element before it is removed.
	 *
	 * ### Methods
	 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
	 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
	 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
	 *   `'ngModel'`).
	 * - `injector()` - retrieves the injector of the current element or its parent.
	 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
	 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
	 *   be enabled.
	 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
	 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
	 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
	 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
	 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
	 *   parent element is reached.
	 *
	 * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
	 * https://github.com/angular/angular.js/issues/14251 for more information.
	 *
	 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
	 * @returns {Object} jQuery object.
	 */

	JQLite.expando = 'ng339';

	var jqCache = JQLite.cache = {},
	    jqId = 1;

	/*
	 * !!! This is an undocumented "private" function !!!
	 */
	JQLite._data = function(node) {
	  //jQuery always returns an object on cache miss
	  return this.cache[node[this.expando]] || {};
	};

	function jqNextId() { return ++jqId; }


	var DASH_LOWERCASE_REGEXP = /-([a-z])/g;
	var MS_HACK_REGEXP = /^-ms-/;
	var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
	var jqLiteMinErr = minErr('jqLite');

	/**
	 * Converts kebab-case to camelCase.
	 * There is also a special case for the ms prefix starting with a lowercase letter.
	 * @param name Name to normalize
	 */
	function cssKebabToCamel(name) {
	    return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-'));
	}

	function fnCamelCaseReplace(all, letter) {
	  return letter.toUpperCase();
	}

	/**
	 * Converts kebab-case to camelCase.
	 * @param name Name to normalize
	 */
	function kebabToCamel(name) {
	  return name
	    .replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
	}

	var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
	var HTML_REGEXP = /<|&#?\w+;/;
	var TAG_NAME_REGEXP = /<([\w:-]+)/;
	var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;

	var wrapMap = {
	  'option': [1, '<select multiple="multiple">', '</select>'],

	  'thead': [1, '<table>', '</table>'],
	  'col': [2, '<table><colgroup>', '</colgroup></table>'],
	  'tr': [2, '<table><tbody>', '</tbody></table>'],
	  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
	  '_default': [0, '', '']
	};

	wrapMap.optgroup = wrapMap.option;
	wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
	wrapMap.th = wrapMap.td;


	function jqLiteIsTextNode(html) {
	  return !HTML_REGEXP.test(html);
	}

	function jqLiteAcceptsData(node) {
	  // The window object can accept data but has no nodeType
	  // Otherwise we are only interested in elements (1) and documents (9)
	  var nodeType = node.nodeType;
	  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
	}

	function jqLiteHasData(node) {
	  for (var key in jqCache[node.ng339]) {
	    return true;
	  }
	  return false;
	}

	function jqLiteCleanData(nodes) {
	  for (var i = 0, ii = nodes.length; i < ii; i++) {
	    jqLiteRemoveData(nodes[i]);
	  }
	}

	function jqLiteBuildFragment(html, context) {
	  var tmp, tag, wrap,
	      fragment = context.createDocumentFragment(),
	      nodes = [], i;

	  if (jqLiteIsTextNode(html)) {
	    // Convert non-html into a text node
	    nodes.push(context.createTextNode(html));
	  } else {
	    // Convert html into DOM nodes
	    tmp = fragment.appendChild(context.createElement('div'));
	    tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
	    wrap = wrapMap[tag] || wrapMap._default;
	    tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];

	    // Descend through wrappers to the right content
	    i = wrap[0];
	    while (i--) {
	      tmp = tmp.lastChild;
	    }

	    nodes = concat(nodes, tmp.childNodes);

	    tmp = fragment.firstChild;
	    tmp.textContent = '';
	  }

	  // Remove wrapper from fragment
	  fragment.textContent = '';
	  fragment.innerHTML = ''; // Clear inner HTML
	  forEach(nodes, function(node) {
	    fragment.appendChild(node);
	  });

	  return fragment;
	}

	function jqLiteParseHTML(html, context) {
	  context = context || window.document;
	  var parsed;

	  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
	    return [context.createElement(parsed[1])];
	  }

	  if ((parsed = jqLiteBuildFragment(html, context))) {
	    return parsed.childNodes;
	  }

	  return [];
	}

	function jqLiteWrapNode(node, wrapper) {
	  var parent = node.parentNode;

	  if (parent) {
	    parent.replaceChild(wrapper, node);
	  }

	  wrapper.appendChild(node);
	}


	// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
	var jqLiteContains = window.Node.prototype.contains || /** @this */ function(arg) {
	  // eslint-disable-next-line no-bitwise
	  return !!(this.compareDocumentPosition(arg) & 16);
	};

	/////////////////////////////////////////////
	function JQLite(element) {
	  if (element instanceof JQLite) {
	    return element;
	  }

	  var argIsString;

	  if (isString(element)) {
	    element = trim(element);
	    argIsString = true;
	  }
	  if (!(this instanceof JQLite)) {
	    if (argIsString && element.charAt(0) !== '<') {
	      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
	    }
	    return new JQLite(element);
	  }

	  if (argIsString) {
	    jqLiteAddNodes(this, jqLiteParseHTML(element));
	  } else if (isFunction(element)) {
	    jqLiteReady(element);
	  } else {
	    jqLiteAddNodes(this, element);
	  }
	}

	function jqLiteClone(element) {
	  return element.cloneNode(true);
	}

	function jqLiteDealoc(element, onlyDescendants) {
	  if (!onlyDescendants) jqLiteRemoveData(element);

	  if (element.querySelectorAll) {
	    var descendants = element.querySelectorAll('*');
	    for (var i = 0, l = descendants.length; i < l; i++) {
	      jqLiteRemoveData(descendants[i]);
	    }
	  }
	}

	function jqLiteOff(element, type, fn, unsupported) {
	  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');

	  var expandoStore = jqLiteExpandoStore(element);
	  var events = expandoStore && expandoStore.events;
	  var handle = expandoStore && expandoStore.handle;

	  if (!handle) return; //no listeners registered

	  if (!type) {
	    for (type in events) {
	      if (type !== '$destroy') {
	        element.removeEventListener(type, handle);
	      }
	      delete events[type];
	    }
	  } else {

	    var removeHandler = function(type) {
	      var listenerFns = events[type];
	      if (isDefined(fn)) {
	        arrayRemove(listenerFns || [], fn);
	      }
	      if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
	        element.removeEventListener(type, handle);
	        delete events[type];
	      }
	    };

	    forEach(type.split(' '), function(type) {
	      removeHandler(type);
	      if (MOUSE_EVENT_MAP[type]) {
	        removeHandler(MOUSE_EVENT_MAP[type]);
	      }
	    });
	  }
	}

	function jqLiteRemoveData(element, name) {
	  var expandoId = element.ng339;
	  var expandoStore = expandoId && jqCache[expandoId];

	  if (expandoStore) {
	    if (name) {
	      delete expandoStore.data[name];
	      return;
	    }

	    if (expandoStore.handle) {
	      if (expandoStore.events.$destroy) {
	        expandoStore.handle({}, '$destroy');
	      }
	      jqLiteOff(element);
	    }
	    delete jqCache[expandoId];
	    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
	  }
	}


	function jqLiteExpandoStore(element, createIfNecessary) {
	  var expandoId = element.ng339,
	      expandoStore = expandoId && jqCache[expandoId];

	  if (createIfNecessary && !expandoStore) {
	    element.ng339 = expandoId = jqNextId();
	    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
	  }

	  return expandoStore;
	}


	function jqLiteData(element, key, value) {
	  if (jqLiteAcceptsData(element)) {
	    var prop;

	    var isSimpleSetter = isDefined(value);
	    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
	    var massGetter = !key;
	    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
	    var data = expandoStore && expandoStore.data;

	    if (isSimpleSetter) { // data('key', value)
	      data[kebabToCamel(key)] = value;
	    } else {
	      if (massGetter) {  // data()
	        return data;
	      } else {
	        if (isSimpleGetter) { // data('key')
	          // don't force creation of expandoStore if it doesn't exist yet
	          return data && data[kebabToCamel(key)];
	        } else { // mass-setter: data({key1: val1, key2: val2})
	          for (prop in key) {
	            data[kebabToCamel(prop)] = key[prop];
	          }
	        }
	      }
	    }
	  }
	}

	function jqLiteHasClass(element, selector) {
	  if (!element.getAttribute) return false;
	  return ((' ' + (element.getAttribute('class') || '') + ' ').replace(/[\n\t]/g, ' ').
	      indexOf(' ' + selector + ' ') > -1);
	}

	function jqLiteRemoveClass(element, cssClasses) {
	  if (cssClasses && element.setAttribute) {
	    forEach(cssClasses.split(' '), function(cssClass) {
	      element.setAttribute('class', trim(
	          (' ' + (element.getAttribute('class') || '') + ' ')
	          .replace(/[\n\t]/g, ' ')
	          .replace(' ' + trim(cssClass) + ' ', ' '))
	      );
	    });
	  }
	}

	function jqLiteAddClass(element, cssClasses) {
	  if (cssClasses && element.setAttribute) {
	    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
	                            .replace(/[\n\t]/g, ' ');

	    forEach(cssClasses.split(' '), function(cssClass) {
	      cssClass = trim(cssClass);
	      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
	        existingClasses += cssClass + ' ';
	      }
	    });

	    element.setAttribute('class', trim(existingClasses));
	  }
	}


	function jqLiteAddNodes(root, elements) {
	  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.

	  if (elements) {

	    // if a Node (the most common case)
	    if (elements.nodeType) {
	      root[root.length++] = elements;
	    } else {
	      var length = elements.length;

	      // if an Array or NodeList and not a Window
	      if (typeof length === 'number' && elements.window !== elements) {
	        if (length) {
	          for (var i = 0; i < length; i++) {
	            root[root.length++] = elements[i];
	          }
	        }
	      } else {
	        root[root.length++] = elements;
	      }
	    }
	  }
	}


	function jqLiteController(element, name) {
	  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
	}

	function jqLiteInheritedData(element, name, value) {
	  // if element is the document object work with the html element instead
	  // this makes $(document).scope() possible
	  if (element.nodeType === NODE_TYPE_DOCUMENT) {
	    element = element.documentElement;
	  }
	  var names = isArray(name) ? name : [name];

	  while (element) {
	    for (var i = 0, ii = names.length; i < ii; i++) {
	      if (isDefined(value = jqLite.data(element, names[i]))) return value;
	    }

	    // If dealing with a document fragment node with a host element, and no parent, use the host
	    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
	    // to lookup parent controllers.
	    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
	  }
	}

	function jqLiteEmpty(element) {
	  jqLiteDealoc(element, true);
	  while (element.firstChild) {
	    element.removeChild(element.firstChild);
	  }
	}

	function jqLiteRemove(element, keepData) {
	  if (!keepData) jqLiteDealoc(element);
	  var parent = element.parentNode;
	  if (parent) parent.removeChild(element);
	}


	function jqLiteDocumentLoaded(action, win) {
	  win = win || window;
	  if (win.document.readyState === 'complete') {
	    // Force the action to be run async for consistent behavior
	    // from the action's point of view
	    // i.e. it will definitely not be in a $apply
	    win.setTimeout(action);
	  } else {
	    // No need to unbind this handler as load is only ever called once
	    jqLite(win).on('load', action);
	  }
	}

	function jqLiteReady(fn) {
	  function trigger() {
	    window.document.removeEventListener('DOMContentLoaded', trigger);
	    window.removeEventListener('load', trigger);
	    fn();
	  }

	  // check if document is already loaded
	  if (window.document.readyState === 'complete') {
	    window.setTimeout(fn);
	  } else {
	    // We can not use jqLite since we are not done loading and jQuery could be loaded later.

	    // Works for modern browsers and IE9
	    window.document.addEventListener('DOMContentLoaded', trigger);

	    // Fallback to window.onload for others
	    window.addEventListener('load', trigger);
	  }
	}

	//////////////////////////////////////////
	// Functions which are declared directly.
	//////////////////////////////////////////
	var JQLitePrototype = JQLite.prototype = {
	  ready: jqLiteReady,
	  toString: function() {
	    var value = [];
	    forEach(this, function(e) { value.push('' + e);});
	    return '[' + value.join(', ') + ']';
	  },

	  eq: function(index) {
	      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
	  },

	  length: 0,
	  push: push,
	  sort: [].sort,
	  splice: [].splice
	};

	//////////////////////////////////////////
	// Functions iterating getter/setters.
	// these functions return self on setter and
	// value on get.
	//////////////////////////////////////////
	var BOOLEAN_ATTR = {};
	forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
	  BOOLEAN_ATTR[lowercase(value)] = value;
	});
	var BOOLEAN_ELEMENTS = {};
	forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
	  BOOLEAN_ELEMENTS[value] = true;
	});
	var ALIASED_ATTR = {
	  'ngMinlength': 'minlength',
	  'ngMaxlength': 'maxlength',
	  'ngMin': 'min',
	  'ngMax': 'max',
	  'ngPattern': 'pattern',
	  'ngStep': 'step'
	};

	function getBooleanAttrName(element, name) {
	  // check dom last since we will most likely fail on name
	  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];

	  // booleanAttr is here twice to minimize DOM access
	  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
	}

	function getAliasedAttrName(name) {
	  return ALIASED_ATTR[name];
	}

	forEach({
	  data: jqLiteData,
	  removeData: jqLiteRemoveData,
	  hasData: jqLiteHasData,
	  cleanData: jqLiteCleanData
	}, function(fn, name) {
	  JQLite[name] = fn;
	});

	forEach({
	  data: jqLiteData,
	  inheritedData: jqLiteInheritedData,

	  scope: function(element) {
	    // Can't use jqLiteData here directly so we stay compatible with jQuery!
	    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
	  },

	  isolateScope: function(element) {
	    // Can't use jqLiteData here directly so we stay compatible with jQuery!
	    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
	  },

	  controller: jqLiteController,

	  injector: function(element) {
	    return jqLiteInheritedData(element, '$injector');
	  },

	  removeAttr: function(element, name) {
	    element.removeAttribute(name);
	  },

	  hasClass: jqLiteHasClass,

	  css: function(element, name, value) {
	    name = cssKebabToCamel(name);

	    if (isDefined(value)) {
	      element.style[name] = value;
	    } else {
	      return element.style[name];
	    }
	  },

	  attr: function(element, name, value) {
	    var ret;
	    var nodeType = element.nodeType;
	    if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
	      !element.getAttribute) {
	      return;
	    }

	    var lowercasedName = lowercase(name);
	    var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];

	    if (isDefined(value)) {
	      // setter

	      if (value === null || (value === false && isBooleanAttr)) {
	        element.removeAttribute(name);
	      } else {
	        element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
	      }
	    } else {
	      // getter

	      ret = element.getAttribute(name);

	      if (isBooleanAttr && ret !== null) {
	        ret = lowercasedName;
	      }
	      // Normalize non-existing attributes to undefined (as jQuery).
	      return ret === null ? undefined : ret;
	    }
	  },

	  prop: function(element, name, value) {
	    if (isDefined(value)) {
	      element[name] = value;
	    } else {
	      return element[name];
	    }
	  },

	  text: (function() {
	    getText.$dv = '';
	    return getText;

	    function getText(element, value) {
	      if (isUndefined(value)) {
	        var nodeType = element.nodeType;
	        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
	      }
	      element.textContent = value;
	    }
	  })(),

	  val: function(element, value) {
	    if (isUndefined(value)) {
	      if (element.multiple && nodeName_(element) === 'select') {
	        var result = [];
	        forEach(element.options, function(option) {
	          if (option.selected) {
	            result.push(option.value || option.text);
	          }
	        });
	        return result;
	      }
	      return element.value;
	    }
	    element.value = value;
	  },

	  html: function(element, value) {
	    if (isUndefined(value)) {
	      return element.innerHTML;
	    }
	    jqLiteDealoc(element, true);
	    element.innerHTML = value;
	  },

	  empty: jqLiteEmpty
	}, function(fn, name) {
	  /**
	   * Properties: writes return selection, reads return first value
	   */
	  JQLite.prototype[name] = function(arg1, arg2) {
	    var i, key;
	    var nodeCount = this.length;

	    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
	    // in a way that survives minification.
	    // jqLiteEmpty takes no arguments but is a setter.
	    if (fn !== jqLiteEmpty &&
	        (isUndefined((fn.length === 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
	      if (isObject(arg1)) {

	        // we are a write, but the object properties are the key/values
	        for (i = 0; i < nodeCount; i++) {
	          if (fn === jqLiteData) {
	            // data() takes the whole object in jQuery
	            fn(this[i], arg1);
	          } else {
	            for (key in arg1) {
	              fn(this[i], key, arg1[key]);
	            }
	          }
	        }
	        // return self for chaining
	        return this;
	      } else {
	        // we are a read, so read the first child.
	        // TODO: do we still need this?
	        var value = fn.$dv;
	        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
	        var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
	        for (var j = 0; j < jj; j++) {
	          var nodeValue = fn(this[j], arg1, arg2);
	          value = value ? value + nodeValue : nodeValue;
	        }
	        return value;
	      }
	    } else {
	      // we are a write, so apply to all children
	      for (i = 0; i < nodeCount; i++) {
	        fn(this[i], arg1, arg2);
	      }
	      // return self for chaining
	      return this;
	    }
	  };
	});

	function createEventHandler(element, events) {
	  var eventHandler = function(event, type) {
	    // jQuery specific api
	    event.isDefaultPrevented = function() {
	      return event.defaultPrevented;
	    };

	    var eventFns = events[type || event.type];
	    var eventFnsLength = eventFns ? eventFns.length : 0;

	    if (!eventFnsLength) return;

	    if (isUndefined(event.immediatePropagationStopped)) {
	      var originalStopImmediatePropagation = event.stopImmediatePropagation;
	      event.stopImmediatePropagation = function() {
	        event.immediatePropagationStopped = true;

	        if (event.stopPropagation) {
	          event.stopPropagation();
	        }

	        if (originalStopImmediatePropagation) {
	          originalStopImmediatePropagation.call(event);
	        }
	      };
	    }

	    event.isImmediatePropagationStopped = function() {
	      return event.immediatePropagationStopped === true;
	    };

	    // Some events have special handlers that wrap the real handler
	    var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;

	    // Copy event handlers in case event handlers array is modified during execution.
	    if ((eventFnsLength > 1)) {
	      eventFns = shallowCopy(eventFns);
	    }

	    for (var i = 0; i < eventFnsLength; i++) {
	      if (!event.isImmediatePropagationStopped()) {
	        handlerWrapper(element, event, eventFns[i]);
	      }
	    }
	  };

	  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
	  //       events on `element`
	  eventHandler.elem = element;
	  return eventHandler;
	}

	function defaultHandlerWrapper(element, event, handler) {
	  handler.call(element, event);
	}

	function specialMouseHandlerWrapper(target, event, handler) {
	  // Refer to jQuery's implementation of mouseenter & mouseleave
	  // Read about mouseenter and mouseleave:
	  // http://www.quirksmode.org/js/events_mouse.html#link8
	  var related = event.relatedTarget;
	  // For mousenter/leave call the handler if related is outside the target.
	  // NB: No relatedTarget if the mouse left/entered the browser window
	  if (!related || (related !== target && !jqLiteContains.call(target, related))) {
	    handler.call(target, event);
	  }
	}

	//////////////////////////////////////////
	// Functions iterating traversal.
	// These functions chain results into a single
	// selector.
	//////////////////////////////////////////
	forEach({
	  removeData: jqLiteRemoveData,

	  on: function jqLiteOn(element, type, fn, unsupported) {
	    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');

	    // Do not add event handlers to non-elements because they will not be cleaned up.
	    if (!jqLiteAcceptsData(element)) {
	      return;
	    }

	    var expandoStore = jqLiteExpandoStore(element, true);
	    var events = expandoStore.events;
	    var handle = expandoStore.handle;

	    if (!handle) {
	      handle = expandoStore.handle = createEventHandler(element, events);
	    }

	    // http://jsperf.com/string-indexof-vs-split
	    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
	    var i = types.length;

	    var addHandler = function(type, specialHandlerWrapper, noEventListener) {
	      var eventFns = events[type];

	      if (!eventFns) {
	        eventFns = events[type] = [];
	        eventFns.specialHandlerWrapper = specialHandlerWrapper;
	        if (type !== '$destroy' && !noEventListener) {
	          element.addEventListener(type, handle);
	        }
	      }

	      eventFns.push(fn);
	    };

	    while (i--) {
	      type = types[i];
	      if (MOUSE_EVENT_MAP[type]) {
	        addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
	        addHandler(type, undefined, true);
	      } else {
	        addHandler(type);
	      }
	    }
	  },

	  off: jqLiteOff,

	  one: function(element, type, fn) {
	    element = jqLite(element);

	    //add the listener twice so that when it is called
	    //you can remove the original function and still be
	    //able to call element.off(ev, fn) normally
	    element.on(type, function onFn() {
	      element.off(type, fn);
	      element.off(type, onFn);
	    });
	    element.on(type, fn);
	  },

	  replaceWith: function(element, replaceNode) {
	    var index, parent = element.parentNode;
	    jqLiteDealoc(element);
	    forEach(new JQLite(replaceNode), function(node) {
	      if (index) {
	        parent.insertBefore(node, index.nextSibling);
	      } else {
	        parent.replaceChild(node, element);
	      }
	      index = node;
	    });
	  },

	  children: function(element) {
	    var children = [];
	    forEach(element.childNodes, function(element) {
	      if (element.nodeType === NODE_TYPE_ELEMENT) {
	        children.push(element);
	      }
	    });
	    return children;
	  },

	  contents: function(element) {
	    return element.contentDocument || element.childNodes || [];
	  },

	  append: function(element, node) {
	    var nodeType = element.nodeType;
	    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;

	    node = new JQLite(node);

	    for (var i = 0, ii = node.length; i < ii; i++) {
	      var child = node[i];
	      element.appendChild(child);
	    }
	  },

	  prepend: function(element, node) {
	    if (element.nodeType === NODE_TYPE_ELEMENT) {
	      var index = element.firstChild;
	      forEach(new JQLite(node), function(child) {
	        element.insertBefore(child, index);
	      });
	    }
	  },

	  wrap: function(element, wrapNode) {
	    jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
	  },

	  remove: jqLiteRemove,

	  detach: function(element) {
	    jqLiteRemove(element, true);
	  },

	  after: function(element, newElement) {
	    var index = element, parent = element.parentNode;

	    if (parent) {
	      newElement = new JQLite(newElement);

	      for (var i = 0, ii = newElement.length; i < ii; i++) {
	        var node = newElement[i];
	        parent.insertBefore(node, index.nextSibling);
	        index = node;
	      }
	    }
	  },

	  addClass: jqLiteAddClass,
	  removeClass: jqLiteRemoveClass,

	  toggleClass: function(element, selector, condition) {
	    if (selector) {
	      forEach(selector.split(' '), function(className) {
	        var classCondition = condition;
	        if (isUndefined(classCondition)) {
	          classCondition = !jqLiteHasClass(element, className);
	        }
	        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
	      });
	    }
	  },

	  parent: function(element) {
	    var parent = element.parentNode;
	    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
	  },

	  next: function(element) {
	    return element.nextElementSibling;
	  },

	  find: function(element, selector) {
	    if (element.getElementsByTagName) {
	      return element.getElementsByTagName(selector);
	    } else {
	      return [];
	    }
	  },

	  clone: jqLiteClone,

	  triggerHandler: function(element, event, extraParameters) {

	    var dummyEvent, eventFnsCopy, handlerArgs;
	    var eventName = event.type || event;
	    var expandoStore = jqLiteExpandoStore(element);
	    var events = expandoStore && expandoStore.events;
	    var eventFns = events && events[eventName];

	    if (eventFns) {
	      // Create a dummy event to pass to the handlers
	      dummyEvent = {
	        preventDefault: function() { this.defaultPrevented = true; },
	        isDefaultPrevented: function() { return this.defaultPrevented === true; },
	        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
	        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
	        stopPropagation: noop,
	        type: eventName,
	        target: element
	      };

	      // If a custom event was provided then extend our dummy event with it
	      if (event.type) {
	        dummyEvent = extend(dummyEvent, event);
	      }

	      // Copy event handlers in case event handlers array is modified during execution.
	      eventFnsCopy = shallowCopy(eventFns);
	      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];

	      forEach(eventFnsCopy, function(fn) {
	        if (!dummyEvent.isImmediatePropagationStopped()) {
	          fn.apply(element, handlerArgs);
	        }
	      });
	    }
	  }
	}, function(fn, name) {
	  /**
	   * chaining functions
	   */
	  JQLite.prototype[name] = function(arg1, arg2, arg3) {
	    var value;

	    for (var i = 0, ii = this.length; i < ii; i++) {
	      if (isUndefined(value)) {
	        value = fn(this[i], arg1, arg2, arg3);
	        if (isDefined(value)) {
	          // any function which returns a value needs to be wrapped
	          value = jqLite(value);
	        }
	      } else {
	        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
	      }
	    }
	    return isDefined(value) ? value : this;
	  };
	});

	// bind legacy bind/unbind to on/off
	JQLite.prototype.bind = JQLite.prototype.on;
	JQLite.prototype.unbind = JQLite.prototype.off;


	// Provider for private $$jqLite service
	/** @this */
	function $$jqLiteProvider() {
	  this.$get = function $$jqLite() {
	    return extend(JQLite, {
	      hasClass: function(node, classes) {
	        if (node.attr) node = node[0];
	        return jqLiteHasClass(node, classes);
	      },
	      addClass: function(node, classes) {
	        if (node.attr) node = node[0];
	        return jqLiteAddClass(node, classes);
	      },
	      removeClass: function(node, classes) {
	        if (node.attr) node = node[0];
	        return jqLiteRemoveClass(node, classes);
	      }
	    });
	  };
	}

	/**
	 * Computes a hash of an 'obj'.
	 * Hash of a:
	 *  string is string
	 *  number is number as string
	 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
	 *         that is also assigned to the $$hashKey property of the object.
	 *
	 * @param obj
	 * @returns {string} hash string such that the same input will have the same hash string.
	 *         The resulting string key is in 'type:hashKey' format.
	 */
	function hashKey(obj, nextUidFn) {
	  var key = obj && obj.$$hashKey;

	  if (key) {
	    if (typeof key === 'function') {
	      key = obj.$$hashKey();
	    }
	    return key;
	  }

	  var objType = typeof obj;
	  if (objType === 'function' || (objType === 'object' && obj !== null)) {
	    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
	  } else {
	    key = objType + ':' + obj;
	  }

	  return key;
	}

	/**
	 * HashMap which can use objects as keys
	 */
	function HashMap(array, isolatedUid) {
	  if (isolatedUid) {
	    var uid = 0;
	    this.nextUid = function() {
	      return ++uid;
	    };
	  }
	  forEach(array, this.put, this);
	}
	HashMap.prototype = {
	  /**
	   * Store key value pair
	   * @param key key to store can be any type
	   * @param value value to store can be any type
	   */
	  put: function(key, value) {
	    this[hashKey(key, this.nextUid)] = value;
	  },

	  /**
	   * @param key
	   * @returns {Object} the value for the key
	   */
	  get: function(key) {
	    return this[hashKey(key, this.nextUid)];
	  },

	  /**
	   * Remove the key/value pair
	   * @param key
	   */
	  remove: function(key) {
	    var value = this[key = hashKey(key, this.nextUid)];
	    delete this[key];
	    return value;
	  }
	};

	var $$HashMapProvider = [/** @this */function() {
	  this.$get = [function() {
	    return HashMap;
	  }];
	}];

	/**
	 * @ngdoc function
	 * @module ng
	 * @name angular.injector
	 * @kind function
	 *
	 * @description
	 * Creates an injector object that can be used for retrieving services as well as for
	 * dependency injection (see {@link guide/di dependency injection}).
	 *
	 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
	 *     {@link angular.module}. The `ng` module must be explicitly added.
	 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
	 *     disallows argument name annotation inference.
	 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
	 *
	 * @example
	 * Typical usage
	 * ```js
	 *   // create an injector
	 *   var $injector = angular.injector(['ng']);
	 *
	 *   // use the injector to kick off your application
	 *   // use the type inference to auto inject arguments, or use implicit injection
	 *   $injector.invoke(function($rootScope, $compile, $document) {
	 *     $compile($document)($rootScope);
	 *     $rootScope.$digest();
	 *   });
	 * ```
	 *
	 * Sometimes you want to get access to the injector of a currently running Angular app
	 * from outside Angular. Perhaps, you want to inject and compile some markup after the
	 * application has been bootstrapped. You can do this using the extra `injector()` added
	 * to JQuery/jqLite elements. See {@link angular.element}.
	 *
	 * *This is fairly rare but could be the case if a third party library is injecting the
	 * markup.*
	 *
	 * In the following example a new block of HTML containing a `ng-controller`
	 * directive is added to the end of the document body by JQuery. We then compile and link
	 * it into the current AngularJS scope.
	 *
	 * ```js
	 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
	 * $(document.body).append($div);
	 *
	 * angular.element(document).injector().invoke(function($compile) {
	 *   var scope = angular.element($div).scope();
	 *   $compile($div)(scope);
	 * });
	 * ```
	 */


	/**
	 * @ngdoc module
	 * @name auto
	 * @installation
	 * @description
	 *
	 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
	 */

	var ARROW_ARG = /^([^(]+?)=>/;
	var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m;
	var FN_ARG_SPLIT = /,/;
	var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
	var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
	var $injectorMinErr = minErr('$injector');

	function stringifyFn(fn) {
	  // Support: Chrome 50-51 only
	  // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
	  // (See https://github.com/angular/angular.js/issues/14487.)
	  // TODO (gkalpak): Remove workaround when Chrome v52 is released
	  return Function.prototype.toString.call(fn) + ' ';
	}

	function extractArgs(fn) {
	  var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
	      args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
	  return args;
	}

	function anonFn(fn) {
	  // For anonymous functions, showing at the very least the function signature can help in
	  // debugging.
	  var args = extractArgs(fn);
	  if (args) {
	    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
	  }
	  return 'fn';
	}

	function annotate(fn, strictDi, name) {
	  var $inject,
	      argDecl,
	      last;

	  if (typeof fn === 'function') {
	    if (!($inject = fn.$inject)) {
	      $inject = [];
	      if (fn.length) {
	        if (strictDi) {
	          if (!isString(name) || !name) {
	            name = fn.name || anonFn(fn);
	          }
	          throw $injectorMinErr('strictdi',
	            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
	        }
	        argDecl = extractArgs(fn);
	        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
	          arg.replace(FN_ARG, function(all, underscore, name) {
	            $inject.push(name);
	          });
	        });
	      }
	      fn.$inject = $inject;
	    }
	  } else if (isArray(fn)) {
	    last = fn.length - 1;
	    assertArgFn(fn[last], 'fn');
	    $inject = fn.slice(0, last);
	  } else {
	    assertArgFn(fn, 'fn', true);
	  }
	  return $inject;
	}

	///////////////////////////////////////

	/**
	 * @ngdoc service
	 * @name $injector
	 *
	 * @description
	 *
	 * `$injector` is used to retrieve object instances as defined by
	 * {@link auto.$provide provider}, instantiate types, invoke methods,
	 * and load modules.
	 *
	 * The following always holds true:
	 *
	 * ```js
	 *   var $injector = angular.injector();
	 *   expect($injector.get('$injector')).toBe($injector);
	 *   expect($injector.invoke(function($injector) {
	 *     return $injector;
	 *   })).toBe($injector);
	 * ```
	 *
	 * # Injection Function Annotation
	 *
	 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
	 * following are all valid ways of annotating function with injection arguments and are equivalent.
	 *
	 * ```js
	 *   // inferred (only works if code not minified/obfuscated)
	 *   $injector.invoke(function(serviceA){});
	 *
	 *   // annotated
	 *   function explicit(serviceA) {};
	 *   explicit.$inject = ['serviceA'];
	 *   $injector.invoke(explicit);
	 *
	 *   // inline
	 *   $injector.invoke(['serviceA', function(serviceA){}]);
	 * ```
	 *
	 * ## Inference
	 *
	 * In JavaScript calling `toString()` on a function returns the function definition. The definition
	 * can then be parsed and the function arguments can be extracted. This method of discovering
	 * annotations is disallowed when the injector is in strict mode.
	 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
	 * argument names.
	 *
	 * ## `$inject` Annotation
	 * By adding an `$inject` property onto a function the injection parameters can be specified.
	 *
	 * ## Inline
	 * As an array of injection names, where the last item in the array is the function to call.
	 */

	/**
	 * @ngdoc method
	 * @name $injector#get
	 *
	 * @description
	 * Return an instance of the service.
	 *
	 * @param {string} name The name of the instance to retrieve.
	 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
	 * @return {*} The instance.
	 */

	/**
	 * @ngdoc method
	 * @name $injector#invoke
	 *
	 * @description
	 * Invoke the method and supply the method arguments from the `$injector`.
	 *
	 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
	 *   injected according to the {@link guide/di $inject Annotation} rules.
	 * @param {Object=} self The `this` for the invoked method.
	 * @param {Object=} locals Optional object. If preset then any argument names are read from this
	 *                         object first, before the `$injector` is consulted.
	 * @returns {*} the value returned by the invoked `fn` function.
	 */

	/**
	 * @ngdoc method
	 * @name $injector#has
	 *
	 * @description
	 * Allows the user to query if the particular service exists.
	 *
	 * @param {string} name Name of the service to query.
	 * @returns {boolean} `true` if injector has given service.
	 */

	/**
	 * @ngdoc method
	 * @name $injector#instantiate
	 * @description
	 * Create a new instance of JS type. The method takes a constructor function, invokes the new
	 * operator, and supplies all of the arguments to the constructor function as specified by the
	 * constructor annotation.
	 *
	 * @param {Function} Type Annotated constructor function.
	 * @param {Object=} locals Optional object. If preset then any argument names are read from this
	 * object first, before the `$injector` is consulted.
	 * @returns {Object} new instance of `Type`.
	 */

	/**
	 * @ngdoc method
	 * @name $injector#annotate
	 *
	 * @description
	 * Returns an array of service names which the function is requesting for injection. This API is
	 * used by the injector to determine which services need to be injected into the function when the
	 * function is invoked. There are three ways in which the function can be annotated with the needed
	 * dependencies.
	 *
	 * # Argument names
	 *
	 * The simplest form is to extract the dependencies from the arguments of the function. This is done
	 * by converting the function into a string using `toString()` method and extracting the argument
	 * names.
	 * ```js
	 *   // Given
	 *   function MyController($scope, $route) {
	 *     // ...
	 *   }
	 *
	 *   // Then
	 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
	 * ```
	 *
	 * You can disallow this method by using strict injection mode.
	 *
	 * This method does not work with code minification / obfuscation. For this reason the following
	 * annotation strategies are supported.
	 *
	 * # The `$inject` property
	 *
	 * If a function has an `$inject` property and its value is an array of strings, then the strings
	 * represent names of services to be injected into the function.
	 * ```js
	 *   // Given
	 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
	 *     // ...
	 *   }
	 *   // Define function dependencies
	 *   MyController['$inject'] = ['$scope', '$route'];
	 *
	 *   // Then
	 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
	 * ```
	 *
	 * # The array notation
	 *
	 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
	 * is very inconvenient. In these situations using the array notation to specify the dependencies in
	 * a way that survives minification is a better choice:
	 *
	 * ```js
	 *   // We wish to write this (not minification / obfuscation safe)
	 *   injector.invoke(function($compile, $rootScope) {
	 *     // ...
	 *   });
	 *
	 *   // We are forced to write break inlining
	 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
	 *     // ...
	 *   };
	 *   tmpFn.$inject = ['$compile', '$rootScope'];
	 *   injector.invoke(tmpFn);
	 *
	 *   // To better support inline function the inline annotation is supported
	 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
	 *     // ...
	 *   }]);
	 *
	 *   // Therefore
	 *   expect(injector.annotate(
	 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
	 *    ).toEqual(['$compile', '$rootScope']);
	 * ```
	 *
	 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
	 * be retrieved as described above.
	 *
	 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
	 *
	 * @returns {Array.<string>} The names of the services which the function requires.
	 */



	/**
	 * @ngdoc service
	 * @name $provide
	 *
	 * @description
	 *
	 * The {@link auto.$provide $provide} service has a number of methods for registering components
	 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
	 * {@link angular.Module}.
	 *
	 * An Angular **service** is a singleton object created by a **service factory**.  These **service
	 * factories** are functions which, in turn, are created by a **service provider**.
	 * The **service providers** are constructor functions. When instantiated they must contain a
	 * property called `$get`, which holds the **service factory** function.
	 *
	 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
	 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
	 * function to get the instance of the **service**.
	 *
	 * Often services have no configuration options and there is no need to add methods to the service
	 * provider.  The provider will be no more than a constructor function with a `$get` property. For
	 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
	 * services without specifying a provider.
	 *
	 * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
	 *     {@link auto.$injector $injector}
	 * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
	 *     providers and services.
	 * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
	 *     services, not providers.
	 * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
	 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
	 *     given factory function.
	 * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
	 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
	 *      a new object using the given constructor function.
	 * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
	 *      will be able to modify or replace the implementation of another service.
	 *
	 * See the individual methods for more information and examples.
	 */

	/**
	 * @ngdoc method
	 * @name $provide#provider
	 * @description
	 *
	 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
	 * are constructor functions, whose instances are responsible for "providing" a factory for a
	 * service.
	 *
	 * Service provider names start with the name of the service they provide followed by `Provider`.
	 * For example, the {@link ng.$log $log} service has a provider called
	 * {@link ng.$logProvider $logProvider}.
	 *
	 * Service provider objects can have additional methods which allow configuration of the provider
	 * and its service. Importantly, you can configure what kind of service is created by the `$get`
	 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
	 * method {@link ng.$logProvider#debugEnabled debugEnabled}
	 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
	 * console or not.
	 *
	 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
	                        'Provider'` key.
	 
Download .txt
gitextract_n7x54ki7/

├── .babelrc
├── .eslintrc
├── .gitignore
├── .travis.yml
├── bower.json
├── dist/
│   ├── angular-file-saver.bundle.js
│   └── angular-file-saver.js
├── docs/
│   ├── assets/
│   │   ├── js/
│   │   │   └── custom.js
│   │   └── stylesheets/
│   │       ├── github-light.css
│   │       ├── normalize.css
│   │       └── stylesheet.css
│   ├── dist/
│   │   ├── examples.css
│   │   └── examples.js
│   ├── index.html
│   └── params.json
├── gulpfile.babel.js
├── karma.conf.js
├── license.md
├── package.json
├── readme.md
├── src/
│   ├── angular-file-saver-bundle.module.js
│   ├── angular-file-saver.module.js
│   ├── angular-file-saver.service.js
│   ├── dependencies/
│   │   ├── blob-bundle.service.js
│   │   ├── blob.service.js
│   │   ├── file-saver-bundle.service.js
│   │   └── file-saver.service.js
│   └── utils/
│       └── utils.service.js
└── test/
    ├── angular-file-saver-bundle.spec.js
    ├── blob-bundle.spec.js
    └── file-saver-bundle.spec.js
Download .txt
SYMBOL INDEX (305 symbols across 5 files)

FILE: dist/angular-file-saver.bundle.js
  function __webpack_require__ (line 16) | function __webpack_require__(moduleId) {
  function save (line 85) | function save(blob, filename, disableAutoBOM) {

FILE: dist/angular-file-saver.js
  function __webpack_require__ (line 16) | function __webpack_require__(moduleId) {
  function save (line 86) | function save(blob, filename, disableAutoBOM) {

FILE: docs/assets/js/custom.js
  function DownloadText (line 6) | function DownloadText(FileSaver, Blob, $timeout) {

FILE: docs/dist/examples.js
  function __webpack_require__ (line 16) | function __webpack_require__(moduleId) {
  function DownloadText (line 62) | function DownloadText(FileSaver, Blob, $timeout) {
  function minErr (line 129) | function minErr(module, ErrorConstructor) {
  function isArrayLike (line 378) | function isArrayLike(obj) {
  function forEach (line 435) | function forEach(obj, iterator, context) {
  function forEachSorted (line 477) | function forEachSorted(obj, iterator, context) {
  function reverseParams (line 491) | function reverseParams(iteratorFn) {
  function nextUid (line 505) | function nextUid() {
  function setHashKey (line 515) | function setHashKey(obj, h) {
  function baseExtend (line 524) | function baseExtend(dst, objs, deep) {
  function extend (line 576) | function extend(dst) {
  function merge (line 599) | function merge(dst) {
  function toInt (line 605) | function toInt(str) {
  function inherit (line 615) | function inherit(parent, extra) {
  function noop (line 635) | function noop() {}
  function identity (line 667) | function identity($) {return $;}
  function valueFn (line 671) | function valueFn(value) {return function valueRef() {return value;};}
  function hasCustomToString (line 673) | function hasCustomToString(obj) {
  function isUndefined (line 690) | function isUndefined(value) {return typeof value === 'undefined';}
  function isDefined (line 705) | function isDefined(value) {return typeof value !== 'undefined';}
  function isObject (line 721) | function isObject(value) {
  function isBlankObject (line 732) | function isBlankObject(value) {
  function isString (line 749) | function isString(value) {return typeof value === 'string';}
  function isNumber (line 770) | function isNumber(value) {return typeof value === 'number';}
  function isDate (line 785) | function isDate(value) {
  function isFunction (line 816) | function isFunction(value) {return typeof value === 'function';}
  function isRegExp (line 826) | function isRegExp(value) {
  function isWindow (line 838) | function isWindow(obj) {
  function isScope (line 843) | function isScope(obj) {
  function isFile (line 848) | function isFile(obj) {
  function isFormData (line 853) | function isFormData(obj) {
  function isBlob (line 858) | function isBlob(obj) {
  function isBoolean (line 863) | function isBoolean(value) {
  function isPromiseLike (line 868) | function isPromiseLike(obj) {
  function isTypedArray (line 874) | function isTypedArray(value) {
  function isArrayBuffer (line 878) | function isArrayBuffer(obj) {
  function isElement (line 910) | function isElement(node) {
  function makeMap (line 920) | function makeMap(str) {
  function nodeName_ (line 929) | function nodeName_(element) {
  function includes (line 933) | function includes(array, obj) {
  function arrayRemove (line 937) | function arrayRemove(array, value) {
  function copy (line 1010) | function copy(source, destination) {
  function equals (line 1214) | function equals(o1, o2) {
  function noUnsafeEval (line 1280) | function noUnsafeEval() {
  function concat (line 1345) | function concat(array1, array2, index) {
  function sliceArgs (line 1349) | function sliceArgs(args, startIndex) {
  function bind (line 1371) | function bind(self, fn) {
  function toJsonReplacer (line 1392) | function toJsonReplacer(key, value) {
  function toJson (line 1445) | function toJson(obj, pretty) {
  function fromJson (line 1466) | function fromJson(json) {
  function timezoneToOffset (line 1474) | function timezoneToOffset(timezone, fallback) {
  function addDateMinutes (line 1483) | function addDateMinutes(date, minutes) {
  function convertTimezoneToLocal (line 1490) | function convertTimezoneToLocal(date, timezone, reverse) {
  function startingTag (line 1501) | function startingTag(element) {
  function tryDecodeURIComponent (line 1531) | function tryDecodeURIComponent(value) {
  function parseKeyValue (line 1544) | function parseKeyValue(/**string*/keyValue) {
  function toKeyValue (line 1571) | function toKeyValue(obj) {
  function encodeUriSegment (line 1599) | function encodeUriSegment(val) {
  function encodeUriQuery (line 1618) | function encodeUriQuery(val, pctEncodeSpaces) {
  function getNgAttribute (line 1630) | function getNgAttribute(element, ngAttr) {
  function allowAutoBootstrap (line 1641) | function allowAutoBootstrap(document) {
  function angularInit (line 1805) | function angularInit(element, bootstrap) {
  function bootstrap (line 1898) | function bootstrap(element, modules, config) {
  function reloadWithDebugInfo (line 1976) | function reloadWithDebugInfo() {
  function getTestability (line 1989) | function getTestability(rootElement) {
  function snake_case (line 1999) | function snake_case(name, separator) {
  function bindJQuery (line 2007) | function bindJQuery() {
  function assertArg (line 2061) | function assertArg(arg, name, reason) {
  function assertArgFn (line 2068) | function assertArgFn(arg, name, acceptArrayAnnotation) {
  function assertNotHasOwnProperty (line 2083) | function assertNotHasOwnProperty(name, context) {
  function getter (line 2097) | function getter(obj, path, bindFnToScope) {
  function getBlockNodes (line 2121) | function getBlockNodes(nodes) {
  function createMap (line 2151) | function createMap() {
  function stringify (line 2155) | function stringify(value) {
  function setupModuleLoader (line 2192) | function setupModuleLoader(window) {
  function shallowCopy (line 2553) | function shallowCopy(src, dst) {
  function serializeObject (line 2575) | function serializeObject(obj) {
  function toDebugString (line 2590) | function toDebugString(obj) {
  function publishExternalAPI (line 2725) | function publishExternalAPI(angular) {
  function jqNextId (line 3001) | function jqNextId() { return ++jqId; }
  function cssKebabToCamel (line 3014) | function cssKebabToCamel(name) {
  function fnCamelCaseReplace (line 3018) | function fnCamelCaseReplace(all, letter) {
  function kebabToCamel (line 3026) | function kebabToCamel(name) {
  function jqLiteIsTextNode (line 3051) | function jqLiteIsTextNode(html) {
  function jqLiteAcceptsData (line 3055) | function jqLiteAcceptsData(node) {
  function jqLiteHasData (line 3062) | function jqLiteHasData(node) {
  function jqLiteCleanData (line 3069) | function jqLiteCleanData(nodes) {
  function jqLiteBuildFragment (line 3075) | function jqLiteBuildFragment(html, context) {
  function jqLiteParseHTML (line 3112) | function jqLiteParseHTML(html, context) {
  function jqLiteWrapNode (line 3127) | function jqLiteWrapNode(node, wrapper) {
  function JQLite (line 3145) | function JQLite(element) {
  function jqLiteClone (line 3172) | function jqLiteClone(element) {
  function jqLiteDealoc (line 3176) | function jqLiteDealoc(element, onlyDescendants) {
  function jqLiteOff (line 3187) | function jqLiteOff(element, type, fn, unsupported) {
  function jqLiteRemoveData (line 3225) | function jqLiteRemoveData(element, name) {
  function jqLiteExpandoStore (line 3247) | function jqLiteExpandoStore(element, createIfNecessary) {
  function jqLiteData (line 3260) | function jqLiteData(element, key, value) {
  function jqLiteHasClass (line 3289) | function jqLiteHasClass(element, selector) {
  function jqLiteRemoveClass (line 3295) | function jqLiteRemoveClass(element, cssClasses) {
  function jqLiteAddClass (line 3307) | function jqLiteAddClass(element, cssClasses) {
  function jqLiteAddNodes (line 3324) | function jqLiteAddNodes(root, elements) {
  function jqLiteController (line 3350) | function jqLiteController(element, name) {
  function jqLiteInheritedData (line 3354) | function jqLiteInheritedData(element, name, value) {
  function jqLiteEmpty (line 3374) | function jqLiteEmpty(element) {
  function jqLiteRemove (line 3381) | function jqLiteRemove(element, keepData) {
  function jqLiteDocumentLoaded (line 3388) | function jqLiteDocumentLoaded(action, win) {
  function jqLiteReady (line 3401) | function jqLiteReady(fn) {
  function getBooleanAttrName (line 3465) | function getBooleanAttrName(element, name) {
  function getAliasedAttrName (line 3473) | function getAliasedAttrName(name) {
  function getText (line 3566) | function getText(element, value) {
  function createEventHandler (line 3651) | function createEventHandler(element, events) {
  function defaultHandlerWrapper (line 3703) | function defaultHandlerWrapper(element, event, handler) {
  function specialMouseHandlerWrapper (line 3707) | function specialMouseHandlerWrapper(target, event, handler) {
  function $$jqLiteProvider (line 3958) | function $$jqLiteProvider() {
  function hashKey (line 3989) | function hashKey(obj, nextUidFn) {
  function HashMap (line 4012) | function HashMap(array, isolatedUid) {
  function stringifyFn (line 4126) | function stringifyFn(fn) {
  function extractArgs (line 4134) | function extractArgs(fn) {
  function anonFn (line 4140) | function anonFn(fn) {
  function annotate (line 4150) | function annotate(fn, strictDi, name) {
  function createInjector (line 4700) | function createInjector(modulesToLoad, strictDi) {
  function $AnchorScrollProvider (line 4975) | function $AnchorScrollProvider() {
  function mergeClasses (line 5243) | function mergeClasses(a,b) {
  function extractElementNode (line 5252) | function extractElementNode(element) {
  function splitClasses (line 5261) | function splitClasses(classes) {
  function prepareAnimateOptions (line 5286) | function prepareAnimateOptions(options) {
  function updateData (line 5337) | function updateData(data, classes, value) {
  function handleCSSClassChanges (line 5352) | function handleCSSClassChanges() {
  function addRemoveClassesPostDigest (line 5385) | function addRemoveClassesPostDigest(element, add, remove) {
  function domInsert (line 5498) | function domInsert(element, parentElement, afterElement) {
  function waitForTick (line 5898) | function waitForTick(fn) {
  function next (line 5937) | function next() {
  function onProgress (line 5961) | function onProgress(response) {
  function AnimateRunner (line 5969) | function AnimateRunner(host) {
  function run (line 6127) | function run() {
  function applyAnimationContents (line 6138) | function applyAnimationContents() {
  function Browser (line 6179) | function Browser(window, document, $log, $sniffer) {
  function $BrowserProvider (line 6511) | function $BrowserProvider() {
  function $CacheFactoryProvider (line 6600) | function $CacheFactoryProvider() {
  function $TemplateCacheProvider (line 6918) | function $TemplateCacheProvider() {
  function UNINITIALIZED_VALUE (line 7881) | function UNINITIALIZED_VALUE() {}
  function $CompileProvider (line 7892) | function $CompileProvider($provide, $$sanitizeUriProvider) {
  function SimpleChange (line 10517) | function SimpleChange(previous, current) {
  function directiveNormalize (line 10531) | function directiveNormalize(name) {
  function nodesetLinkingFn (line 10582) | function nodesetLinkingFn(
  function directiveLinkingFn (line 10589) | function directiveLinkingFn(
  function tokenDifference (line 10597) | function tokenDifference(str1, str2) {
  function removeComments (line 10613) | function removeComments(jqNodes) {
  function identifierForController (line 10635) | function identifierForController(controller, ident) {
  function $ControllerProvider (line 10656) | function $ControllerProvider() {
  function $DocumentProvider (line 10848) | function $DocumentProvider() {
  function $$IsDocumentHiddenProvider (line 10860) | function $$IsDocumentHiddenProvider() {
  function $ExceptionHandlerProvider (line 10925) | function $ExceptionHandlerProvider() {
  function serializeValue (line 10966) | function serializeValue(v) {
  function $HttpParamSerializerProvider (line 10975) | function $HttpParamSerializerProvider() {
  function $HttpParamSerializerJQLikeProvider (line 11013) | function $HttpParamSerializerJQLikeProvider() {
  function defaultHttpResponseTransform (line 11086) | function defaultHttpResponseTransform(data, headers) {
  function isJsonLike (line 11102) | function isJsonLike(str) {
  function parseHeaders (line 11113) | function parseHeaders(headers) {
  function headersGetter (line 11149) | function headersGetter(headers) {
  function transformData (line 11179) | function transformData(data, headers, status, fns) {
  function isSuccess (line 11192) | function isSuccess(status) {
  function $HttpProvider (line 11205) | function $HttpProvider() {
  function $xhrFactoryProvider (line 12382) | function $xhrFactoryProvider() {
  function $HttpBackendProvider (line 12408) | function $HttpBackendProvider() {
  function createHttpBackend (line 12414) | function createHttpBackend($browser, createXhr, $browserDefer, callbacks...
  function $InterpolateProvider (line 12625) | function $InterpolateProvider() {
  function $IntervalProvider (line 12958) | function $IntervalProvider() {
  function createCallback (line 13174) | function createCallback(callbackId) {
  function encodePath (line 13263) | function encodePath(path) {
  function parseAbsoluteUrl (line 13274) | function parseAbsoluteUrl(absoluteUrl, locationObj) {
  function parseAppUrl (line 13283) | function parseAppUrl(url, locationObj) {
  function startsWith (line 13305) | function startsWith(str, search) {
  function stripBaseUrl (line 13316) | function stripBaseUrl(base, url) {
  function stripHash (line 13323) | function stripHash(url) {
  function trimEmptyHash (line 13328) | function trimEmptyHash(url) {
  function stripFile (line 13333) | function stripFile(url) {
  function serverBase (line 13338) | function serverBase(url) {
  function LocationHtml5Url (line 13352) | function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
  function LocationHashbangUrl (line 13432) | function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
  function LocationHashbangInHtml5Url (line 13544) | function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
  function locationGetter (line 13914) | function locationGetter(property) {
  function locationGetterSetter (line 13921) | function locationGetterSetter(property, preprocess) {
  function $LocationProvider (line 13969) | function $LocationProvider() {
  function $LogProvider (line 14313) | function $LogProvider() {
  function getStringValue (line 14462) | function getStringValue(name) {
  function ifDefined (line 15039) | function ifDefined(v, d) {
  function plusFn (line 15043) | function plusFn(l, r) {
  function isStateless (line 15049) | function isStateless($filter, filterName) {
  function findConstantAndWatchExpressions (line 15054) | function findConstantAndWatchExpressions(ast, $filter) {
  function getInputs (line 15164) | function getInputs(body) {
  function isAssignable (line 15172) | function isAssignable(ast) {
  function assignableAST (line 15176) | function assignableAST(ast) {
  function isLiteral (line 15182) | function isLiteral(ast) {
  function isConstant (line 15190) | function isConstant(ast) {
  function ASTCompiler (line 15194) | function ASTCompiler(astBuilder, $filter) {
  function ASTInterpreter (line 15661) | function ASTInterpreter(astBuilder, $filter) {
  function getValueOf (line 16055) | function getValueOf(value) {
  function $ParseProvider (line 16111) | function $ParseProvider() {
  function $QProvider (line 16607) | function $QProvider() {
  function $$QProvider (line 16639) | function $$QProvider() {
  function qFactory (line 16667) | function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
  function $$RAFProvider (line 17056) | function $$RAFProvider() { //rAF
  function $RootScopeProvider (line 17155) | function $RootScopeProvider() {
  function $$SanitizeUriProvider (line 18499) | function $$SanitizeUriProvider() {
  function snakeToCamel (line 18594) | function snakeToCamel(name) {
  function adjustMatcher (line 18599) | function adjustMatcher(matcher) {
  function adjustMatchers (line 18627) | function adjustMatchers(matchers) {
  function $SceDelegateProvider (line 18707) | function $SceDelegateProvider() {
  function $SceProvider (line 19243) | function $SceProvider() {
  function $SnifferProvider (line 19659) | function $SnifferProvider() {
  function $TemplateRequestProvider (line 19735) | function $TemplateRequestProvider() {
  function $$TestabilityProvider (line 19840) | function $$TestabilityProvider() {
  function $TimeoutProvider (line 19956) | function $TimeoutProvider() {
  function urlResolve (line 20108) | function urlResolve(url) {
  function urlIsSameOrigin (line 20143) | function urlIsSameOrigin(requestUrl) {
  function $WindowProvider (line 20191) | function $WindowProvider() {
  function $$CookieReader (line 20204) | function $$CookieReader($document) {
  function $$CookieReaderProvider (line 20255) | function $$CookieReaderProvider() {
  function $FilterProvider (line 20366) | function $FilterProvider($provide) {
  function filterFilter (line 20562) | function filterFilter() {
  function createPredicateFn (line 20599) | function createPredicateFn(expression, comparator, anyPropertyKey, match...
  function deepCompare (line 20636) | function deepCompare(actual, expected, comparator, anyPropertyKey, match...
  function getTypeForFilter (line 20685) | function getTypeForFilter(val) {
  function currencyFilter (line 20746) | function currencyFilter($locale) {
  function numberFilter (line 20820) | function numberFilter($locale) {
  function parse (line 20845) | function parse(numStr) {
  function roundNumber (line 20900) | function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
  function formatNumber (line 20975) | function formatNumber(number, pattern, groupSep, decimalSep, fractionSiz...
  function padNumber (line 21041) | function padNumber(num, digits, trim, negWrap) {
  function dateGetter (line 21060) | function dateGetter(name, size, offset, trim, negWrap) {
  function dateStrGetter (line 21072) | function dateStrGetter(name, shortForm, standAlone) {
  function timeZoneGetter (line 21082) | function timeZoneGetter(date, formats, offset) {
  function getFirstThursdayOfYear (line 21092) | function getFirstThursdayOfYear(year) {
  function getThursdayThisWeek (line 21100) | function getThursdayThisWeek(datetime) {
  function weekGetter (line 21106) | function weekGetter(size) {
  function ampmGetter (line 21118) | function ampmGetter(date, formats) {
  function eraGetter (line 21122) | function eraGetter(date, formats) {
  function longEraGetter (line 21126) | function longEraGetter(date, formats) {
  function dateFilter (line 21262) | function dateFilter($locale) {
  function jsonFilter (line 21369) | function jsonFilter() {
  function limitToFilter (line 21499) | function limitToFilter() {
  function sliceFn (line 21526) | function sliceFn(input, begin, end) {
  function orderByFilter (line 22083) | function orderByFilter($parse) {
  function ngDirective (line 22226) | function ngDirective(directive) {
  function defaultLinkFn (line 22617) | function defaultLinkFn(scope, element, attr) {
  function nullFormRenameControl (line 22721) | function nullFormRenameControl(control, name) {
  function FormController (line 22769) | function FormController($element, $attrs, $scope, $animate, $interpolate) {
  function getSetter (line 23251) | function getSetter(expression) {
  function setupValidity (line 23267) | function setupValidity(instance) {
  function addSetValidityMethod (line 23271) | function addSetValidityMethod(context) {
  function isObjectEmpty (line 23358) | function isObjectEmpty(obj) {
  function stringBasedInputType (line 24589) | function stringBasedInputType(ctrl) {
  function textInputType (line 24595) | function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function baseInputType (line 24600) | function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function weekParser (line 24710) | function weekParser(isoWeek, existingDate) {
  function createDateParser (line 24742) | function createDateParser(regexp, mapping) {
  function createDateInputType (line 24792) | function createDateInputType(type, regexp, parseDate, format) {
  function badInputChecker (line 24864) | function badInputChecker(scope, element, attr, ctrl) {
  function numberFormatterParser (line 24875) | function numberFormatterParser(ctrl) {
  function parseNumberAttrVal (line 24894) | function parseNumberAttrVal(val) {
  function isNumberInteger (line 24901) | function isNumberInteger(num) {
  function countDecimals (line 24909) | function countDecimals(num) {
  function isValidForStep (line 24929) | function isValidForStep(viewValue, stepBase, step) {
  function numberInputType (line 24948) | function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function rangeInputType (line 24995) | function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function urlInputType (line 25129) | function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function emailInputType (line 25142) | function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function radioInputType (line 25155) | function radioInputType(scope, element, attr, ctrl) {
  function parseConstantExpr (line 25186) | function parseConstantExpr($parse, context, name, expression, fallback) {
  function checkboxInputType (line 25199) | function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browse...
  function updateElementValue (line 25498) | function updateElementValue(element, attr, value) {
  function classDirective (line 25813) | function classDirective(name, selector) {
  function NgModelController (line 28110) | function NgModelController($scope, $exceptionHandler, $attr, $element, $...
  function processParseErrors (line 28466) | function processParseErrors() {
  function processSyncValidators (line 28486) | function processSyncValidators() {
  function processAsyncValidators (line 28502) | function processAsyncValidators() {
  function setValidity (line 28528) | function setValidity(name, isValid) {
  function validationDone (line 28534) | function validationDone(allValid) {
  function writeToModelIfNeeded (line 28616) | function writeToModelIfNeeded() {
  function setupModelWatcher (line 28717) | function setupModelWatcher(ctrl) {
  function setTouched (line 29026) | function setTouched() {
  function ModelOptions (line 29055) | function ModelOptions(options) {
  function NgModelOptionsController (line 29377) | function NgModelOptionsController($attrs, $scope) {
  function defaults (line 29402) | function defaults(dst, src) {
  function parseOptionsExpression (line 29692) | function parseOptionsExpression(optionsExp, selectElement, scope) {
  function ngOptionsPostLink (line 29854) | function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
  function updateElementText (line 30398) | function updateElementText(newText) {
  function ngTranscludeCloneAttachFn (line 31786) | function ngTranscludeCloneAttachFn(clone, transcludedScope) {
  function useFallbackContent (line 31797) | function useFallbackContent() {
  function notWhitespace (line 31805) | function notWhitespace(nodes) {
  function scheduleRender (line 32032) | function scheduleRender() {
  function scheduleViewValueUpdate (line 32042) | function scheduleViewValueUpdate(renderAfter) {
  function setOptionAsSelected (line 32159) | function setOptionAsSelected(optionEl) {
  function selectPreLink (line 32426) | function selectPreLink(scope, element, attr, ctrls) {
  function selectPostLink (line 32498) | function selectPostLink(scope, element, attrs, ctrls) {
  function getDecimals (line 32926) | function getDecimals(n) {
  function getVF (line 32932) | function getVF(n, opt_precision) {
  function save (line 33107) | function save(blob, filename, disableAutoBOM) {

FILE: src/angular-file-saver.service.js
  function save (line 5) | function save(blob, filename, disableAutoBOM) {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,442K chars).
[
  {
    "path": ".babelrc",
    "chars": 28,
    "preview": "{\n  \"presets\": [\"es2015\"]\n}\n"
  },
  {
    "path": ".eslintrc",
    "chars": 300,
    "preview": "root: true\n\nenv:\n  node: true\n  browser: true\n  jasmine: true\n  es6: true\n\nextends:\n  \"eslint:recommended\"\n\nrules:\n  ind"
  },
  {
    "path": ".gitignore",
    "chars": 39,
    "preview": "node_modules\nbower_components\n.publish\n"
  },
  {
    "path": ".travis.yml",
    "chars": 137,
    "preview": "language: node_js\nnode_js:\n  - 0.12\n  - stable\ngit:\n  depth: 10\nbefore_script:\n  - export DISPLAY=:99.0\n  - sh -e /etc/i"
  },
  {
    "path": "bower.json",
    "chars": 620,
    "preview": "{\n  \"name\": \"angular-file-saver\",\n  \"version\": \"1.1.3\",\n  \"main\": \"dist/angular-file-saver.bundle.js\",\n  \"authors\": [\n  "
  },
  {
    "path": "dist/angular-file-saver.bundle.js",
    "chars": 17461,
    "preview": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object"
  },
  {
    "path": "dist/angular-file-saver.js",
    "chars": 4591,
    "preview": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object"
  },
  {
    "path": "docs/assets/js/custom.js",
    "chars": 542,
    "preview": "'use strict';\n\nvar angular = require('angular');\nrequire('../../../src/angular-file-saver-bundle.module');\n\nfunction Dow"
  },
  {
    "path": "docs/assets/stylesheets/github-light.css",
    "chars": 2721,
    "preview": "/*\n   Copyright 2014 GitHub Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use "
  },
  {
    "path": "docs/assets/stylesheets/normalize.css",
    "chars": 7699,
    "preview": "/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Pre"
  },
  {
    "path": "docs/assets/stylesheets/stylesheet.css",
    "chars": 5937,
    "preview": "* {\n  box-sizing: border-box;\n}\nbody {\n  padding: 0;\n  margin: 0;\n  font-family: \"Open Sans\", \"Helvetica Neue\", Helvetic"
  },
  {
    "path": "docs/dist/examples.css",
    "chars": 16359,
    "preview": "/*\n   Copyright 2014 GitHub Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use "
  },
  {
    "path": "docs/dist/examples.js",
    "chars": 1280709,
    "preview": "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object"
  },
  {
    "path": "docs/index.html",
    "chars": 6742,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-us\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Angular File Saver - an AngularJS service "
  },
  {
    "path": "docs/params.json",
    "chars": 2085,
    "preview": "{\"name\":\"Angular-file-saver\",\"tagline\":\"An AngularJS service that implements the HTML5 saveAs()\",\"body\":\"### Welcome to "
  },
  {
    "path": "gulpfile.babel.js",
    "chars": 5875,
    "preview": "import gulp from 'gulp';\nimport gulpLoadPlugins from 'gulp-load-plugins';\nimport webpack from 'webpack-stream';\nimport s"
  },
  {
    "path": "karma.conf.js",
    "chars": 688,
    "preview": "'use strict';\n\nmodule.exports = function(config) {\n  config.set({\n    basePath: './',\n    frameworks: ['jasmine'],\n    p"
  },
  {
    "path": "license.md",
    "chars": 1058,
    "preview": "Copyright © 2015 Philipp Alferov.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this "
  },
  {
    "path": "package.json",
    "chars": 1876,
    "preview": "{\n  \"name\": \"angular-file-saver\",\n  \"version\": \"1.1.3\",\n  \"description\": \"An AngularJS service that implements the HTML5"
  },
  {
    "path": "readme.md",
    "chars": 3467,
    "preview": "# Angular File Saver\n\n[![NPM version][npm-image]][npm-url]\n[![Build Status][travis-image]][travis-url]\n[![Dependency Sta"
  },
  {
    "path": "src/angular-file-saver-bundle.module.js",
    "chars": 575,
    "preview": "'use strict';\n/*\n*\n* A AngularJS module that implements the HTML5 W3C saveAs() in browsers that\n* do not natively suppor"
  },
  {
    "path": "src/angular-file-saver.module.js",
    "chars": 609,
    "preview": "'use strict';\n\n/*\n*\n* A AngularJS module that implements the HTML5 W3C saveAs() in browsers that\n* do not natively suppo"
  },
  {
    "path": "src/angular-file-saver.service.js",
    "chars": 1050,
    "preview": "'use strict';\n\nmodule.exports = function FileSaver(Blob, SaveAs, FileSaverUtils) {\n\n  function save(blob, filename, disa"
  },
  {
    "path": "src/dependencies/blob-bundle.service.js",
    "chars": 105,
    "preview": "'use strict';\n\nrequire('blob-tmp');\n\nmodule.exports = function Blob($window) {\n  return $window.Blob;\n};\n"
  },
  {
    "path": "src/dependencies/blob.service.js",
    "chars": 255,
    "preview": "'use strict';\n\nmodule.exports = function Blob($window, FileSaverUtils) {\n  var blob = $window.Blob;\n\n  if (FileSaverUtil"
  },
  {
    "path": "src/dependencies/file-saver-bundle.service.js",
    "chars": 111,
    "preview": "'use strict';\n\nmodule.exports = function SaveAs() {\n  return require('file-saver').saveAs || function() {};\n};\n"
  },
  {
    "path": "src/dependencies/file-saver.service.js",
    "chars": 268,
    "preview": "'use strict';\n\nmodule.exports = function SaveAs($window, FileSaverUtils) {\n  var saveAs = $window.saveAs;\n\n  if (FileSav"
  },
  {
    "path": "src/utils/utils.service.js",
    "chars": 405,
    "preview": "'use strict';\n\nmodule.exports = function FileSaverUtils() {\n  return {\n    handleErrors: function(msg) {\n      throw new"
  },
  {
    "path": "test/angular-file-saver-bundle.spec.js",
    "chars": 1238,
    "preview": "'use strict';\n\ndescribe('angular-file-saver', function() {\n\n  var FileSaver, Blob;\n\n  beforeEach(function() {\n    angula"
  },
  {
    "path": "test/blob-bundle.spec.js",
    "chars": 409,
    "preview": "'use strict';\n\ndescribe('blob', function() {\n\n  var Blob, oMyBlob;\n\n  beforeEach(function() {\n\n    angular.mock.module('"
  },
  {
    "path": "test/file-saver-bundle.spec.js",
    "chars": 323,
    "preview": "'use strict';\n\ndescribe('file-saver', function() {\n\n  var SaveAs;\n\n  beforeEach(function() {\n\n    angular.mock.module('n"
  }
]

About this extraction

This page contains the full source code of the alferov/angular-file-saver GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (1.3 MB), approximately 329.1k tokens, and a symbol index with 305 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!