\n * ```\n *\n * Note:\n * The parameter values expression is `$watch`ed for updates.\n *\n * ### Transition Options\n * You can specify [[TransitionOptions]] to pass to [[StateService.go]] by using the `ui-sref-opts` attribute.\n * Options are restricted to `location`, `inherit`, and `reload`.\n *\n * #### Example:\n * ```html\n * Home\n * ```\n *\n * ### Other DOM Events\n *\n * You can also customize which DOM events to respond to (instead of `click`) by\n * providing an `events` array in the `ui-sref-opts` attribute.\n *\n * #### Example:\n * ```html\n * \n * ```\n *\n * ### Highlighting the active link\n * This directive can be used in conjunction with [[uiSrefActive]] to highlight the active link.\n *\n * ### Examples\n * If you have the following template:\n *\n * ```html\n * Home\n * About\n * Next page\n *\n *
\n * ```\n *\n * Then (assuming the current state is `contacts`) the rendered html including hrefs would be:\n *\n * ```html\n * Home\n * About\n * Next page\n *\n *
\n *\n * Home\n * ```\n *\n * ### Notes\n *\n * - You can use `ui-sref` to change **only the parameter values** by omitting the state name and parentheses.\n * #### Example:\n * Sets the `lang` parameter to `en` and remains on the same state.\n *\n * ```html\n * English\n * ```\n *\n * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example.\n *\n * - Unlike the parameter values expression, the state name is not `$watch`ed (for performance reasons).\n * If you need to dynamically update the state being linked to, use the fully dynamic [[uiState]] directive.\n */\n var uiSrefDirective;\n uiSrefDirective = [\n '$uiRouter',\n '$timeout',\n function $StateRefDirective($uiRouter, $timeout) {\n var $state = $uiRouter.stateService;\n return {\n restrict: 'A',\n require: ['?^uiSrefActive', '?^uiSrefActiveEq'],\n link: function (scope, element, attrs, uiSrefActive) {\n var type = getTypeInfo(element);\n var active = uiSrefActive[1] || uiSrefActive[0];\n var unlinkInfoFn = null;\n var hookFn;\n var rawDef = {};\n var getDef = function () { return processedDef($state, element, rawDef); };\n var ref = parseStateRef(attrs.uiSref);\n rawDef.uiState = ref.state;\n rawDef.uiStateOpts = attrs.uiSrefOpts ? scope.$eval(attrs.uiSrefOpts) : {};\n function update() {\n var def = getDef();\n if (unlinkInfoFn)\n unlinkInfoFn();\n if (active)\n unlinkInfoFn = active.$$addStateInfo(def.uiState, def.uiStateParams);\n if (def.href != null)\n attrs.$set(type.attr, def.href);\n }\n if (ref.paramExpr) {\n scope.$watch(ref.paramExpr, function (val) {\n rawDef.uiStateParams = core.extend({}, val);\n update();\n }, true);\n rawDef.uiStateParams = core.extend({}, scope.$eval(ref.paramExpr));\n }\n update();\n scope.$on('$destroy', $uiRouter.stateRegistry.onStatesChanged(update));\n scope.$on('$destroy', $uiRouter.transitionService.onSuccess({}, update));\n if (!type.clickable)\n return;\n hookFn = clickHook(element, $state, $timeout, type, getDef);\n bindEvents(element, scope, hookFn, rawDef.uiStateOpts);\n },\n };\n },\n ];\n /**\n * `ui-state`: A fully dynamic directive for linking to a state\n *\n * A directive which links to a state (and optionally, parameters).\n * When clicked, this directive activates the linked state with the supplied parameter values.\n *\n * **This directive is very similar to [[uiSref]], but it `$observe`s and `$watch`es/evaluates all its inputs.**\n *\n * A directive which links to a state (and optionally, parameters).\n * When clicked, this directive activates the linked state with the supplied parameter values.\n *\n * ### Linked State\n * The attribute value of `ui-state` is an expression which is `$watch`ed and evaluated as the state to link to.\n * **This is in contrast with `ui-sref`, which takes a state name as a string literal.**\n *\n * #### Example:\n * Create a list of links.\n * ```html\n *
\n * ```\n *\n * ### Relative Links\n * If the expression evaluates to a relative path, it is processed like [[uiSref]].\n * You just need to be aware that the path is relative to the state that *created* the link.\n * This allows a state to create relative `ui-state` which always targets the same destination.\n *\n * ### hrefs\n * If the linked state has a URL, the directive will automatically generate and\n * update the `href` attribute (using the [[StateService.href]] method).\n *\n * ### Parameter Values\n * In addition to the state name expression, a `ui-state` can include parameter values which are applied when activating the state.\n * Param values should be provided using the `ui-state-params` attribute.\n * The `ui-state-params` attribute value is `$watch`ed and evaluated as an expression.\n *\n * #### Example:\n * This example renders a list of links with param values.\n * The state's `userId` parameter value comes from each user's `user.id` property.\n * ```html\n *
\n * ```\n *\n * ### Transition Options\n * You can specify [[TransitionOptions]] to pass to [[StateService.go]] by using the `ui-state-opts` attribute.\n * Options are restricted to `location`, `inherit`, and `reload`.\n * The value of the `ui-state-opts` is `$watch`ed and evaluated as an expression.\n *\n * #### Example:\n * ```html\n * Home\n * ```\n *\n * ### Other DOM Events\n *\n * You can also customize which DOM events to respond to (instead of `click`) by\n * providing an `events` array in the `ui-state-opts` attribute.\n *\n * #### Example:\n * ```html\n * \n * ```\n *\n * ### Highlighting the active link\n * This directive can be used in conjunction with [[uiSrefActive]] to highlight the active link.\n *\n * ### Notes\n *\n * - You can use `ui-params` to change **only the parameter values** by omitting the state name and supplying only `ui-state-params`.\n * However, it might be simpler to use [[uiSref]] parameter-only links.\n *\n * #### Example:\n * Sets the `lang` parameter to `en` and remains on the same state.\n *\n * ```html\n * English\n * ```\n *\n * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example.\n * ```\n */\n var uiStateDirective;\n uiStateDirective = [\n '$uiRouter',\n '$timeout',\n function $StateRefDynamicDirective($uiRouter, $timeout) {\n var $state = $uiRouter.stateService;\n return {\n restrict: 'A',\n require: ['?^uiSrefActive', '?^uiSrefActiveEq'],\n link: function (scope, element, attrs, uiSrefActive) {\n var type = getTypeInfo(element);\n var active = uiSrefActive[1] || uiSrefActive[0];\n var unlinkInfoFn = null;\n var hookFn;\n var rawDef = {};\n var getDef = function () { return processedDef($state, element, rawDef); };\n var inputAttrs = ['uiState', 'uiStateParams', 'uiStateOpts'];\n var watchDeregFns = inputAttrs.reduce(function (acc, attr) { return ((acc[attr] = core.noop), acc); }, {});\n function update() {\n var def = getDef();\n if (unlinkInfoFn)\n unlinkInfoFn();\n if (active)\n unlinkInfoFn = active.$$addStateInfo(def.uiState, def.uiStateParams);\n if (def.href != null)\n attrs.$set(type.attr, def.href);\n }\n inputAttrs.forEach(function (field) {\n rawDef[field] = attrs[field] ? scope.$eval(attrs[field]) : null;\n attrs.$observe(field, function (expr) {\n watchDeregFns[field]();\n watchDeregFns[field] = scope.$watch(expr, function (newval) {\n rawDef[field] = newval;\n update();\n }, true);\n });\n });\n update();\n scope.$on('$destroy', $uiRouter.stateRegistry.onStatesChanged(update));\n scope.$on('$destroy', $uiRouter.transitionService.onSuccess({}, update));\n if (!type.clickable)\n return;\n hookFn = clickHook(element, $state, $timeout, type, getDef);\n bindEvents(element, scope, hookFn, rawDef.uiStateOpts);\n },\n };\n },\n ];\n /**\n * `ui-sref-active` and `ui-sref-active-eq`: A directive that adds a CSS class when a `ui-sref` is active\n *\n * A directive working alongside [[uiSref]] and [[uiState]] to add classes to an element when the\n * related directive's state is active (and remove them when it is inactive).\n *\n * The primary use-case is to highlight the active link in navigation menus,\n * distinguishing it from the inactive menu items.\n *\n * ### Linking to a `ui-sref` or `ui-state`\n * `ui-sref-active` can live on the same element as `ui-sref`/`ui-state`, or it can be on a parent element.\n * If a `ui-sref-active` is a parent to more than one `ui-sref`/`ui-state`, it will apply the CSS class when **any of the links are active**.\n *\n * ### Matching\n *\n * The `ui-sref-active` directive applies the CSS class when the `ui-sref`/`ui-state`'s target state **or any child state is active**.\n * This is a \"fuzzy match\" which uses [[StateService.includes]].\n *\n * The `ui-sref-active-eq` directive applies the CSS class when the `ui-sref`/`ui-state`'s target state is directly active (not when child states are active).\n * This is an \"exact match\" which uses [[StateService.is]].\n *\n * ### Parameter values\n * If the `ui-sref`/`ui-state` includes parameter values, the current parameter values must match the link's values for the link to be highlighted.\n * This allows a list of links to the same state with different parameters to be rendered, and the correct one highlighted.\n *\n * #### Example:\n * ```html\n *
\n * ```\n *\n * When the app state is `app.user` (or any child state),\n * and contains the state parameter \"user\" with value \"bilbobaggins\",\n * the resulting HTML will appear as (note the 'active' class):\n *\n * ```html\n *
\n * ```\n *\n * ### Glob mode\n *\n * It is possible to pass `ui-sref-active` an expression that evaluates to an object.\n * The objects keys represent active class names and values represent the respective state names/globs.\n * `ui-sref-active` will match if the current active state **includes** any of\n * the specified state names/globs, even the abstract ones.\n *\n * #### Example:\n * Given the following template, with \"admin\" being an abstract state:\n * ```html\n *
\n * ```\n *\n * Arrays are also supported as values in the `ngClass`-like interface.\n * This allows multiple states to add `active` class.\n *\n * #### Example:\n * Given the following template, with \"admin.roles\" being the current state, the class will be added too:\n * ```html\n *
\n \n \n angular.module('anchorScrollExample', [])\n .controller('ScrollController', ['$scope', '$location', '$anchorScroll',\n function($scope, $location, $anchorScroll) {\n $scope.gotoBottom = function() {\n // set the location.hash to the id of\n // the element you wish to scroll to.\n $location.hash('bottom');\n\n // call $anchorScroll()\n $anchorScroll();\n };\n }]);\n \n \n #scrollArea {\n height: 280px;\n overflow: auto;\n }\n\n #bottom {\n display: block;\n margin-top: 2000px;\n }\n \n \n *\n * \n * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).\n * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.\n *\n * @example\n \n \n
\n \n \n angular.module('anchorScrollOffsetExample', [])\n .run(['$anchorScroll', function($anchorScroll) {\n $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels\n }])\n .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',\n function($anchorScroll, $location, $scope) {\n $scope.gotoAnchor = function(x) {\n var newHash = 'anchor' + x;\n if ($location.hash() !== newHash) {\n // set the $location.hash to `newHash` and\n // $anchorScroll will automatically scroll to it\n $location.hash('anchor' + x);\n } else {\n // call $anchorScroll() explicitly,\n // since $location.hash hasn't changed\n $anchorScroll();\n }\n };\n }\n ]);\n \n \n body {\n padding-top: 50px;\n }\n\n .anchor {\n border: 2px dashed DarkOrchid;\n padding: 10px 10px 200px 10px;\n }\n\n .fixed-header {\n background-color: rgba(0, 0, 0, 0.2);\n height: 50px;\n position: fixed;\n top: 0; left: 0; right: 0;\n }\n\n .fixed-header > a {\n display: inline-block;\n margin: 5px 15px;\n }\n \n \n */\n this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {\n var document = $window.document;\n\n // Helper function to get first anchor from a NodeList\n // (using `Array#some()` instead of `angular#forEach()` since it's more performant\n // and working in all supported browsers.)\n function getFirstAnchor(list) {\n var result = null;\n Array.prototype.some.call(list, function(element) {\n if (nodeName_(element) === 'a') {\n result = element;\n return true;\n }\n });\n return result;\n }\n\n function getYOffset() {\n\n var offset = scroll.yOffset;\n\n if (isFunction(offset)) {\n offset = offset();\n } else if (isElement(offset)) {\n var elem = offset[0];\n var style = $window.getComputedStyle(elem);\n if (style.position !== 'fixed') {\n offset = 0;\n } else {\n offset = elem.getBoundingClientRect().bottom;\n }\n } else if (!isNumber(offset)) {\n offset = 0;\n }\n\n return offset;\n }\n\n function scrollTo(elem) {\n if (elem) {\n elem.scrollIntoView();\n\n var offset = getYOffset();\n\n if (offset) {\n // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.\n // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the\n // top of the viewport.\n //\n // IF the number of pixels from the top of `elem` to the end of the page's content is less\n // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some\n // way down the page.\n //\n // This is often the case for elements near the bottom of the page.\n //\n // In such cases we do not need to scroll the whole `offset` up, just the difference between\n // the top of the element and the offset, which is enough to align the top of `elem` at the\n // desired position.\n var elemTop = elem.getBoundingClientRect().top;\n $window.scrollBy(0, elemTop - offset);\n }\n } else {\n $window.scrollTo(0, 0);\n }\n }\n\n function scroll(hash) {\n // Allow numeric hashes\n hash = isString(hash) ? hash : isNumber(hash) ? hash.toString() : $location.hash();\n var elm;\n\n // empty hash, scroll to the top of the page\n if (!hash) scrollTo(null);\n\n // element with given id\n else if ((elm = document.getElementById(hash))) scrollTo(elm);\n\n // first anchor with given name :-D\n else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);\n\n // no element and hash === 'top', scroll to the top of the page\n else if (hash === 'top') scrollTo(null);\n }\n\n // does not scroll when user clicks on anchor link that is currently on\n // (no url change, no $location.hash() change), browser native does scroll\n if (autoScrollingEnabled) {\n $rootScope.$watch(function autoScrollWatch() {return $location.hash();},\n function autoScrollWatchAction(newVal, oldVal) {\n // skip the initial scroll if $location.hash is empty\n if (newVal === oldVal && newVal === '') return;\n\n jqLiteDocumentLoaded(function() {\n $rootScope.$evalAsync(scroll);\n });\n });\n }\n\n return scroll;\n }];\n}\n\nvar $animateMinErr = minErr('$animate');\nvar ELEMENT_NODE = 1;\nvar NG_ANIMATE_CLASSNAME = 'ng-animate';\n\nfunction mergeClasses(a,b) {\n if (!a && !b) return '';\n if (!a) return b;\n if (!b) return a;\n if (isArray(a)) a = a.join(' ');\n if (isArray(b)) b = b.join(' ');\n return a + ' ' + b;\n}\n\nfunction extractElementNode(element) {\n for (var i = 0; i < element.length; i++) {\n var elm = element[i];\n if (elm.nodeType === ELEMENT_NODE) {\n return elm;\n }\n }\n}\n\nfunction splitClasses(classes) {\n if (isString(classes)) {\n classes = classes.split(' ');\n }\n\n // Use createMap() to prevent class assumptions involving property names in\n // Object.prototype\n var obj = createMap();\n forEach(classes, function(klass) {\n // sometimes the split leaves empty string values\n // incase extra spaces were applied to the options\n if (klass.length) {\n obj[klass] = true;\n }\n });\n return obj;\n}\n\n// if any other type of options value besides an Object value is\n// passed into the $animate.method() animation then this helper code\n// will be run which will ignore it. While this patch is not the\n// greatest solution to this, a lot of existing plugins depend on\n// $animate to either call the callback (< 1.2) or return a promise\n// that can be changed. This helper function ensures that the options\n// are wiped clean incase a callback function is provided.\nfunction prepareAnimateOptions(options) {\n return isObject(options)\n ? options\n : {};\n}\n\nvar $$CoreAnimateJsProvider = /** @this */ function() {\n this.$get = noop;\n};\n\n// this is prefixed with Core since it conflicts with\n// the animateQueueProvider defined in ngAnimate/animateQueue.js\nvar $$CoreAnimateQueueProvider = /** @this */ function() {\n var postDigestQueue = new NgMap();\n var postDigestElements = [];\n\n this.$get = ['$$AnimateRunner', '$rootScope',\n function($$AnimateRunner, $rootScope) {\n return {\n enabled: noop,\n on: noop,\n off: noop,\n pin: noop,\n\n push: function(element, event, options, domOperation) {\n if (domOperation) {\n domOperation();\n }\n\n options = options || {};\n if (options.from) {\n element.css(options.from);\n }\n if (options.to) {\n element.css(options.to);\n }\n\n if (options.addClass || options.removeClass) {\n addRemoveClassesPostDigest(element, options.addClass, options.removeClass);\n }\n\n var runner = new $$AnimateRunner();\n\n // since there are no animations to run the runner needs to be\n // notified that the animation call is complete.\n runner.complete();\n return runner;\n }\n };\n\n\n function updateData(data, classes, value) {\n var changed = false;\n if (classes) {\n classes = isString(classes) ? classes.split(' ') :\n isArray(classes) ? classes : [];\n forEach(classes, function(className) {\n if (className) {\n changed = true;\n data[className] = value;\n }\n });\n }\n return changed;\n }\n\n function handleCSSClassChanges() {\n forEach(postDigestElements, function(element) {\n var data = postDigestQueue.get(element);\n if (data) {\n var existing = splitClasses(element.attr('class'));\n var toAdd = '';\n var toRemove = '';\n forEach(data, function(status, className) {\n var hasClass = !!existing[className];\n if (status !== hasClass) {\n if (status) {\n toAdd += (toAdd.length ? ' ' : '') + className;\n } else {\n toRemove += (toRemove.length ? ' ' : '') + className;\n }\n }\n });\n\n forEach(element, function(elm) {\n if (toAdd) {\n jqLiteAddClass(elm, toAdd);\n }\n if (toRemove) {\n jqLiteRemoveClass(elm, toRemove);\n }\n });\n postDigestQueue.delete(element);\n }\n });\n postDigestElements.length = 0;\n }\n\n\n function addRemoveClassesPostDigest(element, add, remove) {\n var data = postDigestQueue.get(element) || {};\n\n var classesAdded = updateData(data, add, true);\n var classesRemoved = updateData(data, remove, false);\n\n if (classesAdded || classesRemoved) {\n\n postDigestQueue.set(element, data);\n postDigestElements.push(element);\n\n if (postDigestElements.length === 1) {\n $rootScope.$$postDigest(handleCSSClassChanges);\n }\n }\n }\n }];\n};\n\n/**\n * @ngdoc provider\n * @name $animateProvider\n *\n * @description\n * Default implementation of $animate that doesn't perform any animations, instead just\n * synchronously performs DOM updates and resolves the returned runner promise.\n *\n * In order to enable animations the `ngAnimate` module has to be loaded.\n *\n * To see the functional implementation check out `src/ngAnimate/animate.js`.\n */\nvar $AnimateProvider = ['$provide', /** @this */ function($provide) {\n var provider = this;\n var classNameFilter = null;\n var customFilter = null;\n\n this.$$registeredAnimations = Object.create(null);\n\n /**\n * @ngdoc method\n * @name $animateProvider#register\n *\n * @description\n * Registers a new injectable animation factory function. The factory function produces the\n * animation object which contains callback functions for each event that is expected to be\n * animated.\n *\n * * `eventFn`: `function(element, ... , doneFunction, options)`\n * The element to animate, the `doneFunction` and the options fed into the animation. Depending\n * on the type of animation additional arguments will be injected into the animation function. The\n * list below explains the function signatures for the different animation methods:\n *\n * - setClass: function(element, addedClasses, removedClasses, doneFunction, options)\n * - addClass: function(element, addedClasses, doneFunction, options)\n * - removeClass: function(element, removedClasses, doneFunction, options)\n * - enter, leave, move: function(element, doneFunction, options)\n * - animate: function(element, fromStyles, toStyles, doneFunction, options)\n *\n * Make sure to trigger the `doneFunction` once the animation is fully complete.\n *\n * ```js\n * return {\n * //enter, leave, move signature\n * eventFn : function(element, done, options) {\n * //code to run the animation\n * //once complete, then run done()\n * return function endFunction(wasCancelled) {\n * //code to cancel the animation\n * }\n * }\n * }\n * ```\n *\n * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).\n * @param {Function} factory The factory function that will be executed to return the animation\n * object.\n */\n this.register = function(name, factory) {\n if (name && name.charAt(0) !== '.') {\n throw $animateMinErr('notcsel', 'Expecting class selector starting with \\'.\\' got \\'{0}\\'.', name);\n }\n\n var key = name + '-animation';\n provider.$$registeredAnimations[name.substr(1)] = key;\n $provide.factory(key, factory);\n };\n\n /**\n * @ngdoc method\n * @name $animateProvider#customFilter\n *\n * @description\n * Sets and/or returns the custom filter function that is used to \"filter\" animations, i.e.\n * determine if an animation is allowed or not. When no filter is specified (the default), no\n * animation will be blocked. Setting the `customFilter` value will only allow animations for\n * which the filter function's return value is truthy.\n *\n * This allows to easily create arbitrarily complex rules for filtering animations, such as\n * allowing specific events only, or enabling animations on specific subtrees of the DOM, etc.\n * Filtering animations can also boost performance for low-powered devices, as well as\n * applications containing a lot of structural operations.\n *\n *
\n * **Best Practice:**\n * Keep the filtering function as lean as possible, because it will be called for each DOM\n * action (e.g. insertion, removal, class change) performed by \"animation-aware\" directives.\n * See {@link guide/animations#which-directives-support-animations- here} for a list of built-in\n * directives that support animations.\n * Performing computationally expensive or time-consuming operations on each call of the\n * filtering function can make your animations sluggish.\n *
\n *\n * **Note:** If present, `customFilter` will be checked before\n * {@link $animateProvider#classNameFilter classNameFilter}.\n *\n * @param {Function=} filterFn - The filter function which will be used to filter all animations.\n * If a falsy value is returned, no animation will be performed. The function will be called\n * with the following arguments:\n * - **node** `{DOMElement}` - The DOM element to be animated.\n * - **event** `{String}` - The name of the animation event (e.g. `enter`, `leave`, `addClass`\n * etc).\n * - **options** `{Object}` - A collection of options/styles used for the animation.\n * @return {Function} The current filter function or `null` if there is none set.\n */\n this.customFilter = function(filterFn) {\n if (arguments.length === 1) {\n customFilter = isFunction(filterFn) ? filterFn : null;\n }\n\n return customFilter;\n };\n\n /**\n * @ngdoc method\n * @name $animateProvider#classNameFilter\n *\n * @description\n * Sets and/or returns the CSS class regular expression that is checked when performing\n * an animation. Upon bootstrap the classNameFilter value is not set at all and will\n * therefore enable $animate to attempt to perform an animation on any element that is triggered.\n * When setting the `classNameFilter` value, animations will only be performed on elements\n * that successfully match the filter expression. This in turn can boost performance\n * for low-powered devices as well as applications containing a lot of structural operations.\n *\n * **Note:** If present, `classNameFilter` will be checked after\n * {@link $animateProvider#customFilter customFilter}. If `customFilter` is present and returns\n * false, `classNameFilter` will not be checked.\n *\n * @param {RegExp=} expression The className expression which will be checked against all animations\n * @return {RegExp} The current CSS className expression value. If null then there is no expression value\n */\n this.classNameFilter = function(expression) {\n if (arguments.length === 1) {\n classNameFilter = (expression instanceof RegExp) ? expression : null;\n if (classNameFilter) {\n var reservedRegex = new RegExp('[(\\\\s|\\\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\\\s|\\\\/)]');\n if (reservedRegex.test(classNameFilter.toString())) {\n classNameFilter = null;\n throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the \"{0}\" CSS class.', NG_ANIMATE_CLASSNAME);\n }\n }\n }\n return classNameFilter;\n };\n\n this.$get = ['$$animateQueue', function($$animateQueue) {\n function domInsert(element, parentElement, afterElement) {\n // if for some reason the previous element was removed\n // from the dom sometime before this code runs then let's\n // just stick to using the parent element as the anchor\n if (afterElement) {\n var afterNode = extractElementNode(afterElement);\n if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {\n afterElement = null;\n }\n }\n if (afterElement) {\n afterElement.after(element);\n } else {\n parentElement.prepend(element);\n }\n }\n\n /**\n * @ngdoc service\n * @name $animate\n * @description The $animate service exposes a series of DOM utility methods that provide support\n * for animation hooks. The default behavior is the application of DOM operations, however,\n * when an animation is detected (and animations are enabled), $animate will do the heavy lifting\n * to ensure that animation runs with the triggered DOM operation.\n *\n * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't\n * included and only when it is active then the animation hooks that `$animate` triggers will be\n * functional. Once active then all structural `ng-` directives will trigger animations as they perform\n * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,\n * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.\n *\n * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.\n *\n * To learn more about enabling animation support, click here to visit the\n * {@link ngAnimate ngAnimate module page}.\n */\n return {\n // we don't call it directly since non-existant arguments may\n // be interpreted as null within the sub enabled function\n\n /**\n *\n * @ngdoc method\n * @name $animate#on\n * @kind function\n * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)\n * has fired on the given element or among any of its children. Once the listener is fired, the provided callback\n * is fired with the following params:\n *\n * ```js\n * $animate.on('enter', container,\n * function callback(element, phase) {\n * // cool we detected an enter animation within the container\n * }\n * );\n * ```\n *\n * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)\n * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself\n * as well as among its children\n * @param {Function} callback the callback function that will be fired when the listener is triggered\n *\n * The arguments present in the callback function are:\n * * `element` - The captured DOM element that the animation was fired on.\n * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).\n */\n on: $$animateQueue.on,\n\n /**\n *\n * @ngdoc method\n * @name $animate#off\n * @kind function\n * @description Deregisters an event listener based on the event which has been associated with the provided element. This method\n * can be used in three different ways depending on the arguments:\n *\n * ```js\n * // remove all the animation event listeners listening for `enter`\n * $animate.off('enter');\n *\n * // remove listeners for all animation events from the container element\n * $animate.off(container);\n *\n * // remove all the animation event listeners listening for `enter` on the given element and its children\n * $animate.off('enter', container);\n *\n * // remove the event listener function provided by `callback` that is set\n * // to listen for `enter` on the given `container` as well as its children\n * $animate.off('enter', container, callback);\n * ```\n *\n * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,\n * addClass, removeClass, etc...), or the container element. If it is the element, all other\n * arguments are ignored.\n * @param {DOMElement=} container the container element the event listener was placed on\n * @param {Function=} callback the callback function that was registered as the listener\n */\n off: $$animateQueue.off,\n\n /**\n * @ngdoc method\n * @name $animate#pin\n * @kind function\n * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists\n * outside of the DOM structure of the AngularJS application. By doing so, any animation triggered via `$animate` can be issued on the\n * element despite being outside the realm of the application or within another application. Say for example if the application\n * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated\n * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind\n * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.\n *\n * Note that this feature is only active when the `ngAnimate` module is used.\n *\n * @param {DOMElement} element the external element that will be pinned\n * @param {DOMElement} parentElement the host parent element that will be associated with the external element\n */\n pin: $$animateQueue.pin,\n\n /**\n *\n * @ngdoc method\n * @name $animate#enabled\n * @kind function\n * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This\n * function can be called in four ways:\n *\n * ```js\n * // returns true or false\n * $animate.enabled();\n *\n * // changes the enabled state for all animations\n * $animate.enabled(false);\n * $animate.enabled(true);\n *\n * // returns true or false if animations are enabled for an element\n * $animate.enabled(element);\n *\n * // changes the enabled state for an element and its children\n * $animate.enabled(element, true);\n * $animate.enabled(element, false);\n * ```\n *\n * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state\n * @param {boolean=} enabled whether or not the animations will be enabled for the element\n *\n * @return {boolean} whether or not animations are enabled\n */\n enabled: $$animateQueue.enabled,\n\n /**\n * @ngdoc method\n * @name $animate#cancel\n * @kind function\n * @description Cancels the provided animation.\n *\n * @param {Promise} animationPromise The animation promise that is returned when an animation is started.\n */\n cancel: function(runner) {\n if (runner.end) {\n runner.end();\n }\n },\n\n /**\n *\n * @ngdoc method\n * @name $animate#enter\n * @kind function\n * @description Inserts the element into the DOM either after the `after` element (if provided) or\n * as the first child within the `parent` element and then triggers an animation.\n * A promise is returned that will be resolved during the next digest once the animation\n * has completed.\n *\n * @param {DOMElement} element the element which will be inserted into the DOM\n * @param {DOMElement} parent the parent element which will append the element as\n * a child (so long as the after element is not present)\n * @param {DOMElement=} after the sibling element after which the element will be appended\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n enter: function(element, parent, after, options) {\n parent = parent && jqLite(parent);\n after = after && jqLite(after);\n parent = parent || after.parent();\n domInsert(element, parent, after);\n return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));\n },\n\n /**\n *\n * @ngdoc method\n * @name $animate#move\n * @kind function\n * @description Inserts (moves) the element into its new position in the DOM either after\n * the `after` element (if provided) or as the first child within the `parent` element\n * and then triggers an animation. A promise is returned that will be resolved\n * during the next digest once the animation has completed.\n *\n * @param {DOMElement} element the element which will be moved into the new DOM position\n * @param {DOMElement} parent the parent element which will append the element as\n * a child (so long as the after element is not present)\n * @param {DOMElement=} after the sibling element after which the element will be appended\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n move: function(element, parent, after, options) {\n parent = parent && jqLite(parent);\n after = after && jqLite(after);\n parent = parent || after.parent();\n domInsert(element, parent, after);\n return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));\n },\n\n /**\n * @ngdoc method\n * @name $animate#leave\n * @kind function\n * @description Triggers an animation and then removes the element from the DOM.\n * When the function is called a promise is returned that will be resolved during the next\n * digest once the animation has completed.\n *\n * @param {DOMElement} element the element which will be removed from the DOM\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n leave: function(element, options) {\n return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {\n element.remove();\n });\n },\n\n /**\n * @ngdoc method\n * @name $animate#addClass\n * @kind function\n *\n * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon\n * execution, the addClass operation will only be handled after the next digest and it will not trigger an\n * animation if element already contains the CSS class or if the class is removed at a later step.\n * Note that class-based animations are treated differently compared to structural animations\n * (like enter, move and leave) since the CSS classes may be added/removed at different points\n * depending if CSS or JavaScript animations are used.\n *\n * @param {DOMElement} element the element which the CSS classes will be applied to\n * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n addClass: function(element, className, options) {\n options = prepareAnimateOptions(options);\n options.addClass = mergeClasses(options.addclass, className);\n return $$animateQueue.push(element, 'addClass', options);\n },\n\n /**\n * @ngdoc method\n * @name $animate#removeClass\n * @kind function\n *\n * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon\n * execution, the removeClass operation will only be handled after the next digest and it will not trigger an\n * animation if element does not contain the CSS class or if the class is added at a later step.\n * Note that class-based animations are treated differently compared to structural animations\n * (like enter, move and leave) since the CSS classes may be added/removed at different points\n * depending if CSS or JavaScript animations are used.\n *\n * @param {DOMElement} element the element which the CSS classes will be applied to\n * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n removeClass: function(element, className, options) {\n options = prepareAnimateOptions(options);\n options.removeClass = mergeClasses(options.removeClass, className);\n return $$animateQueue.push(element, 'removeClass', options);\n },\n\n /**\n * @ngdoc method\n * @name $animate#setClass\n * @kind function\n *\n * @description Performs both the addition and removal of a CSS classes on an element and (during the process)\n * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and\n * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has\n * passed. Note that class-based animations are treated differently compared to structural animations\n * (like enter, move and leave) since the CSS classes may be added/removed at different points\n * depending if CSS or JavaScript animations are used.\n *\n * @param {DOMElement} element the element which the CSS classes will be applied to\n * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)\n * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n setClass: function(element, add, remove, options) {\n options = prepareAnimateOptions(options);\n options.addClass = mergeClasses(options.addClass, add);\n options.removeClass = mergeClasses(options.removeClass, remove);\n return $$animateQueue.push(element, 'setClass', options);\n },\n\n /**\n * @ngdoc method\n * @name $animate#animate\n * @kind function\n *\n * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.\n * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take\n * on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and\n * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding\n * style in `to`, the style in `from` is applied immediately, and no animation is run.\n * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`\n * method (or as part of the `options` parameter):\n *\n * ```js\n * ngModule.animation('.my-inline-animation', function() {\n * return {\n * animate : function(element, from, to, done, options) {\n * //animation\n * done();\n * }\n * }\n * });\n * ```\n *\n * @param {DOMElement} element the element which the CSS styles will be applied to\n * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.\n * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.\n * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If\n * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.\n * (Note that if no animation is detected then this value will not be applied to the element.)\n * @param {object=} options an optional collection of options/styles that will be applied to the element.\n * The object can have the following properties:\n *\n * - **addClass** - `{string}` - space-separated CSS classes to add to element\n * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n *\n * @return {Promise} the animation callback promise\n */\n animate: function(element, from, to, className, options) {\n options = prepareAnimateOptions(options);\n options.from = options.from ? extend(options.from, from) : from;\n options.to = options.to ? extend(options.to, to) : to;\n\n className = className || 'ng-inline-animate';\n options.tempClasses = mergeClasses(options.tempClasses, className);\n return $$animateQueue.push(element, 'animate', options);\n }\n };\n }];\n}];\n\nvar $$AnimateAsyncRunFactoryProvider = /** @this */ function() {\n this.$get = ['$$rAF', function($$rAF) {\n var waitQueue = [];\n\n function waitForTick(fn) {\n waitQueue.push(fn);\n if (waitQueue.length > 1) return;\n $$rAF(function() {\n for (var i = 0; i < waitQueue.length; i++) {\n waitQueue[i]();\n }\n waitQueue = [];\n });\n }\n\n return function() {\n var passed = false;\n waitForTick(function() {\n passed = true;\n });\n return function(callback) {\n if (passed) {\n callback();\n } else {\n waitForTick(callback);\n }\n };\n };\n }];\n};\n\nvar $$AnimateRunnerFactoryProvider = /** @this */ function() {\n this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',\n function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) {\n\n var INITIAL_STATE = 0;\n var DONE_PENDING_STATE = 1;\n var DONE_COMPLETE_STATE = 2;\n\n AnimateRunner.chain = function(chain, callback) {\n var index = 0;\n\n next();\n function next() {\n if (index === chain.length) {\n callback(true);\n return;\n }\n\n chain[index](function(response) {\n if (response === false) {\n callback(false);\n return;\n }\n index++;\n next();\n });\n }\n };\n\n AnimateRunner.all = function(runners, callback) {\n var count = 0;\n var status = true;\n forEach(runners, function(runner) {\n runner.done(onProgress);\n });\n\n function onProgress(response) {\n status = status && response;\n if (++count === runners.length) {\n callback(status);\n }\n }\n };\n\n function AnimateRunner(host) {\n this.setHost(host);\n\n var rafTick = $$animateAsyncRun();\n var timeoutTick = function(fn) {\n $timeout(fn, 0, false);\n };\n\n this._doneCallbacks = [];\n this._tick = function(fn) {\n if ($$isDocumentHidden()) {\n timeoutTick(fn);\n } else {\n rafTick(fn);\n }\n };\n this._state = 0;\n }\n\n AnimateRunner.prototype = {\n setHost: function(host) {\n this.host = host || {};\n },\n\n done: function(fn) {\n if (this._state === DONE_COMPLETE_STATE) {\n fn();\n } else {\n this._doneCallbacks.push(fn);\n }\n },\n\n progress: noop,\n\n getPromise: function() {\n if (!this.promise) {\n var self = this;\n this.promise = $q(function(resolve, reject) {\n self.done(function(status) {\n if (status === false) {\n reject();\n } else {\n resolve();\n }\n });\n });\n }\n return this.promise;\n },\n\n then: function(resolveHandler, rejectHandler) {\n return this.getPromise().then(resolveHandler, rejectHandler);\n },\n\n 'catch': function(handler) {\n return this.getPromise()['catch'](handler);\n },\n\n 'finally': function(handler) {\n return this.getPromise()['finally'](handler);\n },\n\n pause: function() {\n if (this.host.pause) {\n this.host.pause();\n }\n },\n\n resume: function() {\n if (this.host.resume) {\n this.host.resume();\n }\n },\n\n end: function() {\n if (this.host.end) {\n this.host.end();\n }\n this._resolve(true);\n },\n\n cancel: function() {\n if (this.host.cancel) {\n this.host.cancel();\n }\n this._resolve(false);\n },\n\n complete: function(response) {\n var self = this;\n if (self._state === INITIAL_STATE) {\n self._state = DONE_PENDING_STATE;\n self._tick(function() {\n self._resolve(response);\n });\n }\n },\n\n _resolve: function(response) {\n if (this._state !== DONE_COMPLETE_STATE) {\n forEach(this._doneCallbacks, function(fn) {\n fn(response);\n });\n this._doneCallbacks.length = 0;\n this._state = DONE_COMPLETE_STATE;\n }\n }\n };\n\n return AnimateRunner;\n }];\n};\n\n/* exported $CoreAnimateCssProvider */\n\n/**\n * @ngdoc service\n * @name $animateCss\n * @kind object\n * @this\n *\n * @description\n * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,\n * then the `$animateCss` service will actually perform animations.\n *\n * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.\n */\nvar $CoreAnimateCssProvider = function() {\n this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {\n\n return function(element, initialOptions) {\n // all of the animation functions should create\n // a copy of the options data, however, if a\n // parent service has already created a copy then\n // we should stick to using that\n var options = initialOptions || {};\n if (!options.$$prepared) {\n options = copy(options);\n }\n\n // there is no point in applying the styles since\n // there is no animation that goes on at all in\n // this version of $animateCss.\n if (options.cleanupStyles) {\n options.from = options.to = null;\n }\n\n if (options.from) {\n element.css(options.from);\n options.from = null;\n }\n\n var closed, runner = new $$AnimateRunner();\n return {\n start: run,\n end: run\n };\n\n function run() {\n $$rAF(function() {\n applyAnimationContents();\n if (!closed) {\n runner.complete();\n }\n closed = true;\n });\n return runner;\n }\n\n function applyAnimationContents() {\n if (options.addClass) {\n element.addClass(options.addClass);\n options.addClass = null;\n }\n if (options.removeClass) {\n element.removeClass(options.removeClass);\n options.removeClass = null;\n }\n if (options.to) {\n element.css(options.to);\n options.to = null;\n }\n }\n };\n }];\n};\n\n/* global stripHash: true */\n\n/**\n * ! This is a private undocumented service !\n *\n * @name $browser\n * @requires $log\n * @description\n * This object has two goals:\n *\n * - hide all the global state in the browser caused by the window object\n * - abstract away all the browser specific features and inconsistencies\n *\n * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`\n * service, which can be used for convenient testing of the application without the interaction with\n * the real browser apis.\n */\n/**\n * @param {object} window The global window object.\n * @param {object} document jQuery wrapped document.\n * @param {object} $log window.console or an object with the same interface.\n * @param {object} $sniffer $sniffer service\n */\nfunction Browser(window, document, $log, $sniffer) {\n var self = this,\n location = window.location,\n history = window.history,\n setTimeout = window.setTimeout,\n clearTimeout = window.clearTimeout,\n pendingDeferIds = {};\n\n self.isMock = false;\n\n var outstandingRequestCount = 0;\n var outstandingRequestCallbacks = [];\n\n // TODO(vojta): remove this temporary api\n self.$$completeOutstandingRequest = completeOutstandingRequest;\n self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };\n\n /**\n * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`\n * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.\n */\n function completeOutstandingRequest(fn) {\n try {\n fn.apply(null, sliceArgs(arguments, 1));\n } finally {\n outstandingRequestCount--;\n if (outstandingRequestCount === 0) {\n while (outstandingRequestCallbacks.length) {\n try {\n outstandingRequestCallbacks.pop()();\n } catch (e) {\n $log.error(e);\n }\n }\n }\n }\n }\n\n function getHash(url) {\n var index = url.indexOf('#');\n return index === -1 ? '' : url.substr(index);\n }\n\n /**\n * @private\n * TODO(vojta): prefix this method with $$ ?\n * @param {function()} callback Function that will be called when no outstanding request\n */\n self.notifyWhenNoOutstandingRequests = function(callback) {\n if (outstandingRequestCount === 0) {\n callback();\n } else {\n outstandingRequestCallbacks.push(callback);\n }\n };\n\n //////////////////////////////////////////////////////////////\n // URL API\n //////////////////////////////////////////////////////////////\n\n var cachedState, lastHistoryState,\n lastBrowserUrl = location.href,\n baseElement = document.find('base'),\n pendingLocation = null,\n getCurrentState = !$sniffer.history ? noop : function getCurrentState() {\n try {\n return history.state;\n } catch (e) {\n // MSIE can reportedly throw when there is no state (UNCONFIRMED).\n }\n };\n\n cacheState();\n\n /**\n * @name $browser#url\n *\n * @description\n * GETTER:\n * Without any argument, this method just returns current value of location.href.\n *\n * SETTER:\n * With at least one argument, this method sets url to new value.\n * If html5 history api supported, pushState/replaceState is used, otherwise\n * location.href/location.replace is used.\n * Returns its own instance to allow chaining\n *\n * NOTE: this api is intended for use only by the $location service. Please use the\n * {@link ng.$location $location service} to change url.\n *\n * @param {string} url New url (when used as setter)\n * @param {boolean=} replace Should new url replace current history record?\n * @param {object=} state object to use with pushState/replaceState\n */\n self.url = function(url, replace, state) {\n // In modern browsers `history.state` is `null` by default; treating it separately\n // from `undefined` would cause `$browser.url('/foo')` to change `history.state`\n // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.\n if (isUndefined(state)) {\n state = null;\n }\n\n // Android Browser BFCache causes location, history reference to become stale.\n if (location !== window.location) location = window.location;\n if (history !== window.history) history = window.history;\n\n // setter\n if (url) {\n var sameState = lastHistoryState === state;\n\n // Don't change anything if previous and current URLs and states match. This also prevents\n // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.\n // See https://github.com/angular/angular.js/commit/ffb2701\n if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {\n return self;\n }\n var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);\n lastBrowserUrl = url;\n lastHistoryState = state;\n // Don't use history API if only the hash changed\n // due to a bug in IE10/IE11 which leads\n // to not firing a `hashchange` nor `popstate` event\n // in some cases (see #9143).\n if ($sniffer.history && (!sameBase || !sameState)) {\n history[replace ? 'replaceState' : 'pushState'](state, '', url);\n cacheState();\n } else {\n if (!sameBase) {\n pendingLocation = url;\n }\n if (replace) {\n location.replace(url);\n } else if (!sameBase) {\n location.href = url;\n } else {\n location.hash = getHash(url);\n }\n if (location.href !== url) {\n pendingLocation = url;\n }\n }\n if (pendingLocation) {\n pendingLocation = url;\n }\n return self;\n // getter\n } else {\n // - pendingLocation is needed as browsers don't allow to read out\n // the new location.href if a reload happened or if there is a bug like in iOS 9 (see\n // https://openradar.appspot.com/22186109).\n // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172\n return pendingLocation || location.href.replace(/%27/g,'\\'');\n }\n };\n\n /**\n * @name $browser#state\n *\n * @description\n * This method is a getter.\n *\n * Return history.state or null if history.state is undefined.\n *\n * @returns {object} state\n */\n self.state = function() {\n return cachedState;\n };\n\n var urlChangeListeners = [],\n urlChangeInit = false;\n\n function cacheStateAndFireUrlChange() {\n pendingLocation = null;\n fireStateOrUrlChange();\n }\n\n // This variable should be used *only* inside the cacheState function.\n var lastCachedState = null;\n function cacheState() {\n // This should be the only place in $browser where `history.state` is read.\n cachedState = getCurrentState();\n cachedState = isUndefined(cachedState) ? null : cachedState;\n\n // Prevent callbacks fo fire twice if both hashchange & popstate were fired.\n if (equals(cachedState, lastCachedState)) {\n cachedState = lastCachedState;\n }\n\n lastCachedState = cachedState;\n lastHistoryState = cachedState;\n }\n\n function fireStateOrUrlChange() {\n var prevLastHistoryState = lastHistoryState;\n cacheState();\n\n if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {\n return;\n }\n\n lastBrowserUrl = self.url();\n lastHistoryState = cachedState;\n forEach(urlChangeListeners, function(listener) {\n listener(self.url(), cachedState);\n });\n }\n\n /**\n * @name $browser#onUrlChange\n *\n * @description\n * Register callback function that will be called, when url changes.\n *\n * It's only called when the url is changed from outside of AngularJS:\n * - user types different url into address bar\n * - user clicks on history (forward/back) button\n * - user clicks on a link\n *\n * It's not called when url is changed by $browser.url() method\n *\n * The listener gets called with new url as parameter.\n *\n * NOTE: this api is intended for use only by the $location service. Please use the\n * {@link ng.$location $location service} to monitor url changes in AngularJS apps.\n *\n * @param {function(string)} listener Listener function to be called when url changes.\n * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.\n */\n self.onUrlChange = function(callback) {\n // TODO(vojta): refactor to use node's syntax for events\n if (!urlChangeInit) {\n // We listen on both (hashchange/popstate) when available, as some browsers don't\n // fire popstate when user changes the address bar and don't fire hashchange when url\n // changed by push/replaceState\n\n // html5 history api - popstate event\n if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);\n // hashchange event\n jqLite(window).on('hashchange', cacheStateAndFireUrlChange);\n\n urlChangeInit = true;\n }\n\n urlChangeListeners.push(callback);\n return callback;\n };\n\n /**\n * @private\n * Remove popstate and hashchange handler from window.\n *\n * NOTE: this api is intended for use only by $rootScope.\n */\n self.$$applicationDestroyed = function() {\n jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);\n };\n\n /**\n * Checks whether the url has changed outside of AngularJS.\n * Needs to be exported to be able to check for changes that have been done in sync,\n * as hashchange/popstate events fire in async.\n */\n self.$$checkUrlChange = fireStateOrUrlChange;\n\n //////////////////////////////////////////////////////////////\n // Misc API\n //////////////////////////////////////////////////////////////\n\n /**\n * @name $browser#baseHref\n *\n * @description\n * Returns current \n * (always relative - without domain)\n *\n * @returns {string} The current base href\n */\n self.baseHref = function() {\n var href = baseElement.attr('href');\n return href ? href.replace(/^(https?:)?\\/\\/[^/]*/, '') : '';\n };\n\n /**\n * @name $browser#defer\n * @param {function()} fn A function, who's execution should be deferred.\n * @param {number=} [delay=0] of milliseconds to defer the function execution.\n * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.\n *\n * @description\n * Executes a fn asynchronously via `setTimeout(fn, delay)`.\n *\n * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using\n * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed\n * via `$browser.defer.flush()`.\n *\n */\n self.defer = function(fn, delay) {\n var timeoutId;\n outstandingRequestCount++;\n timeoutId = setTimeout(function() {\n delete pendingDeferIds[timeoutId];\n completeOutstandingRequest(fn);\n }, delay || 0);\n pendingDeferIds[timeoutId] = true;\n return timeoutId;\n };\n\n\n /**\n * @name $browser#defer.cancel\n *\n * @description\n * Cancels a deferred task identified with `deferId`.\n *\n * @param {*} deferId Token returned by the `$browser.defer` function.\n * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully\n * canceled.\n */\n self.defer.cancel = function(deferId) {\n if (pendingDeferIds[deferId]) {\n delete pendingDeferIds[deferId];\n clearTimeout(deferId);\n completeOutstandingRequest(noop);\n return true;\n }\n return false;\n };\n\n}\n\n/** @this */\nfunction $BrowserProvider() {\n this.$get = ['$window', '$log', '$sniffer', '$document',\n function($window, $log, $sniffer, $document) {\n return new Browser($window, $document, $log, $sniffer);\n }];\n}\n\n/**\n * @ngdoc service\n * @name $cacheFactory\n * @this\n *\n * @description\n * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to\n * them.\n *\n * ```js\n *\n * var cache = $cacheFactory('cacheId');\n * expect($cacheFactory.get('cacheId')).toBe(cache);\n * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();\n *\n * cache.put(\"key\", \"value\");\n * cache.put(\"another key\", \"another value\");\n *\n * // We've specified no options on creation\n * expect(cache.info()).toEqual({id: 'cacheId', size: 2});\n *\n * ```\n *\n *\n * @param {string} cacheId Name or id of the newly created cache.\n * @param {object=} options Options object that specifies the cache behavior. Properties:\n *\n * - `{number=}` `capacity` — turns the cache into LRU cache.\n *\n * @returns {object} Newly created cache object with the following set of methods:\n *\n * - `{object}` `info()` — Returns id, size, and options of cache.\n * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns\n * it.\n * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.\n * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.\n * - `{void}` `removeAll()` — Removes all cached values.\n * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.\n *\n * @example\n \n \n
\n \n \n \n\n
Cached Values
\n
\n \n : \n \n
\n\n
Cache Info
\n
\n \n : \n \n
\n
\n \n \n angular.module('cacheExampleApp', []).\n controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {\n $scope.keys = [];\n $scope.cache = $cacheFactory('cacheId');\n $scope.put = function(key, value) {\n if (angular.isUndefined($scope.cache.get(key))) {\n $scope.keys.push(key);\n }\n $scope.cache.put(key, angular.isUndefined(value) ? null : value);\n };\n }]);\n \n \n p {\n margin: 10px 0 3px;\n }\n \n \n */\nfunction $CacheFactoryProvider() {\n\n this.$get = function() {\n var caches = {};\n\n function cacheFactory(cacheId, options) {\n if (cacheId in caches) {\n throw minErr('$cacheFactory')('iid', 'CacheId \\'{0}\\' is already taken!', cacheId);\n }\n\n var size = 0,\n stats = extend({}, options, {id: cacheId}),\n data = createMap(),\n capacity = (options && options.capacity) || Number.MAX_VALUE,\n lruHash = createMap(),\n freshEnd = null,\n staleEnd = null;\n\n /**\n * @ngdoc type\n * @name $cacheFactory.Cache\n *\n * @description\n * A cache object used to store and retrieve data, primarily used by\n * {@link $templateRequest $templateRequest} and the {@link ng.directive:script script}\n * directive to cache templates and other data.\n *\n * ```js\n * angular.module('superCache')\n * .factory('superCache', ['$cacheFactory', function($cacheFactory) {\n * return $cacheFactory('super-cache');\n * }]);\n * ```\n *\n * Example test:\n *\n * ```js\n * it('should behave like a cache', inject(function(superCache) {\n * superCache.put('key', 'value');\n * superCache.put('another key', 'another value');\n *\n * expect(superCache.info()).toEqual({\n * id: 'super-cache',\n * size: 2\n * });\n *\n * superCache.remove('another key');\n * expect(superCache.get('another key')).toBeUndefined();\n *\n * superCache.removeAll();\n * expect(superCache.info()).toEqual({\n * id: 'super-cache',\n * size: 0\n * });\n * }));\n * ```\n */\n return (caches[cacheId] = {\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#put\n * @kind function\n *\n * @description\n * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be\n * retrieved later, and incrementing the size of the cache if the key was not already\n * present in the cache. If behaving like an LRU cache, it will also remove stale\n * entries from the set.\n *\n * It will not insert undefined values into the cache.\n *\n * @param {string} key the key under which the cached data is stored.\n * @param {*} value the value to store alongside the key. If it is undefined, the key\n * will not be stored.\n * @returns {*} the value stored.\n */\n put: function(key, value) {\n if (isUndefined(value)) return;\n if (capacity < Number.MAX_VALUE) {\n var lruEntry = lruHash[key] || (lruHash[key] = {key: key});\n\n refresh(lruEntry);\n }\n\n if (!(key in data)) size++;\n data[key] = value;\n\n if (size > capacity) {\n this.remove(staleEnd.key);\n }\n\n return value;\n },\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#get\n * @kind function\n *\n * @description\n * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.\n *\n * @param {string} key the key of the data to be retrieved\n * @returns {*} the value stored.\n */\n get: function(key) {\n if (capacity < Number.MAX_VALUE) {\n var lruEntry = lruHash[key];\n\n if (!lruEntry) return;\n\n refresh(lruEntry);\n }\n\n return data[key];\n },\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#remove\n * @kind function\n *\n * @description\n * Removes an entry from the {@link $cacheFactory.Cache Cache} object.\n *\n * @param {string} key the key of the entry to be removed\n */\n remove: function(key) {\n if (capacity < Number.MAX_VALUE) {\n var lruEntry = lruHash[key];\n\n if (!lruEntry) return;\n\n if (lruEntry === freshEnd) freshEnd = lruEntry.p;\n if (lruEntry === staleEnd) staleEnd = lruEntry.n;\n link(lruEntry.n,lruEntry.p);\n\n delete lruHash[key];\n }\n\n if (!(key in data)) return;\n\n delete data[key];\n size--;\n },\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#removeAll\n * @kind function\n *\n * @description\n * Clears the cache object of any entries.\n */\n removeAll: function() {\n data = createMap();\n size = 0;\n lruHash = createMap();\n freshEnd = staleEnd = null;\n },\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#destroy\n * @kind function\n *\n * @description\n * Destroys the {@link $cacheFactory.Cache Cache} object entirely,\n * removing it from the {@link $cacheFactory $cacheFactory} set.\n */\n destroy: function() {\n data = null;\n stats = null;\n lruHash = null;\n delete caches[cacheId];\n },\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory.Cache#info\n * @kind function\n *\n * @description\n * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.\n *\n * @returns {object} an object with the following properties:\n *
\n *
**id**: the id of the cache instance
\n *
**size**: the number of entries kept in the cache instance
\n *
**...**: any additional properties from the options object when creating the\n * cache.
\n *
\n */\n info: function() {\n return extend({}, stats, {size: size});\n }\n });\n\n\n /**\n * makes the `entry` the freshEnd of the LRU linked list\n */\n function refresh(entry) {\n if (entry !== freshEnd) {\n if (!staleEnd) {\n staleEnd = entry;\n } else if (staleEnd === entry) {\n staleEnd = entry.n;\n }\n\n link(entry.n, entry.p);\n link(entry, freshEnd);\n freshEnd = entry;\n freshEnd.n = null;\n }\n }\n\n\n /**\n * bidirectionally links two entries of the LRU linked list\n */\n function link(nextEntry, prevEntry) {\n if (nextEntry !== prevEntry) {\n if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify\n if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify\n }\n }\n }\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory#info\n *\n * @description\n * Get information about all the caches that have been created\n *\n * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`\n */\n cacheFactory.info = function() {\n var info = {};\n forEach(caches, function(cache, cacheId) {\n info[cacheId] = cache.info();\n });\n return info;\n };\n\n\n /**\n * @ngdoc method\n * @name $cacheFactory#get\n *\n * @description\n * Get access to a cache object by the `cacheId` used when it was created.\n *\n * @param {string} cacheId Name or id of a cache to access.\n * @returns {object} Cache object identified by the cacheId or undefined if no such cache.\n */\n cacheFactory.get = function(cacheId) {\n return caches[cacheId];\n };\n\n\n return cacheFactory;\n };\n}\n\n/**\n * @ngdoc service\n * @name $templateCache\n * @this\n *\n * @description\n * `$templateCache` is a {@link $cacheFactory.Cache Cache object} created by the\n * {@link ng.$cacheFactory $cacheFactory}.\n *\n * The first time a template is used, it is loaded in the template cache for quick retrieval. You\n * can load templates directly into the cache in a `script` tag, by using {@link $templateRequest},\n * or by consuming the `$templateCache` service directly.\n *\n * Adding via the `script` tag:\n *\n * ```html\n * \n * ```\n *\n * **Note:** the `script` tag containing the template does not need to be included in the `head` of\n * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (e.g.\n * element with {@link ngApp} attribute), otherwise the template will be ignored.\n *\n * Adding via the `$templateCache` service:\n *\n * ```js\n * var myApp = angular.module('myApp', []);\n * myApp.run(function($templateCache) {\n * $templateCache.put('templateId.html', 'This is the content of the template');\n * });\n * ```\n *\n * To retrieve the template later, simply use it in your component:\n * ```js\n * myApp.component('myComponent', {\n * templateUrl: 'templateId.html'\n * });\n * ```\n *\n * or get it via the `$templateCache` service:\n * ```js\n * $templateCache.get('templateId.html')\n * ```\n *\n */\nfunction $TemplateCacheProvider() {\n this.$get = ['$cacheFactory', function($cacheFactory) {\n return $cacheFactory('templates');\n }];\n}\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Any commits to this file should be reviewed with security in mind. *\n * Changes to this file can potentially create security vulnerabilities. *\n * An approval from 2 Core members with history of modifying *\n * this file is required. *\n * *\n * Does the change somehow allow for arbitrary javascript to be executed? *\n * Or allows for someone to change the prototype of built-in objects? *\n * Or gives undesired access to variables like document or window? *\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!\n *\n * DOM-related variables:\n *\n * - \"node\" - DOM Node\n * - \"element\" - DOM Element or Node\n * - \"$node\" or \"$element\" - jqLite-wrapped node or element\n *\n *\n * Compiler related stuff:\n *\n * - \"linkFn\" - linking fn of a single directive\n * - \"nodeLinkFn\" - function that aggregates all linking fns for a particular node\n * - \"childLinkFn\" - function that aggregates all linking fns for child nodes of a particular node\n * - \"compositeLinkFn\" - function that aggregates all linking fns for a compilation root (nodeList)\n */\n\n\n/**\n * @ngdoc service\n * @name $compile\n * @kind function\n *\n * @description\n * Compiles an HTML string or DOM into a template and produces a template function, which\n * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.\n *\n * The compilation is a process of walking the DOM tree and matching DOM elements to\n * {@link ng.$compileProvider#directive directives}.\n *\n *
\n * **Note:** This document is an in-depth reference of all directive options.\n * For a gentle introduction to directives with examples of common use cases,\n * see the {@link guide/directive directive guide}.\n *
\n *\n * ## Comprehensive Directive API\n *\n * There are many different options for a directive.\n *\n * The difference resides in the return value of the factory function.\n * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}\n * that defines the directive properties, or just the `postLink` function (all other properties will have\n * the default values).\n *\n *
\n * **Best Practice:** It's recommended to use the \"directive definition object\" form.\n *
\n * **Note:** Any unspecified options will use the default value. You can see the default values below.\n *
\n *\n * Therefore the above can be simplified as:\n *\n * ```js\n * var myModule = angular.module(...);\n *\n * myModule.directive('directiveName', function factory(injectables) {\n * var directiveDefinitionObject = {\n * link: function postLink(scope, iElement, iAttrs) { ... }\n * };\n * return directiveDefinitionObject;\n * // or\n * // return function postLink(scope, iElement, iAttrs) { ... }\n * });\n * ```\n *\n * ### Life-cycle hooks\n * Directive controllers can provide the following methods that are called by AngularJS at points in the life-cycle of the\n * directive:\n * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and\n * had their bindings initialized (and before the pre & post linking functions for the directives on\n * this element). This is a good place to put initialization code for your controller.\n * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The\n * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an\n * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a\n * component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will\n * also be called when your bindings are initialized.\n * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on\n * changes. Any actions that you wish to take in response to the changes that you detect must be\n * invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook\n * could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not\n * be detected by AngularJS's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;\n * if detecting changes, you must store the previous value(s) for comparison to the current values.\n * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing\n * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in\n * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent\n * components will have their `$onDestroy()` hook called before child components.\n * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link\n * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.\n * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since\n * they are waiting for their template to load asynchronously and their own compilation and linking has been\n * suspended until that occurs.\n *\n * #### Comparison with life-cycle hooks in the new Angular\n * The new Angular also uses life-cycle hooks for its components. While the AngularJS life-cycle hooks are similar there are\n * some differences that you should be aware of, especially when it comes to moving your code from AngularJS to Angular:\n *\n * * AngularJS hooks are prefixed with `$`, such as `$onInit`. Angular hooks are prefixed with `ng`, such as `ngOnInit`.\n * * AngularJS hooks can be defined on the controller prototype or added to the controller inside its constructor.\n * In Angular you can only define hooks on the prototype of the Component class.\n * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in AngularJS than you would to\n * `ngDoCheck` in Angular.\n * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be\n * propagated throughout the application.\n * Angular does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an\n * error or do nothing depending upon the state of `enableProdMode()`.\n *\n * #### Life-cycle hook examples\n *\n * This example shows how you can check for mutations to a Date object even though the identity of the object\n * has not changed.\n *\n * \n * \n * angular.module('do-check-module', [])\n * .component('app', {\n * template:\n * 'Month: ' +\n * 'Date: {{ $ctrl.date }}' +\n * '',\n * controller: function() {\n * this.date = new Date();\n * this.month = this.date.getMonth();\n * this.updateDate = function() {\n * this.date.setMonth(this.month);\n * };\n * }\n * })\n * .component('test', {\n * bindings: { date: '<' },\n * template:\n * '
{{ $ctrl.log | json }}
',\n * controller: function() {\n * var previousValue;\n * this.log = [];\n * this.$doCheck = function() {\n * var currentValue = this.date && this.date.valueOf();\n * if (previousValue !== currentValue) {\n * this.log.push('doCheck: date mutated: ' + this.date);\n * previousValue = currentValue;\n * }\n * };\n * }\n * });\n * \n * \n * \n * \n * \n *\n * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the\n * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large\n * arrays or objects can have a negative impact on your application performance)\n *\n * \n * \n *
',\n * controller: function() {\n * this.log = [];\n *\n * this.$doCheck = function() {\n * if (this.items_ref !== this.items) {\n * this.log.push('doCheck: items changed');\n * this.items_ref = this.items;\n * }\n * if (!angular.equals(this.items_clone, this.items)) {\n * this.log.push('doCheck: items mutated');\n * this.items_clone = angular.copy(this.items);\n * }\n * };\n * }\n * });\n * \n * \n *\n *\n * ### Directive Definition Object\n *\n * The directive definition object provides instructions to the {@link ng.$compile\n * compiler}. The attributes are:\n *\n * #### `multiElement`\n * When this property is set to true (default is `false`), the HTML compiler will collect DOM nodes between\n * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them\n * together as the directive elements. It is recommended that this feature be used on directives\n * which are not strictly behavioral (such as {@link ngClick}), and which\n * do not manipulate or replace child nodes (such as {@link ngInclude}).\n *\n * #### `priority`\n * When there are multiple directives defined on a single DOM element, sometimes it\n * is necessary to specify the order in which the directives are applied. The `priority` is used\n * to sort the directives before their `compile` functions get called. Priority is defined as a\n * number. Directives with greater numerical `priority` are compiled first. Pre-link functions\n * are also run in priority order, but post-link functions are run in reverse order. The order\n * of directives with the same priority is undefined. The default priority is `0`.\n *\n * #### `terminal`\n * If set to true then the current `priority` will be the last set of directives\n * which will execute (any directives at the current priority will still execute\n * as the order of execution on same `priority` is undefined). Note that expressions\n * and other directives used in the directive's template will also be excluded from execution.\n *\n * #### `scope`\n * The scope property can be `false`, `true`, or an object:\n *\n * * **`false` (default):** No scope will be created for the directive. The directive will use its\n * parent's scope.\n *\n * * **`true`:** A new child scope that prototypically inherits from its parent will be created for\n * the directive's element. If multiple directives on the same element request a new scope,\n * only one new scope is created.\n *\n * * **`{...}` (an object hash):** A new \"isolate\" scope is created for the directive's template.\n * The 'isolate' scope differs from normal scope in that it does not prototypically\n * inherit from its parent scope. This is useful when creating reusable components, which should not\n * accidentally read or modify data in the parent scope. Note that an isolate scope\n * directive without a `template` or `templateUrl` will not apply the isolate scope\n * to its children elements.\n *\n * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the\n * directive's element. These local properties are useful for aliasing values for templates. The keys in\n * the object hash map to the name of the property on the isolate scope; the values define how the property\n * is bound to the parent scope, via matching attributes on the directive's element:\n *\n * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is\n * always a string since DOM attributes are strings. If no `attr` name is specified then the\n * attribute name is assumed to be the same as the local name. Given `` and the isolate scope definition `scope: { localName:'@myAttr' }`,\n * the directive's scope property `localName` will reflect the interpolated value of `hello\n * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's\n * scope. The `name` is read from the parent scope (not the directive's scope).\n *\n * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression\n * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.\n * If no `attr` name is specified then the attribute name is assumed to be the same as the local\n * name. Given `` and the isolate scope definition `scope: {\n * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the\n * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in\n * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:\n * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't\n * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})\n * will be thrown upon discovering changes to the local value, since it will be impossible to sync\n * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}\n * method is used for tracking changes, and the equality check is based on object identity.\n * However, if an object literal or an array literal is passed as the binding expression, the\n * equality check is done by value (using the {@link angular.equals} function). It's also possible\n * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection\n * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).\n *\n * * `<` or `` and directive definition of\n * `scope: { localModel:'` and the isolate scope definition `scope: {\n * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for\n * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope\n * via an expression to the parent scope. This can be done by passing a map of local variable names\n * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`\n * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.\n *\n * In general it's possible to apply more than one directive to one element, but there might be limitations\n * depending on the type of scope required by the directives. The following points will help explain these limitations.\n * For simplicity only two directives are taken into account, but it is also applicable for several directives:\n *\n * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope\n * * **child scope** + **no scope** => Both directives will share one single child scope\n * * **child scope** + **child scope** => Both directives will share one single child scope\n * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use\n * its parent's scope\n * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot\n * be applied to the same element.\n * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives\n * cannot be applied to the same element.\n *\n *\n * #### `bindToController`\n * This property is used to bind scope properties directly to the controller. It can be either\n * `true` or an object hash with the same format as the `scope` property.\n *\n * When an isolate scope is used for a directive (see above), `bindToController: true` will\n * allow a component to have its properties bound to the controller, rather than to scope.\n *\n * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller\n * properties. You can access these bindings once they have been initialized by providing a controller method called\n * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings\n * initialized.\n *\n *
\n * **Deprecation warning:** if `$compileProcvider.preAssignBindingsEnabled(true)` was called, bindings for non-ES6 class\n * controllers are bound to `this` before the controller constructor is called but this use is now deprecated. Please\n * place initialization code that relies upon bindings inside a `$onInit` method on the controller, instead.\n *
\n *\n * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.\n * This will set up the scope bindings to the controller directly. Note that `scope` can still be used\n * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate\n * scope (useful for component directives).\n *\n * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.\n *\n *\n * #### `controller`\n * Controller constructor function. The controller is instantiated before the\n * pre-linking phase and can be accessed by other directives (see\n * `require` attribute). This allows the directives to communicate with each other and augment\n * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:\n *\n * * `$scope` - Current scope associated with the element\n * * `$element` - Current element\n * * `$attrs` - Current attributes object for the element\n * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:\n * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:\n * * `scope`: (optional) override the scope.\n * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.\n * * `futureParentElement` (optional):\n * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.\n * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.\n * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)\n * and when the `cloneLinkingFn` is passed,\n * as those elements need to created and cloned in a special way when they are defined outside their\n * usual containers (e.g. like `