remove angular-animate and angular-touch 83/101783/3
authorAmichai Hemli <amichai.hemli@intl.att.com>
Sun, 16 Feb 2020 10:16:09 +0000 (12:16 +0200)
committerIttay Stern <ittay.stern@att.com>
Wed, 19 Feb 2020 08:20:42 +0000 (08:20 +0000)
Issue-ID: VID-774
Signed-off-by: Amichai Hemli <amichai.hemli@intl.att.com>
Change-Id: Ibb451aeb486bf01ccd30ab1f2a8d4b72c3b92a71

epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-animate.js [deleted file]
epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-touch.js [deleted file]

diff --git a/epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-animate.js b/epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-animate.js
deleted file mode 100755 (executable)
index edea529..0000000
+++ /dev/null
@@ -1,3721 +0,0 @@
-/**\r
- * @license AngularJS v1.4.3\r
- * (c) 2010-2015 Google, Inc. http://angularjs.org\r
- * License: MIT\r
- */\r
-(function(window, angular, undefined) {'use strict';\r
-\r
-/* jshint ignore:start */\r
-var noop        = angular.noop;\r
-var extend      = angular.extend;\r
-var jqLite      = angular.element;\r
-var forEach     = angular.forEach;\r
-var isArray     = angular.isArray;\r
-var isString    = angular.isString;\r
-var isObject    = angular.isObject;\r
-var isUndefined = angular.isUndefined;\r
-var isDefined   = angular.isDefined;\r
-var isFunction  = angular.isFunction;\r
-var isElement   = angular.isElement;\r
-\r
-var ELEMENT_NODE = 1;\r
-var COMMENT_NODE = 8;\r
-\r
-var NG_ANIMATE_CLASSNAME = 'ng-animate';\r
-var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';\r
-\r
-var isPromiseLike = function(p) {\r
-  return p && p.then ? true : false;\r
-}\r
-\r
-function assertArg(arg, name, reason) {\r
-  if (!arg) {\r
-    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));\r
-  }\r
-  return arg;\r
-}\r
-\r
-function mergeClasses(a,b) {\r
-  if (!a && !b) return '';\r
-  if (!a) return b;\r
-  if (!b) return a;\r
-  if (isArray(a)) a = a.join(' ');\r
-  if (isArray(b)) b = b.join(' ');\r
-  return a + ' ' + b;\r
-}\r
-\r
-function packageStyles(options) {\r
-  var styles = {};\r
-  if (options && (options.to || options.from)) {\r
-    styles.to = options.to;\r
-    styles.from = options.from;\r
-  }\r
-  return styles;\r
-}\r
-\r
-function pendClasses(classes, fix, isPrefix) {\r
-  var className = '';\r
-  classes = isArray(classes)\r
-      ? classes\r
-      : classes && isString(classes) && classes.length\r
-          ? classes.split(/\s+/)\r
-          : [];\r
-  forEach(classes, function(klass, i) {\r
-    if (klass && klass.length > 0) {\r
-      className += (i > 0) ? ' ' : '';\r
-      className += isPrefix ? fix + klass\r
-                            : klass + fix;\r
-    }\r
-  });\r
-  return className;\r
-}\r
-\r
-function removeFromArray(arr, val) {\r
-  var index = arr.indexOf(val);\r
-  if (val >= 0) {\r
-    arr.splice(index, 1);\r
-  }\r
-}\r
-\r
-function stripCommentsFromElement(element) {\r
-  if (element instanceof jqLite) {\r
-    switch (element.length) {\r
-      case 0:\r
-        return [];\r
-        break;\r
-\r
-      case 1:\r
-        // there is no point of stripping anything if the element\r
-        // is the only element within the jqLite wrapper.\r
-        // (it's important that we retain the element instance.)\r
-        if (element[0].nodeType === ELEMENT_NODE) {\r
-          return element;\r
-        }\r
-        break;\r
-\r
-      default:\r
-        return jqLite(extractElementNode(element));\r
-        break;\r
-    }\r
-  }\r
-\r
-  if (element.nodeType === ELEMENT_NODE) {\r
-    return jqLite(element);\r
-  }\r
-}\r
-\r
-function extractElementNode(element) {\r
-  if (!element[0]) return element;\r
-  for (var i = 0; i < element.length; i++) {\r
-    var elm = element[i];\r
-    if (elm.nodeType == ELEMENT_NODE) {\r
-      return elm;\r
-    }\r
-  }\r
-}\r
-\r
-function $$addClass($$jqLite, element, className) {\r
-  forEach(element, function(elm) {\r
-    $$jqLite.addClass(elm, className);\r
-  });\r
-}\r
-\r
-function $$removeClass($$jqLite, element, className) {\r
-  forEach(element, function(elm) {\r
-    $$jqLite.removeClass(elm, className);\r
-  });\r
-}\r
-\r
-function applyAnimationClassesFactory($$jqLite) {\r
-  return function(element, options) {\r
-    if (options.addClass) {\r
-      $$addClass($$jqLite, element, options.addClass);\r
-      options.addClass = null;\r
-    }\r
-    if (options.removeClass) {\r
-      $$removeClass($$jqLite, element, options.removeClass);\r
-      options.removeClass = null;\r
-    }\r
-  }\r
-}\r
-\r
-function prepareAnimationOptions(options) {\r
-  options = options || {};\r
-  if (!options.$$prepared) {\r
-    var domOperation = options.domOperation || noop;\r
-    options.domOperation = function() {\r
-      options.$$domOperationFired = true;\r
-      domOperation();\r
-      domOperation = noop;\r
-    };\r
-    options.$$prepared = true;\r
-  }\r
-  return options;\r
-}\r
-\r
-function applyAnimationStyles(element, options) {\r
-  applyAnimationFromStyles(element, options);\r
-  applyAnimationToStyles(element, options);\r
-}\r
-\r
-function applyAnimationFromStyles(element, options) {\r
-  if (options.from) {\r
-    element.css(options.from);\r
-    options.from = null;\r
-  }\r
-}\r
-\r
-function applyAnimationToStyles(element, options) {\r
-  if (options.to) {\r
-    element.css(options.to);\r
-    options.to = null;\r
-  }\r
-}\r
-\r
-function mergeAnimationOptions(element, target, newOptions) {\r
-  var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');\r
-  var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');\r
-  var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);\r
-\r
-  extend(target, newOptions);\r
-\r
-  if (classes.addClass) {\r
-    target.addClass = classes.addClass;\r
-  } else {\r
-    target.addClass = null;\r
-  }\r
-\r
-  if (classes.removeClass) {\r
-    target.removeClass = classes.removeClass;\r
-  } else {\r
-    target.removeClass = null;\r
-  }\r
-\r
-  return target;\r
-}\r
-\r
-function resolveElementClasses(existing, toAdd, toRemove) {\r
-  var ADD_CLASS = 1;\r
-  var REMOVE_CLASS = -1;\r
-\r
-  var flags = {};\r
-  existing = splitClassesToLookup(existing);\r
-\r
-  toAdd = splitClassesToLookup(toAdd);\r
-  forEach(toAdd, function(value, key) {\r
-    flags[key] = ADD_CLASS;\r
-  });\r
-\r
-  toRemove = splitClassesToLookup(toRemove);\r
-  forEach(toRemove, function(value, key) {\r
-    flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;\r
-  });\r
-\r
-  var classes = {\r
-    addClass: '',\r
-    removeClass: ''\r
-  };\r
-\r
-  forEach(flags, function(val, klass) {\r
-    var prop, allow;\r
-    if (val === ADD_CLASS) {\r
-      prop = 'addClass';\r
-      allow = !existing[klass];\r
-    } else if (val === REMOVE_CLASS) {\r
-      prop = 'removeClass';\r
-      allow = existing[klass];\r
-    }\r
-    if (allow) {\r
-      if (classes[prop].length) {\r
-        classes[prop] += ' ';\r
-      }\r
-      classes[prop] += klass;\r
-    }\r
-  });\r
-\r
-  function splitClassesToLookup(classes) {\r
-    if (isString(classes)) {\r
-      classes = classes.split(' ');\r
-    }\r
-\r
-    var obj = {};\r
-    forEach(classes, function(klass) {\r
-      // sometimes the split leaves empty string values\r
-      // incase extra spaces were applied to the options\r
-      if (klass.length) {\r
-        obj[klass] = true;\r
-      }\r
-    });\r
-    return obj;\r
-  }\r
-\r
-  return classes;\r
-}\r
-\r
-function getDomNode(element) {\r
-  return (element instanceof angular.element) ? element[0] : element;\r
-}\r
-\r
-var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {\r
-  var tickQueue = [];\r
-  var cancelFn;\r
-\r
-  function scheduler(tasks) {\r
-    // we make a copy since RAFScheduler mutates the state\r
-    // of the passed in array variable and this would be difficult\r
-    // to track down on the outside code\r
-    tickQueue.push([].concat(tasks));\r
-    nextTick();\r
-  }\r
-\r
-  /* waitUntilQuiet does two things:\r
-   * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through\r
-   * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.\r
-   *\r
-   * The motivation here is that animation code can request more time from the scheduler\r
-   * before the next wave runs. This allows for certain DOM properties such as classes to\r
-   * be resolved in time for the next animation to run.\r
-   */\r
-  scheduler.waitUntilQuiet = function(fn) {\r
-    if (cancelFn) cancelFn();\r
-\r
-    cancelFn = $$rAF(function() {\r
-      cancelFn = null;\r
-      fn();\r
-      nextTick();\r
-    });\r
-  };\r
-\r
-  return scheduler;\r
-\r
-  function nextTick() {\r
-    if (!tickQueue.length) return;\r
-\r
-    var updatedQueue = [];\r
-    for (var i = 0; i < tickQueue.length; i++) {\r
-      var innerQueue = tickQueue[i];\r
-      runNextTask(innerQueue);\r
-      if (innerQueue.length) {\r
-        updatedQueue.push(innerQueue);\r
-      }\r
-    }\r
-    tickQueue = updatedQueue;\r
-\r
-    if (!cancelFn) {\r
-      $$rAF(function() {\r
-        if (!cancelFn) nextTick();\r
-      });\r
-    }\r
-  }\r
-\r
-  function runNextTask(tasks) {\r
-    var nextTask = tasks.shift();\r
-    nextTask();\r
-  }\r
-}];\r
-\r
-var $$AnimateChildrenDirective = [function() {\r
-  return function(scope, element, attrs) {\r
-    var val = attrs.ngAnimateChildren;\r
-    if (angular.isString(val) && val.length === 0) { //empty attribute\r
-      element.data(NG_ANIMATE_CHILDREN_DATA, true);\r
-    } else {\r
-      attrs.$observe('ngAnimateChildren', function(value) {\r
-        value = value === 'on' || value === 'true';\r
-        element.data(NG_ANIMATE_CHILDREN_DATA, value);\r
-      });\r
-    }\r
-  };\r
-}];\r
-\r
-/**\r
- * @ngdoc service\r
- * @name $animateCss\r
- * @kind object\r
- *\r
- * @description\r
- * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes\r
- * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT\r
- * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or\r
- * directives to create more complex animations that can be purely driven using CSS code.\r
- *\r
- * Note that only browsers that support CSS transitions and/or keyframe animations are capable of\r
- * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).\r
- *\r
- * ## Usage\r
- * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that\r
- * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,\r
- * any automatic control over cancelling animations and/or preventing animations from being run on\r
- * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to\r
- * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger\r
- * the CSS animation.\r
- *\r
- * The example below shows how we can create a folding animation on an element using `ng-if`:\r
- *\r
- * ```html\r
- * <!-- notice the `fold-animation` CSS class -->\r
- * <div ng-if="onOff" class="fold-animation">\r
- *   This element will go BOOM\r
- * </div>\r
- * <button ng-click="onOff=true">Fold In</button>\r
- * ```\r
- *\r
- * Now we create the **JavaScript animation** that will trigger the CSS transition:\r
- *\r
- * ```js\r
- * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\r
- *   return {\r
- *     enter: function(element, doneFn) {\r
- *       var height = element[0].offsetHeight;\r
- *       return $animateCss(element, {\r
- *         from: { height:'0px' },\r
- *         to: { height:height + 'px' },\r
- *         duration: 1 // one second\r
- *       });\r
- *     }\r
- *   }\r
- * }]);\r
- * ```\r
- *\r
- * ## More Advanced Uses\r
- *\r
- * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks\r
- * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code.\r
- *\r
- * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation,\r
- * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with\r
- * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order\r
- * to provide a working animation that will run in CSS.\r
- *\r
- * The example below showcases a more advanced version of the `.fold-animation` from the example above:\r
- *\r
- * ```js\r
- * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\r
- *   return {\r
- *     enter: function(element, doneFn) {\r
- *       var height = element[0].offsetHeight;\r
- *       return $animateCss(element, {\r
- *         addClass: 'red large-text pulse-twice',\r
- *         easing: 'ease-out',\r
- *         from: { height:'0px' },\r
- *         to: { height:height + 'px' },\r
- *         duration: 1 // one second\r
- *       });\r
- *     }\r
- *   }\r
- * }]);\r
- * ```\r
- *\r
- * Since we're adding/removing CSS classes then the CSS transition will also pick those up:\r
- *\r
- * ```css\r
- * /&#42; since a hardcoded duration value of 1 was provided in the JavaScript animation code,\r
- * the CSS classes below will be transitioned despite them being defined as regular CSS classes &#42;/\r
- * .red { background:red; }\r
- * .large-text { font-size:20px; }\r
- *\r
- * /&#42; we can also use a keyframe animation and $animateCss will make it work alongside the transition &#42;/\r
- * .pulse-twice {\r
- *   animation: 0.5s pulse linear 2;\r
- *   -webkit-animation: 0.5s pulse linear 2;\r
- * }\r
- *\r
- * @keyframes pulse {\r
- *   from { transform: scale(0.5); }\r
- *   to { transform: scale(1.5); }\r
- * }\r
- *\r
- * @-webkit-keyframes pulse {\r
- *   from { -webkit-transform: scale(0.5); }\r
- *   to { -webkit-transform: scale(1.5); }\r
- * }\r
- * ```\r
- *\r
- * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.\r
- *\r
- * ## How the Options are handled\r
- *\r
- * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation\r
- * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline\r
- * styles using the `from` and `to` properties.\r
- *\r
- * ```js\r
- * var animator = $animateCss(element, {\r
- *   from: { background:'red' },\r
- *   to: { background:'blue' }\r
- * });\r
- * animator.start();\r
- * ```\r
- *\r
- * ```css\r
- * .rotating-animation {\r
- *   animation:0.5s rotate linear;\r
- *   -webkit-animation:0.5s rotate linear;\r
- * }\r
- *\r
- * @keyframes rotate {\r
- *   from { transform: rotate(0deg); }\r
- *   to { transform: rotate(360deg); }\r
- * }\r
- *\r
- * @-webkit-keyframes rotate {\r
- *   from { -webkit-transform: rotate(0deg); }\r
- *   to { -webkit-transform: rotate(360deg); }\r
- * }\r
- * ```\r
- *\r
- * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is\r
- * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition\r
- * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition\r
- * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied\r
- * and spread across the transition and keyframe animation.\r
- *\r
- * ## What is returned\r
- *\r
- * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually\r
- * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are\r
- * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties:\r
- *\r
- * ```js\r
- * var animator = $animateCss(element, { ... });\r
- * ```\r
- *\r
- * Now what do the contents of our `animator` variable look like:\r
- *\r
- * ```js\r
- * {\r
- *   // starts the animation\r
- *   start: Function,\r
- *\r
- *   // ends (aborts) the animation\r
- *   end: Function\r
- * }\r
- * ```\r
- *\r
- * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.\r
- * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been\r
- * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties\r
- * and that changing them will not reconfigure the parameters of the animation.\r
- *\r
- * ### runner.done() vs runner.then()\r
- * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the\r
- * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.\r
- * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`\r
- * unless you really need a digest to kick off afterwards.\r
- *\r
- * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss\r
- * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).\r
- * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.\r
- *\r
- * @param {DOMElement} element the element that will be animated\r
- * @param {object} options the animation-related options that will be applied during the animation\r
- *\r
- * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied\r
- * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)\r
- * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).\r
- * * `transition` - The raw CSS transition style that will be used (e.g. `1s linear all`).\r
- * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).\r
- * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.\r
- * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.\r
- * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.\r
- * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.\r
- * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`\r
- * is provided then the animation will be skipped entirely.\r
- * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is\r
- * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value\r
- * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same\r
- * CSS delay value.\r
- * * `stagger` - A numeric time value representing the delay between successively animated elements\r
- * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})\r
- * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a\r
- * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)\r
- * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)\r
- *\r
- * @return {object} an object with start and end methods and details about the animation.\r
- *\r
- * * `start` - The method to start the animation. This will return a `Promise` when called.\r
- * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.\r
- */\r
-\r
-// Detect proper transitionend/animationend event names.\r
-var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;\r
-\r
-// If unprefixed events are not supported but webkit-prefixed are, use the latter.\r
-// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.\r
-// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`\r
-// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.\r
-// Register both events in case `window.onanimationend` is not supported because of that,\r
-// do the same for `transitionend` as Safari is likely to exhibit similar behavior.\r
-// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit\r
-// therefore there is no reason to test anymore for other vendor prefixes:\r
-// http://caniuse.com/#search=transition\r
-if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {\r
-  CSS_PREFIX = '-webkit-';\r
-  TRANSITION_PROP = 'WebkitTransition';\r
-  TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';\r
-} else {\r
-  TRANSITION_PROP = 'transition';\r
-  TRANSITIONEND_EVENT = 'transitionend';\r
-}\r
-\r
-if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {\r
-  CSS_PREFIX = '-webkit-';\r
-  ANIMATION_PROP = 'WebkitAnimation';\r
-  ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';\r
-} else {\r
-  ANIMATION_PROP = 'animation';\r
-  ANIMATIONEND_EVENT = 'animationend';\r
-}\r
-\r
-var DURATION_KEY = 'Duration';\r
-var PROPERTY_KEY = 'Property';\r
-var DELAY_KEY = 'Delay';\r
-var TIMING_KEY = 'TimingFunction';\r
-var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';\r
-var ANIMATION_PLAYSTATE_KEY = 'PlayState';\r
-var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;\r
-var CLOSING_TIME_BUFFER = 1.5;\r
-var ONE_SECOND = 1000;\r
-var BASE_TEN = 10;\r
-\r
-var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;\r
-\r
-var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;\r
-var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;\r
-\r
-var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;\r
-var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;\r
-\r
-var DETECT_CSS_PROPERTIES = {\r
-  transitionDuration:      TRANSITION_DURATION_PROP,\r
-  transitionDelay:         TRANSITION_DELAY_PROP,\r
-  transitionProperty:      TRANSITION_PROP + PROPERTY_KEY,\r
-  animationDuration:       ANIMATION_DURATION_PROP,\r
-  animationDelay:          ANIMATION_DELAY_PROP,\r
-  animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY\r
-};\r
-\r
-var DETECT_STAGGER_CSS_PROPERTIES = {\r
-  transitionDuration:      TRANSITION_DURATION_PROP,\r
-  transitionDelay:         TRANSITION_DELAY_PROP,\r
-  animationDuration:       ANIMATION_DURATION_PROP,\r
-  animationDelay:          ANIMATION_DELAY_PROP\r
-};\r
-\r
-function computeCssStyles($window, element, properties) {\r
-  var styles = Object.create(null);\r
-  var detectedStyles = $window.getComputedStyle(element) || {};\r
-  forEach(properties, function(formalStyleName, actualStyleName) {\r
-    var val = detectedStyles[formalStyleName];\r
-    if (val) {\r
-      var c = val.charAt(0);\r
-\r
-      // only numerical-based values have a negative sign or digit as the first value\r
-      if (c === '-' || c === '+' || c >= 0) {\r
-        val = parseMaxTime(val);\r
-      }\r
-\r
-      // by setting this to null in the event that the delay is not set or is set directly as 0\r
-      // then we can still allow for zegative values to be used later on and not mistake this\r
-      // value for being greater than any other negative value.\r
-      if (val === 0) {\r
-        val = null;\r
-      }\r
-      styles[actualStyleName] = val;\r
-    }\r
-  });\r
-\r
-  return styles;\r
-}\r
-\r
-function parseMaxTime(str) {\r
-  var maxValue = 0;\r
-  var values = str.split(/\s*,\s*/);\r
-  forEach(values, function(value) {\r
-    // it's always safe to consider only second values and omit `ms` values since\r
-    // getComputedStyle will always handle the conversion for us\r
-    if (value.charAt(value.length - 1) == 's') {\r
-      value = value.substring(0, value.length - 1);\r
-    }\r
-    value = parseFloat(value) || 0;\r
-    maxValue = maxValue ? Math.max(value, maxValue) : value;\r
-  });\r
-  return maxValue;\r
-}\r
-\r
-function truthyTimingValue(val) {\r
-  return val === 0 || val != null;\r
-}\r
-\r
-function getCssTransitionDurationStyle(duration, applyOnlyDuration) {\r
-  var style = TRANSITION_PROP;\r
-  var value = duration + 's';\r
-  if (applyOnlyDuration) {\r
-    style += DURATION_KEY;\r
-  } else {\r
-    value += ' linear all';\r
-  }\r
-  return [style, value];\r
-}\r
-\r
-function getCssKeyframeDurationStyle(duration) {\r
-  return [ANIMATION_DURATION_PROP, duration + 's'];\r
-}\r
-\r
-function getCssDelayStyle(delay, isKeyframeAnimation) {\r
-  var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;\r
-  return [prop, delay + 's'];\r
-}\r
-\r
-function blockTransitions(node, duration) {\r
-  // we use a negative delay value since it performs blocking\r
-  // yet it doesn't kill any existing transitions running on the\r
-  // same element which makes this safe for class-based animations\r
-  var value = duration ? '-' + duration + 's' : '';\r
-  applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);\r
-  return [TRANSITION_DELAY_PROP, value];\r
-}\r
-\r
-function blockKeyframeAnimations(node, applyBlock) {\r
-  var value = applyBlock ? 'paused' : '';\r
-  var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;\r
-  applyInlineStyle(node, [key, value]);\r
-  return [key, value];\r
-}\r
-\r
-function applyInlineStyle(node, styleTuple) {\r
-  var prop = styleTuple[0];\r
-  var value = styleTuple[1];\r
-  node.style[prop] = value;\r
-}\r
-\r
-function createLocalCacheLookup() {\r
-  var cache = Object.create(null);\r
-  return {\r
-    flush: function() {\r
-      cache = Object.create(null);\r
-    },\r
-\r
-    count: function(key) {\r
-      var entry = cache[key];\r
-      return entry ? entry.total : 0;\r
-    },\r
-\r
-    get: function(key) {\r
-      var entry = cache[key];\r
-      return entry && entry.value;\r
-    },\r
-\r
-    put: function(key, value) {\r
-      if (!cache[key]) {\r
-        cache[key] = { total: 1, value: value };\r
-      } else {\r
-        cache[key].total++;\r
-      }\r
-    }\r
-  };\r
-}\r
-\r
-var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {\r
-  var gcsLookup = createLocalCacheLookup();\r
-  var gcsStaggerLookup = createLocalCacheLookup();\r
-\r
-  this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',\r
-               '$document', '$sniffer', '$$rAFScheduler',\r
-       function($window,   $$jqLite,   $$AnimateRunner,   $timeout,\r
-                $document,   $sniffer,   $$rAFScheduler) {\r
-\r
-    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\r
-\r
-    var parentCounter = 0;\r
-    function gcsHashFn(node, extraClasses) {\r
-      var KEY = "$$ngAnimateParentKey";\r
-      var parentNode = node.parentNode;\r
-      var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);\r
-      return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;\r
-    }\r
-\r
-    function computeCachedCssStyles(node, className, cacheKey, properties) {\r
-      var timings = gcsLookup.get(cacheKey);\r
-\r
-      if (!timings) {\r
-        timings = computeCssStyles($window, node, properties);\r
-        if (timings.animationIterationCount === 'infinite') {\r
-          timings.animationIterationCount = 1;\r
-        }\r
-      }\r
-\r
-      // we keep putting this in multiple times even though the value and the cacheKey are the same\r
-      // because we're keeping an interal tally of how many duplicate animations are detected.\r
-      gcsLookup.put(cacheKey, timings);\r
-      return timings;\r
-    }\r
-\r
-    function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {\r
-      var stagger;\r
-\r
-      // if we have one or more existing matches of matching elements\r
-      // containing the same parent + CSS styles (which is how cacheKey works)\r
-      // then staggering is possible\r
-      if (gcsLookup.count(cacheKey) > 0) {\r
-        stagger = gcsStaggerLookup.get(cacheKey);\r
-\r
-        if (!stagger) {\r
-          var staggerClassName = pendClasses(className, '-stagger');\r
-\r
-          $$jqLite.addClass(node, staggerClassName);\r
-\r
-          stagger = computeCssStyles($window, node, properties);\r
-\r
-          // force the conversion of a null value to zero incase not set\r
-          stagger.animationDuration = Math.max(stagger.animationDuration, 0);\r
-          stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);\r
-\r
-          $$jqLite.removeClass(node, staggerClassName);\r
-\r
-          gcsStaggerLookup.put(cacheKey, stagger);\r
-        }\r
-      }\r
-\r
-      return stagger || {};\r
-    }\r
-\r
-    var bod = getDomNode($document).body;\r
-    var rafWaitQueue = [];\r
-    function waitUntilQuiet(callback) {\r
-      rafWaitQueue.push(callback);\r
-      $$rAFScheduler.waitUntilQuiet(function() {\r
-        gcsLookup.flush();\r
-        gcsStaggerLookup.flush();\r
-\r
-        //the line below will force the browser to perform a repaint so\r
-        //that all the animated elements within the animation frame will\r
-        //be properly updated and drawn on screen. This is required to\r
-        //ensure that the preparation animation is properly flushed so that\r
-        //the active state picks up from there. DO NOT REMOVE THIS LINE.\r
-        //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH\r
-        //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND\r
-        //WILL TAKE YEARS AWAY FROM YOUR LIFE.\r
-        var width = bod.offsetWidth + 1;\r
-\r
-        // we use a for loop to ensure that if the queue is changed\r
-        // during this looping then it will consider new requests\r
-        for (var i = 0; i < rafWaitQueue.length; i++) {\r
-          rafWaitQueue[i](width);\r
-        }\r
-        rafWaitQueue.length = 0;\r
-      });\r
-    }\r
-\r
-    return init;\r
-\r
-    function computeTimings(node, className, cacheKey) {\r
-      var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);\r
-      var aD = timings.animationDelay;\r
-      var tD = timings.transitionDelay;\r
-      timings.maxDelay = aD && tD\r
-          ? Math.max(aD, tD)\r
-          : (aD || tD);\r
-      timings.maxDuration = Math.max(\r
-          timings.animationDuration * timings.animationIterationCount,\r
-          timings.transitionDuration);\r
-\r
-      return timings;\r
-    }\r
-\r
-    function init(element, options) {\r
-      var node = getDomNode(element);\r
-      if (!node || !node.parentNode) {\r
-        return closeAndReturnNoopAnimator();\r
-      }\r
-\r
-      options = prepareAnimationOptions(options);\r
-\r
-      var temporaryStyles = [];\r
-      var classes = element.attr('class');\r
-      var styles = packageStyles(options);\r
-      var animationClosed;\r
-      var animationPaused;\r
-      var animationCompleted;\r
-      var runner;\r
-      var runnerHost;\r
-      var maxDelay;\r
-      var maxDelayTime;\r
-      var maxDuration;\r
-      var maxDurationTime;\r
-\r
-      if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {\r
-        return closeAndReturnNoopAnimator();\r
-      }\r
-\r
-      var method = options.event && isArray(options.event)\r
-            ? options.event.join(' ')\r
-            : options.event;\r
-\r
-      var isStructural = method && options.structural;\r
-      var structuralClassName = '';\r
-      var addRemoveClassName = '';\r
-\r
-      if (isStructural) {\r
-        structuralClassName = pendClasses(method, 'ng-', true);\r
-      } else if (method) {\r
-        structuralClassName = method;\r
-      }\r
-\r
-      if (options.addClass) {\r
-        addRemoveClassName += pendClasses(options.addClass, '-add');\r
-      }\r
-\r
-      if (options.removeClass) {\r
-        if (addRemoveClassName.length) {\r
-          addRemoveClassName += ' ';\r
-        }\r
-        addRemoveClassName += pendClasses(options.removeClass, '-remove');\r
-      }\r
-\r
-      // there may be a situation where a structural animation is combined together\r
-      // with CSS classes that need to resolve before the animation is computed.\r
-      // However this means that there is no explicit CSS code to block the animation\r
-      // from happening (by setting 0s none in the class name). If this is the case\r
-      // we need to apply the classes before the first rAF so we know to continue if\r
-      // there actually is a detected transition or keyframe animation\r
-      if (options.applyClassesEarly && addRemoveClassName.length) {\r
-        applyAnimationClasses(element, options);\r
-        addRemoveClassName = '';\r
-      }\r
-\r
-      var setupClasses = [structuralClassName, addRemoveClassName].join(' ').trim();\r
-      var fullClassName = classes + ' ' + setupClasses;\r
-      var activeClasses = pendClasses(setupClasses, '-active');\r
-      var hasToStyles = styles.to && Object.keys(styles.to).length > 0;\r
-      var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;\r
-\r
-      // there is no way we can trigger an animation if no styles and\r
-      // no classes are being applied which would then trigger a transition,\r
-      // unless there a is raw keyframe value that is applied to the element.\r
-      if (!containsKeyframeAnimation\r
-           && !hasToStyles\r
-           && !setupClasses) {\r
-        return closeAndReturnNoopAnimator();\r
-      }\r
-\r
-      var cacheKey, stagger;\r
-      if (options.stagger > 0) {\r
-        var staggerVal = parseFloat(options.stagger);\r
-        stagger = {\r
-          transitionDelay: staggerVal,\r
-          animationDelay: staggerVal,\r
-          transitionDuration: 0,\r
-          animationDuration: 0\r
-        };\r
-      } else {\r
-        cacheKey = gcsHashFn(node, fullClassName);\r
-        stagger = computeCachedCssStaggerStyles(node, setupClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);\r
-      }\r
-\r
-      $$jqLite.addClass(element, setupClasses);\r
-\r
-      var applyOnlyDuration;\r
-\r
-      if (options.transitionStyle) {\r
-        var transitionStyle = [TRANSITION_PROP, options.transitionStyle];\r
-        applyInlineStyle(node, transitionStyle);\r
-        temporaryStyles.push(transitionStyle);\r
-      }\r
-\r
-      if (options.duration >= 0) {\r
-        applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;\r
-        var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);\r
-\r
-        // we set the duration so that it will be picked up by getComputedStyle later\r
-        applyInlineStyle(node, durationStyle);\r
-        temporaryStyles.push(durationStyle);\r
-      }\r
-\r
-      if (options.keyframeStyle) {\r
-        var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];\r
-        applyInlineStyle(node, keyframeStyle);\r
-        temporaryStyles.push(keyframeStyle);\r
-      }\r
-\r
-      var itemIndex = stagger\r
-          ? options.staggerIndex >= 0\r
-              ? options.staggerIndex\r
-              : gcsLookup.count(cacheKey)\r
-          : 0;\r
-\r
-      var isFirst = itemIndex === 0;\r
-\r
-      // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY\r
-      // without causing any combination of transitions to kick in. By adding a negative delay value\r
-      // it forces the setup class' transition to end immediately. We later then remove the negative\r
-      // transition delay to allow for the transition to naturally do it's thing. The beauty here is\r
-      // that if there is no transition defined then nothing will happen and this will also allow\r
-      // other transitions to be stacked on top of each other without any chopping them out.\r
-      if (isFirst) {\r
-        blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);\r
-      }\r
-\r
-      var timings = computeTimings(node, fullClassName, cacheKey);\r
-      var relativeDelay = timings.maxDelay;\r
-      maxDelay = Math.max(relativeDelay, 0);\r
-      maxDuration = timings.maxDuration;\r
-\r
-      var flags = {};\r
-      flags.hasTransitions          = timings.transitionDuration > 0;\r
-      flags.hasAnimations           = timings.animationDuration > 0;\r
-      flags.hasTransitionAll        = flags.hasTransitions && timings.transitionProperty == 'all';\r
-      flags.applyTransitionDuration = hasToStyles && (\r
-                                        (flags.hasTransitions && !flags.hasTransitionAll)\r
-                                         || (flags.hasAnimations && !flags.hasTransitions));\r
-      flags.applyAnimationDuration  = options.duration && flags.hasAnimations;\r
-      flags.applyTransitionDelay    = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);\r
-      flags.applyAnimationDelay     = truthyTimingValue(options.delay) && flags.hasAnimations;\r
-      flags.recalculateTimingStyles = addRemoveClassName.length > 0;\r
-\r
-      if (flags.applyTransitionDuration || flags.applyAnimationDuration) {\r
-        maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;\r
-\r
-        if (flags.applyTransitionDuration) {\r
-          flags.hasTransitions = true;\r
-          timings.transitionDuration = maxDuration;\r
-          applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;\r
-          temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));\r
-        }\r
-\r
-        if (flags.applyAnimationDuration) {\r
-          flags.hasAnimations = true;\r
-          timings.animationDuration = maxDuration;\r
-          temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));\r
-        }\r
-      }\r
-\r
-      if (maxDuration === 0 && !flags.recalculateTimingStyles) {\r
-        return closeAndReturnNoopAnimator();\r
-      }\r
-\r
-      // we need to recalculate the delay value since we used a pre-emptive negative\r
-      // delay value and the delay value is required for the final event checking. This\r
-      // property will ensure that this will happen after the RAF phase has passed.\r
-      if (options.duration == null && timings.transitionDuration > 0) {\r
-        flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;\r
-      }\r
-\r
-      maxDelayTime = maxDelay * ONE_SECOND;\r
-      maxDurationTime = maxDuration * ONE_SECOND;\r
-      if (!options.skipBlocking) {\r
-        flags.blockTransition = timings.transitionDuration > 0;\r
-        flags.blockKeyframeAnimation = timings.animationDuration > 0 &&\r
-                                       stagger.animationDelay > 0 &&\r
-                                       stagger.animationDuration === 0;\r
-      }\r
-\r
-      applyAnimationFromStyles(element, options);\r
-      if (!flags.blockTransition) {\r
-        blockTransitions(node, false);\r
-      }\r
-\r
-      applyBlocking(maxDuration);\r
-\r
-      // TODO(matsko): for 1.5 change this code to have an animator object for better debugging\r
-      return {\r
-        $$willAnimate: true,\r
-        end: endFn,\r
-        start: function() {\r
-          if (animationClosed) return;\r
-\r
-          runnerHost = {\r
-            end: endFn,\r
-            cancel: cancelFn,\r
-            resume: null, //this will be set during the start() phase\r
-            pause: null\r
-          };\r
-\r
-          runner = new $$AnimateRunner(runnerHost);\r
-\r
-          waitUntilQuiet(start);\r
-\r
-          // we don't have access to pause/resume the animation\r
-          // since it hasn't run yet. AnimateRunner will therefore\r
-          // set noop functions for resume and pause and they will\r
-          // later be overridden once the animation is triggered\r
-          return runner;\r
-        }\r
-      };\r
-\r
-      function endFn() {\r
-        close();\r
-      }\r
-\r
-      function cancelFn() {\r
-        close(true);\r
-      }\r
-\r
-      function close(rejected) { // jshint ignore:line\r
-        // if the promise has been called already then we shouldn't close\r
-        // the animation again\r
-        if (animationClosed || (animationCompleted && animationPaused)) return;\r
-        animationClosed = true;\r
-        animationPaused = false;\r
-\r
-        $$jqLite.removeClass(element, setupClasses);\r
-        $$jqLite.removeClass(element, activeClasses);\r
-\r
-        blockKeyframeAnimations(node, false);\r
-        blockTransitions(node, false);\r
-\r
-        forEach(temporaryStyles, function(entry) {\r
-          // There is only one way to remove inline style properties entirely from elements.\r
-          // By using `removeProperty` this works, but we need to convert camel-cased CSS\r
-          // styles down to hyphenated values.\r
-          node.style[entry[0]] = '';\r
-        });\r
-\r
-        applyAnimationClasses(element, options);\r
-        applyAnimationStyles(element, options);\r
-\r
-        // the reason why we have this option is to allow a synchronous closing callback\r
-        // that is fired as SOON as the animation ends (when the CSS is removed) or if\r
-        // the animation never takes off at all. A good example is a leave animation since\r
-        // the element must be removed just after the animation is over or else the element\r
-        // will appear on screen for one animation frame causing an overbearing flicker.\r
-        if (options.onDone) {\r
-          options.onDone();\r
-        }\r
-\r
-        // if the preparation function fails then the promise is not setup\r
-        if (runner) {\r
-          runner.complete(!rejected);\r
-        }\r
-      }\r
-\r
-      function applyBlocking(duration) {\r
-        if (flags.blockTransition) {\r
-          blockTransitions(node, duration);\r
-        }\r
-\r
-        if (flags.blockKeyframeAnimation) {\r
-          blockKeyframeAnimations(node, !!duration);\r
-        }\r
-      }\r
-\r
-      function closeAndReturnNoopAnimator() {\r
-        runner = new $$AnimateRunner({\r
-          end: endFn,\r
-          cancel: cancelFn\r
-        });\r
-\r
-        close();\r
-\r
-        return {\r
-          $$willAnimate: false,\r
-          start: function() {\r
-            return runner;\r
-          },\r
-          end: endFn\r
-        };\r
-      }\r
-\r
-      function start() {\r
-        if (animationClosed) return;\r
-        if (!node.parentNode) {\r
-          close();\r
-          return;\r
-        }\r
-\r
-        var startTime, events = [];\r
-\r
-        // even though we only pause keyframe animations here the pause flag\r
-        // will still happen when transitions are used. Only the transition will\r
-        // not be paused since that is not possible. If the animation ends when\r
-        // paused then it will not complete until unpaused or cancelled.\r
-        var playPause = function(playAnimation) {\r
-          if (!animationCompleted) {\r
-            animationPaused = !playAnimation;\r
-            if (timings.animationDuration) {\r
-              var value = blockKeyframeAnimations(node, animationPaused);\r
-              animationPaused\r
-                  ? temporaryStyles.push(value)\r
-                  : removeFromArray(temporaryStyles, value);\r
-            }\r
-          } else if (animationPaused && playAnimation) {\r
-            animationPaused = false;\r
-            close();\r
-          }\r
-        };\r
-\r
-        // checking the stagger duration prevents an accidently cascade of the CSS delay style\r
-        // being inherited from the parent. If the transition duration is zero then we can safely\r
-        // rely that the delay value is an intential stagger delay style.\r
-        var maxStagger = itemIndex > 0\r
-                         && ((timings.transitionDuration && stagger.transitionDuration === 0) ||\r
-                            (timings.animationDuration && stagger.animationDuration === 0))\r
-                         && Math.max(stagger.animationDelay, stagger.transitionDelay);\r
-        if (maxStagger) {\r
-          $timeout(triggerAnimationStart,\r
-                   Math.floor(maxStagger * itemIndex * ONE_SECOND),\r
-                   false);\r
-        } else {\r
-          triggerAnimationStart();\r
-        }\r
-\r
-        // this will decorate the existing promise runner with pause/resume methods\r
-        runnerHost.resume = function() {\r
-          playPause(true);\r
-        };\r
-\r
-        runnerHost.pause = function() {\r
-          playPause(false);\r
-        };\r
-\r
-        function triggerAnimationStart() {\r
-          // just incase a stagger animation kicks in when the animation\r
-          // itself was cancelled entirely\r
-          if (animationClosed) return;\r
-\r
-          applyBlocking(false);\r
-\r
-          forEach(temporaryStyles, function(entry) {\r
-            var key = entry[0];\r
-            var value = entry[1];\r
-            node.style[key] = value;\r
-          });\r
-\r
-          applyAnimationClasses(element, options);\r
-          $$jqLite.addClass(element, activeClasses);\r
-\r
-          if (flags.recalculateTimingStyles) {\r
-            fullClassName = node.className + ' ' + setupClasses;\r
-            cacheKey = gcsHashFn(node, fullClassName);\r
-\r
-            timings = computeTimings(node, fullClassName, cacheKey);\r
-            relativeDelay = timings.maxDelay;\r
-            maxDelay = Math.max(relativeDelay, 0);\r
-            maxDuration = timings.maxDuration;\r
-\r
-            if (maxDuration === 0) {\r
-              close();\r
-              return;\r
-            }\r
-\r
-            flags.hasTransitions = timings.transitionDuration > 0;\r
-            flags.hasAnimations = timings.animationDuration > 0;\r
-          }\r
-\r
-          if (flags.applyTransitionDelay || flags.applyAnimationDelay) {\r
-            relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay)\r
-                  ? parseFloat(options.delay)\r
-                  : relativeDelay;\r
-\r
-            maxDelay = Math.max(relativeDelay, 0);\r
-\r
-            var delayStyle;\r
-            if (flags.applyTransitionDelay) {\r
-              timings.transitionDelay = relativeDelay;\r
-              delayStyle = getCssDelayStyle(relativeDelay);\r
-              temporaryStyles.push(delayStyle);\r
-              node.style[delayStyle[0]] = delayStyle[1];\r
-            }\r
-\r
-            if (flags.applyAnimationDelay) {\r
-              timings.animationDelay = relativeDelay;\r
-              delayStyle = getCssDelayStyle(relativeDelay, true);\r
-              temporaryStyles.push(delayStyle);\r
-              node.style[delayStyle[0]] = delayStyle[1];\r
-            }\r
-          }\r
-\r
-          maxDelayTime = maxDelay * ONE_SECOND;\r
-          maxDurationTime = maxDuration * ONE_SECOND;\r
-\r
-          if (options.easing) {\r
-            var easeProp, easeVal = options.easing;\r
-            if (flags.hasTransitions) {\r
-              easeProp = TRANSITION_PROP + TIMING_KEY;\r
-              temporaryStyles.push([easeProp, easeVal]);\r
-              node.style[easeProp] = easeVal;\r
-            }\r
-            if (flags.hasAnimations) {\r
-              easeProp = ANIMATION_PROP + TIMING_KEY;\r
-              temporaryStyles.push([easeProp, easeVal]);\r
-              node.style[easeProp] = easeVal;\r
-            }\r
-          }\r
-\r
-          if (timings.transitionDuration) {\r
-            events.push(TRANSITIONEND_EVENT);\r
-          }\r
-\r
-          if (timings.animationDuration) {\r
-            events.push(ANIMATIONEND_EVENT);\r
-          }\r
-\r
-          startTime = Date.now();\r
-          element.on(events.join(' '), onAnimationProgress);\r
-          $timeout(onAnimationExpired, maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime);\r
-\r
-          applyAnimationToStyles(element, options);\r
-        }\r
-\r
-        function onAnimationExpired() {\r
-          // although an expired animation is a failed animation, getting to\r
-          // this outcome is very easy if the CSS code screws up. Therefore we\r
-          // should still continue normally as if the animation completed correctly.\r
-          close();\r
-        }\r
-\r
-        function onAnimationProgress(event) {\r
-          event.stopPropagation();\r
-          var ev = event.originalEvent || event;\r
-          var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();\r
-\r
-          /* Firefox (or possibly just Gecko) likes to not round values up\r
-           * when a ms measurement is used for the animation */\r
-          var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));\r
-\r
-          /* $manualTimeStamp is a mocked timeStamp value which is set\r
-           * within browserTrigger(). This is only here so that tests can\r
-           * mock animations properly. Real events fallback to event.timeStamp,\r
-           * or, if they don't, then a timeStamp is automatically created for them.\r
-           * We're checking to see if the timeStamp surpasses the expected delay,\r
-           * but we're using elapsedTime instead of the timeStamp on the 2nd\r
-           * pre-condition since animations sometimes close off early */\r
-          if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {\r
-            // we set this flag to ensure that if the transition is paused then, when resumed,\r
-            // the animation will automatically close itself since transitions cannot be paused.\r
-            animationCompleted = true;\r
-            close();\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }];\r
-}];\r
-\r
-var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) {\r
-  $$animationProvider.drivers.push('$$animateCssDriver');\r
-\r
-  var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';\r
-  var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';\r
-\r
-  var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';\r
-  var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';\r
-\r
-  this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$document', '$sniffer',\r
-       function($animateCss,   $rootScope,   $$AnimateRunner,   $rootElement,   $document,   $sniffer) {\r
-\r
-    // only browsers that support these properties can render animations\r
-    if (!$sniffer.animations && !$sniffer.transitions) return noop;\r
-\r
-    var bodyNode = getDomNode($document).body;\r
-    var rootNode = getDomNode($rootElement);\r
-\r
-    var rootBodyElement = jqLite(bodyNode.parentNode === rootNode ? bodyNode : rootNode);\r
-\r
-    return function initDriverFn(animationDetails) {\r
-      return animationDetails.from && animationDetails.to\r
-          ? prepareFromToAnchorAnimation(animationDetails.from,\r
-                                         animationDetails.to,\r
-                                         animationDetails.classes,\r
-                                         animationDetails.anchors)\r
-          : prepareRegularAnimation(animationDetails);\r
-    };\r
-\r
-    function filterCssClasses(classes) {\r
-      //remove all the `ng-` stuff\r
-      return classes.replace(/\bng-\S+\b/g, '');\r
-    }\r
-\r
-    function getUniqueValues(a, b) {\r
-      if (isString(a)) a = a.split(' ');\r
-      if (isString(b)) b = b.split(' ');\r
-      return a.filter(function(val) {\r
-        return b.indexOf(val) === -1;\r
-      }).join(' ');\r
-    }\r
-\r
-    function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {\r
-      var clone = jqLite(getDomNode(outAnchor).cloneNode(true));\r
-      var startingClasses = filterCssClasses(getClassVal(clone));\r
-\r
-      outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\r
-      inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\r
-\r
-      clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);\r
-\r
-      rootBodyElement.append(clone);\r
-\r
-      var animatorIn, animatorOut = prepareOutAnimation();\r
-\r
-      // the user may not end up using the `out` animation and\r
-      // only making use of the `in` animation or vice-versa.\r
-      // In either case we should allow this and not assume the\r
-      // animation is over unless both animations are not used.\r
-      if (!animatorOut) {\r
-        animatorIn = prepareInAnimation();\r
-        if (!animatorIn) {\r
-          return end();\r
-        }\r
-      }\r
-\r
-      var startingAnimator = animatorOut || animatorIn;\r
-\r
-      return {\r
-        start: function() {\r
-          var runner;\r
-\r
-          var currentAnimation = startingAnimator.start();\r
-          currentAnimation.done(function() {\r
-            currentAnimation = null;\r
-            if (!animatorIn) {\r
-              animatorIn = prepareInAnimation();\r
-              if (animatorIn) {\r
-                currentAnimation = animatorIn.start();\r
-                currentAnimation.done(function() {\r
-                  currentAnimation = null;\r
-                  end();\r
-                  runner.complete();\r
-                });\r
-                return currentAnimation;\r
-              }\r
-            }\r
-            // in the event that there is no `in` animation\r
-            end();\r
-            runner.complete();\r
-          });\r
-\r
-          runner = new $$AnimateRunner({\r
-            end: endFn,\r
-            cancel: endFn\r
-          });\r
-\r
-          return runner;\r
-\r
-          function endFn() {\r
-            if (currentAnimation) {\r
-              currentAnimation.end();\r
-            }\r
-          }\r
-        }\r
-      };\r
-\r
-      function calculateAnchorStyles(anchor) {\r
-        var styles = {};\r
-\r
-        var coords = getDomNode(anchor).getBoundingClientRect();\r
-\r
-        // we iterate directly since safari messes up and doesn't return\r
-        // all the keys for the coods object when iterated\r
-        forEach(['width','height','top','left'], function(key) {\r
-          var value = coords[key];\r
-          switch (key) {\r
-            case 'top':\r
-              value += bodyNode.scrollTop;\r
-              break;\r
-            case 'left':\r
-              value += bodyNode.scrollLeft;\r
-              break;\r
-          }\r
-          styles[key] = Math.floor(value) + 'px';\r
-        });\r
-        return styles;\r
-      }\r
-\r
-      function prepareOutAnimation() {\r
-        var animator = $animateCss(clone, {\r
-          addClass: NG_OUT_ANCHOR_CLASS_NAME,\r
-          delay: true,\r
-          from: calculateAnchorStyles(outAnchor)\r
-        });\r
-\r
-        // read the comment within `prepareRegularAnimation` to understand\r
-        // why this check is necessary\r
-        return animator.$$willAnimate ? animator : null;\r
-      }\r
-\r
-      function getClassVal(element) {\r
-        return element.attr('class') || '';\r
-      }\r
-\r
-      function prepareInAnimation() {\r
-        var endingClasses = filterCssClasses(getClassVal(inAnchor));\r
-        var toAdd = getUniqueValues(endingClasses, startingClasses);\r
-        var toRemove = getUniqueValues(startingClasses, endingClasses);\r
-\r
-        var animator = $animateCss(clone, {\r
-          to: calculateAnchorStyles(inAnchor),\r
-          addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,\r
-          removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,\r
-          delay: true\r
-        });\r
-\r
-        // read the comment within `prepareRegularAnimation` to understand\r
-        // why this check is necessary\r
-        return animator.$$willAnimate ? animator : null;\r
-      }\r
-\r
-      function end() {\r
-        clone.remove();\r
-        outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\r
-        inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\r
-      }\r
-    }\r
-\r
-    function prepareFromToAnchorAnimation(from, to, classes, anchors) {\r
-      var fromAnimation = prepareRegularAnimation(from);\r
-      var toAnimation = prepareRegularAnimation(to);\r
-\r
-      var anchorAnimations = [];\r
-      forEach(anchors, function(anchor) {\r
-        var outElement = anchor['out'];\r
-        var inElement = anchor['in'];\r
-        var animator = prepareAnchoredAnimation(classes, outElement, inElement);\r
-        if (animator) {\r
-          anchorAnimations.push(animator);\r
-        }\r
-      });\r
-\r
-      // no point in doing anything when there are no elements to animate\r
-      if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;\r
-\r
-      return {\r
-        start: function() {\r
-          var animationRunners = [];\r
-\r
-          if (fromAnimation) {\r
-            animationRunners.push(fromAnimation.start());\r
-          }\r
-\r
-          if (toAnimation) {\r
-            animationRunners.push(toAnimation.start());\r
-          }\r
-\r
-          forEach(anchorAnimations, function(animation) {\r
-            animationRunners.push(animation.start());\r
-          });\r
-\r
-          var runner = new $$AnimateRunner({\r
-            end: endFn,\r
-            cancel: endFn // CSS-driven animations cannot be cancelled, only ended\r
-          });\r
-\r
-          $$AnimateRunner.all(animationRunners, function(status) {\r
-            runner.complete(status);\r
-          });\r
-\r
-          return runner;\r
-\r
-          function endFn() {\r
-            forEach(animationRunners, function(runner) {\r
-              runner.end();\r
-            });\r
-          }\r
-        }\r
-      };\r
-    }\r
-\r
-    function prepareRegularAnimation(animationDetails) {\r
-      var element = animationDetails.element;\r
-      var options = animationDetails.options || {};\r
-\r
-      if (animationDetails.structural) {\r
-        // structural animations ensure that the CSS classes are always applied\r
-        // before the detection starts.\r
-        options.structural = options.applyClassesEarly = true;\r
-\r
-        // we special case the leave animation since we want to ensure that\r
-        // the element is removed as soon as the animation is over. Otherwise\r
-        // a flicker might appear or the element may not be removed at all\r
-        options.event = animationDetails.event;\r
-        if (options.event === 'leave') {\r
-          options.onDone = options.domOperation;\r
-        }\r
-      } else {\r
-        options.event = null;\r
-      }\r
-\r
-      var animator = $animateCss(element, options);\r
-\r
-      // the driver lookup code inside of $$animation attempts to spawn a\r
-      // driver one by one until a driver returns a.$$willAnimate animator object.\r
-      // $animateCss will always return an object, however, it will pass in\r
-      // a flag as a hint as to whether an animation was detected or not\r
-      return animator.$$willAnimate ? animator : null;\r
-    }\r
-  }];\r
-}];\r
-\r
-// TODO(matsko): use caching here to speed things up for detection\r
-// TODO(matsko): add documentation\r
-//  by the time...\r
-\r
-var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {\r
-  this.$get = ['$injector', '$$AnimateRunner', '$$rAFMutex', '$$jqLite',\r
-       function($injector,   $$AnimateRunner,   $$rAFMutex,   $$jqLite) {\r
-\r
-    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\r
-         // $animateJs(element, 'enter');\r
-    return function(element, event, classes, options) {\r
-      // the `classes` argument is optional and if it is not used\r
-      // then the classes will be resolved from the element's className\r
-      // property as well as options.addClass/options.removeClass.\r
-      if (arguments.length === 3 && isObject(classes)) {\r
-        options = classes;\r
-        classes = null;\r
-      }\r
-\r
-      options = prepareAnimationOptions(options);\r
-      if (!classes) {\r
-        classes = element.attr('class') || '';\r
-        if (options.addClass) {\r
-          classes += ' ' + options.addClass;\r
-        }\r
-        if (options.removeClass) {\r
-          classes += ' ' + options.removeClass;\r
-        }\r
-      }\r
-\r
-      var classesToAdd = options.addClass;\r
-      var classesToRemove = options.removeClass;\r
-\r
-      // the lookupAnimations function returns a series of animation objects that are\r
-      // matched up with one or more of the CSS classes. These animation objects are\r
-      // defined via the module.animation factory function. If nothing is detected then\r
-      // we don't return anything which then makes $animation query the next driver.\r
-      var animations = lookupAnimations(classes);\r
-      var before, after;\r
-      if (animations.length) {\r
-        var afterFn, beforeFn;\r
-        if (event == 'leave') {\r
-          beforeFn = 'leave';\r
-          afterFn = 'afterLeave'; // TODO(matsko): get rid of this\r
-        } else {\r
-          beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);\r
-          afterFn = event;\r
-        }\r
-\r
-        if (event !== 'enter' && event !== 'move') {\r
-          before = packageAnimations(element, event, options, animations, beforeFn);\r
-        }\r
-        after  = packageAnimations(element, event, options, animations, afterFn);\r
-      }\r
-\r
-      // no matching animations\r
-      if (!before && !after) return;\r
-\r
-      function applyOptions() {\r
-        options.domOperation();\r
-        applyAnimationClasses(element, options);\r
-      }\r
-\r
-      return {\r
-        start: function() {\r
-          var closeActiveAnimations;\r
-          var chain = [];\r
-\r
-          if (before) {\r
-            chain.push(function(fn) {\r
-              closeActiveAnimations = before(fn);\r
-            });\r
-          }\r
-\r
-          if (chain.length) {\r
-            chain.push(function(fn) {\r
-              applyOptions();\r
-              fn(true);\r
-            });\r
-          } else {\r
-            applyOptions();\r
-          }\r
-\r
-          if (after) {\r
-            chain.push(function(fn) {\r
-              closeActiveAnimations = after(fn);\r
-            });\r
-          }\r
-\r
-          var animationClosed = false;\r
-          var runner = new $$AnimateRunner({\r
-            end: function() {\r
-              endAnimations();\r
-            },\r
-            cancel: function() {\r
-              endAnimations(true);\r
-            }\r
-          });\r
-\r
-          $$AnimateRunner.chain(chain, onComplete);\r
-          return runner;\r
-\r
-          function onComplete(success) {\r
-            animationClosed = true;\r
-            applyOptions();\r
-            applyAnimationStyles(element, options);\r
-            runner.complete(success);\r
-          }\r
-\r
-          function endAnimations(cancelled) {\r
-            if (!animationClosed) {\r
-              (closeActiveAnimations || noop)(cancelled);\r
-              onComplete(cancelled);\r
-            }\r
-          }\r
-        }\r
-      };\r
-\r
-      function executeAnimationFn(fn, element, event, options, onDone) {\r
-        var args;\r
-        switch (event) {\r
-          case 'animate':\r
-            args = [element, options.from, options.to, onDone];\r
-            break;\r
-\r
-          case 'setClass':\r
-            args = [element, classesToAdd, classesToRemove, onDone];\r
-            break;\r
-\r
-          case 'addClass':\r
-            args = [element, classesToAdd, onDone];\r
-            break;\r
-\r
-          case 'removeClass':\r
-            args = [element, classesToRemove, onDone];\r
-            break;\r
-\r
-          default:\r
-            args = [element, onDone];\r
-            break;\r
-        }\r
-\r
-        args.push(options);\r
-\r
-        var value = fn.apply(fn, args);\r
-        if (value) {\r
-          if (isFunction(value.start)) {\r
-            value = value.start();\r
-          }\r
-\r
-          if (value instanceof $$AnimateRunner) {\r
-            value.done(onDone);\r
-          } else if (isFunction(value)) {\r
-            // optional onEnd / onCancel callback\r
-            return value;\r
-          }\r
-        }\r
-\r
-        return noop;\r
-      }\r
-\r
-      function groupEventedAnimations(element, event, options, animations, fnName) {\r
-        var operations = [];\r
-        forEach(animations, function(ani) {\r
-          var animation = ani[fnName];\r
-          if (!animation) return;\r
-\r
-          // note that all of these animations will run in parallel\r
-          operations.push(function() {\r
-            var runner;\r
-            var endProgressCb;\r
-\r
-            var resolved = false;\r
-            var onAnimationComplete = function(rejected) {\r
-              if (!resolved) {\r
-                resolved = true;\r
-                (endProgressCb || noop)(rejected);\r
-                runner.complete(!rejected);\r
-              }\r
-            };\r
-\r
-            runner = new $$AnimateRunner({\r
-              end: function() {\r
-                onAnimationComplete();\r
-              },\r
-              cancel: function() {\r
-                onAnimationComplete(true);\r
-              }\r
-            });\r
-\r
-            endProgressCb = executeAnimationFn(animation, element, event, options, function(result) {\r
-              var cancelled = result === false;\r
-              onAnimationComplete(cancelled);\r
-            });\r
-\r
-            return runner;\r
-          });\r
-        });\r
-\r
-        return operations;\r
-      }\r
-\r
-      function packageAnimations(element, event, options, animations, fnName) {\r
-        var operations = groupEventedAnimations(element, event, options, animations, fnName);\r
-        if (operations.length === 0) {\r
-          var a,b;\r
-          if (fnName === 'beforeSetClass') {\r
-            a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');\r
-            b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');\r
-          } else if (fnName === 'setClass') {\r
-            a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');\r
-            b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');\r
-          }\r
-\r
-          if (a) {\r
-            operations = operations.concat(a);\r
-          }\r
-          if (b) {\r
-            operations = operations.concat(b);\r
-          }\r
-        }\r
-\r
-        if (operations.length === 0) return;\r
-\r
-        // TODO(matsko): add documentation\r
-        return function startAnimation(callback) {\r
-          var runners = [];\r
-          if (operations.length) {\r
-            forEach(operations, function(animateFn) {\r
-              runners.push(animateFn());\r
-            });\r
-          }\r
-\r
-          runners.length ? $$AnimateRunner.all(runners, callback) : callback();\r
-\r
-          return function endFn(reject) {\r
-            forEach(runners, function(runner) {\r
-              reject ? runner.cancel() : runner.end();\r
-            });\r
-          };\r
-        };\r
-      }\r
-    };\r
-\r
-    function lookupAnimations(classes) {\r
-      classes = isArray(classes) ? classes : classes.split(' ');\r
-      var matches = [], flagMap = {};\r
-      for (var i=0; i < classes.length; i++) {\r
-        var klass = classes[i],\r
-            animationFactory = $animateProvider.$$registeredAnimations[klass];\r
-        if (animationFactory && !flagMap[klass]) {\r
-          matches.push($injector.get(animationFactory));\r
-          flagMap[klass] = true;\r
-        }\r
-      }\r
-      return matches;\r
-    }\r
-  }];\r
-}];\r
-\r
-var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) {\r
-  $$animationProvider.drivers.push('$$animateJsDriver');\r
-  this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {\r
-    return function initDriverFn(animationDetails) {\r
-      if (animationDetails.from && animationDetails.to) {\r
-        var fromAnimation = prepareAnimation(animationDetails.from);\r
-        var toAnimation = prepareAnimation(animationDetails.to);\r
-        if (!fromAnimation && !toAnimation) return;\r
-\r
-        return {\r
-          start: function() {\r
-            var animationRunners = [];\r
-\r
-            if (fromAnimation) {\r
-              animationRunners.push(fromAnimation.start());\r
-            }\r
-\r
-            if (toAnimation) {\r
-              animationRunners.push(toAnimation.start());\r
-            }\r
-\r
-            $$AnimateRunner.all(animationRunners, done);\r
-\r
-            var runner = new $$AnimateRunner({\r
-              end: endFnFactory(),\r
-              cancel: endFnFactory()\r
-            });\r
-\r
-            return runner;\r
-\r
-            function endFnFactory() {\r
-              return function() {\r
-                forEach(animationRunners, function(runner) {\r
-                  // at this point we cannot cancel animations for groups just yet. 1.5+\r
-                  runner.end();\r
-                });\r
-              };\r
-            }\r
-\r
-            function done(status) {\r
-              runner.complete(status);\r
-            }\r
-          }\r
-        };\r
-      } else {\r
-        return prepareAnimation(animationDetails);\r
-      }\r
-    };\r
-\r
-    function prepareAnimation(animationDetails) {\r
-      // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations\r
-      var element = animationDetails.element;\r
-      var event = animationDetails.event;\r
-      var options = animationDetails.options;\r
-      var classes = animationDetails.classes;\r
-      return $$animateJs(element, event, classes, options);\r
-    }\r
-  }];\r
-}];\r
-\r
-var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';\r
-var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';\r
-var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {\r
-  var PRE_DIGEST_STATE = 1;\r
-  var RUNNING_STATE = 2;\r
-\r
-  var rules = this.rules = {\r
-    skip: [],\r
-    cancel: [],\r
-    join: []\r
-  };\r
-\r
-  function isAllowed(ruleType, element, currentAnimation, previousAnimation) {\r
-    return rules[ruleType].some(function(fn) {\r
-      return fn(element, currentAnimation, previousAnimation);\r
-    });\r
-  }\r
-\r
-  function hasAnimationClasses(options, and) {\r
-    options = options || {};\r
-    var a = (options.addClass || '').length > 0;\r
-    var b = (options.removeClass || '').length > 0;\r
-    return and ? a && b : a || b;\r
-  }\r
-\r
-  rules.join.push(function(element, newAnimation, currentAnimation) {\r
-    // if the new animation is class-based then we can just tack that on\r
-    return !newAnimation.structural && hasAnimationClasses(newAnimation.options);\r
-  });\r
-\r
-  rules.skip.push(function(element, newAnimation, currentAnimation) {\r
-    // there is no need to animate anything if no classes are being added and\r
-    // there is no structural animation that will be triggered\r
-    return !newAnimation.structural && !hasAnimationClasses(newAnimation.options);\r
-  });\r
-\r
-  rules.skip.push(function(element, newAnimation, currentAnimation) {\r
-    // why should we trigger a new structural animation if the element will\r
-    // be removed from the DOM anyway?\r
-    return currentAnimation.event == 'leave' && newAnimation.structural;\r
-  });\r
-\r
-  rules.skip.push(function(element, newAnimation, currentAnimation) {\r
-    // if there is a current animation then skip the class-based animation\r
-    return currentAnimation.structural && !newAnimation.structural;\r
-  });\r
-\r
-  rules.cancel.push(function(element, newAnimation, currentAnimation) {\r
-    // there can never be two structural animations running at the same time\r
-    return currentAnimation.structural && newAnimation.structural;\r
-  });\r
-\r
-  rules.cancel.push(function(element, newAnimation, currentAnimation) {\r
-    // if the previous animation is already running, but the new animation will\r
-    // be triggered, but the new animation is structural\r
-    return currentAnimation.state === RUNNING_STATE && newAnimation.structural;\r
-  });\r
-\r
-  rules.cancel.push(function(element, newAnimation, currentAnimation) {\r
-    var nO = newAnimation.options;\r
-    var cO = currentAnimation.options;\r
-\r
-    // if the exact same CSS class is added/removed then it's safe to cancel it\r
-    return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);\r
-  });\r
-\r
-  this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',\r
-               '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite',\r
-       function($$rAF,   $rootScope,   $rootElement,   $document,   $$HashMap,\r
-                $$animation,   $$AnimateRunner,   $templateRequest,   $$jqLite) {\r
-\r
-    var activeAnimationsLookup = new $$HashMap();\r
-    var disabledElementsLookup = new $$HashMap();\r
-\r
-    var animationsEnabled = null;\r
-\r
-    // Wait until all directive and route-related templates are downloaded and\r
-    // compiled. The $templateRequest.totalPendingRequests variable keeps track of\r
-    // all of the remote templates being currently downloaded. If there are no\r
-    // templates currently downloading then the watcher will still fire anyway.\r
-    var deregisterWatch = $rootScope.$watch(\r
-      function() { return $templateRequest.totalPendingRequests === 0; },\r
-      function(isEmpty) {\r
-        if (!isEmpty) return;\r
-        deregisterWatch();\r
-\r
-        // Now that all templates have been downloaded, $animate will wait until\r
-        // the post digest queue is empty before enabling animations. By having two\r
-        // calls to $postDigest calls we can ensure that the flag is enabled at the\r
-        // very end of the post digest queue. Since all of the animations in $animate\r
-        // use $postDigest, it's important that the code below executes at the end.\r
-        // This basically means that the page is fully downloaded and compiled before\r
-        // any animations are triggered.\r
-        $rootScope.$$postDigest(function() {\r
-          $rootScope.$$postDigest(function() {\r
-            // we check for null directly in the event that the application already called\r
-            // .enabled() with whatever arguments that it provided it with\r
-            if (animationsEnabled === null) {\r
-              animationsEnabled = true;\r
-            }\r
-          });\r
-        });\r
-      }\r
-    );\r
-\r
-    var bodyElement = jqLite($document[0].body);\r
-\r
-    var callbackRegistry = {};\r
-\r
-    // remember that the classNameFilter is set during the provider/config\r
-    // stage therefore we can optimize here and setup a helper function\r
-    var classNameFilter = $animateProvider.classNameFilter();\r
-    var isAnimatableClassName = !classNameFilter\r
-              ? function() { return true; }\r
-              : function(className) {\r
-                return classNameFilter.test(className);\r
-              };\r
-\r
-    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\r
-\r
-    function normalizeAnimationOptions(element, options) {\r
-      return mergeAnimationOptions(element, options, {});\r
-    }\r
-\r
-    function findCallbacks(element, event) {\r
-      var targetNode = getDomNode(element);\r
-\r
-      var matches = [];\r
-      var entries = callbackRegistry[event];\r
-      if (entries) {\r
-        forEach(entries, function(entry) {\r
-          if (entry.node.contains(targetNode)) {\r
-            matches.push(entry.callback);\r
-          }\r
-        });\r
-      }\r
-\r
-      return matches;\r
-    }\r
-\r
-    function triggerCallback(event, element, phase, data) {\r
-      $$rAF(function() {\r
-        forEach(findCallbacks(element, event), function(callback) {\r
-          callback(element, phase, data);\r
-        });\r
-      });\r
-    }\r
-\r
-    return {\r
-      on: function(event, container, callback) {\r
-        var node = extractElementNode(container);\r
-        callbackRegistry[event] = callbackRegistry[event] || [];\r
-        callbackRegistry[event].push({\r
-          node: node,\r
-          callback: callback\r
-        });\r
-      },\r
-\r
-      off: function(event, container, callback) {\r
-        var entries = callbackRegistry[event];\r
-        if (!entries) return;\r
-\r
-        callbackRegistry[event] = arguments.length === 1\r
-            ? null\r
-            : filterFromRegistry(entries, container, callback);\r
-\r
-        function filterFromRegistry(list, matchContainer, matchCallback) {\r
-          var containerNode = extractElementNode(matchContainer);\r
-          return list.filter(function(entry) {\r
-            var isMatch = entry.node === containerNode &&\r
-                            (!matchCallback || entry.callback === matchCallback);\r
-            return !isMatch;\r
-          });\r
-        }\r
-      },\r
-\r
-      pin: function(element, parentElement) {\r
-        assertArg(isElement(element), 'element', 'not an element');\r
-        assertArg(isElement(parentElement), 'parentElement', 'not an element');\r
-        element.data(NG_ANIMATE_PIN_DATA, parentElement);\r
-      },\r
-\r
-      push: function(element, event, options, domOperation) {\r
-        options = options || {};\r
-        options.domOperation = domOperation;\r
-        return queueAnimation(element, event, options);\r
-      },\r
-\r
-      // this method has four signatures:\r
-      //  () - global getter\r
-      //  (bool) - global setter\r
-      //  (element) - element getter\r
-      //  (element, bool) - element setter<F37>\r
-      enabled: function(element, bool) {\r
-        var argCount = arguments.length;\r
-\r
-        if (argCount === 0) {\r
-          // () - Global getter\r
-          bool = !!animationsEnabled;\r
-        } else {\r
-          var hasElement = isElement(element);\r
-\r
-          if (!hasElement) {\r
-            // (bool) - Global setter\r
-            bool = animationsEnabled = !!element;\r
-          } else {\r
-            var node = getDomNode(element);\r
-            var recordExists = disabledElementsLookup.get(node);\r
-\r
-            if (argCount === 1) {\r
-              // (element) - Element getter\r
-              bool = !recordExists;\r
-            } else {\r
-              // (element, bool) - Element setter\r
-              bool = !!bool;\r
-              if (!bool) {\r
-                disabledElementsLookup.put(node, true);\r
-              } else if (recordExists) {\r
-                disabledElementsLookup.remove(node);\r
-              }\r
-            }\r
-          }\r
-        }\r
-\r
-        return bool;\r
-      }\r
-    };\r
-\r
-    function queueAnimation(element, event, options) {\r
-      var node, parent;\r
-      element = stripCommentsFromElement(element);\r
-      if (element) {\r
-        node = getDomNode(element);\r
-        parent = element.parent();\r
-      }\r
-\r
-      options = prepareAnimationOptions(options);\r
-\r
-      // we create a fake runner with a working promise.\r
-      // These methods will become available after the digest has passed\r
-      var runner = new $$AnimateRunner();\r
-\r
-      // there are situations where a directive issues an animation for\r
-      // a jqLite wrapper that contains only comment nodes... If this\r
-      // happens then there is no way we can perform an animation\r
-      if (!node) {\r
-        close();\r
-        return runner;\r
-      }\r
-\r
-      if (isArray(options.addClass)) {\r
-        options.addClass = options.addClass.join(' ');\r
-      }\r
-\r
-      if (isArray(options.removeClass)) {\r
-        options.removeClass = options.removeClass.join(' ');\r
-      }\r
-\r
-      if (options.from && !isObject(options.from)) {\r
-        options.from = null;\r
-      }\r
-\r
-      if (options.to && !isObject(options.to)) {\r
-        options.to = null;\r
-      }\r
-\r
-      var className = [node.className, options.addClass, options.removeClass].join(' ');\r
-      if (!isAnimatableClassName(className)) {\r
-        close();\r
-        return runner;\r
-      }\r
-\r
-      var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;\r
-\r
-      // this is a hard disable of all animations for the application or on\r
-      // the element itself, therefore  there is no need to continue further\r
-      // past this point if not enabled\r
-      var skipAnimations = !animationsEnabled || disabledElementsLookup.get(node);\r
-      var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};\r
-      var hasExistingAnimation = !!existingAnimation.state;\r
-\r
-      // there is no point in traversing the same collection of parent ancestors if a followup\r
-      // animation will be run on the same element that already did all that checking work\r
-      if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) {\r
-        skipAnimations = !areAnimationsAllowed(element, parent, event);\r
-      }\r
-\r
-      if (skipAnimations) {\r
-        close();\r
-        return runner;\r
-      }\r
-\r
-      if (isStructural) {\r
-        closeChildAnimations(element);\r
-      }\r
-\r
-      var newAnimation = {\r
-        structural: isStructural,\r
-        element: element,\r
-        event: event,\r
-        close: close,\r
-        options: options,\r
-        runner: runner\r
-      };\r
-\r
-      if (hasExistingAnimation) {\r
-        var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation);\r
-        if (skipAnimationFlag) {\r
-          if (existingAnimation.state === RUNNING_STATE) {\r
-            close();\r
-            return runner;\r
-          } else {\r
-            mergeAnimationOptions(element, existingAnimation.options, options);\r
-            return existingAnimation.runner;\r
-          }\r
-        }\r
-\r
-        var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);\r
-        if (cancelAnimationFlag) {\r
-          if (existingAnimation.state === RUNNING_STATE) {\r
-            // this will end the animation right away and it is safe\r
-            // to do so since the animation is already running and the\r
-            // runner callback code will run in async\r
-            existingAnimation.runner.end();\r
-          } else if (existingAnimation.structural) {\r
-            // this means that the animation is queued into a digest, but\r
-            // hasn't started yet. Therefore it is safe to run the close\r
-            // method which will call the runner methods in async.\r
-            existingAnimation.close();\r
-          } else {\r
-            // this will merge the existing animation options into this new follow-up animation\r
-            mergeAnimationOptions(element, newAnimation.options, existingAnimation.options);\r
-          }\r
-        } else {\r
-          // a joined animation means that this animation will take over the existing one\r
-          // so an example would involve a leave animation taking over an enter. Then when\r
-          // the postDigest kicks in the enter will be ignored.\r
-          var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);\r
-          if (joinAnimationFlag) {\r
-            if (existingAnimation.state === RUNNING_STATE) {\r
-              normalizeAnimationOptions(element, options);\r
-            } else {\r
-              event = newAnimation.event = existingAnimation.event;\r
-              options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);\r
-              return runner;\r
-            }\r
-          }\r
-        }\r
-      } else {\r
-        // normalization in this case means that it removes redundant CSS classes that\r
-        // already exist (addClass) or do not exist (removeClass) on the element\r
-        normalizeAnimationOptions(element, options);\r
-      }\r
-\r
-      // when the options are merged and cleaned up we may end up not having to do\r
-      // an animation at all, therefore we should check this before issuing a post\r
-      // digest callback. Structural animations will always run no matter what.\r
-      var isValidAnimation = newAnimation.structural;\r
-      if (!isValidAnimation) {\r
-        // animate (from/to) can be quickly checked first, otherwise we check if any classes are present\r
-        isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)\r
-                            || hasAnimationClasses(newAnimation.options);\r
-      }\r
-\r
-      if (!isValidAnimation) {\r
-        close();\r
-        clearElementAnimationState(element);\r
-        return runner;\r
-      }\r
-\r
-      if (isStructural) {\r
-        closeParentClassBasedAnimations(parent);\r
-      }\r
-\r
-      // the counter keeps track of cancelled animations\r
-      var counter = (existingAnimation.counter || 0) + 1;\r
-      newAnimation.counter = counter;\r
-\r
-      markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation);\r
-\r
-      $rootScope.$$postDigest(function() {\r
-        var animationDetails = activeAnimationsLookup.get(node);\r
-        var animationCancelled = !animationDetails;\r
-        animationDetails = animationDetails || {};\r
-\r
-        // if addClass/removeClass is called before something like enter then the\r
-        // registered parent element may not be present. The code below will ensure\r
-        // that a final value for parent element is obtained\r
-        var parentElement = element.parent() || [];\r
-\r
-        // animate/structural/class-based animations all have requirements. Otherwise there\r
-        // is no point in performing an animation. The parent node must also be set.\r
-        var isValidAnimation = parentElement.length > 0\r
-                                && (animationDetails.event === 'animate'\r
-                                    || animationDetails.structural\r
-                                    || hasAnimationClasses(animationDetails.options));\r
-\r
-        // this means that the previous animation was cancelled\r
-        // even if the follow-up animation is the same event\r
-        if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {\r
-          // if another animation did not take over then we need\r
-          // to make sure that the domOperation and options are\r
-          // handled accordingly\r
-          if (animationCancelled) {\r
-            applyAnimationClasses(element, options);\r
-            applyAnimationStyles(element, options);\r
-          }\r
-\r
-          // if the event changed from something like enter to leave then we do\r
-          // it, otherwise if it's the same then the end result will be the same too\r
-          if (animationCancelled || (isStructural && animationDetails.event !== event)) {\r
-            options.domOperation();\r
-            runner.end();\r
-          }\r
-\r
-          // in the event that the element animation was not cancelled or a follow-up animation\r
-          // isn't allowed to animate from here then we need to clear the state of the element\r
-          // so that any future animations won't read the expired animation data.\r
-          if (!isValidAnimation) {\r
-            clearElementAnimationState(element);\r
-          }\r
-\r
-          return;\r
-        }\r
-\r
-        // this combined multiple class to addClass / removeClass into a setClass event\r
-        // so long as a structural event did not take over the animation\r
-        event = !animationDetails.structural && hasAnimationClasses(animationDetails.options, true)\r
-            ? 'setClass'\r
-            : animationDetails.event;\r
-\r
-        if (animationDetails.structural) {\r
-          closeParentClassBasedAnimations(parentElement);\r
-        }\r
-\r
-        markElementAnimationState(element, RUNNING_STATE);\r
-        var realRunner = $$animation(element, event, animationDetails.options);\r
-        realRunner.done(function(status) {\r
-          close(!status);\r
-          var animationDetails = activeAnimationsLookup.get(node);\r
-          if (animationDetails && animationDetails.counter === counter) {\r
-            clearElementAnimationState(getDomNode(element));\r
-          }\r
-          notifyProgress(runner, event, 'close', {});\r
-        });\r
-\r
-        // this will update the runner's flow-control events based on\r
-        // the `realRunner` object.\r
-        runner.setHost(realRunner);\r
-        notifyProgress(runner, event, 'start', {});\r
-      });\r
-\r
-      return runner;\r
-\r
-      function notifyProgress(runner, event, phase, data) {\r
-        triggerCallback(event, element, phase, data);\r
-        runner.progress(event, phase, data);\r
-      }\r
-\r
-      function close(reject) { // jshint ignore:line\r
-        applyAnimationClasses(element, options);\r
-        applyAnimationStyles(element, options);\r
-        options.domOperation();\r
-        runner.complete(!reject);\r
-      }\r
-    }\r
-\r
-    function closeChildAnimations(element) {\r
-      var node = getDomNode(element);\r
-      var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');\r
-      forEach(children, function(child) {\r
-        var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));\r
-        var animationDetails = activeAnimationsLookup.get(child);\r
-        switch (state) {\r
-          case RUNNING_STATE:\r
-            animationDetails.runner.end();\r
-            /* falls through */\r
-          case PRE_DIGEST_STATE:\r
-            if (animationDetails) {\r
-              activeAnimationsLookup.remove(child);\r
-            }\r
-            break;\r
-        }\r
-      });\r
-    }\r
-\r
-    function clearElementAnimationState(element) {\r
-      var node = getDomNode(element);\r
-      node.removeAttribute(NG_ANIMATE_ATTR_NAME);\r
-      activeAnimationsLookup.remove(node);\r
-    }\r
-\r
-    function isMatchingElement(nodeOrElmA, nodeOrElmB) {\r
-      return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);\r
-    }\r
-\r
-    function closeParentClassBasedAnimations(startingElement) {\r
-      var parentNode = getDomNode(startingElement);\r
-      do {\r
-        if (!parentNode || parentNode.nodeType !== ELEMENT_NODE) break;\r
-\r
-        var animationDetails = activeAnimationsLookup.get(parentNode);\r
-        if (animationDetails) {\r
-          examineParentAnimation(parentNode, animationDetails);\r
-        }\r
-\r
-        parentNode = parentNode.parentNode;\r
-      } while (true);\r
-\r
-      // since animations are detected from CSS classes, we need to flush all parent\r
-      // class-based animations so that the parent classes are all present for child\r
-      // animations to properly function (otherwise any CSS selectors may not work)\r
-      function examineParentAnimation(node, animationDetails) {\r
-        // enter/leave/move always have priority\r
-        if (animationDetails.structural || !hasAnimationClasses(animationDetails.options)) return;\r
-\r
-        if (animationDetails.state === RUNNING_STATE) {\r
-          animationDetails.runner.end();\r
-        }\r
-        clearElementAnimationState(node);\r
-      }\r
-    }\r
-\r
-    function areAnimationsAllowed(element, parentElement, event) {\r
-      var bodyElementDetected = false;\r
-      var rootElementDetected = false;\r
-      var parentAnimationDetected = false;\r
-      var animateChildren;\r
-\r
-      var parentHost = element.data(NG_ANIMATE_PIN_DATA);\r
-      if (parentHost) {\r
-        parentElement = parentHost;\r
-      }\r
-\r
-      while (parentElement && parentElement.length) {\r
-        if (!rootElementDetected) {\r
-          // angular doesn't want to attempt to animate elements outside of the application\r
-          // therefore we need to ensure that the rootElement is an ancestor of the current element\r
-          rootElementDetected = isMatchingElement(parentElement, $rootElement);\r
-        }\r
-\r
-        var parentNode = parentElement[0];\r
-        if (parentNode.nodeType !== ELEMENT_NODE) {\r
-          // no point in inspecting the #document element\r
-          break;\r
-        }\r
-\r
-        var details = activeAnimationsLookup.get(parentNode) || {};\r
-        // either an enter, leave or move animation will commence\r
-        // therefore we can't allow any animations to take place\r
-        // but if a parent animation is class-based then that's ok\r
-        if (!parentAnimationDetected) {\r
-          parentAnimationDetected = details.structural || disabledElementsLookup.get(parentNode);\r
-        }\r
-\r
-        if (isUndefined(animateChildren) || animateChildren === true) {\r
-          var value = parentElement.data(NG_ANIMATE_CHILDREN_DATA);\r
-          if (isDefined(value)) {\r
-            animateChildren = value;\r
-          }\r
-        }\r
-\r
-        // there is no need to continue traversing at this point\r
-        if (parentAnimationDetected && animateChildren === false) break;\r
-\r
-        if (!rootElementDetected) {\r
-          // angular doesn't want to attempt to animate elements outside of the application\r
-          // therefore we need to ensure that the rootElement is an ancestor of the current element\r
-          rootElementDetected = isMatchingElement(parentElement, $rootElement);\r
-          if (!rootElementDetected) {\r
-            parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);\r
-            if (parentHost) {\r
-              parentElement = parentHost;\r
-            }\r
-          }\r
-        }\r
-\r
-        if (!bodyElementDetected) {\r
-          // we also need to ensure that the element is or will be apart of the body element\r
-          // otherwise it is pointless to even issue an animation to be rendered\r
-          bodyElementDetected = isMatchingElement(parentElement, bodyElement);\r
-        }\r
-\r
-        parentElement = parentElement.parent();\r
-      }\r
-\r
-      var allowAnimation = !parentAnimationDetected || animateChildren;\r
-      return allowAnimation && rootElementDetected && bodyElementDetected;\r
-    }\r
-\r
-    function markElementAnimationState(element, state, details) {\r
-      details = details || {};\r
-      details.state = state;\r
-\r
-      var node = getDomNode(element);\r
-      node.setAttribute(NG_ANIMATE_ATTR_NAME, state);\r
-\r
-      var oldValue = activeAnimationsLookup.get(node);\r
-      var newValue = oldValue\r
-          ? extend(oldValue, details)\r
-          : details;\r
-      activeAnimationsLookup.put(node, newValue);\r
-    }\r
-  }];\r
-}];\r
-\r
-var $$rAFMutexFactory = ['$$rAF', function($$rAF) {\r
-  return function() {\r
-    var passed = false;\r
-    $$rAF(function() {\r
-      passed = true;\r
-    });\r
-    return function(fn) {\r
-      passed ? fn() : $$rAF(fn);\r
-    };\r
-  };\r
-}];\r
-\r
-var $$AnimateRunnerFactory = ['$q', '$$rAFMutex', function($q, $$rAFMutex) {\r
-  var INITIAL_STATE = 0;\r
-  var DONE_PENDING_STATE = 1;\r
-  var DONE_COMPLETE_STATE = 2;\r
-\r
-  AnimateRunner.chain = function(chain, callback) {\r
-    var index = 0;\r
-\r
-    next();\r
-    function next() {\r
-      if (index === chain.length) {\r
-        callback(true);\r
-        return;\r
-      }\r
-\r
-      chain[index](function(response) {\r
-        if (response === false) {\r
-          callback(false);\r
-          return;\r
-        }\r
-        index++;\r
-        next();\r
-      });\r
-    }\r
-  };\r
-\r
-  AnimateRunner.all = function(runners, callback) {\r
-    var count = 0;\r
-    var status = true;\r
-    forEach(runners, function(runner) {\r
-      runner.done(onProgress);\r
-    });\r
-\r
-    function onProgress(response) {\r
-      status = status && response;\r
-      if (++count === runners.length) {\r
-        callback(status);\r
-      }\r
-    }\r
-  };\r
-\r
-  function AnimateRunner(host) {\r
-    this.setHost(host);\r
-\r
-    this._doneCallbacks = [];\r
-    this._runInAnimationFrame = $$rAFMutex();\r
-    this._state = 0;\r
-  }\r
-\r
-  AnimateRunner.prototype = {\r
-    setHost: function(host) {\r
-      this.host = host || {};\r
-    },\r
-\r
-    done: function(fn) {\r
-      if (this._state === DONE_COMPLETE_STATE) {\r
-        fn();\r
-      } else {\r
-        this._doneCallbacks.push(fn);\r
-      }\r
-    },\r
-\r
-    progress: noop,\r
-\r
-    getPromise: function() {\r
-      if (!this.promise) {\r
-        var self = this;\r
-        this.promise = $q(function(resolve, reject) {\r
-          self.done(function(status) {\r
-            status === false ? reject() : resolve();\r
-          });\r
-        });\r
-      }\r
-      return this.promise;\r
-    },\r
-\r
-    then: function(resolveHandler, rejectHandler) {\r
-      return this.getPromise().then(resolveHandler, rejectHandler);\r
-    },\r
-\r
-    'catch': function(handler) {\r
-      return this.getPromise()['catch'](handler);\r
-    },\r
-\r
-    'finally': function(handler) {\r
-      return this.getPromise()['finally'](handler);\r
-    },\r
-\r
-    pause: function() {\r
-      if (this.host.pause) {\r
-        this.host.pause();\r
-      }\r
-    },\r
-\r
-    resume: function() {\r
-      if (this.host.resume) {\r
-        this.host.resume();\r
-      }\r
-    },\r
-\r
-    end: function() {\r
-      if (this.host.end) {\r
-        this.host.end();\r
-      }\r
-      this._resolve(true);\r
-    },\r
-\r
-    cancel: function() {\r
-      if (this.host.cancel) {\r
-        this.host.cancel();\r
-      }\r
-      this._resolve(false);\r
-    },\r
-\r
-    complete: function(response) {\r
-      var self = this;\r
-      if (self._state === INITIAL_STATE) {\r
-        self._state = DONE_PENDING_STATE;\r
-        self._runInAnimationFrame(function() {\r
-          self._resolve(response);\r
-        });\r
-      }\r
-    },\r
-\r
-    _resolve: function(response) {\r
-      if (this._state !== DONE_COMPLETE_STATE) {\r
-        forEach(this._doneCallbacks, function(fn) {\r
-          fn(response);\r
-        });\r
-        this._doneCallbacks.length = 0;\r
-        this._state = DONE_COMPLETE_STATE;\r
-      }\r
-    }\r
-  };\r
-\r
-  return AnimateRunner;\r
-}];\r
-\r
-var $$AnimationProvider = ['$animateProvider', function($animateProvider) {\r
-  var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';\r
-\r
-  var drivers = this.drivers = [];\r
-\r
-  var RUNNER_STORAGE_KEY = '$$animationRunner';\r
-\r
-  function setRunner(element, runner) {\r
-    element.data(RUNNER_STORAGE_KEY, runner);\r
-  }\r
-\r
-  function removeRunner(element) {\r
-    element.removeData(RUNNER_STORAGE_KEY);\r
-  }\r
-\r
-  function getRunner(element) {\r
-    return element.data(RUNNER_STORAGE_KEY);\r
-  }\r
-\r
-  this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$rAFScheduler',\r
-       function($$jqLite,   $rootScope,   $injector,   $$AnimateRunner,   $$rAFScheduler) {\r
-\r
-    var animationQueue = [];\r
-    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\r
-\r
-    var totalPendingClassBasedAnimations = 0;\r
-    var totalActiveClassBasedAnimations = 0;\r
-    var classBasedAnimationsQueue = [];\r
-\r
-    // TODO(matsko): document the signature in a better way\r
-    return function(element, event, options) {\r
-      options = prepareAnimationOptions(options);\r
-      var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;\r
-\r
-      // there is no animation at the current moment, however\r
-      // these runner methods will get later updated with the\r
-      // methods leading into the driver's end/cancel methods\r
-      // for now they just stop the animation from starting\r
-      var runner = new $$AnimateRunner({\r
-        end: function() { close(); },\r
-        cancel: function() { close(true); }\r
-      });\r
-\r
-      if (!drivers.length) {\r
-        close();\r
-        return runner;\r
-      }\r
-\r
-      setRunner(element, runner);\r
-\r
-      var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));\r
-      var tempClasses = options.tempClasses;\r
-      if (tempClasses) {\r
-        classes += ' ' + tempClasses;\r
-        options.tempClasses = null;\r
-      }\r
-\r
-      var classBasedIndex;\r
-      if (!isStructural) {\r
-        classBasedIndex = totalPendingClassBasedAnimations;\r
-        totalPendingClassBasedAnimations += 1;\r
-      }\r
-\r
-      animationQueue.push({\r
-        // this data is used by the postDigest code and passed into\r
-        // the driver step function\r
-        element: element,\r
-        classes: classes,\r
-        event: event,\r
-        classBasedIndex: classBasedIndex,\r
-        structural: isStructural,\r
-        options: options,\r
-        beforeStart: beforeStart,\r
-        close: close\r
-      });\r
-\r
-      element.on('$destroy', handleDestroyedElement);\r
-\r
-      // we only want there to be one function called within the post digest\r
-      // block. This way we can group animations for all the animations that\r
-      // were apart of the same postDigest flush call.\r
-      if (animationQueue.length > 1) return runner;\r
-\r
-      $rootScope.$$postDigest(function() {\r
-        totalActiveClassBasedAnimations = totalPendingClassBasedAnimations;\r
-        totalPendingClassBasedAnimations = 0;\r
-        classBasedAnimationsQueue.length = 0;\r
-\r
-        var animations = [];\r
-        forEach(animationQueue, function(entry) {\r
-          // the element was destroyed early on which removed the runner\r
-          // form its storage. This means we can't animate this element\r
-          // at all and it already has been closed due to destruction.\r
-          if (getRunner(entry.element)) {\r
-            animations.push(entry);\r
-          }\r
-        });\r
-\r
-        // now any future animations will be in another postDigest\r
-        animationQueue.length = 0;\r
-\r
-        forEach(groupAnimations(animations), function(animationEntry) {\r
-          if (animationEntry.structural) {\r
-            triggerAnimationStart();\r
-          } else {\r
-            classBasedAnimationsQueue.push({\r
-              node: getDomNode(animationEntry.element),\r
-              fn: triggerAnimationStart\r
-            });\r
-\r
-            if (animationEntry.classBasedIndex === totalActiveClassBasedAnimations - 1) {\r
-              // we need to sort each of the animations in order of parent to child\r
-              // relationships. This ensures that the child classes are applied at the\r
-              // right time.\r
-              classBasedAnimationsQueue = classBasedAnimationsQueue.sort(function(a,b) {\r
-                return b.node.contains(a.node);\r
-              }).map(function(entry) {\r
-                return entry.fn;\r
-              });\r
-\r
-              $$rAFScheduler(classBasedAnimationsQueue);\r
-            }\r
-          }\r
-\r
-          function triggerAnimationStart() {\r
-            // it's important that we apply the `ng-animate` CSS class and the\r
-            // temporary classes before we do any driver invoking since these\r
-            // CSS classes may be required for proper CSS detection.\r
-            animationEntry.beforeStart();\r
-\r
-            var startAnimationFn, closeFn = animationEntry.close;\r
-\r
-            // in the event that the element was removed before the digest runs or\r
-            // during the RAF sequencing then we should not trigger the animation.\r
-            var targetElement = animationEntry.anchors\r
-                ? (animationEntry.from.element || animationEntry.to.element)\r
-                : animationEntry.element;\r
-\r
-            if (getRunner(targetElement) && getDomNode(targetElement).parentNode) {\r
-              var operation = invokeFirstDriver(animationEntry);\r
-              if (operation) {\r
-                startAnimationFn = operation.start;\r
-              }\r
-            }\r
-\r
-            if (!startAnimationFn) {\r
-              closeFn();\r
-            } else {\r
-              var animationRunner = startAnimationFn();\r
-              animationRunner.done(function(status) {\r
-                closeFn(!status);\r
-              });\r
-              updateAnimationRunners(animationEntry, animationRunner);\r
-            }\r
-          }\r
-        });\r
-      });\r
-\r
-      return runner;\r
-\r
-      // TODO(matsko): change to reference nodes\r
-      function getAnchorNodes(node) {\r
-        var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';\r
-        var items = node.hasAttribute(NG_ANIMATE_REF_ATTR)\r
-              ? [node]\r
-              : node.querySelectorAll(SELECTOR);\r
-        var anchors = [];\r
-        forEach(items, function(node) {\r
-          var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);\r
-          if (attr && attr.length) {\r
-            anchors.push(node);\r
-          }\r
-        });\r
-        return anchors;\r
-      }\r
-\r
-      function groupAnimations(animations) {\r
-        var preparedAnimations = [];\r
-        var refLookup = {};\r
-        forEach(animations, function(animation, index) {\r
-          var element = animation.element;\r
-          var node = getDomNode(element);\r
-          var event = animation.event;\r
-          var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;\r
-          var anchorNodes = animation.structural ? getAnchorNodes(node) : [];\r
-\r
-          if (anchorNodes.length) {\r
-            var direction = enterOrMove ? 'to' : 'from';\r
-\r
-            forEach(anchorNodes, function(anchor) {\r
-              var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);\r
-              refLookup[key] = refLookup[key] || {};\r
-              refLookup[key][direction] = {\r
-                animationID: index,\r
-                element: jqLite(anchor)\r
-              };\r
-            });\r
-          } else {\r
-            preparedAnimations.push(animation);\r
-          }\r
-        });\r
-\r
-        var usedIndicesLookup = {};\r
-        var anchorGroups = {};\r
-        forEach(refLookup, function(operations, key) {\r
-          var from = operations.from;\r
-          var to = operations.to;\r
-\r
-          if (!from || !to) {\r
-            // only one of these is set therefore we can't have an\r
-            // anchor animation since all three pieces are required\r
-            var index = from ? from.animationID : to.animationID;\r
-            var indexKey = index.toString();\r
-            if (!usedIndicesLookup[indexKey]) {\r
-              usedIndicesLookup[indexKey] = true;\r
-              preparedAnimations.push(animations[index]);\r
-            }\r
-            return;\r
-          }\r
-\r
-          var fromAnimation = animations[from.animationID];\r
-          var toAnimation = animations[to.animationID];\r
-          var lookupKey = from.animationID.toString();\r
-          if (!anchorGroups[lookupKey]) {\r
-            var group = anchorGroups[lookupKey] = {\r
-              structural: true,\r
-              beforeStart: function() {\r
-                fromAnimation.beforeStart();\r
-                toAnimation.beforeStart();\r
-              },\r
-              close: function() {\r
-                fromAnimation.close();\r
-                toAnimation.close();\r
-              },\r
-              classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),\r
-              from: fromAnimation,\r
-              to: toAnimation,\r
-              anchors: [] // TODO(matsko): change to reference nodes\r
-            };\r
-\r
-            // the anchor animations require that the from and to elements both have at least\r
-            // one shared CSS class which effictively marries the two elements together to use\r
-            // the same animation driver and to properly sequence the anchor animation.\r
-            if (group.classes.length) {\r
-              preparedAnimations.push(group);\r
-            } else {\r
-              preparedAnimations.push(fromAnimation);\r
-              preparedAnimations.push(toAnimation);\r
-            }\r
-          }\r
-\r
-          anchorGroups[lookupKey].anchors.push({\r
-            'out': from.element, 'in': to.element\r
-          });\r
-        });\r
-\r
-        return preparedAnimations;\r
-      }\r
-\r
-      function cssClassesIntersection(a,b) {\r
-        a = a.split(' ');\r
-        b = b.split(' ');\r
-        var matches = [];\r
-\r
-        for (var i = 0; i < a.length; i++) {\r
-          var aa = a[i];\r
-          if (aa.substring(0,3) === 'ng-') continue;\r
-\r
-          for (var j = 0; j < b.length; j++) {\r
-            if (aa === b[j]) {\r
-              matches.push(aa);\r
-              break;\r
-            }\r
-          }\r
-        }\r
-\r
-        return matches.join(' ');\r
-      }\r
-\r
-      function invokeFirstDriver(animationDetails) {\r
-        // we loop in reverse order since the more general drivers (like CSS and JS)\r
-        // may attempt more elements, but custom drivers are more particular\r
-        for (var i = drivers.length - 1; i >= 0; i--) {\r
-          var driverName = drivers[i];\r
-          if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check\r
-\r
-          var factory = $injector.get(driverName);\r
-          var driver = factory(animationDetails);\r
-          if (driver) {\r
-            return driver;\r
-          }\r
-        }\r
-      }\r
-\r
-      function beforeStart() {\r
-        element.addClass(NG_ANIMATE_CLASSNAME);\r
-        if (tempClasses) {\r
-          $$jqLite.addClass(element, tempClasses);\r
-        }\r
-      }\r
-\r
-      function updateAnimationRunners(animation, newRunner) {\r
-        if (animation.from && animation.to) {\r
-          update(animation.from.element);\r
-          update(animation.to.element);\r
-        } else {\r
-          update(animation.element);\r
-        }\r
-\r
-        function update(element) {\r
-          getRunner(element).setHost(newRunner);\r
-        }\r
-      }\r
-\r
-      function handleDestroyedElement() {\r
-        var runner = getRunner(element);\r
-        if (runner && (event !== 'leave' || !options.$$domOperationFired)) {\r
-          runner.end();\r
-        }\r
-      }\r
-\r
-      function close(rejected) { // jshint ignore:line\r
-        element.off('$destroy', handleDestroyedElement);\r
-        removeRunner(element);\r
-\r
-        applyAnimationClasses(element, options);\r
-        applyAnimationStyles(element, options);\r
-        options.domOperation();\r
-\r
-        if (tempClasses) {\r
-          $$jqLite.removeClass(element, tempClasses);\r
-        }\r
-\r
-        element.removeClass(NG_ANIMATE_CLASSNAME);\r
-        runner.complete(!rejected);\r
-      }\r
-    };\r
-  }];\r
-}];\r
-\r
-/* global angularAnimateModule: true,\r
-\r
-   $$rAFMutexFactory,\r
-   $$rAFSchedulerFactory,\r
-   $$AnimateChildrenDirective,\r
-   $$AnimateRunnerFactory,\r
-   $$AnimateQueueProvider,\r
-   $$AnimationProvider,\r
-   $AnimateCssProvider,\r
-   $$AnimateCssDriverProvider,\r
-   $$AnimateJsProvider,\r
-   $$AnimateJsDriverProvider,\r
-*/\r
-\r
-/**\r
- * @ngdoc module\r
- * @name ngAnimate\r
- * @description\r
- *\r
- * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via\r
- * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` then the animation hooks are enabled for an Angular app.\r
- *\r
- * <div doc-module-components="ngAnimate"></div>\r
- *\r
- * # Usage\r
- * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based\r
- * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For\r
- * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within\r
- * the HTML element that the animation will be triggered on.\r
- *\r
- * ## Directive Support\r
- * The following directives are "animation aware":\r
- *\r
- * | Directive                                                                                                | Supported Animations                                                     |\r
- * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|\r
- * | {@link ng.directive:ngRepeat#animations ngRepeat}                                                        | enter, leave and move                                                    |\r
- * | {@link ngRoute.directive:ngView#animations ngView}                                                       | enter and leave                                                          |\r
- * | {@link ng.directive:ngInclude#animations ngInclude}                                                      | enter and leave                                                          |\r
- * | {@link ng.directive:ngSwitch#animations ngSwitch}                                                        | enter and leave                                                          |\r
- * | {@link ng.directive:ngIf#animations ngIf}                                                                | enter and leave                                                          |\r
- * | {@link ng.directive:ngClass#animations ngClass}                                                          | add and remove (the CSS class(es) present)                               |\r
- * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide}            | add and remove (the ng-hide class value)                                 |\r
- * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel}    | add and remove (dirty, pristine, valid, invalid & all other validations) |\r
- * | {@link module:ngMessages#animations ngMessages}                                                          | add and remove (ng-active & ng-inactive)                                 |\r
- * | {@link module:ngMessages#animations ngMessage}                                                           | enter and leave                                                          |\r
- *\r
- * (More information can be found by visiting each the documentation associated with each directive.)\r
- *\r
- * ## CSS-based Animations\r
- *\r
- * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML\r
- * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.\r
- *\r
- * The example below shows how an `enter` animation can be made possible on a element using `ng-if`:\r
- *\r
- * ```html\r
- * <div ng-if="bool" class="fade">\r
- *    Fade me in out\r
- * </div>\r
- * <button ng-click="bool=true">Fade In!</button>\r
- * <button ng-click="bool=false">Fade Out!</button>\r
- * ```\r
- *\r
- * Notice the CSS class **fade**? We can now create the CSS transition code that references this class:\r
- *\r
- * ```css\r
- * /&#42; The starting CSS styles for the enter animation &#42;/\r
- * .fade.ng-enter {\r
- *   transition:0.5s linear all;\r
- *   opacity:0;\r
- * }\r
- *\r
- * /&#42; The finishing CSS styles for the enter animation &#42;/\r
- * .fade.ng-enter.ng-enter-active {\r
- *   opacity:1;\r
- * }\r
- * ```\r
- *\r
- * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two\r
- * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition\r
- * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.\r
- *\r
- * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:\r
- *\r
- * ```css\r
- * /&#42; now the element will fade out before it is removed from the DOM &#42;/\r
- * .fade.ng-leave {\r
- *   transition:0.5s linear all;\r
- *   opacity:1;\r
- * }\r
- * .fade.ng-leave.ng-leave-active {\r
- *   opacity:0;\r
- * }\r
- * ```\r
- *\r
- * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:\r
- *\r
- * ```css\r
- * /&#42; there is no need to define anything inside of the destination\r
- * CSS class since the keyframe will take charge of the animation &#42;/\r
- * .fade.ng-leave {\r
- *   animation: my_fade_animation 0.5s linear;\r
- *   -webkit-animation: my_fade_animation 0.5s linear;\r
- * }\r
- *\r
- * @keyframes my_fade_animation {\r
- *   from { opacity:1; }\r
- *   to { opacity:0; }\r
- * }\r
- *\r
- * @-webkit-keyframes my_fade_animation {\r
- *   from { opacity:1; }\r
- *   to { opacity:0; }\r
- * }\r
- * ```\r
- *\r
- * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.\r
- *\r
- * ### CSS Class-based Animations\r
- *\r
- * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different\r
- * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added\r
- * and removed.\r
- *\r
- * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:\r
- *\r
- * ```html\r
- * <div ng-show="bool" class="fade">\r
- *   Show and hide me\r
- * </div>\r
- * <button ng-click="bool=true">Toggle</button>\r
- *\r
- * <style>\r
- * .fade.ng-hide {\r
- *   transition:0.5s linear all;\r
- *   opacity:0;\r
- * }\r
- * </style>\r
- * ```\r
- *\r
- * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since\r
- * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.\r
- *\r
- * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation\r
- * with CSS styles.\r
- *\r
- * ```html\r
- * <div ng-class="{on:onOff}" class="highlight">\r
- *   Highlight this box\r
- * </div>\r
- * <button ng-click="onOff=!onOff">Toggle</button>\r
- *\r
- * <style>\r
- * .highlight {\r
- *   transition:0.5s linear all;\r
- * }\r
- * .highlight.on-add {\r
- *   background:white;\r
- * }\r
- * .highlight.on {\r
- *   background:yellow;\r
- * }\r
- * .highlight.on-remove {\r
- *   background:black;\r
- * }\r
- * </style>\r
- * ```\r
- *\r
- * We can also make use of CSS keyframes by placing them within the CSS classes.\r
- *\r
- *\r
- * ### CSS Staggering Animations\r
- * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a\r
- * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be\r
- * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for\r
- * the animation. The style property expected within the stagger class can either be a **transition-delay** or an\r
- * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).\r
- *\r
- * ```css\r
- * .my-animation.ng-enter {\r
- *   /&#42; standard transition code &#42;/\r
- *   transition: 1s linear all;\r
- *   opacity:0;\r
- * }\r
- * .my-animation.ng-enter-stagger {\r
- *   /&#42; this will have a 100ms delay between each successive leave animation &#42;/\r
- *   transition-delay: 0.1s;\r
- *\r
- *   /&#42; in case the stagger doesn't work then the duration value\r
- *    must be set to 0 to avoid an accidental CSS inheritance &#42;/\r
- *   transition-duration: 0s;\r
- * }\r
- * .my-animation.ng-enter.ng-enter-active {\r
- *   /&#42; standard transition styles &#42;/\r
- *   opacity:1;\r
- * }\r
- * ```\r
- *\r
- * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations\r
- * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this\r
- * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation\r
- * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired.\r
- *\r
- * The following code will issue the **ng-leave-stagger** event on the element provided:\r
- *\r
- * ```js\r
- * var kids = parent.children();\r
- *\r
- * $animate.leave(kids[0]); //stagger index=0\r
- * $animate.leave(kids[1]); //stagger index=1\r
- * $animate.leave(kids[2]); //stagger index=2\r
- * $animate.leave(kids[3]); //stagger index=3\r
- * $animate.leave(kids[4]); //stagger index=4\r
- *\r
- * window.requestAnimationFrame(function() {\r
- *   //stagger has reset itself\r
- *   $animate.leave(kids[5]); //stagger index=0\r
- *   $animate.leave(kids[6]); //stagger index=1\r
- *\r
- *   $scope.$digest();\r
- * });\r
- * ```\r
- *\r
- * Stagger animations are currently only supported within CSS-defined animations.\r
- *\r
- * ### The `ng-animate` CSS class\r
- *\r
- * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.\r
- * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).\r
- *\r
- * Therefore, animations can be applied to an element using this temporary class directly via CSS.\r
- *\r
- * ```css\r
- * .zipper.ng-animate {\r
- *   transition:0.5s linear all;\r
- * }\r
- * .zipper.ng-enter {\r
- *   opacity:0;\r
- * }\r
- * .zipper.ng-enter.ng-enter-active {\r
- *   opacity:1;\r
- * }\r
- * .zipper.ng-leave {\r
- *   opacity:1;\r
- * }\r
- * .zipper.ng-leave.ng-leave-active {\r
- *   opacity:0;\r
- * }\r
- * ```\r
- *\r
- * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove\r
- * the CSS class once an animation has completed.)\r
- *\r
- *\r
- * ## JavaScript-based Animations\r
- *\r
- * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared\r
- * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the\r
- * `module.animation()` module function we can register the ainmation.\r
- *\r
- * Let's see an example of a enter/leave animation using `ngRepeat`:\r
- *\r
- * ```html\r
- * <div ng-repeat="item in items" class="slide">\r
- *   {{ item }}\r
- * </div>\r
- * ```\r
- *\r
- * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:\r
- *\r
- * ```js\r
- * myModule.animation('.slide', [function() {\r
- *   return {\r
- *     // make note that other events (like addClass/removeClass)\r
- *     // have different function input parameters\r
- *     enter: function(element, doneFn) {\r
- *       jQuery(element).fadeIn(1000, doneFn);\r
- *\r
- *       // remember to call doneFn so that angular\r
- *       // knows that the animation has concluded\r
- *     },\r
- *\r
- *     move: function(element, doneFn) {\r
- *       jQuery(element).fadeIn(1000, doneFn);\r
- *     },\r
- *\r
- *     leave: function(element, doneFn) {\r
- *       jQuery(element).fadeOut(1000, doneFn);\r
- *     }\r
- *   }\r
- * }]\r
- * ```\r
- *\r
- * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as\r
- * greensock.js and velocity.js.\r
- *\r
- * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define\r
- * our animations inside of the same registered animation, however, the function input arguments are a bit different:\r
- *\r
- * ```html\r
- * <div ng-class="color" class="colorful">\r
- *   this box is moody\r
- * </div>\r
- * <button ng-click="color='red'">Change to red</button>\r
- * <button ng-click="color='blue'">Change to blue</button>\r
- * <button ng-click="color='green'">Change to green</button>\r
- * ```\r
- *\r
- * ```js\r
- * myModule.animation('.colorful', [function() {\r
- *   return {\r
- *     addClass: function(element, className, doneFn) {\r
- *       // do some cool animation and call the doneFn\r
- *     },\r
- *     removeClass: function(element, className, doneFn) {\r
- *       // do some cool animation and call the doneFn\r
- *     },\r
- *     setClass: function(element, addedClass, removedClass, doneFn) {\r
- *       // do some cool animation and call the doneFn\r
- *     }\r
- *   }\r
- * }]\r
- * ```\r
- *\r
- * ## CSS + JS Animations Together\r
- *\r
- * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,\r
- * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking\r
- * charge of the animation**:\r
- *\r
- * ```html\r
- * <div ng-if="bool" class="slide">\r
- *   Slide in and out\r
- * </div>\r
- * ```\r
- *\r
- * ```js\r
- * myModule.animation('.slide', [function() {\r
- *   return {\r
- *     enter: function(element, doneFn) {\r
- *       jQuery(element).slideIn(1000, doneFn);\r
- *     }\r
- *   }\r
- * }]\r
- * ```\r
- *\r
- * ```css\r
- * .slide.ng-enter {\r
- *   transition:0.5s linear all;\r
- *   transform:translateY(-100px);\r
- * }\r
- * .slide.ng-enter.ng-enter-active {\r
- *   transform:translateY(0);\r
- * }\r
- * ```\r
- *\r
- * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the\r
- * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from\r
- * our own JS-based animation code:\r
- *\r
- * ```js\r
- * myModule.animation('.slide', ['$animateCss', function($animateCss) {\r
- *   return {\r
- *     enter: function(element, doneFn) {\r
-*        // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.\r
- *       var runner = $animateCss(element, {\r
- *         event: 'enter',\r
- *         structural: true\r
- *       }).start();\r
-*        runner.done(doneFn);\r
- *     }\r
- *   }\r
- * }]\r
- * ```\r
- *\r
- * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.\r
- *\r
- * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or\r
- * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that\r
- * data into `$animateCss` directly:\r
- *\r
- * ```js\r
- * myModule.animation('.slide', ['$animateCss', function($animateCss) {\r
- *   return {\r
- *     enter: function(element, doneFn) {\r
- *       var runner = $animateCss(element, {\r
- *         event: 'enter',\r
- *         addClass: 'maroon-setting',\r
- *         from: { height:0 },\r
- *         to: { height: 200 }\r
- *       }).start();\r
- *\r
- *       runner.done(doneFn);\r
- *     }\r
- *   }\r
- * }]\r
- * ```\r
- *\r
- * Now we can fill in the rest via our transition CSS code:\r
- *\r
- * ```css\r
- * /&#42; the transition tells ngAnimate to make the animation happen &#42;/\r
- * .slide.ng-enter { transition:0.5s linear all; }\r
- *\r
- * /&#42; this extra CSS class will be absorbed into the transition\r
- * since the $animateCss code is adding the class &#42;/\r
- * .maroon-setting { background:red; }\r
- * ```\r
- *\r
- * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.\r
- *\r
- * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.\r
- *\r
- * ## Animation Anchoring (via `ng-animate-ref`)\r
- *\r
- * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between\r
- * structural areas of an application (like views) by pairing up elements using an attribute\r
- * called `ng-animate-ref`.\r
- *\r
- * Let's say for example we have two views that are managed by `ng-view` and we want to show\r
- * that there is a relationship between two components situated in within these views. By using the\r
- * `ng-animate-ref` attribute we can identify that the two components are paired together and we\r
- * can then attach an animation, which is triggered when the view changes.\r
- *\r
- * Say for example we have the following template code:\r
- *\r
- * ```html\r
- * <!-- index.html -->\r
- * <div ng-view class="view-animation">\r
- * </div>\r
- *\r
- * <!-- home.html -->\r
- * <a href="#/banner-page">\r
- *   <img src="./banner.jpg" class="banner" ng-animate-ref="banner">\r
- * </a>\r
- *\r
- * <!-- banner-page.html -->\r
- * <img src="./banner.jpg" class="banner" ng-animate-ref="banner">\r
- * ```\r
- *\r
- * Now, when the view changes (once the link is clicked), ngAnimate will examine the\r
- * HTML contents to see if there is a match reference between any components in the view\r
- * that is leaving and the view that is entering. It will scan both the view which is being\r
- * removed (leave) and inserted (enter) to see if there are any paired DOM elements that\r
- * contain a matching ref value.\r
- *\r
- * The two images match since they share the same ref value. ngAnimate will now create a\r
- * transport element (which is a clone of the first image element) and it will then attempt\r
- * to animate to the position of the second image element in the next view. For the animation to\r
- * work a special CSS class called `ng-anchor` will be added to the transported element.\r
- *\r
- * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then\r
- * ngAnimate will handle the entire transition for us as well as the addition and removal of\r
- * any changes of CSS classes between the elements:\r
- *\r
- * ```css\r
- * .banner.ng-anchor {\r
- *   /&#42; this animation will last for 1 second since there are\r
- *          two phases to the animation (an `in` and an `out` phase) &#42;/\r
- *   transition:0.5s linear all;\r
- * }\r
- * ```\r
- *\r
- * We also **must** include animations for the views that are being entered and removed\r
- * (otherwise anchoring wouldn't be possible since the new view would be inserted right away).\r
- *\r
- * ```css\r
- * .view-animation.ng-enter, .view-animation.ng-leave {\r
- *   transition:0.5s linear all;\r
- *   position:fixed;\r
- *   left:0;\r
- *   top:0;\r
- *   width:100%;\r
- * }\r
- * .view-animation.ng-enter {\r
- *   transform:translateX(100%);\r
- * }\r
- * .view-animation.ng-leave,\r
- * .view-animation.ng-enter.ng-enter-active {\r
- *   transform:translateX(0%);\r
- * }\r
- * .view-animation.ng-leave.ng-leave-active {\r
- *   transform:translateX(-100%);\r
- * }\r
- * ```\r
- *\r
- * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:\r
- * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away\r
- * from its origin. Once that animation is over then the `in` stage occurs which animates the\r
- * element to its destination. The reason why there are two animations is to give enough time\r
- * for the enter animation on the new element to be ready.\r
- *\r
- * The example above sets up a transition for both the in and out phases, but we can also target the out or\r
- * in phases directly via `ng-anchor-out` and `ng-anchor-in`.\r
- *\r
- * ```css\r
- * .banner.ng-anchor-out {\r
- *   transition: 0.5s linear all;\r
- *\r
- *   /&#42; the scale will be applied during the out animation,\r
- *          but will be animated away when the in animation runs &#42;/\r
- *   transform: scale(1.2);\r
- * }\r
- *\r
- * .banner.ng-anchor-in {\r
- *   transition: 1s linear all;\r
- * }\r
- * ```\r
- *\r
- *\r
- *\r
- *\r
- * ### Anchoring Demo\r
- *\r
-  <example module="anchoringExample"\r
-           name="anchoringExample"\r
-           id="anchoringExample"\r
-           deps="angular-animate.js;angular-route.js"\r
-           animations="true">\r
-    <file name="index.html">\r
-      <a href="#/">Home</a>\r
-      <hr />\r
-      <div class="view-container">\r
-        <div ng-view class="view"></div>\r
-      </div>\r
-    </file>\r
-    <file name="script.js">\r
-      angular.module('anchoringExample', ['ngAnimate', 'ngRoute'])\r
-        .config(['$routeProvider', function($routeProvider) {\r
-          $routeProvider.when('/', {\r
-            templateUrl: 'home.html',\r
-            controller: 'HomeController as home'\r
-          });\r
-          $routeProvider.when('/profile/:id', {\r
-            templateUrl: 'profile.html',\r
-            controller: 'ProfileController as profile'\r
-          });\r
-        }])\r
-        .run(['$rootScope', function($rootScope) {\r
-          $rootScope.records = [\r
-            { id:1, title: "Miss Beulah Roob" },\r
-            { id:2, title: "Trent Morissette" },\r
-            { id:3, title: "Miss Ava Pouros" },\r
-            { id:4, title: "Rod Pouros" },\r
-            { id:5, title: "Abdul Rice" },\r
-            { id:6, title: "Laurie Rutherford Sr." },\r
-            { id:7, title: "Nakia McLaughlin" },\r
-            { id:8, title: "Jordon Blanda DVM" },\r
-            { id:9, title: "Rhoda Hand" },\r
-            { id:10, title: "Alexandrea Sauer" }\r
-          ];\r
-        }])\r
-        .controller('HomeController', [function() {\r
-          //empty\r
-        }])\r
-        .controller('ProfileController', ['$rootScope', '$routeParams', function($rootScope, $routeParams) {\r
-          var index = parseInt($routeParams.id, 10);\r
-          var record = $rootScope.records[index - 1];\r
-\r
-          this.title = record.title;\r
-          this.id = record.id;\r
-        }]);\r
-    </file>\r
-    <file name="home.html">\r
-      <h2>Welcome to the home page</h1>\r
-      <p>Please click on an element</p>\r
-      <a class="record"\r
-         ng-href="#/profile/{{ record.id }}"\r
-         ng-animate-ref="{{ record.id }}"\r
-         ng-repeat="record in records">\r
-        {{ record.title }}\r
-      </a>\r
-    </file>\r
-    <file name="profile.html">\r
-      <div class="profile record" ng-animate-ref="{{ profile.id }}">\r
-        {{ profile.title }}\r
-      </div>\r
-    </file>\r
-    <file name="animations.css">\r
-      .record {\r
-        display:block;\r
-        font-size:20px;\r
-      }\r
-      .profile {\r
-        background:black;\r
-        color:white;\r
-        font-size:100px;\r
-      }\r
-      .view-container {\r
-        position:relative;\r
-      }\r
-      .view-container > .view.ng-animate {\r
-        position:absolute;\r
-        top:0;\r
-        left:0;\r
-        width:100%;\r
-        min-height:500px;\r
-      }\r
-      .view.ng-enter, .view.ng-leave,\r
-      .record.ng-anchor {\r
-        transition:0.5s linear all;\r
-      }\r
-      .view.ng-enter {\r
-        transform:translateX(100%);\r
-      }\r
-      .view.ng-enter.ng-enter-active, .view.ng-leave {\r
-        transform:translateX(0%);\r
-      }\r
-      .view.ng-leave.ng-leave-active {\r
-        transform:translateX(-100%);\r
-      }\r
-      .record.ng-anchor-out {\r
-        background:red;\r
-      }\r
-    </file>\r
-  </example>\r
- *\r
- * ### How is the element transported?\r
- *\r
- * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting\r
- * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element\r
- * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The\r
- * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match\r
- * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied\r
- * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class\r
- * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element\r
- * will become visible since the shim class will be removed.\r
- *\r
- * ### How is the morphing handled?\r
- *\r
- * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out\r
- * what CSS classes differ between the starting element and the destination element. These different CSS classes\r
- * will be added/removed on the anchor element and a transition will be applied (the transition that is provided\r
- * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will\r
- * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that\r
- * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since\r
- * the cloned element is placed inside of root element which is likely close to the body element).\r
- *\r
- * Note that if the root element is on the `<html>` element then the cloned node will be placed inside of body.\r
- *\r
- *\r
- * ## Using $animate in your directive code\r
- *\r
- * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?\r
- * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's\r
- * imagine we have a greeting box that shows and hides itself when the data changes\r
- *\r
- * ```html\r
- * <greeting-box active="onOrOff">Hi there</greeting-box>\r
- * ```\r
- *\r
- * ```js\r
- * ngModule.directive('greetingBox', ['$animate', function($animate) {\r
- *   return function(scope, element, attrs) {\r
- *     attrs.$observe('active', function(value) {\r
- *       value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');\r
- *     });\r
- *   });\r
- * }]);\r
- * ```\r
- *\r
- * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element\r
- * in our HTML code then we can trigger a CSS or JS animation to happen.\r
- *\r
- * ```css\r
- * /&#42; normally we would create a CSS class to reference on the element &#42;/\r
- * greeting-box.on { transition:0.5s linear all; background:green; color:white; }\r
- * ```\r
- *\r
- * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's\r
- * possible be sure to visit the {@link ng.$animate $animate service API page}.\r
- *\r
- *\r
- * ### Preventing Collisions With Third Party Libraries\r
- *\r
- * Some third-party frameworks place animation duration defaults across many element or className\r
- * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which\r
- * is expecting actual animations on these elements and has to wait for their completion.\r
- *\r
- * You can prevent this unwanted behavior by using a prefix on all your animation classes:\r
- *\r
- * ```css\r
- * /&#42; prefixed with animate- &#42;/\r
- * .animate-fade-add.animate-fade-add-active {\r
- *   transition:1s linear all;\r
- *   opacity:0;\r
- * }\r
- * ```\r
- *\r
- * You then configure `$animate` to enforce this prefix:\r
- *\r
- * ```js\r
- * $animateProvider.classNameFilter(/animate-/);\r
- * ```\r
- *\r
- * This also may provide your application with a speed boost since only specific elements containing CSS class prefix\r
- * will be evaluated for animation when any DOM changes occur in the application.\r
- *\r
- * ## Callbacks and Promises\r
- *\r
- * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger\r
- * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has\r
- * ended by chaining onto the returned promise that animation method returns.\r
- *\r
- * ```js\r
- * // somewhere within the depths of the directive\r
- * $animate.enter(element, parent).then(function() {\r
- *   //the animation has completed\r
- * });\r
- * ```\r
- *\r
- * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case\r
- * anymore.)\r
- *\r
- * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering\r
- * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view\r
- * routing controller to hook into that:\r
- *\r
- * ```js\r
- * ngModule.controller('HomePageController', ['$animate', function($animate) {\r
- *   $animate.on('enter', ngViewElement, function(element) {\r
- *     // the animation for this route has completed\r
- *   }]);\r
- * }])\r
- * ```\r
- *\r
- * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)\r
- */\r
-\r
-/**\r
- * @ngdoc service\r
- * @name $animate\r
- * @kind object\r
- *\r
- * @description\r
- * The ngAnimate `$animate` service documentation is the same for the core `$animate` service.\r
- *\r
- * Click here {@link ng.$animate $animate to learn more about animations with `$animate`}.\r
- */\r
-angular.module('ngAnimate', [])\r
-  .directive('ngAnimateChildren', $$AnimateChildrenDirective)\r
-\r
-  .factory('$$rAFMutex', $$rAFMutexFactory)\r
-  .factory('$$rAFScheduler', $$rAFSchedulerFactory)\r
-\r
-  .factory('$$AnimateRunner', $$AnimateRunnerFactory)\r
-\r
-  .provider('$$animateQueue', $$AnimateQueueProvider)\r
-  .provider('$$animation', $$AnimationProvider)\r
-\r
-  .provider('$animateCss', $AnimateCssProvider)\r
-  .provider('$$animateCssDriver', $$AnimateCssDriverProvider)\r
-\r
-  .provider('$$animateJs', $$AnimateJsProvider)\r
-  .provider('$$animateJsDriver', $$AnimateJsDriverProvider);\r
-\r
-\r
-})(window, window.angular);\r
diff --git a/epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-touch.js b/epsdk-app-onap/src/main/webapp/app/fusion/external/ebz/angular_js/angular-touch.js
deleted file mode 100755 (executable)
index 8934ff6..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/**\r
- * @license AngularJS v1.4.3\r
- * (c) 2010-2015 Google, Inc. http://angularjs.org\r
- * License: MIT\r
- */\r
-(function(window, angular, undefined) {'use strict';\r
-\r
-/**\r
- * @ngdoc module\r
- * @name ngTouch\r
- * @description\r
- *\r
- * # ngTouch\r
- *\r
- * The `ngTouch` module provides touch events and other helpers for touch-enabled devices.\r
- * The implementation is based on jQuery Mobile touch event handling\r
- * ([jquerymobile.com](http://jquerymobile.com/)).\r
- *\r
- *\r
- * See {@link ngTouch.$swipe `$swipe`} for usage.\r
- *\r
- * <div doc-module-components="ngTouch"></div>\r
- *\r
- */\r
-\r
-// define ngTouch module\r
-/* global -ngTouch */\r
-var ngTouch = angular.module('ngTouch', []);\r
-\r
-function nodeName_(element) {\r
-  return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));\r
-}\r
-\r
-/* global ngTouch: false */\r
-\r
-    /**\r
-     * @ngdoc service\r
-     * @name $swipe\r
-     *\r
-     * @description\r
-     * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe\r
-     * behavior, to make implementing swipe-related directives more convenient.\r
-     *\r
-     * Requires the {@link ngTouch `ngTouch`} module to be installed.\r
-     *\r
-     * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`, and by\r
-     * `ngCarousel` in a separate component.\r
-     *\r
-     * # Usage\r
-     * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element\r
-     * which is to be watched for swipes, and an object with four handler functions. See the\r
-     * documentation for `bind` below.\r
-     */\r
-\r
-ngTouch.factory('$swipe', [function() {\r
-  // The total distance in any direction before we make the call on swipe vs. scroll.\r
-  var MOVE_BUFFER_RADIUS = 10;\r
-\r
-  var POINTER_EVENTS = {\r
-    'mouse': {\r
-      start: 'mousedown',\r
-      move: 'mousemove',\r
-      end: 'mouseup'\r
-    },\r
-    'touch': {\r
-      start: 'touchstart',\r
-      move: 'touchmove',\r
-      end: 'touchend',\r
-      cancel: 'touchcancel'\r
-    }\r
-  };\r
-\r
-  function getCoordinates(event) {\r
-    var originalEvent = event.originalEvent || event;\r
-    var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];\r
-    var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0];\r
-\r
-    return {\r
-      x: e.clientX,\r
-      y: e.clientY\r
-    };\r
-  }\r
-\r
-  function getEvents(pointerTypes, eventType) {\r
-    var res = [];\r
-    angular.forEach(pointerTypes, function(pointerType) {\r
-      var eventName = POINTER_EVENTS[pointerType][eventType];\r
-      if (eventName) {\r
-        res.push(eventName);\r
-      }\r
-    });\r
-    return res.join(' ');\r
-  }\r
-\r
-  return {\r
-    /**\r
-     * @ngdoc method\r
-     * @name $swipe#bind\r
-     *\r
-     * @description\r
-     * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an\r
-     * object containing event handlers.\r
-     * The pointer types that should be used can be specified via the optional\r
-     * third argument, which is an array of strings `'mouse'` and `'touch'`. By default,\r
-     * `$swipe` will listen for `mouse` and `touch` events.\r
-     *\r
-     * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`\r
-     * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw\r
-     * `event`. `cancel` receives the raw `event` as its single parameter.\r
-     *\r
-     * `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is\r
-     * watching for `touchmove` or `mousemove` events. These events are ignored until the total\r
-     * distance moved in either dimension exceeds a small threshold.\r
-     *\r
-     * Once this threshold is exceeded, either the horizontal or vertical delta is greater.\r
-     * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow.\r
-     * - If the vertical distance is greater, this is a scroll, and we let the browser take over.\r
-     *   A `cancel` event is sent.\r
-     *\r
-     * `move` is called on `mousemove` and `touchmove` after the above logic has determined that\r
-     * a swipe is in progress.\r
-     *\r
-     * `end` is called when a swipe is successfully completed with a `touchend` or `mouseup`.\r
-     *\r
-     * `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling\r
-     * as described above.\r
-     *\r
-     */\r
-    bind: function(element, eventHandlers, pointerTypes) {\r
-      // Absolute total movement, used to control swipe vs. scroll.\r
-      var totalX, totalY;\r
-      // Coordinates of the start position.\r
-      var startCoords;\r
-      // Last event's position.\r
-      var lastPos;\r
-      // Whether a swipe is active.\r
-      var active = false;\r
-\r
-      pointerTypes = pointerTypes || ['mouse', 'touch'];\r
-      element.on(getEvents(pointerTypes, 'start'), function(event) {\r
-        startCoords = getCoordinates(event);\r
-        active = true;\r
-        totalX = 0;\r
-        totalY = 0;\r
-        lastPos = startCoords;\r
-        eventHandlers['start'] && eventHandlers['start'](startCoords, event);\r
-      });\r
-      var events = getEvents(pointerTypes, 'cancel');\r
-      if (events) {\r
-        element.on(events, function(event) {\r
-          active = false;\r
-          eventHandlers['cancel'] && eventHandlers['cancel'](event);\r
-        });\r
-      }\r
-\r
-      element.on(getEvents(pointerTypes, 'move'), function(event) {\r
-        if (!active) return;\r
-\r
-        // Android will send a touchcancel if it thinks we're starting to scroll.\r
-        // So when the total distance (+ or - or both) exceeds 10px in either direction,\r
-        // we either:\r
-        // - On totalX > totalY, we send preventDefault() and treat this as a swipe.\r
-        // - On totalY > totalX, we let the browser handle it as a scroll.\r
-\r
-        if (!startCoords) return;\r
-        var coords = getCoordinates(event);\r
-\r
-        totalX += Math.abs(coords.x - lastPos.x);\r
-        totalY += Math.abs(coords.y - lastPos.y);\r
-\r
-        lastPos = coords;\r
-\r
-        if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) {\r
-          return;\r
-        }\r
-\r
-        // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll.\r
-        if (totalY > totalX) {\r
-          // Allow native scrolling to take over.\r
-          active = false;\r
-          eventHandlers['cancel'] && eventHandlers['cancel'](event);\r
-          return;\r
-        } else {\r
-          // Prevent the browser from scrolling.\r
-          event.preventDefault();\r
-          eventHandlers['move'] && eventHandlers['move'](coords, event);\r
-        }\r
-      });\r
-\r
-      element.on(getEvents(pointerTypes, 'end'), function(event) {\r
-        if (!active) return;\r
-        active = false;\r
-        eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event);\r
-      });\r
-    }\r
-  };\r
-}]);\r
-\r
-/* global ngTouch: false,\r
-  nodeName_: false\r
-*/\r
-\r
-/**\r
- * @ngdoc directive\r
- * @name ngClick\r
- *\r
- * @description\r
- * A more powerful replacement for the default ngClick designed to be used on touchscreen\r
- * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending\r
- * the click event. This version handles them immediately, and then prevents the\r
- * following click event from propagating.\r
- *\r
- * Requires the {@link ngTouch `ngTouch`} module to be installed.\r
- *\r
- * This directive can fall back to using an ordinary click event, and so works on desktop\r
- * browsers as well as mobile.\r
- *\r
- * This directive also sets the CSS class `ng-click-active` while the element is being held\r
- * down (by a mouse click or touch) so you can restyle the depressed element if you wish.\r
- *\r
- * @element ANY\r
- * @param {expression} ngClick {@link guide/expression Expression} to evaluate\r
- * upon tap. (Event object is available as `$event`)\r
- *\r
- * @example\r
-    <example module="ngClickExample" deps="angular-touch.js">\r
-      <file name="index.html">\r
-        <button ng-click="count = count + 1" ng-init="count=0">\r
-          Increment\r
-        </button>\r
-        count: {{ count }}\r
-      </file>\r
-      <file name="script.js">\r
-        angular.module('ngClickExample', ['ngTouch']);\r
-      </file>\r
-    </example>\r
- */\r
-\r
-ngTouch.config(['$provide', function($provide) {\r
-  $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {\r
-    // drop the default ngClick directive\r
-    $delegate.shift();\r
-    return $delegate;\r
-  }]);\r
-}]);\r
-\r
-ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',\r
-    function($parse, $timeout, $rootElement) {\r
-  var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.\r
-  var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.\r
-  var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click\r
-  var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks.\r
-\r
-  var ACTIVE_CLASS_NAME = 'ng-click-active';\r
-  var lastPreventedTime;\r
-  var touchCoordinates;\r
-  var lastLabelClickCoordinates;\r
-\r
-\r
-  // TAP EVENTS AND GHOST CLICKS\r
-  //\r
-  // Why tap events?\r
-  // Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're\r
-  // double-tapping, and then fire a click event.\r
-  //\r
-  // This delay sucks and makes mobile apps feel unresponsive.\r
-  // So we detect touchstart, touchcancel and touchend ourselves and determine when\r
-  // the user has tapped on something.\r
-  //\r
-  // What happens when the browser then generates a click event?\r
-  // The browser, of course, also detects the tap and fires a click after a delay. This results in\r
-  // tapping/clicking twice. We do "clickbusting" to prevent it.\r
-  //\r
-  // How does it work?\r
-  // We attach global touchstart and click handlers, that run during the capture (early) phase.\r
-  // So the sequence for a tap is:\r
-  // - global touchstart: Sets an "allowable region" at the point touched.\r
-  // - element's touchstart: Starts a touch\r
-  // (- touchcancel ends the touch, no click follows)\r
-  // - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold\r
-  //   too long) and fires the user's tap handler. The touchend also calls preventGhostClick().\r
-  // - preventGhostClick() removes the allowable region the global touchstart created.\r
-  // - The browser generates a click event.\r
-  // - The global click handler catches the click, and checks whether it was in an allowable region.\r
-  //     - If preventGhostClick was called, the region will have been removed, the click is busted.\r
-  //     - If the region is still there, the click proceeds normally. Therefore clicks on links and\r
-  //       other elements without ngTap on them work normally.\r
-  //\r
-  // This is an ugly, terrible hack!\r
-  // Yeah, tell me about it. The alternatives are using the slow click events, or making our users\r
-  // deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular\r
-  // encapsulates this ugly logic away from the user.\r
-  //\r
-  // Why not just put click handlers on the element?\r
-  // We do that too, just to be sure. If the tap event caused the DOM to change,\r
-  // it is possible another element is now in that position. To take account for these possibly\r
-  // distinct elements, the handlers are global and care only about coordinates.\r
-\r
-  // Checks if the coordinates are close enough to be within the region.\r
-  function hit(x1, y1, x2, y2) {\r
-    return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD;\r
-  }\r
-\r
-  // Checks a list of allowable regions against a click location.\r
-  // Returns true if the click should be allowed.\r
-  // Splices out the allowable region from the list after it has been used.\r
-  function checkAllowableRegions(touchCoordinates, x, y) {\r
-    for (var i = 0; i < touchCoordinates.length; i += 2) {\r
-      if (hit(touchCoordinates[i], touchCoordinates[i + 1], x, y)) {\r
-        touchCoordinates.splice(i, i + 2);\r
-        return true; // allowable region\r
-      }\r
-    }\r
-    return false; // No allowable region; bust it.\r
-  }\r
-\r
-  // Global click handler that prevents the click if it's in a bustable zone and preventGhostClick\r
-  // was called recently.\r
-  function onClick(event) {\r
-    if (Date.now() - lastPreventedTime > PREVENT_DURATION) {\r
-      return; // Too old.\r
-    }\r
-\r
-    var touches = event.touches && event.touches.length ? event.touches : [event];\r
-    var x = touches[0].clientX;\r
-    var y = touches[0].clientY;\r
-    // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label\r
-    // and on the input element). Depending on the exact browser, this second click we don't want\r
-    // to bust has either (0,0), negative coordinates, or coordinates equal to triggering label\r
-    // click event\r
-    if (x < 1 && y < 1) {\r
-      return; // offscreen\r
-    }\r
-    if (lastLabelClickCoordinates &&\r
-        lastLabelClickCoordinates[0] === x && lastLabelClickCoordinates[1] === y) {\r
-      return; // input click triggered by label click\r
-    }\r
-    // reset label click coordinates on first subsequent click\r
-    if (lastLabelClickCoordinates) {\r
-      lastLabelClickCoordinates = null;\r
-    }\r
-    // remember label click coordinates to prevent click busting of trigger click event on input\r
-    if (nodeName_(event.target) === 'label') {\r
-      lastLabelClickCoordinates = [x, y];\r
-    }\r
-\r
-    // Look for an allowable region containing this click.\r
-    // If we find one, that means it was created by touchstart and not removed by\r
-    // preventGhostClick, so we don't bust it.\r
-    if (checkAllowableRegions(touchCoordinates, x, y)) {\r
-      return;\r
-    }\r
-\r
-    // If we didn't find an allowable region, bust the click.\r
-    event.stopPropagation();\r
-    event.preventDefault();\r
-\r
-    // Blur focused form elements\r
-    event.target && event.target.blur && event.target.blur();\r
-  }\r
-\r
-\r
-  // Global touchstart handler that creates an allowable region for a click event.\r
-  // This allowable region can be removed by preventGhostClick if we want to bust it.\r
-  function onTouchStart(event) {\r
-    var touches = event.touches && event.touches.length ? event.touches : [event];\r
-    var x = touches[0].clientX;\r
-    var y = touches[0].clientY;\r
-    touchCoordinates.push(x, y);\r
-\r
-    $timeout(function() {\r
-      // Remove the allowable region.\r
-      for (var i = 0; i < touchCoordinates.length; i += 2) {\r
-        if (touchCoordinates[i] == x && touchCoordinates[i + 1] == y) {\r
-          touchCoordinates.splice(i, i + 2);\r
-          return;\r
-        }\r
-      }\r
-    }, PREVENT_DURATION, false);\r
-  }\r
-\r
-  // On the first call, attaches some event handlers. Then whenever it gets called, it creates a\r
-  // zone around the touchstart where clicks will get busted.\r
-  function preventGhostClick(x, y) {\r
-    if (!touchCoordinates) {\r
-      $rootElement[0].addEventListener('click', onClick, true);\r
-      $rootElement[0].addEventListener('touchstart', onTouchStart, true);\r
-      touchCoordinates = [];\r
-    }\r
-\r
-    lastPreventedTime = Date.now();\r
-\r
-    checkAllowableRegions(touchCoordinates, x, y);\r
-  }\r
-\r
-  // Actual linking function.\r
-  return function(scope, element, attr) {\r
-    var clickHandler = $parse(attr.ngClick),\r
-        tapping = false,\r
-        tapElement,  // Used to blur the element after a tap.\r
-        startTime,   // Used to check if the tap was held too long.\r
-        touchStartX,\r
-        touchStartY;\r
-\r
-    function resetState() {\r
-      tapping = false;\r
-      element.removeClass(ACTIVE_CLASS_NAME);\r
-    }\r
-\r
-    element.on('touchstart', function(event) {\r
-      tapping = true;\r
-      tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement.\r
-      // Hack for Safari, which can target text nodes instead of containers.\r
-      if (tapElement.nodeType == 3) {\r
-        tapElement = tapElement.parentNode;\r
-      }\r
-\r
-      element.addClass(ACTIVE_CLASS_NAME);\r
-\r
-      startTime = Date.now();\r
-\r
-      // Use jQuery originalEvent\r
-      var originalEvent = event.originalEvent || event;\r
-      var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];\r
-      var e = touches[0];\r
-      touchStartX = e.clientX;\r
-      touchStartY = e.clientY;\r
-    });\r
-\r
-    element.on('touchcancel', function(event) {\r
-      resetState();\r
-    });\r
-\r
-    element.on('touchend', function(event) {\r
-      var diff = Date.now() - startTime;\r
-\r
-      // Use jQuery originalEvent\r
-      var originalEvent = event.originalEvent || event;\r
-      var touches = (originalEvent.changedTouches && originalEvent.changedTouches.length) ?\r
-          originalEvent.changedTouches :\r
-          ((originalEvent.touches && originalEvent.touches.length) ? originalEvent.touches : [originalEvent]);\r
-      var e = touches[0];\r
-      var x = e.clientX;\r
-      var y = e.clientY;\r
-      var dist = Math.sqrt(Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2));\r
-\r
-      if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) {\r
-        // Call preventGhostClick so the clickbuster will catch the corresponding click.\r
-        preventGhostClick(x, y);\r
-\r
-        // Blur the focused element (the button, probably) before firing the callback.\r
-        // This doesn't work perfectly on Android Chrome, but seems to work elsewhere.\r
-        // I couldn't get anything to work reliably on Android Chrome.\r
-        if (tapElement) {\r
-          tapElement.blur();\r
-        }\r
-\r
-        if (!angular.isDefined(attr.disabled) || attr.disabled === false) {\r
-          element.triggerHandler('click', [event]);\r
-        }\r
-      }\r
-\r
-      resetState();\r
-    });\r
-\r
-    // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click\r
-    // something else nearby.\r
-    element.onclick = function(event) { };\r
-\r
-    // Actual click handler.\r
-    // There are three different kinds of clicks, only two of which reach this point.\r
-    // - On desktop browsers without touch events, their clicks will always come here.\r
-    // - On mobile browsers, the simulated "fast" click will call this.\r
-    // - But the browser's follow-up slow click will be "busted" before it reaches this handler.\r
-    // Therefore it's safe to use this directive on both mobile and desktop.\r
-    element.on('click', function(event, touchend) {\r
-      scope.$apply(function() {\r
-        clickHandler(scope, {$event: (touchend || event)});\r
-      });\r
-    });\r
-\r
-    element.on('mousedown', function(event) {\r
-      element.addClass(ACTIVE_CLASS_NAME);\r
-    });\r
-\r
-    element.on('mousemove mouseup', function(event) {\r
-      element.removeClass(ACTIVE_CLASS_NAME);\r
-    });\r
-\r
-  };\r
-}]);\r
-\r
-/* global ngTouch: false */\r
-\r
-/**\r
- * @ngdoc directive\r
- * @name ngSwipeLeft\r
- *\r
- * @description\r
- * Specify custom behavior when an element is swiped to the left on a touchscreen device.\r
- * A leftward swipe is a quick, right-to-left slide of the finger.\r
- * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag\r
- * too.\r
- *\r
- * To disable the mouse click and drag functionality, add `ng-swipe-disable-mouse` to\r
- * the `ng-swipe-left` or `ng-swipe-right` DOM Element.\r
- *\r
- * Requires the {@link ngTouch `ngTouch`} module to be installed.\r
- *\r
- * @element ANY\r
- * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate\r
- * upon left swipe. (Event object is available as `$event`)\r
- *\r
- * @example\r
-    <example module="ngSwipeLeftExample" deps="angular-touch.js">\r
-      <file name="index.html">\r
-        <div ng-show="!showActions" ng-swipe-left="showActions = true">\r
-          Some list content, like an email in the inbox\r
-        </div>\r
-        <div ng-show="showActions" ng-swipe-right="showActions = false">\r
-          <button ng-click="reply()">Reply</button>\r
-          <button ng-click="delete()">Delete</button>\r
-        </div>\r
-      </file>\r
-      <file name="script.js">\r
-        angular.module('ngSwipeLeftExample', ['ngTouch']);\r
-      </file>\r
-    </example>\r
- */\r
-\r
-/**\r
- * @ngdoc directive\r
- * @name ngSwipeRight\r
- *\r
- * @description\r
- * Specify custom behavior when an element is swiped to the right on a touchscreen device.\r
- * A rightward swipe is a quick, left-to-right slide of the finger.\r
- * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag\r
- * too.\r
- *\r
- * Requires the {@link ngTouch `ngTouch`} module to be installed.\r
- *\r
- * @element ANY\r
- * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate\r
- * upon right swipe. (Event object is available as `$event`)\r
- *\r
- * @example\r
-    <example module="ngSwipeRightExample" deps="angular-touch.js">\r
-      <file name="index.html">\r
-        <div ng-show="!showActions" ng-swipe-left="showActions = true">\r
-          Some list content, like an email in the inbox\r
-        </div>\r
-        <div ng-show="showActions" ng-swipe-right="showActions = false">\r
-          <button ng-click="reply()">Reply</button>\r
-          <button ng-click="delete()">Delete</button>\r
-        </div>\r
-      </file>\r
-      <file name="script.js">\r
-        angular.module('ngSwipeRightExample', ['ngTouch']);\r
-      </file>\r
-    </example>\r
- */\r
-\r
-function makeSwipeDirective(directiveName, direction, eventName) {\r
-  ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) {\r
-    // The maximum vertical delta for a swipe should be less than 75px.\r
-    var MAX_VERTICAL_DISTANCE = 75;\r
-    // Vertical distance should not be more than a fraction of the horizontal distance.\r
-    var MAX_VERTICAL_RATIO = 0.3;\r
-    // At least a 30px lateral motion is necessary for a swipe.\r
-    var MIN_HORIZONTAL_DISTANCE = 30;\r
-\r
-    return function(scope, element, attr) {\r
-      var swipeHandler = $parse(attr[directiveName]);\r
-\r
-      var startCoords, valid;\r
-\r
-      function validSwipe(coords) {\r
-        // Check that it's within the coordinates.\r
-        // Absolute vertical distance must be within tolerances.\r
-        // Horizontal distance, we take the current X - the starting X.\r
-        // This is negative for leftward swipes and positive for rightward swipes.\r
-        // After multiplying by the direction (-1 for left, +1 for right), legal swipes\r
-        // (ie. same direction as the directive wants) will have a positive delta and\r
-        // illegal ones a negative delta.\r
-        // Therefore this delta must be positive, and larger than the minimum.\r
-        if (!startCoords) return false;\r
-        var deltaY = Math.abs(coords.y - startCoords.y);\r
-        var deltaX = (coords.x - startCoords.x) * direction;\r
-        return valid && // Short circuit for already-invalidated swipes.\r
-            deltaY < MAX_VERTICAL_DISTANCE &&\r
-            deltaX > 0 &&\r
-            deltaX > MIN_HORIZONTAL_DISTANCE &&\r
-            deltaY / deltaX < MAX_VERTICAL_RATIO;\r
-      }\r
-\r
-      var pointerTypes = ['touch'];\r
-      if (!angular.isDefined(attr['ngSwipeDisableMouse'])) {\r
-        pointerTypes.push('mouse');\r
-      }\r
-      $swipe.bind(element, {\r
-        'start': function(coords, event) {\r
-          startCoords = coords;\r
-          valid = true;\r
-        },\r
-        'cancel': function(event) {\r
-          valid = false;\r
-        },\r
-        'end': function(coords, event) {\r
-          if (validSwipe(coords)) {\r
-            scope.$apply(function() {\r
-              element.triggerHandler(eventName);\r
-              swipeHandler(scope, {$event: event});\r
-            });\r
-          }\r
-        }\r
-      }, pointerTypes);\r
-    };\r
-  }]);\r
-}\r
-\r
-// Left is negative X-coordinate, right is positive.\r
-makeSwipeDirective('ngSwipeLeft', -1, 'swipeleft');\r
-makeSwipeDirective('ngSwipeRight', 1, 'swiperight');\r
-\r
-\r
-\r
-})(window, window.angular);\r