PageSourceSearch

https://surfomania.hu/interface/output/angular-v-639252475260000000.js

js surfomania.hu collected 2026-10-08 23:38:30 UTC 1,567,900 bytes, 38,759 lines download raw bytes

vendor: 22,881 bytes, lines 1-2
1/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
2!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||v(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:"jQuery"+(t+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==i.call(e))&&(!(t=r(e))||"function"==typeof(n=ue.call(t,"constructor")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},text:function(e){var t,n="",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||"HTML")},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(c(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:le}),"function"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge="[\\x20\\t\\r\\n\\f]",ve=new RegExp("^"+ge+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ge+"+$","g");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function p(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e}ce.escapeSelector=function(e){return(e+"").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",t="(?:\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",p="\\["+ge+"*("+t+")(?:"+ge+"*([*^$|!~]?=)"+ge+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+t+"))|)"+ge+"*\\]",g=":("+t+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+p+")*)|.*)\\)|)",v=new RegExp(ge+"+","g"),y=new RegExp("^"+ge+"*,"+ge+"*"),m=new RegExp("^"+ge+"*([>+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="<a id='"+S+"' href='' disabled='disabled'></a><select id='"+S+"-\r\\' disabled='disabled'><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0<I(t,T,null,[e]).length},I.contains=function(e,t){return(e.ownerDocument||e)!=T&&V(e),ce.contains(e,t)},I.attr=function(e,t){(e.ownerDocument||e)!=T&&V(e);var n=b.attrHandle[t.toLowerCase()],r=n&&ue.call(b.attrHandle,t.toLowerCase())?n(e,t,!C):void 0;return void 0!==r?r:e.getAttribute(t)},I.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ce.uniqueSort=function(e){var t,n=[],r=0,i=0;if(a=!le.sortStable,o=!le.sortStable&&ae.call(e,0),de.call(e,l),a){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)he.call(e,n[r],1)}return o=null,e},ce.fn.uniqueSort=function(){return this.pushStack(ce.uniqueSort(ae.apply(this)))},(b=ce.expr={cacheLength:50,createPseudo:F,match:D,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(v," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(d,e,t,h,g){var v="nth"!==d.slice(0,3),y="last"!==d.slice(-4),m="of-type"===e;return 1===h&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u=v!==y?"nextSibling":"previousSibling",l=e.parentNode,c=m&&e.nodeName.toLowerCase(),f=!n&&!m,p=!1;if(l){if(v){while(u){o=e;while(o=o[u])if(m?fe(o,c):1===o.nodeType)return!1;s=u="only"===d&&!s&&"nextSibling"}return!0}if(s=[y?l.firstChild:l.lastChild],y&&f){p=(a=(r=(i=l[S]||(l[S]={}))[d]||[])[0]===E&&r[1])&&r[2],o=a&&l.childNodes[a];while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if(1===o.nodeType&&++p&&o===e){i[d]=[E,a,p];break}}else if(f&&(p=a=(r=(i=e[S]||(e[S]={}))[d]||[])[0]===E&&r[1]),!1===p)while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if((m?fe(o,c):1===o.nodeType)&&++p&&(f&&((i=o[S]||(o[S]={}))[d]=[E,p]),o===e))break;return(p-=g)===h||p%h==0&&0<=p/h}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||I.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?F(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=se.call(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:F(function(e){var r=[],i=[],s=ne(e.replace(ve,"$1"));return s[S]?F(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:F(function(t){return function(e){return 0<I(t,e).length}}),contains:F(function(t){return t=t.replace(O,P),function(e){return-1<(e.textContent||ce.text(e)).indexOf(t)}}),lang:F(function(n){return A.test(n||"")||I.error("unsupported lang: "+n),n=n.replace(O,P).toLowerCase(),function(e){var t;do{if(t=C?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=ie.location&&ie.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===r},focus:function(e){return e===function(){try{return T.activeElement}catch(e){}}()&&T.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:z(!1),disabled:z(!0),checked:function(e){return fe(e,"input")&&!!e.checked||fe(e,"option")&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return q.test(e.nodeName)},input:function(e){return N.test(e.nodeName)},button:function(e){return fe(e,"input")&&"button"===e.type||fe(e,"button")},text:function(e){var t;return fe(e,"input")&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:X(function(){return[0]}),last:X(function(e,t){return[t-1]}),eq:X(function(e,t,n){return[n<0?n+t:n]}),even:X(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:X(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:X(function(e,t,n){var r;for(r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:X(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=B(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=_(e);function G(){}function Y(e,t){var n,r,i,o,a,s,u,l=c[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=y.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=m.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ve," ")}),a=a.slice(n.length)),b.filter)!(r=D[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?I.error(e):c(e,s).slice(0)}function Q(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function J(a,e,t){var s=e.dir,u=e.next,l=u||s,c=t&&"parentNode"===l,f=n++;return e.first?function(e,t,n){while(e=e[s])if(1===e.nodeType||c)return a(e,t,n);return!1}:function(e,t,n){var r,i,o=[E,f];if(n){while(e=e[s])if((1===e.nodeType||c)&&a(e,t,n))return!0}else while(e=e[s])if(1===e.nodeType||c)if(i=e[S]||(e[S]={}),u&&fe(e,u))e=e[s]||e;else{if((r=i[l])&&r[0]===E&&r[1]===f)return o[2]=r[2];if((i[l]=o)[2]=a(e,t,n))return!0}return!1}}function K(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Z(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function ee(d,h,g,v,y,e){return v&&!v[S]&&(v=ee(v)),y&&!y[S]&&(y=ee(y,e)),F(function(e,t,n,r){var i,o,a,s,u=[],l=[],c=t.length,f=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)I(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),p=!d||!e&&h?f:Z(f,u,d,n,r);if(g?g(p,s=y||(e?d:c||v)?[]:t,n,r):s=p,v){i=Z(s,l),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(s[l[o]]=!(p[l[o]]=a))}if(e){if(y||d){if(y){i=[],o=s.length;while(o--)(a=s[o])&&i.push(p[o]=a);y(null,s=[],i,r)}o=s.length;while(o--)(a=s[o])&&-1<(i=y?se.call(e,a):u[o])&&(e[i]=!(t[i]=a))}}else s=Z(s===t?s.splice(c,s.length):s),y?y(null,t,s,r):k.apply(t,s)})}function te(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=J(function(e){return e===i},a,!0),l=J(function(e){return-1<se.call(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!=w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[J(K(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return ee(1<s&&K(c),1<s&&Q(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(ve,"$1"),t,s<n&&te(e.slice(s,n)),n<r&&te(e=e.slice(n)),n<r&&Q(e))}c.push(t)}return K(c)}function ne(e,t){var n,v,y,m,x,r,i=[],o=[],a=u[e+" "];if(!a){t||(t=Y(e)),n=t.length;while(n--)(a=te(t[n]))[S]?i.push(a):o.push(a);(a=u(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=E+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==T||(V(o),n=!C);while(s=v[a++])if(s(o,t||T,n)){k.call(r,o);break}i&&(E=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=pe.call(r));f=Z(f)}k.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&ce.uniqueSort(r)}return i&&(E=h,w=p),c},m?F(r):r))).selector=e}return a}function re(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&Y(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&C&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(O,P),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=D.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(O,P),H.test(o[0].type)&&U(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&Q(o)))return k.apply(n,r),n;break}}}return(l||ne(e,c))(r,t,!C,n,!t||H.test(e)&&U(t.parentNode)||t),n}G.prototype=b.filters=b.pseudos,b.setFilters=new G,le.sortStable=S.split("").sort(l).join("")===S,V(),le.sortDetached=$(function(e){return 1&e.compareDocumentPosition(T.createElement("fieldset"))}),ce.find=I,ce.expr[":"]=ce.expr.pseudos,ce.unique=ce.uniqueSort,I.compile=ne,I.select=re,I.setDocument=V,I.tokenize=Y,I.escape=ce.escapeSelector,I.getText=ce.text,I.isXML=ce.isXMLDoc,I.selectors=ce.expr,I.support=ce.support,I.uniqueSort=ce.uniqueSort}();var d=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&ce(e).is(n))break;r.push(e)}return r},h=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},b=ce.expr.match.needsContext,w=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1<se.call(n,e)!==r}):ce.filter(n,e,r)}ce.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?ce.find.matchesSelector(r,e)?[r]:[]:ce.find.matches(e,ce.grep(t,function(e){return 1===e.nodeType}))},ce.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(ce(e).filter(function(){for(t=0;t<r;t++)if(ce.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)ce.find(e,i[t],n);return 1<r?ce.uniqueSort(n):n},filter:function(e){return this.pushStack(T(this,e||[],!1))},not:function(e){return this.pushStack(T(this,e||[],!0))},is:function(e){return!!T(this,"string"==typeof e&&b.test(e)?ce(e):e||[],!1).length}});var k,S=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}
vendor: 1,967 bytes, line 2
2return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(ce.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&ce(e);if(!b.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&ce.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?ce.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?se.call(ce(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ce.uniqueSort(ce.merge(this.get(),ce(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ce.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return d(e,"parentNode")},parentsUntil:function(e,t,n){return d(e,"parentNode",n)},next:function(e){return A(e,"nextSibling")},prev:function(e){return A(e,"previousSibling")},nextAll:function(e){return d(e,"nextSibling")},prevAll:function(e){return d(e,"previousSibling")},nextUntil:function(e,t,n){return d(e,"nextSibling",n)},prevUntil:function(e,t,n){return d(e,"previousSibling",n)},siblings:function(e){return h((e.parentNode||{}).firstChild,e)},children:function(e){return h(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(fe(e,"template")&&(e=e.content||e),ce.merge([],e.childNodes))}},function(r,i){ce.fn[r]=function(e,t){var n=ce.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=ce.filter(t,n)),1<this.length&&(j[r]||
vendor: 9,546 bytes, line 2
2ce.uniqueSort(n),E.test(r)&&n.reverse()),this.pushStack(n)}});var D=/[^\x20\t\r\n\f]+/g;function N(e){return e}function q(e){throw e}function L(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}ce.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},ce.each(e.match(D)||[],function(e,t){n[t]=!0}),n):ce.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){ce.each(e,function(e,t){v(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==x(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return ce.each(arguments,function(e,t){var n;while(-1<(n=ce.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<ce.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},ce.extend({Deferred:function(e){var o=[["notify","progress",ce.Callbacks("memory"),ce.Callbacks("memory"),2],["resolve","done",ce.Callbacks("once memory"),ce.Callbacks("once memory"),0,"resolved"],["reject","fail",ce.Callbacks("once memory"),ce.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return ce.Deferred(function(r){ce.each(o,function(e,t){var n=v(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&v(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,v(t)?s?t.call(e,l(u,o,N,s),l(u,o,q,s)):(u++,t.call(e,l(u,o,N,s),l(u,o,q,s),l(u,o,N,o.notifyWith))):(a!==N&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){ce.Deferred.exceptionHook&&ce.Deferred.exceptionHook(e,t.error),u<=i+1&&(a!==q&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(ce.Deferred.getErrorHook?t.error=ce.Deferred.getErrorHook():ce.Deferred.getStackHook&&(t.error=ce.Deferred.getStackHook()),ie.setTimeout(t))}}return ce.Deferred(function(e){o[0][3].add(l(0,e,v(r)?r:N,e.notifyWith)),o[1][3].add(l(0,e,v(t)?t:N)),o[2][3].add(l(0,e,v(n)?n:q))}).promise()},promise:function(e){return null!=e?ce.extend(e,a):a}},s={};return ce.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=ae.call(arguments),o=ce.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?ae.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(L(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||v(i[t]&&i[t].then)))return o.then();while(t--)L(i[t],a(t),o.reject);return o.promise()}});var H=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ce.Deferred.exceptionHook=function(e,t){ie.console&&ie.console.warn&&e&&H.test(e.name)&&ie.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},ce.readyException=function(e){ie.setTimeout(function(){throw e})};var O=ce.Deferred();function P(){C.removeEventListener("DOMContentLoaded",P),ie.removeEventListener("load",P),ce.ready()}ce.fn.ready=function(e){return O.then(e)["catch"](function(e){ce.readyException(e)}),this},ce.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ce.readyWait:ce.isReady)||(ce.isReady=!0)!==e&&0<--ce.readyWait||O.resolveWith(C,[ce])}}),ce.ready.then=O.then,"complete"===C.readyState||"loading"!==C.readyState&&!C.documentElement.doScroll?ie.setTimeout(ce.ready):(C.addEventListener("DOMContentLoaded",P),ie.addEventListener("load",P));var M=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n))for(s in i=!0,n)M(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(ce(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},R=/^-ms-/,I=/-([a-z])/g;function W(e,t){return t.toUpperCase()}function F(e){return e.replace(R,"ms-").replace(I,W)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function B(){this.expando=ce.expando+B.uid++}B.uid=1,B.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[F(t)]=n;else for(r in t)i[F(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][F(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(F):(t=F(t))in r?[t]:t.match(D)||[]).length;while(n--)delete r[t[n]]}(void 0===t||ce.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!ce.isEmptyObject(t)}};var _=new B,z=new B,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,U=/[A-Z]/g;function V(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(U,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:X.test(i)?JSON.parse(i):i)}catch(e){}z.set(e,t,n)}else n=void 0;return n}ce.extend({hasData:function(e){return z.hasData(e)||_.hasData(e)},data:function(e,t,n){return z.access(e,t,n)},removeData:function(e,t){z.remove(e,t)},_data:function(e,t,n){return _.access(e,t,n)},_removeData:function(e,t){_.remove(e,t)}}),ce.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=z.get(o),1===o.nodeType&&!_.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=F(r.slice(5)),V(o,r,i[r]));_.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){z.set(this,n)}):M(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=z.get(o,n))?t:void 0!==(t=V(o,n))?t:void 0;this.each(function(){z.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){z.remove(this,e)})}}),ce.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=_.get(e,t),n&&(!r||Array.isArray(n)?r=_.access(e,t,ce.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=ce.queue(e,t),r=n.length,i=n.shift(),o=ce._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){ce.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return _.get(e,n)||_.access(e,n,{empty:ce.Callbacks("once memory").add(function(){_.remove(e,[t+"queue",n])})})}}),ce.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?ce.queue(this[0],t):void 0===n?this:this.each(function(){var e=ce.queue(this,t,n);ce._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&ce.dequeue(this,t)})},dequeue:function(e){return this.each(function(){ce.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=ce.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=_.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var G=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,Y=new RegExp("^(?:([+-])=|)("+G+")([a-z%]*)$","i"),Q=["Top","Right","Bottom","Left"],J=C.documentElement,K=function(e){return ce.contains(e.ownerDocument,e)},Z={composed:!0};J.getRootNode&&(K=function(e){return ce.contains(e.ownerDocument,e)||e.getRootNode(Z)===e.ownerDocument});var ee=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&K(e)&&"none"===ce.css(e,"display")};function te(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return ce.css(e,t,"")},u=s(),l=n&&n[3]||(ce.cssNumber[t]?"":"px"),c=e.nodeType&&(ce.cssNumber[t]||"px"!==l&&+u)&&Y.exec(ce.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)ce.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,ce.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ne={};function re(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=_.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ee(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ne[s])||
vendor: 8,814 bytes, line 2
2(o=a.body.appendChild(a.createElement(s)),u=ce.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ne[s]=u)))):"none"!==n&&(l[c]="none",_.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}ce.fn.extend({show:function(){return re(this,!0)},hide:function(){return re(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ee(this)?ce(this).show():ce(this).hide()})}});var xe,be,we=/^(?:checkbox|radio)$/i,Te=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="<textarea>x</textarea>",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="<option></option>",le.option=!!xe.lastChild;var ke={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n<r;n++)_.set(e[n],"globalEval",!t||_.get(t[n],"globalEval"))}ke.tbody=ke.tfoot=ke.colgroup=ke.caption=ke.thead,ke.th=ke.td,le.option||(ke.optgroup=ke.option=[1,"<select multiple='multiple'>","</select>"]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===x(o))ce.merge(p,o.nodeType?[o]:o);else if(je.test(o)){a=a||f.appendChild(t.createElement("div")),s=(Te.exec(o)||["",""])[1].toLowerCase(),u=ke[s]||ke._default,a.innerHTML=u[1]+ce.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;ce.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<ce.inArray(o,r))i&&i.push(o);else if(l=K(o),a=Se(f.appendChild(o),"script"),l&&Ee(a),n){c=0;while(o=a[c++])Ce.test(o.type||"")&&n.push(o)}return f}var De=/^([^.]*)(?:\.(.+)|)/;function Ne(){return!0}function qe(){return!1}function Le(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Le(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=qe;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return ce().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=ce.guid++)),e.each(function(){ce.event.add(this,t,i,r,n)})}function He(e,r,t){t?(_.set(e,r,!1),ce.event.add(e,r,{namespace:!1,handler:function(e){var t,n=_.get(this,r);if(1&e.isTrigger&&this[r]){if(n)(ce.event.special[r]||{}).delegateType&&e.stopPropagation();else if(n=ae.call(arguments),_.set(this,r,n),this[r](),t=_.get(this,r),_.set(this,r,!1),n!==t)return e.stopImmediatePropagation(),e.preventDefault(),t}else n&&(_.set(this,r,ce.event.trigger(n[0],n.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ne)}})):void 0===_.get(e,r)&&ce.event.add(e,r,Ne)}ce.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.get(t);if($(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&ce.find.matchesSelector(J,i),n.guid||(n.guid=ce.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof ce&&ce.event.triggered!==e.type?ce.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(D)||[""]).length;while(l--)d=g=(s=De.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=ce.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ce.event.special[d]||{},c=ce.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ce.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),ce.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.hasData(e)&&_.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(D)||[""]).length;while(l--)if(d=g=(s=De.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=ce.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||ce.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ce.event.remove(e,d+t[l],n,r,!0);ce.isEmptyObject(u)&&_.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=ce.event.fix(e),l=(_.get(this,"events")||Object.create(null))[u.type]||[],c=ce.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=ce.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((ce.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<ce(i,this).index(l):ce.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(ce.Event.prototype,t,{enumerable:!0,configurable:!0,get:v(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[ce.expando]?e:new ce.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click",!0),!1},trigger:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click"),!0},_default:function(e){var t=e.target;return we.test(t.type)&&t.click&&fe(t,"input")&&_.get(t,"click")||fe(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},ce.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},ce.Event=function(e,t){if(!(this instanceof ce.Event))return new ce.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ne:qe,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&ce.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[ce.expando]=!0},ce.Event.prototype={constructor:ce.Event,isDefaultPrevented:qe,isPropagationStopped:qe,isImmediatePropagationStopped:qe,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ne,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ne,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ne,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},ce.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},ce.event.addProp),ce.each({focus:"focusin",blur:"focusout"},function(r,i){function o(e){if(C.documentMode){var t=_.get(this,"handle"),n=ce.event.fix(e);
vendor: 14,182 bytes, line 2
2n.type="focusin"===e.type?"focus":"blur",n.isSimulated=!0,t(e),n.target===n.currentTarget&&t(n)}else ce.event.simulate(i,e.target,ce.event.fix(e))}ce.event.special[r]={setup:function(){var e;if(He(this,r,!0),!C.documentMode)return!1;(e=_.get(this,i))||this.addEventListener(i,o),_.set(this,i,(e||0)+1)},trigger:function(){return He(this,r),!0},teardown:function(){var e;if(!C.documentMode)return!1;(e=_.get(this,i)-1)?_.set(this,i,e):(this.removeEventListener(i,o),_.remove(this,i))},_default:function(e){return _.get(e.target,r)},delegateType:i},ce.event.special[i]={setup:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i);n||(C.documentMode?this.addEventListener(i,o):e.addEventListener(r,o,!0)),_.set(t,i,(n||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i)-1;n?_.set(t,i,n):(C.documentMode?this.removeEventListener(i,o):e.removeEventListener(r,o,!0),_.remove(t,i))}}}),ce.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){ce.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||ce.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),ce.fn.extend({on:function(e,t,n,r){return Le(this,e,t,n,r)},one:function(e,t,n,r){return Le(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,ce(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=qe),this.each(function(){ce.event.remove(this,e,n,t)})}});var Oe=/<script|<style|<link/i,Pe=/checked\s*(?:[^=]|=\s*.checked.)/i,Me=/^\s*<!\[CDATA\[|\]\]>\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)ce.event.add(t,i,s[i][n]);z.hasData(e)&&(o=z.access(e),a=ce.extend({},o),z.set(t,a))}}function $e(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=v(d);if(h||1<f&&"string"==typeof d&&!le.checkClone&&Pe.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),$e(t,r,i,o)});if(f&&(t=(e=Ae(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=ce.map(Se(e,"script"),Ie)).length;c<f;c++)u=e,c!==p&&(u=ce.clone(u,!0,!0),s&&ce.merge(a,Se(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,ce.map(a,We),c=0;c<s;c++)u=a[c],Ce.test(u.type||"")&&!_.access(u,"globalEval")&&ce.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?ce._evalUrl&&!u.noModule&&ce._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):m(u.textContent.replace(Me,""),u,l))}return n}function Be(e,t,n){for(var r,i=t?ce.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||ce.cleanData(Se(r)),r.parentNode&&(n&&K(r)&&Ee(Se(r,"script")),r.parentNode.removeChild(r));return e}ce.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=K(e);if(!(le.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ce.isXMLDoc(e)))for(a=Se(c),r=0,i=(o=Se(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&we.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||Se(e),a=a||Se(c),r=0,i=o.length;r<i;r++)Fe(o[r],a[r]);else Fe(e,c);return 0<(a=Se(c,"script")).length&&Ee(a,!f&&Se(e,"script")),c},cleanData:function(e){for(var t,n,r,i=ce.event.special,o=0;void 0!==(n=e[o]);o++)if($(n)){if(t=n[_.expando]){if(t.events)for(r in t.events)i[r]?ce.event.remove(n,r):ce.removeEvent(n,r,t.handle);n[_.expando]=void 0}n[z.expando]&&(n[z.expando]=void 0)}}}),ce.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return M(this,function(e){return void 0===e?ce.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return $e(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Re(this,e).appendChild(e)})},prepend:function(){return $e(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Re(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(ce.cleanData(Se(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ce.clone(this,e,t)})},html:function(e){return M(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Oe.test(e)&&!ke[(Te.exec(e)||["",""])[1].toLowerCase()]){e=ce.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(ce.cleanData(Se(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return $e(this,arguments,function(e){var t=this.parentNode;ce.inArray(this,n)<0&&(ce.cleanData(Se(this)),t&&t.replaceChild(e,this))},n)}}),ce.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){ce.fn[e]=function(e){for(var t,n=[],r=ce(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),ce(r[o])[a](t),s.apply(n,t.get());return this.pushStack(n)}});var _e=new RegExp("^("+G+")(?!px)[a-z%]+$","i"),ze=/^--/,Xe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=ie),t.getComputedStyle(e)},Ue=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ve=new RegExp(Q.join("|"),"i");function Ge(e,t,n){var r,i,o,a,s=ze.test(t),u=e.style;return(n=n||Xe(e))&&(a=n.getPropertyValue(t)||n[t],s&&a&&(a=a.replace(ve,"$1")||void 0),""!==a||K(e)||(a=ce.style(e,t)),!le.pixelBoxStyles()&&_e.test(a)&&Ve.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+"":a}function Ye(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",J.appendChild(u).appendChild(l);var e=ie.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),J.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=C.createElement("div"),l=C.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",le.clearCloneStyle="content-box"===l.style.backgroundClip,ce.extend(le,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=C.createElement("table"),t=C.createElement("tr"),n=C.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="box-sizing:content-box;border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",J.appendChild(e).appendChild(t).appendChild(n),r=ie.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,J.removeChild(e)),a}}))}();var Qe=["Webkit","Moz","ms"],Je=C.createElement("div").style,Ke={};function Ze(e){var t=ce.cssProps[e]||Ke[e];return t||(e in Je?e:Ke[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Qe.length;while(n--)if((e=Qe[n]+t)in Je)return e}(e)||e)}var et=/^(none|table(?!-c[ea]).+)/,tt={position:"absolute",visibility:"hidden",display:"block"},nt={letterSpacing:"0",fontWeight:"400"};function rt(e,t,n){var r=Y.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function it(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0,l=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(l+=ce.css(e,n+Q[a],!0,i)),r?("content"===n&&(u-=ce.css(e,"padding"+Q[a],!0,i)),"margin"!==n&&(u-=ce.css(e,"border"+Q[a]+"Width",!0,i))):(u+=ce.css(e,"padding"+Q[a],!0,i),"padding"!==n?u+=ce.css(e,"border"+Q[a]+"Width",!0,i):s+=ce.css(e,"border"+Q[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u+l}function ot(e,t,n){var r=Xe(e),i=(!le.boxSizingReliable()||n)&&"border-box"===ce.css(e,"boxSizing",!1,r),o=i,a=Ge(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(_e.test(a)){if(!n)return a;a="auto"}return(!le.boxSizingReliable()&&i||!le.reliableTrDimensions()&&fe(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===ce.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===ce.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+it(e,t,n||(i?"border":"content"),o,r,a)+"px"}function at(e,t,n,r,i){return new at.prototype.init(e,t,n,r,i)}ce.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=F(t),u=ze.test(t),l=e.style;if(u||(t=Ze(s)),a=ce.cssHooks[t]||ce.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=Y.exec(n))&&i[1]&&(n=te(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(ce.cssNumber[s]?"":"px")),le.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=F(t);return ze.test(t)||(t=Ze(s)),(a=ce.cssHooks[t]||ce.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ge(e,t,r)),"normal"===i&&t in nt&&(i=nt[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),ce.each(["height","width"],function(e,u){ce.cssHooks[u]={get:function(e,t,n){if(t)return!et.test(ce.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?ot(e,u,n):Ue(e,tt,function(){return ot(e,u,n)})},set:function(e,t,n){var r,i=Xe(e),o=!le.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===ce.css(e,"boxSizing",!1,i),s=n?it(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-it(e,u,"border",!1,i)-.5)),s&&(r=Y.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=ce.css(e,u)),rt(0,t,s)}}}),ce.cssHooks.marginLeft=Ye(le.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,"marginLeft"))||e.getBoundingClientRect().left-Ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),ce.each({margin:"",padding:"",border:"Width"},function(i,o){ce.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+Q[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(ce.cssHooks[i+o].set=rt)}),ce.fn.extend({css:function(e,t){return M(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Xe(e),i=t.length;a<i;a++)o[t[a]]=ce.css(e,t[a],!1,r);return o}return void 0!==n?ce.style(e,t,n):ce.css(e,t)},e,t,1<arguments.length)}}),((ce.Tween=at).prototype={constructor:at,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ce.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ce.cssNumber[n]?"":"px")},cur:function(){var e=at.propHooks[this.prop];return e&&e.get?e.get(this):at.propHooks._default.get(this)},run:function(e){var t,n=at.propHooks[this.prop];return this.options.duration?this.pos=t=ce.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):at.propHooks._default.set(this),this}}).init.prototype=at.prototype,(at.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=ce.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){ce.fx.step[e.prop]?ce.fx.step[e.prop](e):1!==e.elem.nodeType||!ce.cssHooks[e.prop]&&null==e.elem.style[Ze(e.prop)]?e.elem[e.prop]=e.now:ce.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=at.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ce.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ce.fx=at.prototype.init,ce.fx.step={};var st,ut,lt,ct,ft=/^(?:toggle|show|hide)$/,pt=/queueHooks$/;function dt(){ut&&(!1===C.hidden&&ie.requestAnimationFrame?ie.requestAnimationFrame(dt):ie.setTimeout(dt,ce.fx.interval),ce.fx.tick())}function ht(){return ie.setTimeout(function(){st=void 0}),st=Date.now()}function gt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=Q[r])]=i["padding"+n]=e;
vendor: 4,590 bytes, line 2
2return t&&(i.opacity=i.width=e),i}function vt(e,t,n){for(var r,i=(yt.tweeners[t]||[]).concat(yt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function yt(o,e,t){var n,a,r=0,i=yt.prefilters.length,s=ce.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=st||ht(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:ce.extend({},e),opts:ce.extend(!0,{specialEasing:{},easing:ce.easing._default},t),originalProperties:e,originalOptions:t,startTime:st||ht(),duration:t.duration,tweens:[],createTween:function(e,t){var n=ce.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=F(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=ce.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=yt.prefilters[r].call(l,o,c,l.opts))return v(n.stop)&&(ce._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return ce.map(c,vt,l),v(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),ce.fx.timer(ce.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}ce.Animation=ce.extend(yt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return te(n.elem,e,Y.exec(t),n),n}]},tweener:function(e,t){v(e)?(t=e,e=["*"]):e=e.match(D);for(var n,r=0,i=e.length;r<i;r++)n=e[r],yt.tweeners[n]=yt.tweeners[n]||[],yt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ee(e),v=_.get(e,"fxshow");for(r in n.queue||(null==(a=ce._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,ce.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ft.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||ce.style(e,r)}if((u=!ce.isEmptyObject(t))||!ce.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=_.get(e,"display")),"none"===(c=ce.css(e,"display"))&&(l?c=l:(re([e],!0),l=e.style.display||l,c=ce.css(e,"display"),re([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===ce.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=_.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&re([e],!0),p.done(function(){for(r in g||re([e]),_.remove(e,"fxshow"),d)ce.style(e,r,d[r])})),u=vt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?yt.prefilters.unshift(e):yt.prefilters.push(e)}}),ce.speed=function(e,t,n){var r=e&&"object"==typeof e?ce.extend({},e):{complete:n||!n&&t||v(e)&&e,duration:e,easing:n&&t||t&&!v(t)&&t};return ce.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in ce.fx.speeds?r.duration=ce.fx.speeds[r.duration]:r.duration=ce.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){v(r.old)&&r.old.call(this),r.queue&&ce.dequeue(this,r.queue)},r},ce.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ee).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=ce.isEmptyObject(t),o=ce.speed(e,n,r),a=function(){var e=yt(this,ce.extend({},t),o);(i||_.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=ce.timers,r=_.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&pt.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1)
vendor: 13,972 bytes, line 2
2);!e&&o||ce.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=_.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=ce.timers,o=n?n.length:0;for(t.finish=!0,ce.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),ce.each(["toggle","show","hide"],function(e,r){var i=ce.fn[r];ce.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(gt(r,!0),e,t,n)}}),ce.each({slideDown:gt("show"),slideUp:gt("hide"),slideToggle:gt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){ce.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),ce.timers=[],ce.fx.tick=function(){var e,t=0,n=ce.timers;for(st=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||ce.fx.stop(),st=void 0},ce.fx.timer=function(e){ce.timers.push(e),ce.fx.start()},ce.fx.interval=13,ce.fx.start=function(){ut||(ut=!0,dt())},ce.fx.stop=function(){ut=null},ce.fx.speeds={slow:600,fast:200,_default:400},ce.fn.delay=function(r,e){return r=ce.fx&&ce.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=ie.setTimeout(e,r);t.stop=function(){ie.clearTimeout(n)}})},lt=C.createElement("input"),ct=C.createElement("select").appendChild(C.createElement("option")),lt.type="checkbox",le.checkOn=""!==lt.value,le.optSelected=ct.selected,(lt=C.createElement("input")).value="t",lt.type="radio",le.radioValue="t"===lt.value;var mt,xt=ce.expr.attrHandle;ce.fn.extend({attr:function(e,t){return M(this,ce.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){ce.removeAttr(this,e)})}}),ce.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?ce.prop(e,t,n):(1===o&&ce.isXMLDoc(e)||(i=ce.attrHooks[t.toLowerCase()]||(ce.expr.match.bool.test(t)?mt:void 0)),void 0!==n?null===n?void ce.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=ce.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!le.radioValue&&"radio"===t&&fe(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(D);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),mt={set:function(e,t,n){return!1===t?ce.removeAttr(e,n):e.setAttribute(n,n),n}},ce.each(ce.expr.match.bool.source.match(/\w+/g),function(e,t){var a=xt[t]||ce.find.attr;xt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=xt[o],xt[o]=r,r=null!=a(e,t,n)?o:null,xt[o]=i),r}});var bt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;function Tt(e){return(e.match(D)||[]).join(" ")}function Ct(e){return e.getAttribute&&e.getAttribute("class")||""}function kt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(D)||[]}ce.fn.extend({prop:function(e,t){return M(this,ce.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[ce.propFix[e]||e]})}}),ce.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ce.isXMLDoc(e)||(t=ce.propFix[t]||t,i=ce.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=ce.find.attr(e,"tabindex");return t?parseInt(t,10):bt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),le.optSelected||(ce.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),ce.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ce.propFix[this.toLowerCase()]=this}),ce.fn.extend({addClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).addClass(t.call(this,e,Ct(this)))}):(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++)i=e[o],n.indexOf(" "+i+" ")<0&&(n+=i+" ");a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).removeClass(t.call(this,e,Ct(this)))}):arguments.length?(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(" "+i+" "))n=n.replace(" "+i+" "," ")}a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this:this.attr("class","")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s="string"===a||Array.isArray(t);return v(t)?this.each(function(e){ce(this).toggleClass(t.call(this,e,Ct(this),n),n)}):"boolean"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=kt(t),this.each(function(){if(s)for(o=ce(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&"boolean"!==a||((r=Ct(this))&&_.set(this,"__className__",r),this.setAttribute&&this.setAttribute("class",r||!1===t?"":_.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+Tt(Ct(n))+" ").indexOf(t))return!0;return!1}});var St=/\r/g;ce.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=v(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,ce(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=ce.map(t,function(e){return null==e?"":e+""})),(r=ce.valHooks[this.type]||ce.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=ce.valHooks[t.type]||ce.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(St,""):null==e?"":e:void 0}}),ce.extend({valHooks:{option:{get:function(e){var t=ce.find.attr(e,"value");return null!=t?t:Tt(ce.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!fe(n.parentNode,"optgroup"))){if(t=ce(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=ce.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<ce.inArray(ce.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ce.each(["radio","checkbox"],function(){ce.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<ce.inArray(ce(e).val(),t)}},le.checkOn||(ce.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Et=ie.location,jt={guid:Date.now()},At=/\?/;ce.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new ie.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||ce.error("Invalid XML: "+(n?ce.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Dt=/^(?:focusinfocus|focusoutblur)$/,Nt=function(e){e.stopPropagation()};ce.extend(ce.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||C],d=ue.call(e,"type")?e.type:e,h=ue.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||C,3!==n.nodeType&&8!==n.nodeType&&!Dt.test(d+ce.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[ce.expando]?e:new ce.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:ce.makeArray(t,[e]),c=ce.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!y(n)){for(s=c.delegateType||d,Dt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||C)&&p.push(a.defaultView||a.parentWindow||ie)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(_.get(o,"events")||Object.create(null))[e.type]&&_.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&$(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!$(n)||u&&v(n[d])&&!y(n)&&((a=n[u])&&(n[u]=null),ce.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Nt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Nt),ce.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=ce.extend(new ce.Event,n,{type:e,isSimulated:!0});ce.event.trigger(r,null,t)}}),ce.fn.extend({trigger:function(e,t){return this.each(function(){ce.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ce.event.trigger(e,t,n,!0)}});var qt=/\[\]$/,Lt=/\r?\n/g,Ht=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Pt(n,e,r,i){var t;if(Array.isArray(e))ce.each(e,function(e,t){r||qt.test(n)?i(n,t):Pt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==x(e))i(n,e);else for(t in e)Pt(n+"["+t+"]",e[t],r,i)}ce.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!ce.isPlainObject(e))ce.each(e,function(){i(this.name,this.value)});else for(n in e)Pt(n,e[n],t,i);return r.join("&")},ce.fn.extend({serialize:function(){return ce.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ce.prop(this,"elements");return e?ce.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ce(this).is(":disabled")&&Ot.test(this.nodeName)&&!Ht.test(e)&&(this.checked||!we.test(e))}).map(function(e,t){var n=ce(this).val();return null==n?null:Array.isArray(n)?ce.map(n,function(e){return{name:t.name,value:e.replace(Lt,"\r\n")}}):{name:t.name,value:n.replace(Lt,"\r\n")}}).get()}});var Mt=/%20/g,Rt=/#.*$/,It=/([?&])_=[^&]*/,Wt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ft=/^(?:GET|HEAD)$/,$t=/^\/\//,Bt={},_t={},zt="*/".concat("*"),Xt=C.createElement("a");function Ut(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(D)||[];if(v(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Vt(t,i,o,a){var s={},u=t===_t;function l(e){var r;return s[e]=!0,ce.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Gt(e,t){var n,r,i=ce.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&ce.extend(!0,e,r),e}Xt.href=Et.href,ce.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":zt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":ce.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Gt(Gt(e,ce.ajaxSettings),t):Gt(ce.ajaxSettings,e)},ajaxPrefilter:Ut(Bt),ajaxTransport:Ut(_t),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=ce.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?ce(y):ce.event,x=ce.Deferred(),b=ce.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Wt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace($t,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(D)||[""],null==v.crossDomain){r=C.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Xt.protocol+"//"+Xt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=ce.param(v.data,v.traditional)),Vt(Bt,v,t,T),h)return T;for(i in(g=ce.event&&v.global)&&0==ce.active++&&ce.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ft.test(v.type),f=v.url.replace(Rt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Mt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(At.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(It,"$1"),o=(At.test(f)?"&":"?")+"_="+jt.guid+++o),v.url=f+o),v.ifModified&&(ce.lastModified[f]&&T.setRequestHeader("If-Modified-Since",ce.lastModified[f]),ce.etag[f]&&T.setRequestHeader("If-None-Match",ce.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+zt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);
vendor: 9,033 bytes, line 2
2if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Vt(_t,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=ie.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&ie.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<ce.inArray("script",v.dataTypes)&&ce.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(ce.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(ce.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--ce.active||ce.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return ce.get(e,t,n,"json")},getScript:function(e,t){return ce.get(e,void 0,t,"script")}}),ce.each(["get","post"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})},ce.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=ce(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return v(n)?this.each(function(e){ce(this).wrapInner(n.call(this,e))}):this.each(function(){var e=ce(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=v(t);return this.each(function(e){ce(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){ce(this).replaceWith(this.childNodes)}),this}}),ce.expr.pseudos.hidden=function(e){return!ce.expr.pseudos.visible(e)},ce.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ce.ajaxSettings.xhr=function(){try{return new ie.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Qt=ce.ajaxSettings.xhr();le.cors=!!Qt&&"withCredentials"in Qt,le.ajax=Qt=!!Qt,ce.ajaxTransport(function(i){var o,a;if(le.cors||Qt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Yt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&ie.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),ce.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ce.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return ce.globalEval(e),e}}}),ce.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ce.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=ce("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=Tt(e.slice(s)),e=e.slice(0,s)),v(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&ce.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?ce("<div>").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return 
vendor: 2,549 bytes, lines 2-3
2M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var en=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;ce.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),v(e))return r=ae.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(ae.call(arguments)))}).guid=e.guid=e.guid||ce.guid++,i},ce.holdReady=function(e){e?ce.readyWait++:ce.ready(!0)},ce.isArray=Array.isArray,ce.parseJSON=JSON.parse,ce.nodeName=fe,ce.isFunction=v,ce.isWindow=y,ce.camelCase=F,ce.type=x,ce.now=Date.now,ce.isNumeric=function(e){var t=ce.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},ce.trim=function(e){return null==e?"":(e+"").replace(en,"$1")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return ce});var tn=ie.jQuery,nn=ie.$;return ce.noConflict=function(e){return ie.$===ce&&(ie.$=nn),e&&ie.jQuery===ce&&(ie.jQuery=tn),ce},"undefined"==typeof e&&(ie.jQuery=ie.$=ce),ce});
3
vendor: 1,377,909 bytes, lines 4-36603
4/**
5 * @license AngularJS v1.8.3
6 * (c) 2010-2020 Google LLC. http://angularjs.org
7 * License: MIT
8 */
9(function(window) {'use strict';
10
11/* exported
12  minErrConfig,
13  errorHandlingConfig,
14  isValidObjectMaxDepth
15*/
16
17var minErrConfig = {
18  objectMaxDepth: 5,
19  urlErrorParamsEnabled: true
20};
21
22/**
23 * @ngdoc function
24 * @name angular.errorHandlingConfig
25 * @module ng
26 * @kind function
27 *
28 * @description
29 * Configure several aspects of error handling in AngularJS if used as a setter or return the
30 * current configuration if used as a getter. The following options are supported:
31 *
32 * - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
33 *
34 * Omitted or undefined options will leave the corresponding configuration values unchanged.
35 *
36 * @param {Object=} config - The configuration object. May only contain the options that need to be
37 *     updated. Supported keys:
38 *
39 * * `objectMaxDepth`  **{Number}** - The max depth for stringifying objects. Setting to a
40 *   non-positive or non-numeric value, removes the max depth limit.
41 *   Default: 5
42 *
43 * * `urlErrorParamsEnabled`  **{Boolean}** - Specifies whether the generated error url will
44 *   contain the parameters of the thrown error. Disabling the parameters can be useful if the
45 *   generated error url is very long.
46 *
47 *   Default: true. When used without argument, it returns the current value.
48 */
49function errorHandlingConfig(config) {
50  if (isObject(config)) {
51    if (isDefined(config.objectMaxDepth)) {
52      minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
53    }
54    if (isDefined(config.urlErrorParamsEnabled) && isBoolean(config.urlErrorParamsEnabled)) {
55      minErrConfig.urlErrorParamsEnabled = config.urlErrorParamsEnabled;
56    }
57  } else {
58    return minErrConfig;
59  }
60}
61
62/**
63 * @private
64 * @param {Number} maxDepth
65 * @return {boolean}
66 */
67function isValidObjectMaxDepth(maxDepth) {
68  return isNumber(maxDepth) && maxDepth > 0;
69}
70
71
72/**
73 * @description
74 *
75 * This object provides a utility for producing rich Error messages within
76 * AngularJS. It can be called as follows:
77 *
78 * var exampleMinErr = minErr('example');
79 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
80 *
81 * The above creates an instance of minErr in the example namespace. The
82 * resulting error will have a namespaced error code of example.one.  The
83 * resulting error will replace {0} with the value of foo, and {1} with the
84 * value of bar. The object is not restricted in the number of arguments it can
85 * take.
86 *
87 * If fewer arguments are specified than necessary for interpolation, the extra
88 * interpolation markers will be preserved in the final string.
89 *
90 * Since data will be parsed statically during a build step, some restrictions
91 * are applied with respect to how minErr instances are created and called.
92 * Instances should have names of the form namespaceMinErr for a minErr created
93 * using minErr('namespace'). Error codes, namespaces and template strings
94 * should all be static strings, not variables or general expressions.
95 *
96 * @param {string} module The namespace to use for the new minErr instance.
97 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
98 *   error from returned function, for cases when a particular type of error is useful.
99 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
100 */
101
102function minErr(module, ErrorConstructor) {
103  ErrorConstructor = ErrorConstructor || Error;
104
105  var url = 'https://errors.angularjs.org/1.8.3/';
106  var regex = url.replace('.', '\\.') + '[\\s\\S]*';
107  var errRegExp = new RegExp(regex, 'g');
108
109  return function() {
110    var code = arguments[0],
111      template = arguments[1],
112      message = '[' + (module ? module + ':' : '') + code + '] ',
113      templateArgs = sliceArgs(arguments, 2).map(function(arg) {
114        return toDebugString(arg, minErrConfig.objectMaxDepth);
115      }),
116      paramPrefix, i;
117
118    // A minErr message has two parts: the message itself and the url that contains the
119    // encoded message.
120    // The message's parameters can contain other error messages which also include error urls.
121    // To prevent the messages from getting too long, we strip the error urls from the parameters.
122
123    message += template.replace(/\{\d+\}/g, function(match) {
124      var index = +match.slice(1, -1);
125
126      if (index < templateArgs.length) {
127        return templateArgs[index].replace(errRegExp, '');
128      }
129
130      return match;
131    });
132
133    message += '\n' + url + (module ? module + '/' : '') + code;
134
135    if (minErrConfig.urlErrorParamsEnabled) {
136      for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
137        message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
138      }
139    }
140
141    return new ErrorConstructor(message);
142  };
143}
144
145/* We need to tell ESLint what variables are being exported */
146/* exported
147  angular,
148  msie,
149  jqLite,
150  jQuery,
151  slice,
152  splice,
153  push,
154  toString,
155  minErrConfig,
156  errorHandlingConfig,
157  isValidObjectMaxDepth,
158  ngMinErr,
159  angularModule,
160  uid,
161  REGEX_STRING_REGEXP,
162  VALIDITY_STATE_PROPERTY,
163
164  lowercase,
165  uppercase,
166  nodeName_,
167  isArrayLike,
168  forEach,
169  forEachSorted,
170  reverseParams,
171  nextUid,
172  setHashKey,
173  extend,
174  toInt,
175  inherit,
176  merge,
177  noop,
178  identity,
179  valueFn,
180  isUndefined,
181  isDefined,
182  isObject,
183  isBlankObject,
184  isString,
185  isNumber,
186  isNumberNaN,
187  isDate,
188  isError,
189  isArray,
190  isFunction,
191  isRegExp,
192  isWindow,
193  isScope,
194  isFile,
195  isFormData,
196  isBlob,
197  isBoolean,
198  isPromiseLike,
199  trim,
200  escapeForRegexp,
201  isElement,
202  makeMap,
203  includes,
204  arrayRemove,
205  copy,
206  simpleCompare,
207  equals,
208  csp,
209  jq,
210  concat,
211  sliceArgs,
212  bind,
213  toJsonReplacer,
214  toJson,
215  fromJson,
216  convertTimezoneToLocal,
217  timezoneToOffset,
218  addDateMinutes,
219  startingTag,
220  tryDecodeURIComponent,
221  parseKeyValue,
222  toKeyValue,
223  encodeUriSegment,
224  encodeUriQuery,
225  angularInit,
226  bootstrap,
227  getTestability,
228  snake_case,
229  bindJQuery,
230  assertArg,
231  assertArgFn,
232  assertNotHasOwnProperty,
233  getter,
234  getBlockNodes,
235  hasOwnProperty,
236  createMap,
237  stringify,
238  UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
239
240  NODE_TYPE_ELEMENT,
241  NODE_TYPE_ATTRIBUTE,
242  NODE_TYPE_TEXT,
243  NODE_TYPE_COMMENT,
244  NODE_TYPE_DOCUMENT,
245  NODE_TYPE_DOCUMENT_FRAGMENT
246*/
247
248////////////////////////////////////
249
250/**
251 * @ngdoc module
252 * @name ng
253 * @module ng
254 * @installation
255 * @description
256 *
257 * The ng module is loaded by default when an AngularJS application is started. The module itself
258 * contains the essential components for an AngularJS application to function. The table below
259 * lists a high level breakdown of each of the services/factories, filters, directives and testing
260 * components available within this core module.
261 *
262 */
263
264var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
265
266// The name of a form control's ValidityState property.
267// This is used so that it's possible for internal tests to create mock ValidityStates.
268var VALIDITY_STATE_PROPERTY = 'validity';
269
270
271var hasOwnProperty = Object.prototype.hasOwnProperty;
272
273/**
274 * @private
275 *
276 * @description Converts the specified string to lowercase.
277 * @param {string} string String to be converted to lowercase.
278 * @returns {string} Lowercased string.
279 */
280var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
281
282/**
283 * @private
284 *
285 * @description Converts the specified string to uppercase.
286 * @param {string} string String to be converted to uppercase.
287 * @returns {string} Uppercased string.
288 */
289var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
290
291
292var
293    msie,             // holds major version number for IE, or NaN if UA is not IE.
294    jqLite,           // delay binding since jQuery could be loaded after us.
295    jQuery,           // delay binding
296    slice             = [].slice,
297    splice            = [].splice,
298    push              = [].push,
299    toString          = Object.prototype.toString,
300    getPrototypeOf    = Object.getPrototypeOf,
301    ngMinErr          = minErr('ng'),
302
303    /** @name angular */
304    angular           = window.angular || (window.angular = {}),
305    angularModule,
306    uid               = 0;
307
308// Support: IE 9-11 only
309/**
310 * documentMode is an IE-only property
311 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
312 */
313msie = window.document.documentMode;
314
315
316/**
317 * @private
318 * @param {*} obj
319 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
320 *                   String ...)
321 */
322function isArrayLike(obj) {
323
324  // `null`, `undefined` and `window` are not array-like
325  if (obj == null || isWindow(obj)) return false;
326
327  // arrays, strings and jQuery/jqLite objects are array like
328  // * jqLite is either the jQuery or jqLite constructor function
329  // * we have to check the existence of jqLite first as this method is called
330  //   via the forEach method when constructing the jqLite object in the first place
331  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
332
333  // Support: iOS 8.2 (not reproducible in simulator)
334  // "length" in obj used to prevent JIT error (gh-11508)
335  var length = 'length' in Object(obj) && obj.length;
336
337  // NodeList objects (with `item` method) and
338  // other objects with suitable length characteristics are array-like
339  return isNumber(length) && (length >= 0 && (length - 1) in obj || typeof obj.item === 'function');
340
341}
342
343/**
344 * @ngdoc function
345 * @name angular.forEach
346 * @module ng
347 * @kind function
348 *
349 * @description
350 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
351 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
352 * is the value of an object property or an array element, `key` is the object property key or
353 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
354 *
355 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
356 * using the `hasOwnProperty` method.
357 *
358 * Unlike ES262's
359 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
360 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
361 * return the value provided.
362 *
363   ```js
364     var values = {name: 'misko', gender: 'male'};
365     var log = [];
366     angular.forEach(values, function(value, key) {
367       this.push(key + ': ' + value);
368     }, log);
369     expect(log).toEqual(['name: misko', 'gender: male']);
370   ```
371 *
372 * @param {Object|Array} obj Object to iterate over.
373 * @param {Function} iterator Iterator function.
374 * @param {Object=} context Object to become context (`this`) for the iterator function.
375 * @returns {Object|Array} Reference to `obj`.
376 */
377
378function forEach(obj, iterator, context) {
379  var key, length;
380  if (obj) {
381    if (isFunction(obj)) {
382      for (key in obj) {
383        if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
384          iterator.call(context, obj[key], key, obj);
385        }
386      }
387    } else if (isArray(obj) || isArrayLike(obj)) {
388      var isPrimitive = typeof obj !== 'object';
389      for (key = 0, length = obj.length; key < length; key++) {
390        if (isPrimitive || key in obj) {
391          iterator.call(context, obj[key], key, obj);
392        }
393      }
394    } else if (obj.forEach && obj.forEach !== forEach) {
395        obj.forEach(iterator, context, obj);
396    } else if (isBlankObject(obj)) {
397      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
398      for (key in obj) {
399        iterator.call(context, obj[key], key, obj);
400      }
401    } else if (typeof obj.hasOwnProperty === 'function') {
402      // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
403      for (key in obj) {
404        if (obj.hasOwnProperty(key)) {
405          iterator.call(context, obj[key], key, obj);
406        }
407      }
408    } else {
409      // Slow path for objects which do not have a method `hasOwnProperty`
410      for (key in obj) {
411        if (hasOwnProperty.call(obj, key)) {
412          iterator.call(context, obj[key], key, obj);
413        }
414      }
415    }
416  }
417  return obj;
418}
419
420function forEachSorted(obj, iterator, context) {
421  var keys = Object.keys(obj).sort();
422  for (var i = 0; i < keys.length; i++) {
423    iterator.call(context, obj[keys[i]], keys[i]);
424  }
425  return keys;
426}
427
428
429/**
430 * when using forEach the params are value, key, but it is often useful to have key, value.
431 * @param {function(string, *)} iteratorFn
432 * @returns {function(*, string)}
433 */
434function reverseParams(iteratorFn) {
435  return function(value, key) {iteratorFn(key, value);};
436}
437
438/**
439 * A consistent way of creating unique IDs in angular.
440 *
441 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
442 * we hit number precision issues in JavaScript.
443 *
444 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
445 *
446 * @returns {number} an unique alpha-numeric string
447 */
448function nextUid() {
449  return ++uid;
450}
451
452
453/**
454 * Set or clear the hashkey for an object.
455 * @param obj object
456 * @param h the hashkey (!truthy to delete the hashkey)
457 */
458function setHashKey(obj, h) {
459  if (h) {
460    obj.$$hashKey = h;
461  } else {
462    delete obj.$$hashKey;
463  }
464}
465
466
467function baseExtend(dst, objs, deep) {
468  var h = dst.$$hashKey;
469
470  for (var i = 0, ii = objs.length; i < ii; ++i) {
471    var obj = objs[i];
472    if (!isObject(obj) && !isFunction(obj)) continue;
473    var keys = Object.keys(obj);
474    for (var j = 0, jj = keys.length; j < jj; j++) {
475      var key = keys[j];
476      var src = obj[key];
477
478      if (deep && isObject(src)) {
479        if (isDate(src)) {
480          dst[key] = new Date(src.valueOf());
481        } else if (isRegExp(src)) {
482          dst[key] = new RegExp(src);
483        } else if (src.nodeName) {
484          dst[key] = src.cloneNode(true);
485        } else if (isElement(src)) {
486          dst[key] = src.clone();
487        } else {
488          if (key !== '__proto__') {
489            if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
490            baseExtend(dst[key], [src], true);
491          }
492        }
493      } else {
494        dst[key] = src;
495      }
496    }
497  }
498
499  setHashKey(dst, h);
500  return dst;
501}
502
503/**
504 * @ngdoc function
505 * @name angular.extend
506 * @module ng
507 * @kind function
508 *
509 * @description
510 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
511 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
512 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
513 *
514 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
515 * {@link angular.merge} for this.
516 *
517 * @param {Object} dst Destination object.
518 * @param {...Object} src Source object(s).
519 * @returns {Object} Reference to `dst`.
520 */
521function extend(dst) {
522  return baseExtend(dst, slice.call(arguments, 1), false);
523}
524
525
526/**
527* @ngdoc function
528* @name angular.merge
529* @module ng
530* @kind function
531*
532* @description
533* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
534* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
535* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
536*
537* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
538* objects, performing a deep copy.
539*
540* @deprecated
541* sinceVersion="1.6.5"
542* This function is deprecated, but will not be removed in the 1.x lifecycle.
543* There are edge cases (see {@link angular.merge#known-issues known issues}) that are not
544* supported by this function. We suggest using another, similar library for all-purpose merging,
545* such as [lodash's merge()](https://lodash.com/docs/4.17.4#merge).
546*
547* @knownIssue
548* This is a list of (known) object types that are not handled correctly by this function:
549* - [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob)
550* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
551* - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient)
552* - AngularJS {@link $rootScope.Scope scopes};
553*
554* `angular.merge` also does not support merging objects with circular references.
555*
556* @param {Object} dst Destination object.
557* @param {...Object} src Source object(s).
558* @returns {Object} Reference to `dst`.
559*/
560function merge(dst) {
561  return baseExtend(dst, slice.call(arguments, 1), true);
562}
563
564
565
566function toInt(str) {
567  return parseInt(str, 10);
568}
569
570var isNumberNaN = Number.isNaN || function isNumberNaN(num) {
571  // eslint-disable-next-line no-self-compare
572  return num !== num;
573};
574
575
576function inherit(parent, extra) {
577  return extend(Object.create(parent), extra);
578}
579
580/**
581 * @ngdoc function
582 * @name angular.noop
583 * @module ng
584 * @kind function
585 *
586 * @description
587 * A function that performs no operations. This function can be useful when writing code in the
588 * functional style.
589   ```js
590     function foo(callback) {
591       var result = calculateResult();
592       (callback || angular.noop)(result);
593     }
594   ```
595 */
596function noop() {}
597noop.$inject = [];
598
599
600/**
601 * @ngdoc function
602 * @name angular.identity
603 * @module ng
604 * @kind function
605 *
606 * @description
607 * A function that returns its first argument. This function is useful when writing code in the
608 * functional style.
609 *
610   ```js
611   function transformer(transformationFn, value) {
612     return (transformationFn || angular.identity)(value);
613   };
614
615   // E.g.
616   function getResult(fn, input) {
617     return (fn || angular.identity)(input);
618   };
619
620   getResult(function(n) { return n * 2; }, 21);   // returns 42
621   getResult(null, 21);                            // returns 21
622   getResult(undefined, 21);                       // returns 21
623   ```
624 *
625 * @param {*} value to be returned.
626 * @returns {*} the value passed in.
627 */
628function identity($) {return $;}
629identity.$inject = [];
630
631
632function valueFn(value) {return function valueRef() {return value;};}
633
634function hasCustomToString(obj) {
635  return isFunction(obj.toString) && obj.toString !== toString;
636}
637
638
639/**
640 * @ngdoc function
641 * @name angular.isUndefined
642 * @module ng
643 * @kind function
644 *
645 * @description
646 * Determines if a reference is undefined.
647 *
648 * @param {*} value Reference to check.
649 * @returns {boolean} True if `value` is undefined.
650 */
651function isUndefined(value) {return typeof value === 'undefined';}
652
653
654/**
655 * @ngdoc function
656 * @name angular.isDefined
657 * @module ng
658 * @kind function
659 *
660 * @description
661 * Determines if a reference is defined.
662 *
663 * @param {*} value Reference to check.
664 * @returns {boolean} True if `value` is defined.
665 */
666function isDefined(value) {return typeof value !== 'undefined';}
667
668
669/**
670 * @ngdoc function
671 * @name angular.isObject
672 * @module ng
673 * @kind function
674 *
675 * @description
676 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
677 * considered to be objects. Note that JavaScript arrays are objects.
678 *
679 * @param {*} value Reference to check.
680 * @returns {boolean} True if `value` is an `Object` but not `null`.
681 */
682function isObject(value) {
683  // http://jsperf.com/isobject4
684  return value !== null && typeof value === 'object';
685}
686
687
688/**
689 * Determine if a value is an object with a null prototype
690 *
691 * @returns {boolean} True if `value` is an `Object` with a null prototype
692 */
693function isBlankObject(value) {
694  return value !== null && typeof value === 'object' && !getPrototypeOf(value);
695}
696
697
698/**
699 * @ngdoc function
700 * @name angular.isString
701 * @module ng
702 * @kind function
703 *
704 * @description
705 * Determines if a reference is a `String`.
706 *
707 * @param {*} value Reference to check.
708 * @returns {boolean} True if `value` is a `String`.
709 */
710function isString(value) {return typeof value === 'string';}
711
712
713/**
714 * @ngdoc function
715 * @name angular.isNumber
716 * @module ng
717 * @kind function
718 *
719 * @description
720 * Determines if a reference is a `Number`.
721 *
722 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
723 *
724 * If you wish to exclude these then you can use the native
725 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
726 * method.
727 *
728 * @param {*} value Reference to check.
729 * @returns {boolean} True if `value` is a `Number`.
730 */
731function isNumber(value) {return typeof value === 'number';}
732
733
734/**
735 * @ngdoc function
736 * @name angular.isDate
737 * @module ng
738 * @kind function
739 *
740 * @description
741 * Determines if a value is a date.
742 *
743 * @param {*} value Reference to check.
744 * @returns {boolean} True if `value` is a `Date`.
745 */
746function isDate(value) {
747  return toString.call(value) === '[object Date]';
748}
749
750
751/**
752 * @ngdoc function
753 * @name angular.isArray
754 * @module ng
755 * @kind function
756 *
757 * @description
758 * Determines if a reference is an `Array`.
759 *
760 * @param {*} value Reference to check.
761 * @returns {boolean} True if `value` is an `Array`.
762 */
763function isArray(arr) {
764  return Array.isArray(arr) || arr instanceof Array;
765}
766
767/**
768 * @description
769 * Determines if a reference is an `Error`.
770 * Loosely based on https://www.npmjs.com/package/iserror
771 *
772 * @param {*} value Reference to check.
773 * @returns {boolean} True if `value` is an `Error`.
774 */
775function isError(value) {
776  var tag = toString.call(value);
777  switch (tag) {
778    case '[object Error]': return true;
779    case '[object Exception]': return true;
780    case '[object DOMException]': return true;
781    default: return value instanceof Error;
782  }
783}
784
785/**
786 * @ngdoc function
787 * @name angular.isFunction
788 * @module ng
789 * @kind function
790 *
791 * @description
792 * Determines if a reference is a `Function`.
793 *
794 * @param {*} value Reference to check.
795 * @returns {boolean} True if `value` is a `Function`.
796 */
797function isFunction(value) {return typeof value === 'function';}
798
799
800/**
801 * Determines if a value is a regular expression object.
802 *
803 * @private
804 * @param {*} value Reference to check.
805 * @returns {boolean} True if `value` is a `RegExp`.
806 */
807function isRegExp(value) {
808  return toString.call(value) === '[object RegExp]';
809}
810
811
812/**
813 * Checks if `obj` is a window object.
814 *
815 * @private
816 * @param {*} obj Object to check
817 * @returns {boolean} True if `obj` is a window obj.
818 */
819function isWindow(obj) {
820  return obj && obj.window === obj;
821}
822
823
824function isScope(obj) {
825  return obj && obj.$evalAsync && obj.$watch;
826}
827
828
829function isFile(obj) {
830  return toString.call(obj) === '[object File]';
831}
832
833
834function isFormData(obj) {
835  return toString.call(obj) === '[object FormData]';
836}
837
838
839function isBlob(obj) {
840  return toString.call(obj) === '[object Blob]';
841}
842
843
844function isBoolean(value) {
845  return typeof value === 'boolean';
846}
847
848
849function isPromiseLike(obj) {
850  return obj && isFunction(obj.then);
851}
852
853
854var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
855function isTypedArray(value) {
856  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
857}
858
859function isArrayBuffer(obj) {
860  return toString.call(obj) === '[object ArrayBuffer]';
861}
862
863
864var trim = function(value) {
865  return isString(value) ? value.trim() : value;
866};
867
868// Copied from:
869// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
870// Prereq: s is a string.
871var escapeForRegexp = function(s) {
872  return s
873    .replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
874    // eslint-disable-next-line no-control-regex
875    .replace(/\x08/g, '\\x08');
876};
877
878
879/**
880 * @ngdoc function
881 * @name angular.isElement
882 * @module ng
883 * @kind function
884 *
885 * @description
886 * Determines if a reference is a DOM element (or wrapped jQuery element).
887 *
888 * @param {*} value Reference to check.
889 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
890 */
891function isElement(node) {
892  return !!(node &&
893    (node.nodeName  // We are a direct element.
894    || (node.prop && node.attr && node.find)));  // We have an on and find method part of jQuery API.
895}
896
897/**
898 * @param str 'key1,key2,...'
899 * @returns {object} in the form of {key1:true, key2:true, ...}
900 */
901function makeMap(str) {
902  var obj = {}, items = str.split(','), i;
903  for (i = 0; i < items.length; i++) {
904    obj[items[i]] = true;
905  }
906  return obj;
907}
908
909
910function nodeName_(element) {
911  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
912}
913
914function includes(array, obj) {
915  return Array.prototype.indexOf.call(array, obj) !== -1;
916}
917
918function arrayRemove(array, value) {
919  var index = array.indexOf(value);
920  if (index >= 0) {
921    array.splice(index, 1);
922  }
923  return index;
924}
925
926/**
927 * @ngdoc function
928 * @name angular.copy
929 * @module ng
930 * @kind function
931 *
932 * @description
933 * Creates a deep copy of `source`, which should be an object or an array. This functions is used
934 * internally, mostly in the change-detection code. It is not intended as an all-purpose copy
935 * function, and has several limitations (see below).
936 *
937 * * If no destination is supplied, a copy of the object or array is created.
938 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
939 *   are deleted and then all elements/properties from the source are copied to it.
940 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
941 * * If `source` is identical to `destination` an exception will be thrown.
942 *
943 * <br />
944 *
945 * <div class="alert alert-warning">
946 *   Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
947 *   and on `destination`) will be ignored.
948 * </div>
949 *
950 * <div class="alert alert-warning">
951 *   `angular.copy` does not check if destination and source are of the same type. It's the
952 *   developer's responsibility to make sure they are compatible.
953 * </div>
954 *
955 * @knownIssue
956 * This is a non-exhaustive list of object types / features that are not handled correctly by
957 * `angular.copy`. Note that since this functions is used by the change detection code, this
958 * means binding or watching objects of these types (or that include these types) might not work
959 * correctly.
960 * - [`File`](https://developer.mozilla.org/docs/Web/API/File)
961 * - [`Map`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map)
962 * - [`ImageData`](https://developer.mozilla.org/docs/Web/API/ImageData)
963 * - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
964 * - [`Set`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set)
965 * - [`WeakMap`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
966 * - [`getter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/
967 *   [`setter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)
968 *
969 * @param {*} source The source that will be used to make a copy. Can be any type, including
970 *     primitives, `null`, and `undefined`.
971 * @param {(Object|Array)=} destination Destination into which the source is copied. If provided,
972 *     must be of the same type as `source`.
973 * @returns {*} The copy or updated `destination`, if `destination` was specified.
974 *
975 * @example
976  <example module="copyExample" name="angular-copy">
977    <file name="index.html">
978      <div ng-controller="ExampleController">
979        <form novalidate class="simple-form">
980          <label>Name: <input type="text" ng-model="user.name" /></label><br />
981          <label>Age:  <input type="number" ng-model="user.age" /></label><br />
982          Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
983                  <label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
984          <button ng-click="reset()">RESET</button>
985          <button ng-click="update(user)">SAVE</button>
986        </form>
987        <pre>form = {{user | json}}</pre>
988        <pre>leader = {{leader | json}}</pre>
989      </div>
990    </file>
991    <file name="script.js">
992      // Module: copyExample
993      angular.
994        module('copyExample', []).
995        controller('ExampleController', ['$scope', function($scope) {
996          $scope.leader = {};
997
998          $scope.reset = function() {
999            // Example with 1 argument
1000            $scope.user = angular.copy($scope.leader);
1001          };
1002
1003          $scope.update = function(user) {
1004            // Example with 2 arguments
1005            angular.copy(user, $scope.leader);
1006          };
1007
1008          $scope.reset();
1009        }]);
1010    </file>
1011  </example>
1012 */
1013function copy(source, destination, maxDepth) {
1014  var stackSource = [];
1015  var stackDest = [];
1016  maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
1017
1018  if (destination) {
1019    if (isTypedArray(destination) || isArrayBuffer(destination)) {
1020      throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.');
1021    }
1022    if (source === destination) {
1023      throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.');
1024    }
1025
1026    // Empty the destination object
1027    if (isArray(destination)) {
1028      destination.length = 0;
1029    } else {
1030      forEach(destination, function(value, key) {
1031        if (key !== '$$hashKey') {
1032          delete destination[key];
1033        }
1034      });
1035    }
1036
1037    stackSource.push(source);
1038    stackDest.push(destination);
1039    return copyRecurse(source, destination, maxDepth);
1040  }
1041
1042  return copyElement(source, maxDepth);
1043
1044  function copyRecurse(source, destination, maxDepth) {
1045    maxDepth--;
1046    if (maxDepth < 0) {
1047      return '...';
1048    }
1049    var h = destination.$$hashKey;
1050    var key;
1051    if (isArray(source)) {
1052      for (var i = 0, ii = source.length; i < ii; i++) {
1053        destination.push(copyElement(source[i], maxDepth));
1054      }
1055    } else if (isBlankObject(source)) {
1056      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
1057      for (key in source) {
1058        destination[key] = copyElement(source[key], maxDepth);
1059      }
1060    } else if (source && typeof source.hasOwnProperty === 'function') {
1061      // Slow path, which must rely on hasOwnProperty
1062      for (key in source) {
1063        if (source.hasOwnProperty(key)) {
1064          destination[key] = copyElement(source[key], maxDepth);
1065        }
1066      }
1067    } else {
1068      // Slowest path --- hasOwnProperty can't be called as a method
1069      for (key in source) {
1070        if (hasOwnProperty.call(source, key)) {
1071          destination[key] = copyElement(source[key], maxDepth);
1072        }
1073      }
1074    }
1075    setHashKey(destination, h);
1076    return destination;
1077  }
1078
1079  function copyElement(source, maxDepth) {
1080    // Simple values
1081    if (!isObject(source)) {
1082      return source;
1083    }
1084
1085    // Already copied values
1086    var index = stackSource.indexOf(source);
1087    if (index !== -1) {
1088      return stackDest[index];
1089    }
1090
1091    if (isWindow(source) || isScope(source)) {
1092      throw ngMinErr('cpws',
1093        'Can\'t copy! Making copies of Window or Scope instances is not supported.');
1094    }
1095
1096    var needsRecurse = false;
1097    var destination = copyType(source);
1098
1099    if (destination === undefined) {
1100      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
1101      needsRecurse = true;
1102    }
1103
1104    stackSource.push(source);
1105    stackDest.push(destination);
1106
1107    return needsRecurse
1108      ? copyRecurse(source, destination, maxDepth)
1109      : destination;
1110  }
1111
1112  function copyType(source) {
1113    switch (toString.call(source)) {
1114      case '[object Int8Array]':
1115      case '[object Int16Array]':
1116      case '[object Int32Array]':
1117      case '[object Float32Array]':
1118      case '[object Float64Array]':
1119      case '[object Uint8Array]':
1120      case '[object Uint8ClampedArray]':
1121      case '[object Uint16Array]':
1122      case '[object Uint32Array]':
1123        return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
1124
1125      case '[object ArrayBuffer]':
1126        // Support: IE10
1127        if (!source.slice) {
1128          // If we're in this case we know the environment supports ArrayBuffer
1129          /* eslint-disable no-undef */
1130          var copied = new ArrayBuffer(source.byteLength);
1131          new Uint8Array(copied).set(new Uint8Array(source));
1132          /* eslint-enable */
1133          return copied;
1134        }
1135        return source.slice(0);
1136
1137      case '[object Boolean]':
1138      case '[object Number]':
1139      case '[object String]':
1140      case '[object Date]':
1141        return new source.constructor(source.valueOf());
1142
1143      case '[object RegExp]':
1144        var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
1145        re.lastIndex = source.lastIndex;
1146        return re;
1147
1148      case '[object Blob]':
1149        return new source.constructor([source], {type: source.type});
1150    }
1151
1152    if (isFunction(source.cloneNode)) {
1153      return source.cloneNode(true);
1154    }
1155  }
1156}
1157
1158
1159// eslint-disable-next-line no-self-compare
1160function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }
1161
1162
1163/**
1164 * @ngdoc function
1165 * @name angular.equals
1166 * @module ng
1167 * @kind function
1168 *
1169 * @description
1170 * Determines if two objects or two values are equivalent. Supports value types, regular
1171 * expressions, arrays and objects.
1172 *
1173 * Two objects or values are considered equivalent if at least one of the following is true:
1174 *
1175 * * Both objects or values pass `===` comparison.
1176 * * Both objects or values are of the same type and all of their properties are equal by
1177 *   comparing them with `angular.equals`.
1178 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1179 * * Both values represent the same regular expression (In JavaScript,
1180 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1181 *   representation matches).
1182 *
1183 * During a property comparison, properties of `function` type and properties with names
1184 * that begin with `$` are ignored.
1185 *
1186 * Scope and DOMWindow objects are being compared only by identify (`===`).
1187 *
1188 * @param {*} o1 Object or value to compare.
1189 * @param {*} o2 Object or value to compare.
1190 * @returns {boolean} True if arguments are equal.
1191 *
1192 * @example
1193   <example module="equalsExample" name="equalsExample">
1194     <file name="index.html">
1195      <div ng-controller="ExampleController">
1196        <form novalidate>
1197          <h3>User 1</h3>
1198          Name: <input type="text" ng-model="user1.name">
1199          Age: <input type="number" ng-model="user1.age">
1200
1201          <h3>User 2</h3>
1202          Name: <input type="text" ng-model="user2.name">
1203          Age: <input type="number" ng-model="user2.age">
1204
1205          <div>
1206            <br/>
1207            <input type="button" value="Compare" ng-click="compare()">
1208          </div>
1209          User 1: <pre>{{user1 | json}}</pre>
1210          User 2: <pre>{{user2 | json}}</pre>
1211          Equal: <pre>{{result}}</pre>
1212        </form>
1213      </div>
1214    </file>
1215    <file name="script.js">
1216        angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
1217          $scope.user1 = {};
1218          $scope.user2 = {};
1219          $scope.compare = function() {
1220            $scope.result = angular.equals($scope.user1, $scope.user2);
1221          };
1222        }]);
1223    </file>
1224  </example>
1225 */
1226function equals(o1, o2) {
1227  if (o1 === o2) return true;
1228  if (o1 === null || o2 === null) return false;
1229  // eslint-disable-next-line no-self-compare
1230  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1231  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1232  if (t1 === t2 && t1 === 'object') {
1233    if (isArray(o1)) {
1234      if (!isArray(o2)) return false;
1235      if ((length = o1.length) === o2.length) {
1236        for (key = 0; key < length; key++) {
1237          if (!equals(o1[key], o2[key])) return false;
1238        }
1239        return true;
1240      }
1241    } else if (isDate(o1)) {
1242      if (!isDate(o2)) return false;
1243      return simpleCompare(o1.getTime(), o2.getTime());
1244    } else if (isRegExp(o1)) {
1245      if (!isRegExp(o2)) return false;
1246      return o1.toString() === o2.toString();
1247    } else {
1248      if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1249        isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1250      keySet = createMap();
1251      for (key in o1) {
1252        if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1253        if (!equals(o1[key], o2[key])) return false;
1254        keySet[key] = true;
1255      }
1256      for (key in o2) {
1257        if (!(key in keySet) &&
1258            key.charAt(0) !== '$' &&
1259            isDefined(o2[key]) &&
1260            !isFunction(o2[key])) return false;
1261      }
1262      return true;
1263    }
1264  }
1265  return false;
1266}
1267
1268var csp = function() {
1269  if (!isDefined(csp.rules)) {
1270
1271
1272    var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1273                    window.document.querySelector('[data-ng-csp]'));
1274
1275    if (ngCspElement) {
1276      var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1277                    ngCspElement.getAttribute('data-ng-csp');
1278      csp.rules = {
1279        noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1280        noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1281      };
1282    } else {
1283      csp.rules = {
1284        noUnsafeEval: noUnsafeEval(),
1285        noInlineStyle: false
1286      };
1287    }
1288  }
1289
1290  return csp.rules;
1291
1292  function noUnsafeEval() {
1293    try {
1294      // eslint-disable-next-line no-new, no-new-func
1295      new Function('');
1296      return false;
1297    } catch (e) {
1298      return true;
1299    }
1300  }
1301};
1302
1303/**
1304 * @ngdoc directive
1305 * @module ng
1306 * @name ngJq
1307 *
1308 * @element ANY
1309 * @param {string=} ngJq the name of the library available under `window`
1310 * to be used for angular.element
1311 * @description
1312 * Use this directive to force the angular.element library.  This should be
1313 * used to force either jqLite by leaving ng-jq blank or setting the name of
1314 * the jquery variable under window (eg. jQuery).
1315 *
1316 * Since AngularJS looks for this directive when it is loaded (doesn't wait for the
1317 * DOMContentLoaded event), it must be placed on an element that comes before the script
1318 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1319 * others ignored.
1320 *
1321 * @example
1322 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1323 ```html
1324 <!doctype html>
1325 <html ng-app ng-jq>
1326 ...
1327 ...
1328 </html>
1329 ```
1330 * @example
1331 * This example shows how to use a jQuery based library of a different name.
1332 * The library name must be available at the top most 'window'.
1333 ```html
1334 <!doctype html>
1335 <html ng-app ng-jq="jQueryLib">
1336 ...
1337 ...
1338 </html>
1339 ```
1340 */
1341var jq = function() {
1342  if (isDefined(jq.name_)) return jq.name_;
1343  var el;
1344  var i, ii = ngAttrPrefixes.length, prefix, name;
1345  for (i = 0; i < ii; ++i) {
1346    prefix = ngAttrPrefixes[i];
1347    el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]');
1348    if (el) {
1349      name = el.getAttribute(prefix + 'jq');
1350      break;
1351    }
1352  }
1353
1354  return (jq.name_ = name);
1355};
1356
1357function concat(array1, array2, index) {
1358  return array1.concat(slice.call(array2, index));
1359}
1360
1361function sliceArgs(args, startIndex) {
1362  return slice.call(args, startIndex || 0);
1363}
1364
1365
1366/**
1367 * @ngdoc function
1368 * @name angular.bind
1369 * @module ng
1370 * @kind function
1371 *
1372 * @description
1373 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1374 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1375 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1376 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1377 *
1378 * @param {Object} self Context which `fn` should be evaluated in.
1379 * @param {function()} fn Function to be bound.
1380 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1381 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1382 */
1383function bind(self, fn) {
1384  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1385  if (isFunction(fn) && !(fn instanceof RegExp)) {
1386    return curryArgs.length
1387      ? function() {
1388          return arguments.length
1389            ? fn.apply(self, concat(curryArgs, arguments, 0))
1390            : fn.apply(self, curryArgs);
1391        }
1392      : function() {
1393          return arguments.length
1394            ? fn.apply(self, arguments)
1395            : fn.call(self);
1396        };
1397  } else {
1398    // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
1399    return fn;
1400  }
1401}
1402
1403
1404function toJsonReplacer(key, value) {
1405  var val = value;
1406
1407  if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1408    val = undefined;
1409  } else if (isWindow(value)) {
1410    val = '$WINDOW';
1411  } else if (value &&  window.document === value) {
1412    val = '$DOCUMENT';
1413  } else if (isScope(value)) {
1414    val = '$SCOPE';
1415  }
1416
1417  return val;
1418}
1419
1420
1421/**
1422 * @ngdoc function
1423 * @name angular.toJson
1424 * @module ng
1425 * @kind function
1426 *
1427 * @description
1428 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1429 * stripped since AngularJS uses this notation internally.
1430 *
1431 * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON.
1432 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1433 *    If set to an integer, the JSON output will contain that many spaces per indentation.
1434 * @returns {string|undefined} JSON-ified string representing `obj`.
1435 * @knownIssue
1436 *
1437 * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
1438 * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
1439 * `Date.prototype.toJSON` method as follows:
1440 *
1441 * ```
1442 * var _DatetoJSON = Date.prototype.toJSON;
1443 * Date.prototype.toJSON = function() {
1444 *   try {
1445 *     return _DatetoJSON.call(this);
1446 *   } catch(e) {
1447 *     if (e instanceof RangeError) {
1448 *       return null;
1449 *     }
1450 *     throw e;
1451 *   }
1452 * };
1453 * ```
1454 *
1455 * See https://github.com/angular/angular.js/pull/14221 for more information.
1456 */
1457function toJson(obj, pretty) {
1458  if (isUndefined(obj)) return undefined;
1459  if (!isNumber(pretty)) {
1460    pretty = pretty ? 2 : null;
1461  }
1462  return JSON.stringify(obj, toJsonReplacer, pretty);
1463}
1464
1465
1466/**
1467 * @ngdoc function
1468 * @name angular.fromJson
1469 * @module ng
1470 * @kind function
1471 *
1472 * @description
1473 * Deserializes a JSON string.
1474 *
1475 * @param {string} json JSON string to deserialize.
1476 * @returns {Object|Array|string|number} Deserialized JSON string.
1477 */
1478function fromJson(json) {
1479  return isString(json)
1480      ? JSON.parse(json)
1481      : json;
1482}
1483
1484
1485var ALL_COLONS = /:/g;
1486function timezoneToOffset(timezone, fallback) {
1487  // Support: IE 9-11 only, Edge 13-15+
1488  // IE/Edge do not "understand" colon (`:`) in timezone
1489  timezone = timezone.replace(ALL_COLONS, '');
1490  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1491  return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1492}
1493
1494
1495function addDateMinutes(date, minutes) {
1496  date = new Date(date.getTime());
1497  date.setMinutes(date.getMinutes() + minutes);
1498  return date;
1499}
1500
1501
1502function convertTimezoneToLocal(date, timezone, reverse) {
1503  reverse = reverse ? -1 : 1;
1504  var dateTimezoneOffset = date.getTimezoneOffset();
1505  var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1506  return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
1507}
1508
1509
1510/**
1511 * @returns {string} Returns the string representation of the element.
1512 */
1513function startingTag(element) {
1514  element = jqLite(element).clone().empty();
1515  var elemHtml = jqLite('<div></div>').append(element).html();
1516  try {
1517    return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1518        elemHtml.
1519          match(/^(<[^>]+>)/)[1].
1520          replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
1521  } catch (e) {
1522    return lowercase(elemHtml);
1523  }
1524
1525}
1526
1527
1528/////////////////////////////////////////////////
1529
1530/**
1531 * Tries to decode the URI component without throwing an exception.
1532 *
1533 * @private
1534 * @param str value potential URI component to check.
1535 * @returns {boolean} True if `value` can be decoded
1536 * with the decodeURIComponent function.
1537 */
1538function tryDecodeURIComponent(value) {
1539  try {
1540    return decodeURIComponent(value);
1541  } catch (e) {
1542    // Ignore any invalid uri component.
1543  }
1544}
1545
1546
1547/**
1548 * Parses an escaped url query string into key-value pairs.
1549 * @returns {Object.<string,boolean|Array>}
1550 */
1551function parseKeyValue(/**string*/keyValue) {
1552  var obj = {};
1553  forEach((keyValue || '').split('&'), function(keyValue) {
1554    var splitPoint, key, val;
1555    if (keyValue) {
1556      key = keyValue = keyValue.replace(/\+/g,'%20');
1557      splitPoint = keyValue.indexOf('=');
1558      if (splitPoint !== -1) {
1559        key = keyValue.substring(0, splitPoint);
1560        val = keyValue.substring(splitPoint + 1);
1561      }
1562      key = tryDecodeURIComponent(key);
1563      if (isDefined(key)) {
1564        val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1565        if (!hasOwnProperty.call(obj, key)) {
1566          obj[key] = val;
1567        } else if (isArray(obj[key])) {
1568          obj[key].push(val);
1569        } else {
1570          obj[key] = [obj[key],val];
1571        }
1572      }
1573    }
1574  });
1575  return obj;
1576}
1577
1578function toKeyValue(obj) {
1579  var parts = [];
1580  forEach(obj, function(value, key) {
1581    if (isArray(value)) {
1582      forEach(value, function(arrayValue) {
1583        parts.push(encodeUriQuery(key, true) +
1584                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1585      });
1586    } else {
1587    parts.push(encodeUriQuery(key, true) +
1588               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1589    }
1590  });
1591  return parts.length ? parts.join('&') : '';
1592}
1593
1594
1595/**
1596 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1597 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1598 * segments:
1599 *    segment       = *pchar
1600 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1601 *    pct-encoded   = "%" HEXDIG HEXDIG
1602 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1603 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1604 *                     / "*" / "+" / "," / ";" / "="
1605 */
1606function encodeUriSegment(val) {
1607  return encodeUriQuery(val, true).
1608             replace(/%26/gi, '&').
1609             replace(/%3D/gi, '=').
1610             replace(/%2B/gi, '+');
1611}
1612
1613
1614/**
1615 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1616 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1617 * encoded per http://tools.ietf.org/html/rfc3986:
1618 *    query         = *( pchar / "/" / "?" )
1619 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1620 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1621 *    pct-encoded   = "%" HEXDIG HEXDIG
1622 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1623 *                     / "*" / "+" / "," / ";" / "="
1624 */
1625function encodeUriQuery(val, pctEncodeSpaces) {
1626  return encodeURIComponent(val).
1627             replace(/%40/gi, '@').
1628             replace(/%3A/gi, ':').
1629             replace(/%24/g, '$').
1630             replace(/%2C/gi, ',').
1631             replace(/%3B/gi, ';').
1632             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1633}
1634
1635var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1636
1637function getNgAttribute(element, ngAttr) {
1638  var attr, i, ii = ngAttrPrefixes.length;
1639  for (i = 0; i < ii; ++i) {
1640    attr = ngAttrPrefixes[i] + ngAttr;
1641    if (isString(attr = element.getAttribute(attr))) {
1642      return attr;
1643    }
1644  }
1645  return null;
1646}
1647
1648function allowAutoBootstrap(document) {
1649  var script = document.currentScript;
1650
1651  if (!script) {
1652    // Support: IE 9-11 only
1653    // IE does not have `document.currentScript`
1654    return true;
1655  }
1656
1657  // If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
1658  if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
1659    return false;
1660  }
1661
1662  var attributes = script.attributes;
1663  var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
1664
1665  return srcs.every(function(src) {
1666    if (!src) {
1667      return true;
1668    }
1669    if (!src.value) {
1670      return false;
1671    }
1672
1673    var link = document.createElement('a');
1674    link.href = src.value;
1675
1676    if (document.location.origin === link.origin) {
1677      // Same-origin resources are always allowed, even for banned URL schemes.
1678      return true;
1679    }
1680    // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
1681    // This is to prevent angular.js bundled with browser extensions from being used to bypass the
1682    // content security policy in web pages and other browser extensions.
1683    switch (link.protocol) {
1684      case 'http:':
1685      case 'https:':
1686      case 'ftp:':
1687      case 'blob:':
1688      case 'file:':
1689      case 'data:':
1690        return true;
1691      default:
1692        return false;
1693    }
1694  });
1695}
1696
1697// Cached as it has to run during loading so that document.currentScript is available.
1698var isAutoBootstrapAllowed = allowAutoBootstrap(window.document);
1699
1700/**
1701 * @ngdoc directive
1702 * @name ngApp
1703 * @module ng
1704 *
1705 * @element ANY
1706 * @param {angular.Module} ngApp an optional application
1707 *   {@link angular.module module} name to load.
1708 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1709 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1710 *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1711 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1712 *   tracking down the root of these bugs.
1713 *
1714 * @description
1715 *
1716 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1717 * designates the **root element** of the application and is typically placed near the root element
1718 * of the page - e.g. on the `<body>` or `<html>` tags.
1719 *
1720 * There are a few things to keep in mind when using `ngApp`:
1721 * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1722 *   found in the document will be used to define the root element to auto-bootstrap as an
1723 *   application. To run multiple applications in an HTML document you must manually bootstrap them using
1724 *   {@link angular.bootstrap} instead.
1725 * - AngularJS applications cannot be nested within each other.
1726 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
1727 *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
1728 *   {@link ngRoute.ngView `ngView`}.
1729 *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1730 *   causing animations to stop working and making the injector inaccessible from outside the app.
1731 *
1732 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1733 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1734 * should contain the application code needed or have dependencies on other modules that will
1735 * contain the code. See {@link angular.module} for more information.
1736 *
1737 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1738 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1739 * would not be resolved to `3`.
1740 *
1741 * @example
1742 *
1743 * ### Simple Usage
1744 *
1745 * `ngApp` is the easiest, and most common way to bootstrap an application.
1746 *
1747 <example module="ngAppDemo" name="ng-app">
1748   <file name="index.html">
1749   <div ng-controller="ngAppDemoController">
1750     I can add: {{a}} + {{b}} =  {{ a+b }}
1751   </div>
1752   </file>
1753   <file name="script.js">
1754   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1755     $scope.a = 1;
1756     $scope.b = 2;
1757   });
1758   </file>
1759 </example>
1760 *
1761 * @example
1762 *
1763 * ### With `ngStrictDi`
1764 *
1765 * Using `ngStrictDi`, you would see something like this:
1766 *
1767 <example ng-app-included="true" name="strict-di">
1768   <file name="index.html">
1769   <div ng-app="ngAppStrictDemo" ng-strict-di>
1770       <div ng-controller="GoodController1">
1771           I can add: {{a}} + {{b}} =  {{ a+b }}
1772
1773           <p>This renders because the controller does not fail to
1774              instantiate, by using explicit annotation style (see
1775              script.js for details)
1776           </p>
1777       </div>
1778
1779       <div ng-controller="GoodController2">
1780           Name: <input ng-model="name"><br />
1781           Hello, {{name}}!
1782
1783           <p>This renders because the controller does not fail to
1784              instantiate, by using explicit annotation style
1785              (see script.js for details)
1786           </p>
1787       </div>
1788
1789       <div ng-controller="BadController">
1790           I can add: {{a}} + {{b}} =  {{ a+b }}
1791
1792           <p>The controller could not be instantiated, due to relying
1793              on automatic function annotations (which are disabled in
1794              strict mode). As such, the content of this section is not
1795              interpolated, and there should be an error in your web console.
1796           </p>
1797       </div>
1798   </div>
1799   </file>
1800   <file name="script.js">
1801   angular.module('ngAppStrictDemo', [])
1802     // BadController will fail to instantiate, due to relying on automatic function annotation,
1803     // rather than an explicit annotation
1804     .controller('BadController', function($scope) {
1805       $scope.a = 1;
1806       $scope.b = 2;
1807     })
1808     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1809     // due to using explicit annotations using the array style and $inject property, respectively.
1810     .controller('GoodController1', ['$scope', function($scope) {
1811       $scope.a = 1;
1812       $scope.b = 2;
1813     }])
1814     .controller('GoodController2', GoodController2);
1815     function GoodController2($scope) {
1816       $scope.name = 'World';
1817     }
1818     GoodController2.$inject = ['$scope'];
1819   </file>
1820   <file name="style.css">
1821   div[ng-controller] {
1822       margin-bottom: 1em;
1823       -webkit-border-radius: 4px;
1824       border-radius: 4px;
1825       border: 1px solid;
1826       padding: .5em;
1827   }
1828   div[ng-controller^=Good] {
1829       border-color: #d6e9c6;
1830       background-color: #dff0d8;
1831       color: #3c763d;
1832   }
1833   div[ng-controller^=Bad] {
1834       border-color: #ebccd1;
1835       background-color: #f2dede;
1836       color: #a94442;
1837       margin-bottom: 0;
1838   }
1839   </file>
1840 </example>
1841 */
1842function angularInit(element, bootstrap) {
1843  var appElement,
1844      module,
1845      config = {};
1846
1847  // The element `element` has priority over any other element.
1848  forEach(ngAttrPrefixes, function(prefix) {
1849    var name = prefix + 'app';
1850
1851    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1852      appElement = element;
1853      module = element.getAttribute(name);
1854    }
1855  });
1856  forEach(ngAttrPrefixes, function(prefix) {
1857    var name = prefix + 'app';
1858    var candidate;
1859
1860    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1861      appElement = candidate;
1862      module = candidate.getAttribute(name);
1863    }
1864  });
1865  if (appElement) {
1866    if (!isAutoBootstrapAllowed) {
1867      window.console.error('AngularJS: disabling automatic bootstrap. <script> protocol indicates ' +
1868          'an extension, document.location.href does not match.');
1869      return;
1870    }
1871    config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
1872    bootstrap(appElement, module ? [module] : [], config);
1873  }
1874}
1875
1876/**
1877 * @ngdoc function
1878 * @name angular.bootstrap
1879 * @module ng
1880 * @description
1881 * Use this function to manually start up AngularJS application.
1882 *
1883 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
1884 *
1885 * AngularJS will detect if it has been loaded into the browser more than once and only allow the
1886 * first loaded script to be bootstrapped and will report a warning to the browser console for
1887 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1888 * multiple instances of AngularJS try to work on the DOM.
1889 *
1890 * <div class="alert alert-warning">
1891 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
1892 * They must use {@link ng.directive:ngApp ngApp}.
1893 * </div>
1894 *
1895 * <div class="alert alert-warning">
1896 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
1897 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
1898 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1899 * causing animations to stop working and making the injector inaccessible from outside the app.
1900 * </div>
1901 *
1902 * ```html
1903 * <!doctype html>
1904 * <html>
1905 * <body>
1906 * <div ng-controller="WelcomeController">
1907 *   {{greeting}}
1908 * </div>
1909 *
1910 * <script src="angular.js"></script>
1911 * <script>
1912 *   var app = angular.module('demo', [])
1913 *   .controller('WelcomeController', function($scope) {
1914 *       $scope.greeting = 'Welcome!';
1915 *   });
1916 *   angular.bootstrap(document, ['demo']);
1917 * </script>
1918 * </body>
1919 * </html>
1920 * ```
1921 *
1922 * @param {DOMElement} element DOM element which is the root of AngularJS application.
1923 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1924 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1925 *     function that will be invoked by the injector as a `config` block.
1926 *     See: {@link angular.module modules}
1927 * @param {Object=} config an object for defining configuration options for the application. The
1928 *     following keys are supported:
1929 *
1930 * * `strictDi` - disable automatic function annotation for the application. This is meant to
1931 *   assist in finding bugs which break minified code. Defaults to `false`.
1932 *
1933 * @returns {auto.$injector} Returns the newly created injector for this app.
1934 */
1935function bootstrap(element, modules, config) {
1936  if (!isObject(config)) config = {};
1937  var defaultConfig = {
1938    strictDi: false
1939  };
1940  config = extend(defaultConfig, config);
1941  var doBootstrap = function() {
1942    element = jqLite(element);
1943
1944    if (element.injector()) {
1945      var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1946      // Encode angle brackets to prevent input from being sanitized to empty string #8683.
1947      throw ngMinErr(
1948          'btstrpd',
1949          'App already bootstrapped with this element \'{0}\'',
1950          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1951    }
1952
1953    modules = modules || [];
1954    modules.unshift(['$provide', function($provide) {
1955      $provide.value('$rootElement', element);
1956    }]);
1957
1958    if (config.debugInfoEnabled) {
1959      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1960      modules.push(['$compileProvider', function($compileProvider) {
1961        $compileProvider.debugInfoEnabled(true);
1962      }]);
1963    }
1964
1965    modules.unshift('ng');
1966    var injector = createInjector(modules, config.strictDi);
1967    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1968       function bootstrapApply(scope, element, compile, injector) {
1969        scope.$apply(function() {
1970          element.data('$injector', injector);
1971          compile(element)(scope);
1972        });
1973      }]
1974    );
1975    return injector;
1976  };
1977
1978  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1979  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1980
1981  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1982    config.debugInfoEnabled = true;
1983    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1984  }
1985
1986  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1987    return doBootstrap();
1988  }
1989
1990  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1991  angular.resumeBootstrap = function(extraModules) {
1992    forEach(extraModules, function(module) {
1993      modules.push(module);
1994    });
1995    return doBootstrap();
1996  };
1997
1998  if (isFunction(angular.resumeDeferredBootstrap)) {
1999    angular.resumeDeferredBootstrap();
2000  }
2001}
2002
2003/**
2004 * @ngdoc function
2005 * @name angular.reloadWithDebugInfo
2006 * @module ng
2007 * @description
2008 * Use this function to reload the current application with debug information turned on.
2009 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
2010 *
2011 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
2012 */
2013function reloadWithDebugInfo() {
2014  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
2015  window.location.reload();
2016}
2017
2018/**
2019 * @name angular.getTestability
2020 * @module ng
2021 * @description
2022 * Get the testability service for the instance of AngularJS on the given
2023 * element.
2024 * @param {DOMElement} element DOM element which is the root of AngularJS application.
2025 */
2026function getTestability(rootElement) {
2027  var injector = angular.element(rootElement).injector();
2028  if (!injector) {
2029    throw ngMinErr('test',
2030      'no injector found for element argument to getTestability');
2031  }
2032  return injector.get('$$testability');
2033}
2034
2035var SNAKE_CASE_REGEXP = /[A-Z]/g;
2036function snake_case(name, separator) {
2037  separator = separator || '_';
2038  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
2039    return (pos ? separator : '') + letter.toLowerCase();
2040  });
2041}
2042
2043var bindJQueryFired = false;
2044function bindJQuery() {
2045  var originalCleanData;
2046
2047  if (bindJQueryFired) {
2048    return;
2049  }
2050
2051  // bind to jQuery if present;
2052  var jqName = jq();
2053  jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
2054           !jqName             ? undefined     :   // use jqLite
2055                                 window[jqName];   // use jQuery specified by `ngJq`
2056
2057  // Use jQuery if it exists with proper functionality, otherwise default to us.
2058  // AngularJS 1.2+ requires jQuery 1.7+ for on()/off() support.
2059  // AngularJS 1.3+ technically requires at least jQuery 2.1+ but it may work with older
2060  // versions. It will not work for sure with jQuery <1.7, though.
2061  if (jQuery && jQuery.fn.on) {
2062    jqLite = jQuery;
2063    extend(jQuery.fn, {
2064      scope: JQLitePrototype.scope,
2065      isolateScope: JQLitePrototype.isolateScope,
2066      controller: /** @type {?} */ (JQLitePrototype).controller,
2067      injector: JQLitePrototype.injector,
2068      inheritedData: JQLitePrototype.inheritedData
2069    });
2070  } else {
2071    jqLite = JQLite;
2072  }
2073
2074  // All nodes removed from the DOM via various jqLite/jQuery APIs like .remove()
2075  // are passed through jqLite/jQuery.cleanData. Monkey-patch this method to fire
2076  // the $destroy event on all removed nodes.
2077  originalCleanData = jqLite.cleanData;
2078  jqLite.cleanData = function(elems) {
2079    var events;
2080    for (var i = 0, elem; (elem = elems[i]) != null; i++) {
2081      events = (jqLite._data(elem) || {}).events;
2082      if (events && events.$destroy) {
2083        jqLite(elem).triggerHandler('$destroy');
2084      }
2085    }
2086    originalCleanData(elems);
2087  };
2088
2089  angular.element = jqLite;
2090
2091  // Prevent double-proxying.
2092  bindJQueryFired = true;
2093}
2094
2095/**
2096 * @ngdoc function
2097 * @name angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement
2098 * @module ng
2099 * @kind function
2100 *
2101 * @description
2102 * Restores the pre-1.8 behavior of jqLite that turns XHTML-like strings like
2103 * `<div /><span />` to `<div></div><span></span>` instead of `<div><span></span></div>`.
2104 * The new behavior is a security fix. Thus, if you need to call this function, please try to adjust
2105 * your code for this change and remove your use of this function as soon as possible.
2106
2107 * Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
2108 * [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
2109 * about the workarounds.
2110 */
2111function UNSAFE_restoreLegacyJqLiteXHTMLReplacement() {
2112  JQLite.legacyXHTMLReplacement = true;
2113}
2114
2115/**
2116 * throw error if the argument is falsy.
2117 */
2118function assertArg(arg, name, reason) {
2119  if (!arg) {
2120    throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
2121  }
2122  return arg;
2123}
2124
2125function assertArgFn(arg, name, acceptArrayAnnotation) {
2126  if (acceptArrayAnnotation && isArray(arg)) {
2127      arg = arg[arg.length - 1];
2128  }
2129
2130  assertArg(isFunction(arg), name, 'not a function, got ' +
2131      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
2132  return arg;
2133}
2134
2135/**
2136 * throw error if the name given is hasOwnProperty
2137 * @param  {String} name    the name to test
2138 * @param  {String} context the context in which the name is used, such as module or directive
2139 */
2140function assertNotHasOwnProperty(name, context) {
2141  if (name === 'hasOwnProperty') {
2142    throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2143  }
2144}
2145
2146/**
2147 * Return the value accessible from the object by path. Any undefined traversals are ignored
2148 * @param {Object} obj starting object
2149 * @param {String} path path to traverse
2150 * @param {boolean} [bindFnToScope=true]
2151 * @returns {Object} value as accessible by path
2152 */
2153//TODO(misko): this function needs to be removed
2154function getter(obj, path, bindFnToScope) {
2155  if (!path) return obj;
2156  var keys = path.split('.');
2157  var key;
2158  var lastInstance = obj;
2159  var len = keys.length;
2160
2161  for (var i = 0; i < len; i++) {
2162    key = keys[i];
2163    if (obj) {
2164      obj = (lastInstance = obj)[key];
2165    }
2166  }
2167  if (!bindFnToScope && isFunction(obj)) {
2168    return bind(lastInstance, obj);
2169  }
2170  return obj;
2171}
2172
2173/**
2174 * Return the DOM siblings between the first and last node in the given array.
2175 * @param {Array} array like object
2176 * @returns {Array} the inputted object or a jqLite collection containing the nodes
2177 */
2178function getBlockNodes(nodes) {
2179  // TODO(perf): update `nodes` instead of creating a new object?
2180  var node = nodes[0];
2181  var endNode = nodes[nodes.length - 1];
2182  var blockNodes;
2183
2184  for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
2185    if (blockNodes || nodes[i] !== node) {
2186      if (!blockNodes) {
2187        blockNodes = jqLite(slice.call(nodes, 0, i));
2188      }
2189      blockNodes.push(node);
2190    }
2191  }
2192
2193  return blockNodes || nodes;
2194}
2195
2196
2197/**
2198 * Creates a new object without a prototype. This object is useful for lookup without having to
2199 * guard against prototypically inherited properties via hasOwnProperty.
2200 *
2201 * Related micro-benchmarks:
2202 * - http://jsperf.com/object-create2
2203 * - http://jsperf.com/proto-map-lookup/2
2204 * - http://jsperf.com/for-in-vs-object-keys2
2205 *
2206 * @returns {Object}
2207 */
2208function createMap() {
2209  return Object.create(null);
2210}
2211
2212function stringify(value) {
2213  if (value == null) { // null || undefined
2214    return '';
2215  }
2216  switch (typeof value) {
2217    case 'string':
2218      break;
2219    case 'number':
2220      value = '' + value;
2221      break;
2222    default:
2223      if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
2224        value = value.toString();
2225      } else {
2226        value = toJson(value);
2227      }
2228  }
2229
2230  return value;
2231}
2232
2233var NODE_TYPE_ELEMENT = 1;
2234var NODE_TYPE_ATTRIBUTE = 2;
2235var NODE_TYPE_TEXT = 3;
2236var NODE_TYPE_COMMENT = 8;
2237var NODE_TYPE_DOCUMENT = 9;
2238var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
2239
2240/**
2241 * @ngdoc type
2242 * @name angular.Module
2243 * @module ng
2244 * @description
2245 *
2246 * Interface for configuring AngularJS {@link angular.module modules}.
2247 */
2248
2249function setupModuleLoader(window) {
2250
2251  var $injectorMinErr = minErr('$injector');
2252  var ngMinErr = minErr('ng');
2253
2254  function ensure(obj, name, factory) {
2255    return obj[name] || (obj[name] = factory());
2256  }
2257
2258  var angular = ensure(window, 'angular', Object);
2259
2260  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2261  angular.$$minErr = angular.$$minErr || minErr;
2262
2263  return ensure(angular, 'module', function() {
2264    /** @type {Object.<string, angular.Module>} */
2265    var modules = {};
2266
2267    /**
2268     * @ngdoc function
2269     * @name angular.module
2270     * @module ng
2271     * @description
2272     *
2273     * The `angular.module` is a global place for creating, registering and retrieving AngularJS
2274     * modules.
2275     * All modules (AngularJS core or 3rd party) that should be available to an application must be
2276     * registered using this mechanism.
2277     *
2278     * Passing one argument retrieves an existing {@link angular.Module},
2279     * whereas passing more than one argument creates a new {@link angular.Module}
2280     *
2281     *
2282     * # Module
2283     *
2284     * A module is a collection of services, directives, controllers, filters, and configuration information.
2285     * `angular.module` is used to configure the {@link auto.$injector $injector}.
2286     *
2287     * ```js
2288     * // Create a new module
2289     * var myModule = angular.module('myModule', []);
2290     *
2291     * // register a new service
2292     * myModule.value('appName', 'MyCoolApp');
2293     *
2294     * // configure existing services inside initialization blocks.
2295     * myModule.config(['$locationProvider', function($locationProvider) {
2296     *   // Configure existing providers
2297     *   $locationProvider.hashPrefix('!');
2298     * }]);
2299     * ```
2300     *
2301     * Then you can create an injector and load your modules like this:
2302     *
2303     * ```js
2304     * var injector = angular.injector(['ng', 'myModule'])
2305     * ```
2306     *
2307     * However it's more likely that you'll just use
2308     * {@link ng.directive:ngApp ngApp} or
2309     * {@link angular.bootstrap} to simplify this process for you.
2310     *
2311     * @param {!string} name The name of the module to create or retrieve.
2312     * @param {!Array.<string>=} requires If specified then new module is being created. If
2313     *        unspecified then the module is being retrieved for further configuration.
2314     * @param {Function=} configFn Optional configuration function for the module. Same as
2315     *        {@link angular.Module#config Module#config()}.
2316     * @returns {angular.Module} new module with the {@link angular.Module} api.
2317     */
2318    return function module(name, requires, configFn) {
2319
2320      var info = {};
2321
2322      var assertNotHasOwnProperty = function(name, context) {
2323        if (name === 'hasOwnProperty') {
2324          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2325        }
2326      };
2327
2328      assertNotHasOwnProperty(name, 'module');
2329      if (requires && modules.hasOwnProperty(name)) {
2330        modules[name] = null;
2331      }
2332      return ensure(modules, name, function() {
2333        if (!requires) {
2334          throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
2335             'the module name or forgot to load it. If registering a module ensure that you ' +
2336             'specify the dependencies as the second argument.', name);
2337        }
2338
2339        /** @type {!Array.<Array.<*>>} */
2340        var invokeQueue = [];
2341
2342        /** @type {!Array.<Function>} */
2343        var configBlocks = [];
2344
2345        /** @type {!Array.<Function>} */
2346        var runBlocks = [];
2347
2348        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2349
2350        /** @type {angular.Module} */
2351        var moduleInstance = {
2352          // Private state
2353          _invokeQueue: invokeQueue,
2354          _configBlocks: configBlocks,
2355          _runBlocks: runBlocks,
2356
2357          /**
2358           * @ngdoc method
2359           * @name angular.Module#info
2360           * @module ng
2361           *
2362           * @param {Object=} info Information about the module
2363           * @returns {Object|Module} The current info object for this module if called as a getter,
2364           *                          or `this` if called as a setter.
2365           *
2366           * @description
2367           * Read and write custom information about this module.
2368           * For example you could put the version of the module in here.
2369           *
2370           * ```js
2371           * angular.module('myModule', []).info({ version: '1.0.0' });
2372           * ```
2373           *
2374           * The version could then be read back out by accessing the module elsewhere:
2375           *
2376           * ```
2377           * var version = angular.module('myModule').info().version;
2378           * ```
2379           *
2380           * You can also retrieve this information during runtime via the
2381           * {@link $injector#modules `$injector.modules`} property:
2382           *
2383           * ```js
2384           * var version = $injector.modules['myModule'].info().version;
2385           * ```
2386           */
2387          info: function(value) {
2388            if (isDefined(value)) {
2389              if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
2390              info = value;
2391              return this;
2392            }
2393            return info;
2394          },
2395
2396          /**
2397           * @ngdoc property
2398           * @name angular.Module#requires
2399           * @module ng
2400           *
2401           * @description
2402           * Holds the list of modules which the injector will load before the current module is
2403           * loaded.
2404           */
2405          requires: requires,
2406
2407          /**
2408           * @ngdoc property
2409           * @name angular.Module#name
2410           * @module ng
2411           *
2412           * @description
2413           * Name of the module.
2414           */
2415          name: name,
2416
2417
2418          /**
2419           * @ngdoc method
2420           * @name angular.Module#provider
2421           * @module ng
2422           * @param {string} name service name
2423           * @param {Function} providerType Construction function for creating new instance of the
2424           *                                service.
2425           * @description
2426           * See {@link auto.$provide#provider $provide.provider()}.
2427           */
2428          provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2429
2430          /**
2431           * @ngdoc method
2432           * @name angular.Module#factory
2433           * @module ng
2434           * @param {string} name service name
2435           * @param {Function} providerFunction Function for creating new instance of the service.
2436           * @description
2437           * See {@link auto.$provide#factory $provide.factory()}.
2438           */
2439          factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2440
2441          /**
2442           * @ngdoc method
2443           * @name angular.Module#service
2444           * @module ng
2445           * @param {string} name service name
2446           * @param {Function} constructor A constructor function that will be instantiated.
2447           * @description
2448           * See {@link auto.$provide#service $provide.service()}.
2449           */
2450          service: invokeLaterAndSetModuleName('$provide', 'service'),
2451
2452          /**
2453           * @ngdoc method
2454           * @name angular.Module#value
2455           * @module ng
2456           * @param {string} name service name
2457           * @param {*} object Service instance object.
2458           * @description
2459           * See {@link auto.$provide#value $provide.value()}.
2460           */
2461          value: invokeLater('$provide', 'value'),
2462
2463          /**
2464           * @ngdoc method
2465           * @name angular.Module#constant
2466           * @module ng
2467           * @param {string} name constant name
2468           * @param {*} object Constant value.
2469           * @description
2470           * Because the constants are fixed, they get applied before other provide methods.
2471           * See {@link auto.$provide#constant $provide.constant()}.
2472           */
2473          constant: invokeLater('$provide', 'constant', 'unshift'),
2474
2475           /**
2476           * @ngdoc method
2477           * @name angular.Module#decorator
2478           * @module ng
2479           * @param {string} name The name of the service to decorate.
2480           * @param {Function} decorFn This function will be invoked when the service needs to be
2481           *                           instantiated and should return the decorated service instance.
2482           * @description
2483           * See {@link auto.$provide#decorator $provide.decorator()}.
2484           */
2485          decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
2486
2487          /**
2488           * @ngdoc method
2489           * @name angular.Module#animation
2490           * @module ng
2491           * @param {string} name animation name
2492           * @param {Function} animationFactory Factory function for creating new instance of an
2493           *                                    animation.
2494           * @description
2495           *
2496           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2497           *
2498           *
2499           * Defines an animation hook that can be later used with
2500           * {@link $animate $animate} service and directives that use this service.
2501           *
2502           * ```js
2503           * module.animation('.animation-name', function($inject1, $inject2) {
2504           *   return {
2505           *     eventName : function(element, done) {
2506           *       //code to run the animation
2507           *       //once complete, then run done()
2508           *       return function cancellationFunction(element) {
2509           *         //code to cancel the animation
2510           *       }
2511           *     }
2512           *   }
2513           * })
2514           * ```
2515           *
2516           * See {@link ng.$animateProvider#register $animateProvider.register()} and
2517           * {@link ngAnimate ngAnimate module} for more information.
2518           */
2519          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2520
2521          /**
2522           * @ngdoc method
2523           * @name angular.Module#filter
2524           * @module ng
2525           * @param {string} name Filter name - this must be a valid AngularJS expression identifier
2526           * @param {Function} filterFactory Factory function for creating new instance of filter.
2527           * @description
2528           * See {@link ng.$filterProvider#register $filterProvider.register()}.
2529           *
2530           * <div class="alert alert-warning">
2531           * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`.
2532           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2533           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2534           * (`myapp_subsection_filterx`).
2535           * </div>
2536           */
2537          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2538
2539          /**
2540           * @ngdoc method
2541           * @name angular.Module#controller
2542           * @module ng
2543           * @param {string|Object} name Controller name, or an object map of controllers where the
2544           *    keys are the names and the values are the constructors.
2545           * @param {Function} constructor Controller constructor function.
2546           * @description
2547           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2548           */
2549          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2550
2551          /**
2552           * @ngdoc method
2553           * @name angular.Module#directive
2554           * @module ng
2555           * @param {string|Object} name Directive name, or an object map of directives where the
2556           *    keys are the names and the values are the factories.
2557           * @param {Function} directiveFactory Factory function for creating new instance of
2558           * directives.
2559           * @description
2560           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2561           */
2562          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2563
2564          /**
2565           * @ngdoc method
2566           * @name angular.Module#component
2567           * @module ng
2568           * @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`),
2569           *    or an object map of components where the keys are the names and the values are the component definition objects.
2570           * @param {Object} options Component definition object (a simplified
2571           *    {@link ng.$compile#directive-definition-object directive definition object})
2572           *
2573           * @description
2574           * See {@link ng.$compileProvider#component $compileProvider.component()}.
2575           */
2576          component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
2577
2578          /**
2579           * @ngdoc method
2580           * @name angular.Module#config
2581           * @module ng
2582           * @param {Function} configFn Execute this function on module load. Useful for service
2583           *    configuration.
2584           * @description
2585           * Use this method to configure services by injecting their
2586           * {@link angular.Module#provider `providers`}, e.g. for adding routes to the
2587           * {@link ngRoute.$routeProvider $routeProvider}.
2588           *
2589           * Note that you can only inject {@link angular.Module#provider `providers`} and
2590           * {@link angular.Module#constant `constants`} into this function.
2591           *
2592           * For more about how to configure services, see
2593           * {@link providers#provider-recipe Provider Recipe}.
2594           */
2595          config: config,
2596
2597          /**
2598           * @ngdoc method
2599           * @name angular.Module#run
2600           * @module ng
2601           * @param {Function} initializationFn Execute this function after injector creation.
2602           *    Useful for application initialization.
2603           * @description
2604           * Use this method to register work which should be performed when the injector is done
2605           * loading all modules.
2606           */
2607          run: function(block) {
2608            runBlocks.push(block);
2609            return this;
2610          }
2611        };
2612
2613        if (configFn) {
2614          config(configFn);
2615        }
2616
2617        return moduleInstance;
2618
2619        /**
2620         * @param {string} provider
2621         * @param {string} method
2622         * @param {String=} insertMethod
2623         * @returns {angular.Module}
2624         */
2625        function invokeLater(provider, method, insertMethod, queue) {
2626          if (!queue) queue = invokeQueue;
2627          return function() {
2628            queue[insertMethod || 'push']([provider, method, arguments]);
2629            return moduleInstance;
2630          };
2631        }
2632
2633        /**
2634         * @param {string} provider
2635         * @param {string} method
2636         * @returns {angular.Module}
2637         */
2638        function invokeLaterAndSetModuleName(provider, method, queue) {
2639          if (!queue) queue = invokeQueue;
2640          return function(recipeName, factoryFunction) {
2641            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2642            queue.push([provider, method, arguments]);
2643            return moduleInstance;
2644          };
2645        }
2646      });
2647    };
2648  });
2649
2650}
2651
2652/* global shallowCopy: true */
2653
2654/**
2655 * Creates a shallow copy of an object, an array or a primitive.
2656 *
2657 * Assumes that there are no proto properties for objects.
2658 */
2659function shallowCopy(src, dst) {
2660  if (isArray(src)) {
2661    dst = dst || [];
2662
2663    for (var i = 0, ii = src.length; i < ii; i++) {
2664      dst[i] = src[i];
2665    }
2666  } else if (isObject(src)) {
2667    dst = dst || {};
2668
2669    for (var key in src) {
2670      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
2671        dst[key] = src[key];
2672      }
2673    }
2674  }
2675
2676  return dst || src;
2677}
2678
2679/* exported toDebugString */
2680
2681function serializeObject(obj, maxDepth) {
2682  var seen = [];
2683
2684  // There is no direct way to stringify object until reaching a specific depth
2685  // and a very deep object can cause a performance issue, so we copy the object
2686  // based on this specific depth and then stringify it.
2687  if (isValidObjectMaxDepth(maxDepth)) {
2688    // This file is also included in `angular-loader`, so `copy()` might not always be available in
2689    // the closure. Therefore, it is lazily retrieved as `angular.copy()` when needed.
2690    obj = angular.copy(obj, null, maxDepth);
2691  }
2692  return JSON.stringify(obj, function(key, val) {
2693    val = toJsonReplacer(key, val);
2694    if (isObject(val)) {
2695
2696      if (seen.indexOf(val) >= 0) return '...';
2697
2698      seen.push(val);
2699    }
2700    return val;
2701  });
2702}
2703
2704function toDebugString(obj, maxDepth) {
2705  if (typeof obj === 'function') {
2706    return obj.toString().replace(/ \{[\s\S]*$/, '');
2707  } else if (isUndefined(obj)) {
2708    return 'undefined';
2709  } else if (typeof obj !== 'string') {
2710    return serializeObject(obj, maxDepth);
2711  }
2712  return obj;
2713}
2714
2715/* global angularModule: true,
2716  version: true,
2717
2718  $CompileProvider,
2719
2720  htmlAnchorDirective,
2721  inputDirective,
2722  hiddenInputBrowserCacheDirective,
2723  formDirective,
2724  scriptDirective,
2725  selectDirective,
2726  optionDirective,
2727  ngBindDirective,
2728  ngBindHtmlDirective,
2729  ngBindTemplateDirective,
2730  ngClassDirective,
2731  ngClassEvenDirective,
2732  ngClassOddDirective,
2733  ngCloakDirective,
2734  ngControllerDirective,
2735  ngFormDirective,
2736  ngHideDirective,
2737  ngIfDirective,
2738  ngIncludeDirective,
2739  ngIncludeFillContentDirective,
2740  ngInitDirective,
2741  ngNonBindableDirective,
2742  ngPluralizeDirective,
2743  ngRefDirective,
2744  ngRepeatDirective,
2745  ngShowDirective,
2746  ngStyleDirective,
2747  ngSwitchDirective,
2748  ngSwitchWhenDirective,
2749  ngSwitchDefaultDirective,
2750  ngOptionsDirective,
2751  ngTranscludeDirective,
2752  ngModelDirective,
2753  ngListDirective,
2754  ngChangeDirective,
2755  patternDirective,
2756  patternDirective,
2757  requiredDirective,
2758  requiredDirective,
2759  minlengthDirective,
2760  minlengthDirective,
2761  maxlengthDirective,
2762  maxlengthDirective,
2763  ngValueDirective,
2764  ngModelOptionsDirective,
2765  ngAttributeAliasDirectives,
2766  ngEventDirectives,
2767
2768  $AnchorScrollProvider,
2769  $AnimateProvider,
2770  $CoreAnimateCssProvider,
2771  $$CoreAnimateJsProvider,
2772  $$CoreAnimateQueueProvider,
2773  $$AnimateRunnerFactoryProvider,
2774  $$AnimateAsyncRunFactoryProvider,
2775  $BrowserProvider,
2776  $CacheFactoryProvider,
2777  $ControllerProvider,
2778  $DateProvider,
2779  $DocumentProvider,
2780  $$IsDocumentHiddenProvider,
2781  $ExceptionHandlerProvider,
2782  $FilterProvider,
2783  $$ForceReflowProvider,
2784  $InterpolateProvider,
2785  $$IntervalFactoryProvider,
2786  $IntervalProvider,
2787  $HttpProvider,
2788  $HttpParamSerializerProvider,
2789  $HttpParamSerializerJQLikeProvider,
2790  $HttpBackendProvider,
2791  $xhrFactoryProvider,
2792  $jsonpCallbacksProvider,
2793  $LocationProvider,
2794  $LogProvider,
2795  $$MapProvider,
2796  $ParseProvider,
2797  $RootScopeProvider,
2798  $QProvider,
2799  $$QProvider,
2800  $$SanitizeUriProvider,
2801  $SceProvider,
2802  $SceDelegateProvider,
2803  $SnifferProvider,
2804  $$TaskTrackerFactoryProvider,
2805  $TemplateCacheProvider,
2806  $TemplateRequestProvider,
2807  $$TestabilityProvider,
2808  $TimeoutProvider,
2809  $$RAFProvider,
2810  $WindowProvider,
2811  $$jqLiteProvider,
2812  $$CookieReaderProvider
2813*/
2814
2815
2816/**
2817 * @ngdoc object
2818 * @name angular.version
2819 * @module ng
2820 * @description
2821 * An object that contains information about the current AngularJS version.
2822 *
2823 * This object has the following properties:
2824 *
2825 * - `full` – `{string}` – Full version string, such as "0.9.18".
2826 * - `major` – `{number}` – Major version number, such as "0".
2827 * - `minor` – `{number}` – Minor version number, such as "9".
2828 * - `dot` – `{number}` – Dot version number, such as "18".
2829 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2830 */
2831var version = {
2832  // These placeholder strings will be replaced by grunt's `build` task.
2833  // They need to be double- or single-quoted.
2834  full: '1.8.3',
2835  major: 1,
2836  minor: 8,
2837  dot: 3,
2838  codeName: 'ultimate-farewell'
2839};
2840
2841
2842function publishExternalAPI(angular) {
2843  extend(angular, {
2844    'errorHandlingConfig': errorHandlingConfig,
2845    'bootstrap': bootstrap,
2846    'copy': copy,
2847    'extend': extend,
2848    'merge': merge,
2849    'equals': equals,
2850    'element': jqLite,
2851    'forEach': forEach,
2852    'injector': createInjector,
2853    'noop': noop,
2854    'bind': bind,
2855    'toJson': toJson,
2856    'fromJson': fromJson,
2857    'identity': identity,
2858    'isUndefined': isUndefined,
2859    'isDefined': isDefined,
2860    'isString': isString,
2861    'isFunction': isFunction,
2862    'isObject': isObject,
2863    'isNumber': isNumber,
2864    'isElement': isElement,
2865    'isArray': isArray,
2866    'version': version,
2867    'isDate': isDate,
2868    'callbacks': {$$counter: 0},
2869    'getTestability': getTestability,
2870    'reloadWithDebugInfo': reloadWithDebugInfo,
2871    'UNSAFE_restoreLegacyJqLiteXHTMLReplacement': UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
2872    '$$minErr': minErr,
2873    '$$csp': csp,
2874    '$$encodeUriSegment': encodeUriSegment,
2875    '$$encodeUriQuery': encodeUriQuery,
2876    '$$lowercase': lowercase,
2877    '$$stringify': stringify,
2878    '$$uppercase': uppercase
2879  });
2880
2881  angularModule = setupModuleLoader(window);
2882
2883  angularModule('ng', ['ngLocale'], ['$provide',
2884    function ngModule($provide) {
2885      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2886      $provide.provider({
2887        $$sanitizeUri: $$SanitizeUriProvider
2888      });
2889      $provide.provider('$compile', $CompileProvider).
2890        directive({
2891            a: htmlAnchorDirective,
2892            input: inputDirective,
2893            textarea: inputDirective,
2894            form: formDirective,
2895            script: scriptDirective,
2896            select: selectDirective,
2897            option: optionDirective,
2898            ngBind: ngBindDirective,
2899            ngBindHtml: ngBindHtmlDirective,
2900            ngBindTemplate: ngBindTemplateDirective,
2901            ngClass: ngClassDirective,
2902            ngClassEven: ngClassEvenDirective,
2903            ngClassOdd: ngClassOddDirective,
2904            ngCloak: ngCloakDirective,
2905            ngController: ngControllerDirective,
2906            ngForm: ngFormDirective,
2907            ngHide: ngHideDirective,
2908            ngIf: ngIfDirective,
2909            ngInclude: ngIncludeDirective,
2910            ngInit: ngInitDirective,
2911            ngNonBindable: ngNonBindableDirective,
2912            ngPluralize: ngPluralizeDirective,
2913            ngRef: ngRefDirective,
2914            ngRepeat: ngRepeatDirective,
2915            ngShow: ngShowDirective,
2916            ngStyle: ngStyleDirective,
2917            ngSwitch: ngSwitchDirective,
2918            ngSwitchWhen: ngSwitchWhenDirective,
2919            ngSwitchDefault: ngSwitchDefaultDirective,
2920            ngOptions: ngOptionsDirective,
2921            ngTransclude: ngTranscludeDirective,
2922            ngModel: ngModelDirective,
2923            ngList: ngListDirective,
2924            ngChange: ngChangeDirective,
2925            pattern: patternDirective,
2926            ngPattern: patternDirective,
2927            required: requiredDirective,
2928            ngRequired: requiredDirective,
2929            minlength: minlengthDirective,
2930            ngMinlength: minlengthDirective,
2931            maxlength: maxlengthDirective,
2932            ngMaxlength: maxlengthDirective,
2933            ngValue: ngValueDirective,
2934            ngModelOptions: ngModelOptionsDirective
2935        }).
2936        directive({
2937          ngInclude: ngIncludeFillContentDirective,
2938          input: hiddenInputBrowserCacheDirective
2939        }).
2940        directive(ngAttributeAliasDirectives).
2941        directive(ngEventDirectives);
2942      $provide.provider({
2943        $anchorScroll: $AnchorScrollProvider,
2944        $animate: $AnimateProvider,
2945        $animateCss: $CoreAnimateCssProvider,
2946        $$animateJs: $$CoreAnimateJsProvider,
2947        $$animateQueue: $$CoreAnimateQueueProvider,
2948        $$AnimateRunner: $$AnimateRunnerFactoryProvider,
2949        $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
2950        $browser: $BrowserProvider,
2951        $cacheFactory: $CacheFactoryProvider,
2952        $controller: $ControllerProvider,
2953        $document: $DocumentProvider,
2954        $$isDocumentHidden: $$IsDocumentHiddenProvider,
2955        $exceptionHandler: $ExceptionHandlerProvider,
2956        $filter: $FilterProvider,
2957        $$forceReflow: $$ForceReflowProvider,
2958        $interpolate: $InterpolateProvider,
2959        $interval: $IntervalProvider,
2960        $$intervalFactory: $$IntervalFactoryProvider,
2961        $http: $HttpProvider,
2962        $httpParamSerializer: $HttpParamSerializerProvider,
2963        $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2964        $httpBackend: $HttpBackendProvider,
2965        $xhrFactory: $xhrFactoryProvider,
2966        $jsonpCallbacks: $jsonpCallbacksProvider,
2967        $location: $LocationProvider,
2968        $log: $LogProvider,
2969        $parse: $ParseProvider,
2970        $rootScope: $RootScopeProvider,
2971        $q: $QProvider,
2972        $$q: $$QProvider,
2973        $sce: $SceProvider,
2974        $sceDelegate: $SceDelegateProvider,
2975        $sniffer: $SnifferProvider,
2976        $$taskTrackerFactory: $$TaskTrackerFactoryProvider,
2977        $templateCache: $TemplateCacheProvider,
2978        $templateRequest: $TemplateRequestProvider,
2979        $$testability: $$TestabilityProvider,
2980        $timeout: $TimeoutProvider,
2981        $window: $WindowProvider,
2982        $$rAF: $$RAFProvider,
2983        $$jqLite: $$jqLiteProvider,
2984        $$Map: $$MapProvider,
2985        $$cookieReader: $$CookieReaderProvider
2986      });
2987    }
2988  ])
2989  .info({ angularVersion: '1.8.3' });
2990}
2991
2992/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2993 *     Any commits to this file should be reviewed with security in mind.  *
2994 *   Changes to this file can potentially create security vulnerabilities. *
2995 *          An approval from 2 Core members with history of modifying      *
2996 *                         this file is required.                          *
2997 *                                                                         *
2998 *  Does the change somehow allow for arbitrary javascript to be executed? *
2999 *    Or allows for someone to change the prototype of built-in objects?   *
3000 *     Or gives undesired access to variables likes document or window?    *
3001 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3002
3003/* global
3004  JQLitePrototype: true,
3005  BOOLEAN_ATTR: true,
3006  ALIASED_ATTR: true
3007*/
3008
3009//////////////////////////////////
3010//JQLite
3011//////////////////////////////////
3012
3013/**
3014 * @ngdoc function
3015 * @name angular.element
3016 * @module ng
3017 * @kind function
3018 *
3019 * @description
3020 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
3021 *
3022 * If jQuery is available, `angular.element` is an alias for the
3023 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
3024 * delegates to AngularJS's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
3025 *
3026 * jqLite is a tiny, API-compatible subset of jQuery that allows
3027 * AngularJS to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
3028 * commonly needed functionality with the goal of having a very small footprint.
3029 *
3030 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
3031 * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
3032 * specific version of jQuery if multiple versions exist on the page.
3033 *
3034 * <div class="alert alert-info">**Note:** All element references in AngularJS are always wrapped with jQuery or
3035 * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
3036 *
3037 * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
3038 * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
3039 * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
3040 *
3041 * ## AngularJS's jqLite
3042 * jqLite provides only the following jQuery methods:
3043 *
3044 * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
3045 * - [`after()`](http://api.jquery.com/after/)
3046 * - [`append()`](http://api.jquery.com/append/) - Contrary to jQuery, this doesn't clone elements
3047 *   so will not work correctly when invoked on a jqLite object containing more than one DOM node
3048 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
3049 * - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
3050 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
3051 * - [`clone()`](http://api.jquery.com/clone/)
3052 * - [`contents()`](http://api.jquery.com/contents/)
3053 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
3054 *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
3055 * - [`data()`](http://api.jquery.com/data/)
3056 * - [`detach()`](http://api.jquery.com/detach/)
3057 * - [`empty()`](http://api.jquery.com/empty/)
3058 * - [`eq()`](http://api.jquery.com/eq/)
3059 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
3060 * - [`hasClass()`](http://api.jquery.com/hasClass/)
3061 * - [`html()`](http://api.jquery.com/html/)
3062 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
3063 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
3064 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
3065 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
3066 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
3067 * - [`prepend()`](http://api.jquery.com/prepend/)
3068 * - [`prop()`](http://api.jquery.com/prop/)
3069 * - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
3070 * - [`remove()`](http://api.jquery.com/remove/)
3071 * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
3072 * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
3073 * - [`removeData()`](http://api.jquery.com/removeData/)
3074 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
3075 * - [`text()`](http://api.jquery.com/text/)
3076 * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
3077 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
3078 * - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
3079 * - [`val()`](http://api.jquery.com/val/)
3080 * - [`wrap()`](http://api.jquery.com/wrap/)
3081 *
3082 * jqLite also provides a method restoring pre-1.8 insecure treatment of XHTML-like tags.
3083 * This legacy behavior turns input like `<div /><span />` to `<div></div><span></span>`
3084 * instead of `<div><span></span></div>` like version 1.8 & newer do. To restore it, invoke:
3085 * ```js
3086 * angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
3087 * ```
3088 * Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
3089 * [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
3090 * about the workarounds.
3091 *
3092 * ## jQuery/jqLite Extras
3093 * AngularJS also provides the following additional methods and events to both jQuery and jqLite:
3094 *
3095 * ### Events
3096 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
3097 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
3098 *    element before it is removed.
3099 *
3100 * ### Methods
3101 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
3102 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
3103 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
3104 *   `'ngModel'`).
3105 * - `injector()` - retrieves the injector of the current element or its parent.
3106 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
3107 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
3108 *   be enabled.
3109 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
3110 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
3111 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
3112 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
3113 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
3114 *   parent element is reached.
3115 *
3116 * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
3117 * https://github.com/angular/angular.js/issues/14251 for more information.
3118 *
3119 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
3120 * @returns {Object} jQuery object.
3121 */
3122
3123JQLite.expando = 'ng339';
3124
3125var jqCache = JQLite.cache = {},
3126    jqId = 1;
3127
3128/*
3129 * !!! This is an undocumented "private" function !!!
3130 */
3131JQLite._data = function(node) {
3132  //jQuery always returns an object on cache miss
3133  return this.cache[node[this.expando]] || {};
3134};
3135
3136function jqNextId() { return ++jqId; }
3137
3138
3139var DASH_LOWERCASE_REGEXP = /-([a-z])/g;
3140var MS_HACK_REGEXP = /^-ms-/;
3141var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
3142var jqLiteMinErr = minErr('jqLite');
3143
3144/**
3145 * Converts kebab-case to camelCase.
3146 * There is also a special case for the ms prefix starting with a lowercase letter.
3147 * @param name Name to normalize
3148 */
3149function cssKebabToCamel(name) {
3150    return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-'));
3151}
3152
3153function fnCamelCaseReplace(all, letter) {
3154  return letter.toUpperCase();
3155}
3156
3157/**
3158 * Converts kebab-case to camelCase.
3159 * @param name Name to normalize
3160 */
3161function kebabToCamel(name) {
3162  return name
3163    .replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
3164}
3165
3166var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
3167var HTML_REGEXP = /<|&#?\w+;/;
3168var TAG_NAME_REGEXP = /<([\w:-]+)/;
3169var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
3170
3171// Table parts need to be wrapped with `<table>` or they're
3172// stripped to their contents when put in a div.
3173// XHTML parsers do not magically insert elements in the
3174// same way that tag soup parsers do, so we cannot shorten
3175// this by omitting <tbody> or other required elements.
3176var wrapMap = {
3177  thead: ['table'],
3178  col: ['colgroup', 'table'],
3179  tr: ['tbody', 'table'],
3180  td: ['tr', 'tbody', 'table']
3181};
3182
3183wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
3184wrapMap.th = wrapMap.td;
3185
3186// Support: IE <10 only
3187// IE 9 requires an option wrapper & it needs to have the whole table structure
3188// set up in advance; assigning `"<td></td>"` to `tr.innerHTML` doesn't work, etc.
3189var wrapMapIE9 = {
3190  option: [1, '<select multiple="multiple">', '</select>'],
3191  _default: [0, '', '']
3192};
3193
3194for (var key in wrapMap) {
3195  var wrapMapValueClosing = wrapMap[key];
3196  var wrapMapValue = wrapMapValueClosing.slice().reverse();
3197  wrapMapIE9[key] = [wrapMapValue.length, '<' + wrapMapValue.join('><') + '>', '</' + wrapMapValueClosing.join('></') + '>'];
3198}
3199
3200wrapMapIE9.optgroup = wrapMapIE9.option;
3201
3202function jqLiteIsTextNode(html) {
3203  return !HTML_REGEXP.test(html);
3204}
3205
3206function jqLiteAcceptsData(node) {
3207  // The window object can accept data but has no nodeType
3208  // Otherwise we are only interested in elements (1) and documents (9)
3209  var nodeType = node.nodeType;
3210  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
3211}
3212
3213function jqLiteHasData(node) {
3214  for (var key in jqCache[node.ng339]) {
3215    return true;
3216  }
3217  return false;
3218}
3219
3220function jqLiteBuildFragment(html, context) {
3221  var tmp, tag, wrap, finalHtml,
3222      fragment = context.createDocumentFragment(),
3223      nodes = [], i;
3224
3225  if (jqLiteIsTextNode(html)) {
3226    // Convert non-html into a text node
3227    nodes.push(context.createTextNode(html));
3228  } else {
3229    // Convert html into DOM nodes
3230    tmp = fragment.appendChild(context.createElement('div'));
3231    tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
3232    finalHtml = JQLite.legacyXHTMLReplacement ?
3233      html.replace(XHTML_TAG_REGEXP, '<$1></$2>') :
3234      html;
3235
3236    if (msie < 10) {
3237      wrap = wrapMapIE9[tag] || wrapMapIE9._default;
3238      tmp.innerHTML = wrap[1] + finalHtml + wrap[2];
3239
3240      // Descend through wrappers to the right content
3241      i = wrap[0];
3242      while (i--) {
3243        tmp = tmp.firstChild;
3244      }
3245    } else {
3246      wrap = wrapMap[tag] || [];
3247
3248      // Create wrappers & descend into them
3249      i = wrap.length;
3250      while (--i > -1) {
3251        tmp.appendChild(window.document.createElement(wrap[i]));
3252        tmp = tmp.firstChild;
3253      }
3254
3255      tmp.innerHTML = finalHtml;
3256    }
3257
3258    nodes = concat(nodes, tmp.childNodes);
3259
3260    tmp = fragment.firstChild;
3261    tmp.textContent = '';
3262  }
3263
3264  // Remove wrapper from fragment
3265  fragment.textContent = '';
3266  fragment.innerHTML = ''; // Clear inner HTML
3267  forEach(nodes, function(node) {
3268    fragment.appendChild(node);
3269  });
3270
3271  return fragment;
3272}
3273
3274function jqLiteParseHTML(html, context) {
3275  context = context || window.document;
3276  var parsed;
3277
3278  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
3279    return [context.createElement(parsed[1])];
3280  }
3281
3282  if ((parsed = jqLiteBuildFragment(html, context))) {
3283    return parsed.childNodes;
3284  }
3285
3286  return [];
3287}
3288
3289function jqLiteWrapNode(node, wrapper) {
3290  var parent = node.parentNode;
3291
3292  if (parent) {
3293    parent.replaceChild(wrapper, node);
3294  }
3295
3296  wrapper.appendChild(node);
3297}
3298
3299
3300// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
3301var jqLiteContains = window.Node.prototype.contains || /** @this */ function(arg) {
3302  // eslint-disable-next-line no-bitwise
3303  return !!(this.compareDocumentPosition(arg) & 16);
3304};
3305
3306/////////////////////////////////////////////
3307function JQLite(element) {
3308  if (element instanceof JQLite) {
3309    return element;
3310  }
3311
3312  var argIsString;
3313
3314  if (isString(element)) {
3315    element = trim(element);
3316    argIsString = true;
3317  }
3318  if (!(this instanceof JQLite)) {
3319    if (argIsString && element.charAt(0) !== '<') {
3320      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
3321    }
3322    return new JQLite(element);
3323  }
3324
3325  if (argIsString) {
3326    jqLiteAddNodes(this, jqLiteParseHTML(element));
3327  } else if (isFunction(element)) {
3328    jqLiteReady(element);
3329  } else {
3330    jqLiteAddNodes(this, element);
3331  }
3332}
3333
3334function jqLiteClone(element) {
3335  return element.cloneNode(true);
3336}
3337
3338function jqLiteDealoc(element, onlyDescendants) {
3339  if (!onlyDescendants && jqLiteAcceptsData(element)) jqLite.cleanData([element]);
3340
3341  if (element.querySelectorAll) {
3342    jqLite.cleanData(element.querySelectorAll('*'));
3343  }
3344}
3345
3346function isEmptyObject(obj) {
3347  var name;
3348
3349  for (name in obj) {
3350    return false;
3351  }
3352  return true;
3353}
3354
3355function removeIfEmptyData(element) {
3356  var expandoId = element.ng339;
3357  var expandoStore = expandoId && jqCache[expandoId];
3358
3359  var events = expandoStore && expandoStore.events;
3360  var data = expandoStore && expandoStore.data;
3361
3362  if ((!data || isEmptyObject(data)) && (!events || isEmptyObject(events))) {
3363    delete jqCache[expandoId];
3364    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
3365  }
3366}
3367
3368function jqLiteOff(element, type, fn, unsupported) {
3369  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
3370
3371  var expandoStore = jqLiteExpandoStore(element);
3372  var events = expandoStore && expandoStore.events;
3373  var handle = expandoStore && expandoStore.handle;
3374
3375  if (!handle) return; //no listeners registered
3376
3377  if (!type) {
3378    for (type in events) {
3379      if (type !== '$destroy') {
3380        element.removeEventListener(type, handle);
3381      }
3382      delete events[type];
3383    }
3384  } else {
3385
3386    var removeHandler = function(type) {
3387      var listenerFns = events[type];
3388      if (isDefined(fn)) {
3389        arrayRemove(listenerFns || [], fn);
3390      }
3391      if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
3392        element.removeEventListener(type, handle);
3393        delete events[type];
3394      }
3395    };
3396
3397    forEach(type.split(' '), function(type) {
3398      removeHandler(type);
3399      if (MOUSE_EVENT_MAP[type]) {
3400        removeHandler(MOUSE_EVENT_MAP[type]);
3401      }
3402    });
3403  }
3404
3405  removeIfEmptyData(element);
3406}
3407
3408function jqLiteRemoveData(element, name) {
3409  var expandoId = element.ng339;
3410  var expandoStore = expandoId && jqCache[expandoId];
3411
3412  if (expandoStore) {
3413    if (name) {
3414      delete expandoStore.data[name];
3415    } else {
3416      expandoStore.data = {};
3417    }
3418
3419    removeIfEmptyData(element);
3420  }
3421}
3422
3423
3424function jqLiteExpandoStore(element, createIfNecessary) {
3425  var expandoId = element.ng339,
3426      expandoStore = expandoId && jqCache[expandoId];
3427
3428  if (createIfNecessary && !expandoStore) {
3429    element.ng339 = expandoId = jqNextId();
3430    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
3431  }
3432
3433  return expandoStore;
3434}
3435
3436
3437function jqLiteData(element, key, value) {
3438  if (jqLiteAcceptsData(element)) {
3439    var prop;
3440
3441    var isSimpleSetter = isDefined(value);
3442    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
3443    var massGetter = !key;
3444    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
3445    var data = expandoStore && expandoStore.data;
3446
3447    if (isSimpleSetter) { // data('key', value)
3448      data[kebabToCamel(key)] = value;
3449    } else {
3450      if (massGetter) {  // data()
3451        return data;
3452      } else {
3453        if (isSimpleGetter) { // data('key')
3454          // don't force creation of expandoStore if it doesn't exist yet
3455          return data && data[kebabToCamel(key)];
3456        } else { // mass-setter: data({key1: val1, key2: val2})
3457          for (prop in key) {
3458            data[kebabToCamel(prop)] = key[prop];
3459          }
3460        }
3461      }
3462    }
3463  }
3464}
3465
3466function jqLiteHasClass(element, selector) {
3467  if (!element.getAttribute) return false;
3468  return ((' ' + (element.getAttribute('class') || '') + ' ').replace(/[\n\t]/g, ' ').
3469      indexOf(' ' + selector + ' ') > -1);
3470}
3471
3472function jqLiteRemoveClass(element, cssClasses) {
3473  if (cssClasses && element.setAttribute) {
3474    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3475                            .replace(/[\n\t]/g, ' ');
3476    var newClasses = existingClasses;
3477
3478    forEach(cssClasses.split(' '), function(cssClass) {
3479      cssClass = trim(cssClass);
3480      newClasses = newClasses.replace(' ' + cssClass + ' ', ' ');
3481    });
3482
3483    if (newClasses !== existingClasses) {
3484      element.setAttribute('class', trim(newClasses));
3485    }
3486  }
3487}
3488
3489function jqLiteAddClass(element, cssClasses) {
3490  if (cssClasses && element.setAttribute) {
3491    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3492                            .replace(/[\n\t]/g, ' ');
3493    var newClasses = existingClasses;
3494
3495    forEach(cssClasses.split(' '), function(cssClass) {
3496      cssClass = trim(cssClass);
3497      if (newClasses.indexOf(' ' + cssClass + ' ') === -1) {
3498        newClasses += cssClass + ' ';
3499      }
3500    });
3501
3502    if (newClasses !== existingClasses) {
3503      element.setAttribute('class', trim(newClasses));
3504    }
3505  }
3506}
3507
3508
3509function jqLiteAddNodes(root, elements) {
3510  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3511
3512  if (elements) {
3513
3514    // if a Node (the most common case)
3515    if (elements.nodeType) {
3516      root[root.length++] = elements;
3517    } else {
3518      var length = elements.length;
3519
3520      // if an Array or NodeList and not a Window
3521      if (typeof length === 'number' && elements.window !== elements) {
3522        if (length) {
3523          for (var i = 0; i < length; i++) {
3524            root[root.length++] = elements[i];
3525          }
3526        }
3527      } else {
3528        root[root.length++] = elements;
3529      }
3530    }
3531  }
3532}
3533
3534
3535function jqLiteController(element, name) {
3536  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3537}
3538
3539function jqLiteInheritedData(element, name, value) {
3540  // if element is the document object work with the html element instead
3541  // this makes $(document).scope() possible
3542  if (element.nodeType === NODE_TYPE_DOCUMENT) {
3543    element = element.documentElement;
3544  }
3545  var names = isArray(name) ? name : [name];
3546
3547  while (element) {
3548    for (var i = 0, ii = names.length; i < ii; i++) {
3549      if (isDefined(value = jqLite.data(element, names[i]))) return value;
3550    }
3551
3552    // If dealing with a document fragment node with a host element, and no parent, use the host
3553    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3554    // to lookup parent controllers.
3555    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3556  }
3557}
3558
3559function jqLiteEmpty(element) {
3560  jqLiteDealoc(element, true);
3561  while (element.firstChild) {
3562    element.removeChild(element.firstChild);
3563  }
3564}
3565
3566function jqLiteRemove(element, keepData) {
3567  if (!keepData) jqLiteDealoc(element);
3568  var parent = element.parentNode;
3569  if (parent) parent.removeChild(element);
3570}
3571
3572
3573function jqLiteDocumentLoaded(action, win) {
3574  win = win || window;
3575  if (win.document.readyState === 'complete') {
3576    // Force the action to be run async for consistent behavior
3577    // from the action's point of view
3578    // i.e. it will definitely not be in a $apply
3579    win.setTimeout(action);
3580  } else {
3581    // No need to unbind this handler as load is only ever called once
3582    jqLite(win).on('load', action);
3583  }
3584}
3585
3586function jqLiteReady(fn) {
3587  function trigger() {
3588    window.document.removeEventListener('DOMContentLoaded', trigger);
3589    window.removeEventListener('load', trigger);
3590    fn();
3591  }
3592
3593  // check if document is already loaded
3594  if (window.document.readyState === 'complete') {
3595    window.setTimeout(fn);
3596  } else {
3597    // We can not use jqLite since we are not done loading and jQuery could be loaded later.
3598
3599    // Works for modern browsers and IE9
3600    window.document.addEventListener('DOMContentLoaded', trigger);
3601
3602    // Fallback to window.onload for others
3603    window.addEventListener('load', trigger);
3604  }
3605}
3606
3607//////////////////////////////////////////
3608// Functions which are declared directly.
3609//////////////////////////////////////////
3610var JQLitePrototype = JQLite.prototype = {
3611  ready: jqLiteReady,
3612  toString: function() {
3613    var value = [];
3614    forEach(this, function(e) { value.push('' + e);});
3615    return '[' + value.join(', ') + ']';
3616  },
3617
3618  eq: function(index) {
3619      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3620  },
3621
3622  length: 0,
3623  push: push,
3624  sort: [].sort,
3625  splice: [].splice
3626};
3627
3628//////////////////////////////////////////
3629// Functions iterating getter/setters.
3630// these functions return self on setter and
3631// value on get.
3632//////////////////////////////////////////
3633var BOOLEAN_ATTR = {};
3634forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3635  BOOLEAN_ATTR[lowercase(value)] = value;
3636});
3637var BOOLEAN_ELEMENTS = {};
3638forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3639  BOOLEAN_ELEMENTS[value] = true;
3640});
3641var ALIASED_ATTR = {
3642  'ngMinlength': 'minlength',
3643  'ngMaxlength': 'maxlength',
3644  'ngMin': 'min',
3645  'ngMax': 'max',
3646  'ngPattern': 'pattern',
3647  'ngStep': 'step'
3648};
3649
3650function getBooleanAttrName(element, name) {
3651  // check dom last since we will most likely fail on name
3652  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3653
3654  // booleanAttr is here twice to minimize DOM access
3655  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3656}
3657
3658function getAliasedAttrName(name) {
3659  return ALIASED_ATTR[name];
3660}
3661
3662forEach({
3663  data: jqLiteData,
3664  removeData: jqLiteRemoveData,
3665  hasData: jqLiteHasData,
3666  cleanData: function jqLiteCleanData(nodes) {
3667    for (var i = 0, ii = nodes.length; i < ii; i++) {
3668      jqLiteRemoveData(nodes[i]);
3669      jqLiteOff(nodes[i]);
3670    }
3671  }
3672}, function(fn, name) {
3673  JQLite[name] = fn;
3674});
3675
3676forEach({
3677  data: jqLiteData,
3678  inheritedData: jqLiteInheritedData,
3679
3680  scope: function(element) {
3681    // Can't use jqLiteData here directly so we stay compatible with jQuery!
3682    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3683  },
3684
3685  isolateScope: function(element) {
3686    // Can't use jqLiteData here directly so we stay compatible with jQuery!
3687    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3688  },
3689
3690  controller: jqLiteController,
3691
3692  injector: function(element) {
3693    return jqLiteInheritedData(element, '$injector');
3694  },
3695
3696  removeAttr: function(element, name) {
3697    element.removeAttribute(name);
3698  },
3699
3700  hasClass: jqLiteHasClass,
3701
3702  css: function(element, name, value) {
3703    name = cssKebabToCamel(name);
3704
3705    if (isDefined(value)) {
3706      element.style[name] = value;
3707    } else {
3708      return element.style[name];
3709    }
3710  },
3711
3712  attr: function(element, name, value) {
3713    var ret;
3714    var nodeType = element.nodeType;
3715    if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
3716      !element.getAttribute) {
3717      return;
3718    }
3719
3720    var lowercasedName = lowercase(name);
3721    var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
3722
3723    if (isDefined(value)) {
3724      // setter
3725
3726      if (value === null || (value === false && isBooleanAttr)) {
3727        element.removeAttribute(name);
3728      } else {
3729        element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
3730      }
3731    } else {
3732      // getter
3733
3734      ret = element.getAttribute(name);
3735
3736      if (isBooleanAttr && ret !== null) {
3737        ret = lowercasedName;
3738      }
3739      // Normalize non-existing attributes to undefined (as jQuery).
3740      return ret === null ? undefined : ret;
3741    }
3742  },
3743
3744  prop: function(element, name, value) {
3745    if (isDefined(value)) {
3746      element[name] = value;
3747    } else {
3748      return element[name];
3749    }
3750  },
3751
3752  text: (function() {
3753    getText.$dv = '';
3754    return getText;
3755
3756    function getText(element, value) {
3757      if (isUndefined(value)) {
3758        var nodeType = element.nodeType;
3759        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3760      }
3761      element.textContent = value;
3762    }
3763  })(),
3764
3765  val: function(element, value) {
3766    if (isUndefined(value)) {
3767      if (element.multiple && nodeName_(element) === 'select') {
3768        var result = [];
3769        forEach(element.options, function(option) {
3770          if (option.selected) {
3771            result.push(option.value || option.text);
3772          }
3773        });
3774        return result;
3775      }
3776      return element.value;
3777    }
3778    element.value = value;
3779  },
3780
3781  html: function(element, value) {
3782    if (isUndefined(value)) {
3783      return element.innerHTML;
3784    }
3785    jqLiteDealoc(element, true);
3786    element.innerHTML = value;
3787  },
3788
3789  empty: jqLiteEmpty
3790}, function(fn, name) {
3791  /**
3792   * Properties: writes return selection, reads return first value
3793   */
3794  JQLite.prototype[name] = function(arg1, arg2) {
3795    var i, key;
3796    var nodeCount = this.length;
3797
3798    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3799    // in a way that survives minification.
3800    // jqLiteEmpty takes no arguments but is a setter.
3801    if (fn !== jqLiteEmpty &&
3802        (isUndefined((fn.length === 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3803      if (isObject(arg1)) {
3804
3805        // we are a write, but the object properties are the key/values
3806        for (i = 0; i < nodeCount; i++) {
3807          if (fn === jqLiteData) {
3808            // data() takes the whole object in jQuery
3809            fn(this[i], arg1);
3810          } else {
3811            for (key in arg1) {
3812              fn(this[i], key, arg1[key]);
3813            }
3814          }
3815        }
3816        // return self for chaining
3817        return this;
3818      } else {
3819        // we are a read, so read the first child.
3820        // TODO: do we still need this?
3821        var value = fn.$dv;
3822        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3823        var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3824        for (var j = 0; j < jj; j++) {
3825          var nodeValue = fn(this[j], arg1, arg2);
3826          value = value ? value + nodeValue : nodeValue;
3827        }
3828        return value;
3829      }
3830    } else {
3831      // we are a write, so apply to all children
3832      for (i = 0; i < nodeCount; i++) {
3833        fn(this[i], arg1, arg2);
3834      }
3835      // return self for chaining
3836      return this;
3837    }
3838  };
3839});
3840
3841function createEventHandler(element, events) {
3842  var eventHandler = function(event, type) {
3843    // jQuery specific api
3844    event.isDefaultPrevented = function() {
3845      return event.defaultPrevented;
3846    };
3847
3848    var eventFns = events[type || event.type];
3849    var eventFnsLength = eventFns ? eventFns.length : 0;
3850
3851    if (!eventFnsLength) return;
3852
3853    if (isUndefined(event.immediatePropagationStopped)) {
3854      var originalStopImmediatePropagation = event.stopImmediatePropagation;
3855      event.stopImmediatePropagation = function() {
3856        event.immediatePropagationStopped = true;
3857
3858        if (event.stopPropagation) {
3859          event.stopPropagation();
3860        }
3861
3862        if (originalStopImmediatePropagation) {
3863          originalStopImmediatePropagation.call(event);
3864        }
3865      };
3866    }
3867
3868    event.isImmediatePropagationStopped = function() {
3869      return event.immediatePropagationStopped === true;
3870    };
3871
3872    // Some events have special handlers that wrap the real handler
3873    var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3874
3875    // Copy event handlers in case event handlers array is modified during execution.
3876    if ((eventFnsLength > 1)) {
3877      eventFns = shallowCopy(eventFns);
3878    }
3879
3880    for (var i = 0; i < eventFnsLength; i++) {
3881      if (!event.isImmediatePropagationStopped()) {
3882        handlerWrapper(element, event, eventFns[i]);
3883      }
3884    }
3885  };
3886
3887  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3888  //       events on `element`
3889  eventHandler.elem = element;
3890  return eventHandler;
3891}
3892
3893function defaultHandlerWrapper(element, event, handler) {
3894  handler.call(element, event);
3895}
3896
3897function specialMouseHandlerWrapper(target, event, handler) {
3898  // Refer to jQuery's implementation of mouseenter & mouseleave
3899  // Read about mouseenter and mouseleave:
3900  // http://www.quirksmode.org/js/events_mouse.html#link8
3901  var related = event.relatedTarget;
3902  // For mousenter/leave call the handler if related is outside the target.
3903  // NB: No relatedTarget if the mouse left/entered the browser window
3904  if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3905    handler.call(target, event);
3906  }
3907}
3908
3909//////////////////////////////////////////
3910// Functions iterating traversal.
3911// These functions chain results into a single
3912// selector.
3913//////////////////////////////////////////
3914forEach({
3915  removeData: jqLiteRemoveData,
3916
3917  on: function jqLiteOn(element, type, fn, unsupported) {
3918    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3919
3920    // Do not add event handlers to non-elements because they will not be cleaned up.
3921    if (!jqLiteAcceptsData(element)) {
3922      return;
3923    }
3924
3925    var expandoStore = jqLiteExpandoStore(element, true);
3926    var events = expandoStore.events;
3927    var handle = expandoStore.handle;
3928
3929    if (!handle) {
3930      handle = expandoStore.handle = createEventHandler(element, events);
3931    }
3932
3933    // http://jsperf.com/string-indexof-vs-split
3934    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3935    var i = types.length;
3936
3937    var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3938      var eventFns = events[type];
3939
3940      if (!eventFns) {
3941        eventFns = events[type] = [];
3942        eventFns.specialHandlerWrapper = specialHandlerWrapper;
3943        if (type !== '$destroy' && !noEventListener) {
3944          element.addEventListener(type, handle);
3945        }
3946      }
3947
3948      eventFns.push(fn);
3949    };
3950
3951    while (i--) {
3952      type = types[i];
3953      if (MOUSE_EVENT_MAP[type]) {
3954        addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3955        addHandler(type, undefined, true);
3956      } else {
3957        addHandler(type);
3958      }
3959    }
3960  },
3961
3962  off: jqLiteOff,
3963
3964  one: function(element, type, fn) {
3965    element = jqLite(element);
3966
3967    //add the listener twice so that when it is called
3968    //you can remove the original function and still be
3969    //able to call element.off(ev, fn) normally
3970    element.on(type, function onFn() {
3971      element.off(type, fn);
3972      element.off(type, onFn);
3973    });
3974    element.on(type, fn);
3975  },
3976
3977  replaceWith: function(element, replaceNode) {
3978    var index, parent = element.parentNode;
3979    jqLiteDealoc(element);
3980    forEach(new JQLite(replaceNode), function(node) {
3981      if (index) {
3982        parent.insertBefore(node, index.nextSibling);
3983      } else {
3984        parent.replaceChild(node, element);
3985      }
3986      index = node;
3987    });
3988  },
3989
3990  children: function(element) {
3991    var children = [];
3992    forEach(element.childNodes, function(element) {
3993      if (element.nodeType === NODE_TYPE_ELEMENT) {
3994        children.push(element);
3995      }
3996    });
3997    return children;
3998  },
3999
4000  contents: function(element) {
4001    return element.contentDocument || element.childNodes || [];
4002  },
4003
4004  append: function(element, node) {
4005    var nodeType = element.nodeType;
4006    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
4007
4008    node = new JQLite(node);
4009
4010    for (var i = 0, ii = node.length; i < ii; i++) {
4011      var child = node[i];
4012      element.appendChild(child);
4013    }
4014  },
4015
4016  prepend: function(element, node) {
4017    if (element.nodeType === NODE_TYPE_ELEMENT) {
4018      var index = element.firstChild;
4019      forEach(new JQLite(node), function(child) {
4020        element.insertBefore(child, index);
4021      });
4022    }
4023  },
4024
4025  wrap: function(element, wrapNode) {
4026    jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
4027  },
4028
4029  remove: jqLiteRemove,
4030
4031  detach: function(element) {
4032    jqLiteRemove(element, true);
4033  },
4034
4035  after: function(element, newElement) {
4036    var index = element, parent = element.parentNode;
4037
4038    if (parent) {
4039      newElement = new JQLite(newElement);
4040
4041      for (var i = 0, ii = newElement.length; i < ii; i++) {
4042        var node = newElement[i];
4043        parent.insertBefore(node, index.nextSibling);
4044        index = node;
4045      }
4046    }
4047  },
4048
4049  addClass: jqLiteAddClass,
4050  removeClass: jqLiteRemoveClass,
4051
4052  toggleClass: function(element, selector, condition) {
4053    if (selector) {
4054      forEach(selector.split(' '), function(className) {
4055        var classCondition = condition;
4056        if (isUndefined(classCondition)) {
4057          classCondition = !jqLiteHasClass(element, className);
4058        }
4059        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
4060      });
4061    }
4062  },
4063
4064  parent: function(element) {
4065    var parent = element.parentNode;
4066    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
4067  },
4068
4069  next: function(element) {
4070    return element.nextElementSibling;
4071  },
4072
4073  find: function(element, selector) {
4074    if (element.getElementsByTagName) {
4075      return element.getElementsByTagName(selector);
4076    } else {
4077      return [];
4078    }
4079  },
4080
4081  clone: jqLiteClone,
4082
4083  triggerHandler: function(element, event, extraParameters) {
4084
4085    var dummyEvent, eventFnsCopy, handlerArgs;
4086    var eventName = event.type || event;
4087    var expandoStore = jqLiteExpandoStore(element);
4088    var events = expandoStore && expandoStore.events;
4089    var eventFns = events && events[eventName];
4090
4091    if (eventFns) {
4092      // Create a dummy event to pass to the handlers
4093      dummyEvent = {
4094        preventDefault: function() { this.defaultPrevented = true; },
4095        isDefaultPrevented: function() { return this.defaultPrevented === true; },
4096        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
4097        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
4098        stopPropagation: noop,
4099        type: eventName,
4100        target: element
4101      };
4102
4103      // If a custom event was provided then extend our dummy event with it
4104      if (event.type) {
4105        dummyEvent = extend(dummyEvent, event);
4106      }
4107
4108      // Copy event handlers in case event handlers array is modified during execution.
4109      eventFnsCopy = shallowCopy(eventFns);
4110      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
4111
4112      forEach(eventFnsCopy, function(fn) {
4113        if (!dummyEvent.isImmediatePropagationStopped()) {
4114          fn.apply(element, handlerArgs);
4115        }
4116      });
4117    }
4118  }
4119}, function(fn, name) {
4120  /**
4121   * chaining functions
4122   */
4123  JQLite.prototype[name] = function(arg1, arg2, arg3) {
4124    var value;
4125
4126    for (var i = 0, ii = this.length; i < ii; i++) {
4127      if (isUndefined(value)) {
4128        value = fn(this[i], arg1, arg2, arg3);
4129        if (isDefined(value)) {
4130          // any function which returns a value needs to be wrapped
4131          value = jqLite(value);
4132        }
4133      } else {
4134        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
4135      }
4136    }
4137    return isDefined(value) ? value : this;
4138  };
4139});
4140
4141// bind legacy bind/unbind to on/off
4142JQLite.prototype.bind = JQLite.prototype.on;
4143JQLite.prototype.unbind = JQLite.prototype.off;
4144
4145
4146// Provider for private $$jqLite service
4147/** @this */
4148function $$jqLiteProvider() {
4149  this.$get = function $$jqLite() {
4150    return extend(JQLite, {
4151      hasClass: function(node, classes) {
4152        if (node.attr) node = node[0];
4153        return jqLiteHasClass(node, classes);
4154      },
4155      addClass: function(node, classes) {
4156        if (node.attr) node = node[0];
4157        return jqLiteAddClass(node, classes);
4158      },
4159      removeClass: function(node, classes) {
4160        if (node.attr) node = node[0];
4161        return jqLiteRemoveClass(node, classes);
4162      }
4163    });
4164  };
4165}
4166
4167/**
4168 * Computes a hash of an 'obj'.
4169 * Hash of a:
4170 *  string is string
4171 *  number is number as string
4172 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
4173 *         that is also assigned to the $$hashKey property of the object.
4174 *
4175 * @param obj
4176 * @returns {string} hash string such that the same input will have the same hash string.
4177 *         The resulting string key is in 'type:hashKey' format.
4178 */
4179function hashKey(obj, nextUidFn) {
4180  var key = obj && obj.$$hashKey;
4181
4182  if (key) {
4183    if (typeof key === 'function') {
4184      key = obj.$$hashKey();
4185    }
4186    return key;
4187  }
4188
4189  var objType = typeof obj;
4190  if (objType === 'function' || (objType === 'object' && obj !== null)) {
4191    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
4192  } else {
4193    key = objType + ':' + obj;
4194  }
4195
4196  return key;
4197}
4198
4199// A minimal ES2015 Map implementation.
4200// Should be bug/feature equivalent to the native implementations of supported browsers
4201// (for the features required in Angular).
4202// See https://kangax.github.io/compat-table/es6/#test-Map
4203var nanKey = Object.create(null);
4204function NgMapShim() {
4205  this._keys = [];
4206  this._values = [];
4207  this._lastKey = NaN;
4208  this._lastIndex = -1;
4209}
4210NgMapShim.prototype = {
4211  _idx: function(key) {
4212    if (key !== this._lastKey) {
4213      this._lastKey = key;
4214      this._lastIndex = this._keys.indexOf(key);
4215    }
4216    return this._lastIndex;
4217  },
4218  _transformKey: function(key) {
4219    return isNumberNaN(key) ? nanKey : key;
4220  },
4221  get: function(key) {
4222    key = this._transformKey(key);
4223    var idx = this._idx(key);
4224    if (idx !== -1) {
4225      return this._values[idx];
4226    }
4227  },
4228  has: function(key) {
4229    key = this._transformKey(key);
4230    var idx = this._idx(key);
4231    return idx !== -1;
4232  },
4233  set: function(key, value) {
4234    key = this._transformKey(key);
4235    var idx = this._idx(key);
4236    if (idx === -1) {
4237      idx = this._lastIndex = this._keys.length;
4238    }
4239    this._keys[idx] = key;
4240    this._values[idx] = value;
4241
4242    // Support: IE11
4243    // Do not `return this` to simulate the partial IE11 implementation
4244  },
4245  delete: function(key) {
4246    key = this._transformKey(key);
4247    var idx = this._idx(key);
4248    if (idx === -1) {
4249      return false;
4250    }
4251    this._keys.splice(idx, 1);
4252    this._values.splice(idx, 1);
4253    this._lastKey = NaN;
4254    this._lastIndex = -1;
4255    return true;
4256  }
4257};
4258
4259// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
4260// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
4261// implementations get more stable, we can reconsider switching to `window.Map` (when available).
4262var NgMap = NgMapShim;
4263
4264var $$MapProvider = [/** @this */function() {
4265  this.$get = [function() {
4266    return NgMap;
4267  }];
4268}];
4269
4270/**
4271 * @ngdoc function
4272 * @module ng
4273 * @name angular.injector
4274 * @kind function
4275 *
4276 * @description
4277 * Creates an injector object that can be used for retrieving services as well as for
4278 * dependency injection (see {@link guide/di dependency injection}).
4279 *
4280 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
4281 *     {@link angular.module}. The `ng` module must be explicitly added.
4282 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
4283 *     disallows argument name annotation inference.
4284 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
4285 *
4286 * @example
4287 * Typical usage
4288 * ```js
4289 *   // create an injector
4290 *   var $injector = angular.injector(['ng']);
4291 *
4292 *   // use the injector to kick off your application
4293 *   // use the type inference to auto inject arguments, or use implicit injection
4294 *   $injector.invoke(function($rootScope, $compile, $document) {
4295 *     $compile($document)($rootScope);
4296 *     $rootScope.$digest();
4297 *   });
4298 * ```
4299 *
4300 * Sometimes you want to get access to the injector of a currently running AngularJS app
4301 * from outside AngularJS. Perhaps, you want to inject and compile some markup after the
4302 * application has been bootstrapped. You can do this using the extra `injector()` added
4303 * to JQuery/jqLite elements. See {@link angular.element}.
4304 *
4305 * *This is fairly rare but could be the case if a third party library is injecting the
4306 * markup.*
4307 *
4308 * In the following example a new block of HTML containing a `ng-controller`
4309 * directive is added to the end of the document body by JQuery. We then compile and link
4310 * it into the current AngularJS scope.
4311 *
4312 * ```js
4313 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
4314 * $(document.body).append($div);
4315 *
4316 * angular.element(document).injector().invoke(function($compile) {
4317 *   var scope = angular.element($div).scope();
4318 *   $compile($div)(scope);
4319 * });
4320 * ```
4321 */
4322
4323
4324/**
4325 * @ngdoc module
4326 * @name auto
4327 * @installation
4328 * @description
4329 *
4330 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
4331 */
4332
4333var ARROW_ARG = /^([^(]+?)=>/;
4334var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m;
4335var FN_ARG_SPLIT = /,/;
4336var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
4337var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
4338var $injectorMinErr = minErr('$injector');
4339
4340function stringifyFn(fn) {
4341  return Function.prototype.toString.call(fn);
4342}
4343
4344function extractArgs(fn) {
4345  var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
4346      args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
4347  return args;
4348}
4349
4350function anonFn(fn) {
4351  // For anonymous functions, showing at the very least the function signature can help in
4352  // debugging.
4353  var args = extractArgs(fn);
4354  if (args) {
4355    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
4356  }
4357  return 'fn';
4358}
4359
4360function annotate(fn, strictDi, name) {
4361  var $inject,
4362      argDecl,
4363      last;
4364
4365  if (typeof fn === 'function') {
4366    if (!($inject = fn.$inject)) {
4367      $inject = [];
4368      if (fn.length) {
4369        if (strictDi) {
4370          if (!isString(name) || !name) {
4371            name = fn.name || anonFn(fn);
4372          }
4373          throw $injectorMinErr('strictdi',
4374            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
4375        }
4376        argDecl = extractArgs(fn);
4377        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
4378          arg.replace(FN_ARG, function(all, underscore, name) {
4379            $inject.push(name);
4380          });
4381        });
4382      }
4383      fn.$inject = $inject;
4384    }
4385  } else if (isArray(fn)) {
4386    last = fn.length - 1;
4387    assertArgFn(fn[last], 'fn');
4388    $inject = fn.slice(0, last);
4389  } else {
4390    assertArgFn(fn, 'fn', true);
4391  }
4392  return $inject;
4393}
4394
4395///////////////////////////////////////
4396
4397/**
4398 * @ngdoc service
4399 * @name $injector
4400 *
4401 * @description
4402 *
4403 * `$injector` is used to retrieve object instances as defined by
4404 * {@link auto.$provide provider}, instantiate types, invoke methods,
4405 * and load modules.
4406 *
4407 * The following always holds true:
4408 *
4409 * ```js
4410 *   var $injector = angular.injector();
4411 *   expect($injector.get('$injector')).toBe($injector);
4412 *   expect($injector.invoke(function($injector) {
4413 *     return $injector;
4414 *   })).toBe($injector);
4415 * ```
4416 *
4417 * ## Injection Function Annotation
4418 *
4419 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
4420 * following are all valid ways of annotating function with injection arguments and are equivalent.
4421 *
4422 * ```js
4423 *   // inferred (only works if code not minified/obfuscated)
4424 *   $injector.invoke(function(serviceA){});
4425 *
4426 *   // annotated
4427 *   function explicit(serviceA) {};
4428 *   explicit.$inject = ['serviceA'];
4429 *   $injector.invoke(explicit);
4430 *
4431 *   // inline
4432 *   $injector.invoke(['serviceA', function(serviceA){}]);
4433 * ```
4434 *
4435 * ### Inference
4436 *
4437 * In JavaScript calling `toString()` on a function returns the function definition. The definition
4438 * can then be parsed and the function arguments can be extracted. This method of discovering
4439 * annotations is disallowed when the injector is in strict mode.
4440 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
4441 * argument names.
4442 *
4443 * ### `$inject` Annotation
4444 * By adding an `$inject` property onto a function the injection parameters can be specified.
4445 *
4446 * ### Inline
4447 * As an array of injection names, where the last item in the array is the function to call.
4448 */
4449
4450/**
4451 * @ngdoc property
4452 * @name $injector#modules
4453 * @type {Object}
4454 * @description
4455 * A hash containing all the modules that have been loaded into the
4456 * $injector.
4457 *
4458 * You can use this property to find out information about a module via the
4459 * {@link angular.Module#info `myModule.info(...)`} method.
4460 *
4461 * For example:
4462 *
4463 * ```
4464 * var info = $injector.modules['ngAnimate'].info();
4465 * ```
4466 *
4467 * **Do not use this property to attempt to modify the modules after the application
4468 * has been bootstrapped.**
4469 */
4470
4471
4472/**
4473 * @ngdoc method
4474 * @name $injector#get
4475 *
4476 * @description
4477 * Return an instance of the service.
4478 *
4479 * @param {string} name The name of the instance to retrieve.
4480 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
4481 * @return {*} The instance.
4482 */
4483
4484/**
4485 * @ngdoc method
4486 * @name $injector#invoke
4487 *
4488 * @description
4489 * Invoke the method and supply the method arguments from the `$injector`.
4490 *
4491 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
4492 *   injected according to the {@link guide/di $inject Annotation} rules.
4493 * @param {Object=} self The `this` for the invoked method.
4494 * @param {Object=} locals Optional object. If preset then any argument names are read from this
4495 *                         object first, before the `$injector` is consulted.
4496 * @returns {*} the value returned by the invoked `fn` function.
4497 */
4498
4499/**
4500 * @ngdoc method
4501 * @name $injector#has
4502 *
4503 * @description
4504 * Allows the user to query if the particular service exists.
4505 *
4506 * @param {string} name Name of the service to query.
4507 * @returns {boolean} `true` if injector has given service.
4508 */
4509
4510/**
4511 * @ngdoc method
4512 * @name $injector#instantiate
4513 * @description
4514 * Create a new instance of JS type. The method takes a constructor function, invokes the new
4515 * operator, and supplies all of the arguments to the constructor function as specified by the
4516 * constructor annotation.
4517 *
4518 * @param {Function} Type Annotated constructor function.
4519 * @param {Object=} locals Optional object. If preset then any argument names are read from this
4520 * object first, before the `$injector` is consulted.
4521 * @returns {Object} new instance of `Type`.
4522 */
4523
4524/**
4525 * @ngdoc method
4526 * @name $injector#annotate
4527 *
4528 * @description
4529 * Returns an array of service names which the function is requesting for injection. This API is
4530 * used by the injector to determine which services need to be injected into the function when the
4531 * function is invoked. There are three ways in which the function can be annotated with the needed
4532 * dependencies.
4533 *
4534 * #### Argument names
4535 *
4536 * The simplest form is to extract the dependencies from the arguments of the function. This is done
4537 * by converting the function into a string using `toString()` method and extracting the argument
4538 * names.
4539 * ```js
4540 *   // Given
4541 *   function MyController($scope, $route) {
4542 *     // ...
4543 *   }
4544 *
4545 *   // Then
4546 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4547 * ```
4548 *
4549 * You can disallow this method by using strict injection mode.
4550 *
4551 * This method does not work with code minification / obfuscation. For this reason the following
4552 * annotation strategies are supported.
4553 *
4554 * #### The `$inject` property
4555 *
4556 * If a function has an `$inject` property and its value is an array of strings, then the strings
4557 * represent names of services to be injected into the function.
4558 * ```js
4559 *   // Given
4560 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
4561 *     // ...
4562 *   }
4563 *   // Define function dependencies
4564 *   MyController['$inject'] = ['$scope', '$route'];
4565 *
4566 *   // Then
4567 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4568 * ```
4569 *
4570 * #### The array notation
4571 *
4572 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4573 * is very inconvenient. In these situations using the array notation to specify the dependencies in
4574 * a way that survives minification is a better choice:
4575 *
4576 * ```js
4577 *   // We wish to write this (not minification / obfuscation safe)
4578 *   injector.invoke(function($compile, $rootScope) {
4579 *     // ...
4580 *   });
4581 *
4582 *   // We are forced to write break inlining
4583 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4584 *     // ...
4585 *   };
4586 *   tmpFn.$inject = ['$compile', '$rootScope'];
4587 *   injector.invoke(tmpFn);
4588 *
4589 *   // To better support inline function the inline annotation is supported
4590 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4591 *     // ...
4592 *   }]);
4593 *
4594 *   // Therefore
4595 *   expect(injector.annotate(
4596 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4597 *    ).toEqual(['$compile', '$rootScope']);
4598 * ```
4599 *
4600 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4601 * be retrieved as described above.
4602 *
4603 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4604 *
4605 * @returns {Array.<string>} The names of the services which the function requires.
4606 */
4607/**
4608 * @ngdoc method
4609 * @name $injector#loadNewModules
4610 *
4611 * @description
4612 *
4613 * **This is a dangerous API, which you use at your own risk!**
4614 *
4615 * Add the specified modules to the current injector.
4616 *
4617 * This method will add each of the injectables to the injector and execute all of the config and run
4618 * blocks for each module passed to the method.
4619 *
4620 * If a module has already been loaded into the injector then it will not be loaded again.
4621 *
4622 * * The application developer is responsible for loading the code containing the modules; and for
4623 * ensuring that lazy scripts are not downloaded and executed more often that desired.
4624 * * Previously compiled HTML will not be affected by newly loaded directives, filters and components.
4625 * * Modules cannot be unloaded.
4626 *
4627 * You can use {@link $injector#modules `$injector.modules`} to check whether a module has been loaded
4628 * into the injector, which may indicate whether the script has been executed already.
4629 *
4630 * @example
4631 * Here is an example of loading a bundle of modules, with a utility method called `getScript`:
4632 *
4633 * ```javascript
4634 * app.factory('loadModule', function($injector) {
4635 *   return function loadModule(moduleName, bundleUrl) {
4636 *     return getScript(bundleUrl).then(function() { $injector.loadNewModules([moduleName]); });
4637 *   };
4638 * })
4639 * ```
4640 *
4641 * @param {Array<String|Function|Array>=} mods an array of modules to load into the application.
4642 *     Each item in the array should be the name of a predefined module or a (DI annotated)
4643 *     function that will be invoked by the injector as a `config` block.
4644 *     See: {@link angular.module modules}
4645 */
4646
4647
4648/**
4649 * @ngdoc service
4650 * @name $provide
4651 *
4652 * @description
4653 *
4654 * The {@link auto.$provide $provide} service has a number of methods for registering components
4655 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4656 * {@link angular.Module}.
4657 *
4658 * An AngularJS **service** is a singleton object created by a **service factory**.  These **service
4659 * factories** are functions which, in turn, are created by a **service provider**.
4660 * The **service providers** are constructor functions. When instantiated they must contain a
4661 * property called `$get`, which holds the **service factory** function.
4662 *
4663 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4664 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4665 * function to get the instance of the **service**.
4666 *
4667 * Often services have no configuration options and there is no need to add methods to the service
4668 * provider.  The provider will be no more than a constructor function with a `$get` property. For
4669 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4670 * services without specifying a provider.
4671 *
4672 * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
4673 *     {@link auto.$injector $injector}
4674 * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
4675 *     providers and services.
4676 * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
4677 *     services, not providers.
4678 * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
4679 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4680 *     given factory function.
4681 * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
4682 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4683 *      a new object using the given constructor function.
4684 * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
4685 *      will be able to modify or replace the implementation of another service.
4686 *
4687 * See the individual methods for more information and examples.
4688 */
4689
4690/**
4691 * @ngdoc method
4692 * @name $provide#provider
4693 * @description
4694 *
4695 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4696 * are constructor functions, whose instances are responsible for "providing" a factory for a
4697 * service.
4698 *
4699 * Service provider names start with the name of the service they provide followed by `Provider`.
4700 * For example, the {@link ng.$log $log} service has a provider called
4701 * {@link ng.$logProvider $logProvider}.
4702 *
4703 * Service provider objects can have additional methods which allow configuration of the provider
4704 * and its service. Importantly, you can configure what kind of service is created by the `$get`
4705 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4706 * method {@link ng.$logProvider#debugEnabled debugEnabled}
4707 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4708 * console or not.
4709 *
4710 * It is possible to inject other providers into the provider function,
4711 * but the injected provider must have been defined before the one that requires it.
4712 *
4713 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4714                        'Provider'` key.
4715 * @param {(Object|function())} provider If the provider is:
4716 *
4717 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4718 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4719 *   - `Constructor`: a new instance of the provider will be created using
4720 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4721 *
4722 * @returns {Object} registered provider instance
4723
4724 * @example
4725 *
4726 * The following example shows how to create a simple event tracking service and register it using
4727 * {@link auto.$provide#provider $provide.provider()}.
4728 *
4729 * ```js
4730 *  // Define the eventTracker provider
4731 *  function EventTrackerProvider() {
4732 *    var trackingUrl = '/track';
4733 *
4734 *    // A provider method for configuring where the tracked events should been saved
4735 *    this.setTrackingUrl = function(url) {
4736 *      trackingUrl = url;
4737 *    };
4738 *
4739 *    // The service factory function
4740 *    this.$get = ['$http', function($http) {
4741 *      var trackedEvents = {};
4742 *      return {
4743 *        // Call this to track an event
4744 *        event: function(event) {
4745 *          var count = trackedEvents[event] || 0;
4746 *          count += 1;
4747 *          trackedEvents[event] = count;
4748 *          return count;
4749 *        },
4750 *        // Call this to save the tracked events to the trackingUrl
4751 *        save: function() {
4752 *          $http.post(trackingUrl, trackedEvents);
4753 *        }
4754 *      };
4755 *    }];
4756 *  }
4757 *
4758 *  describe('eventTracker', function() {
4759 *    var postSpy;
4760 *
4761 *    beforeEach(module(function($provide) {
4762 *      // Register the eventTracker provider
4763 *      $provide.provider('eventTracker', EventTrackerProvider);
4764 *    }));
4765 *
4766 *    beforeEach(module(function(eventTrackerProvider) {
4767 *      // Configure eventTracker provider
4768 *      eventTrackerProvider.setTrackingUrl('/custom-track');
4769 *    }));
4770 *
4771 *    it('tracks events', inject(function(eventTracker) {
4772 *      expect(eventTracker.event('login')).toEqual(1);
4773 *      expect(eventTracker.event('login')).toEqual(2);
4774 *    }));
4775 *
4776 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4777 *      postSpy = spyOn($http, 'post');
4778 *      eventTracker.event('login');
4779 *      eventTracker.save();
4780 *      expect(postSpy).toHaveBeenCalled();
4781 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4782 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4783 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4784 *    }));
4785 *  });
4786 * ```
4787 */
4788
4789/**
4790 * @ngdoc method
4791 * @name $provide#factory
4792 * @description
4793 *
4794 * Register a **service factory**, which will be called to return the service instance.
4795 * This is short for registering a service where its provider consists of only a `$get` property,
4796 * which is the given service factory function.
4797 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4798 * configure your service in a provider.
4799 *
4800 * @param {string} name The name of the instance.
4801 * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4802 *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4803 * @returns {Object} registered provider instance
4804 *
4805 * @example
4806 * Here is an example of registering a service
4807 * ```js
4808 *   $provide.factory('ping', ['$http', function($http) {
4809 *     return function ping() {
4810 *       return $http.send('/ping');
4811 *     };
4812 *   }]);
4813 * ```
4814 * You would then inject and use this service like this:
4815 * ```js
4816 *   someModule.controller('Ctrl', ['ping', function(ping) {
4817 *     ping();
4818 *   }]);
4819 * ```
4820 */
4821
4822
4823/**
4824 * @ngdoc method
4825 * @name $provide#service
4826 * @description
4827 *
4828 * Register a **service constructor**, which will be invoked with `new` to create the service
4829 * instance.
4830 * This is short for registering a service where its provider's `$get` property is a factory
4831 * function that returns an instance instantiated by the injector from the service constructor
4832 * function.
4833 *
4834 * Internally it looks a bit like this:
4835 *
4836 * ```
4837 * {
4838 *   $get: function() {
4839 *     return $injector.instantiate(constructor);
4840 *   }
4841 * }
4842 * ```
4843 *
4844 *
4845 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4846 * as a type/class.
4847 *
4848 * @param {string} name The name of the instance.
4849 * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4850 *     that will be instantiated.
4851 * @returns {Object} registered provider instance
4852 *
4853 * @example
4854 * Here is an example of registering a service using
4855 * {@link auto.$provide#service $provide.service(class)}.
4856 * ```js
4857 *   var Ping = function($http) {
4858 *     this.$http = $http;
4859 *   };
4860 *
4861 *   Ping.$inject = ['$http'];
4862 *
4863 *   Ping.prototype.send = function() {
4864 *     return this.$http.get('/ping');
4865 *   };
4866 *   $provide.service('ping', Ping);
4867 * ```
4868 * You would then inject and use this service like this:
4869 * ```js
4870 *   someModule.controller('Ctrl', ['ping', function(ping) {
4871 *     ping.send();
4872 *   }]);
4873 * ```
4874 */
4875
4876
4877/**
4878 * @ngdoc method
4879 * @name $provide#value
4880 * @description
4881 *
4882 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4883 * number, an array, an object or a function. This is short for registering a service where its
4884 * provider's `$get` property is a factory function that takes no arguments and returns the **value
4885 * service**. That also means it is not possible to inject other services into a value service.
4886 *
4887 * Value services are similar to constant services, except that they cannot be injected into a
4888 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4889 * an AngularJS {@link auto.$provide#decorator decorator}.
4890 *
4891 * @param {string} name The name of the instance.
4892 * @param {*} value The value.
4893 * @returns {Object} registered provider instance
4894 *
4895 * @example
4896 * Here are some examples of creating value services.
4897 * ```js
4898 *   $provide.value('ADMIN_USER', 'admin');
4899 *
4900 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4901 *
4902 *   $provide.value('halfOf', function(value) {
4903 *     return value / 2;
4904 *   });
4905 * ```
4906 */
4907
4908
4909/**
4910 * @ngdoc method
4911 * @name $provide#constant
4912 * @description
4913 *
4914 * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
4915 * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
4916 * possible to inject other services into a constant.
4917 *
4918 * But unlike {@link auto.$provide#value value}, a constant can be
4919 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4920 * be overridden by an AngularJS {@link auto.$provide#decorator decorator}.
4921 *
4922 * @param {string} name The name of the constant.
4923 * @param {*} value The constant value.
4924 * @returns {Object} registered instance
4925 *
4926 * @example
4927 * Here a some examples of creating constants:
4928 * ```js
4929 *   $provide.constant('SHARD_HEIGHT', 306);
4930 *
4931 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4932 *
4933 *   $provide.constant('double', function(value) {
4934 *     return value * 2;
4935 *   });
4936 * ```
4937 */
4938
4939
4940/**
4941 * @ngdoc method
4942 * @name $provide#decorator
4943 * @description
4944 *
4945 * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
4946 * intercepts the creation of a service, allowing it to override or modify the behavior of the
4947 * service. The return value of the decorator function may be the original service, or a new service
4948 * that replaces (or wraps and delegates to) the original service.
4949 *
4950 * You can find out more about using decorators in the {@link guide/decorators} guide.
4951 *
4952 * @param {string} name The name of the service to decorate.
4953 * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4954 *    provided and should return the decorated service instance. The function is called using
4955 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4956 *    Local injection arguments:
4957 *
4958 *    * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
4959 *      decorated or delegated to.
4960 *
4961 * @example
4962 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4963 * calls to {@link ng.$log#error $log.warn()}.
4964 * ```js
4965 *   $provide.decorator('$log', ['$delegate', function($delegate) {
4966 *     $delegate.warn = $delegate.error;
4967 *     return $delegate;
4968 *   }]);
4969 * ```
4970 */
4971
4972
4973function createInjector(modulesToLoad, strictDi) {
4974  strictDi = (strictDi === true);
4975  var INSTANTIATING = {},
4976      providerSuffix = 'Provider',
4977      path = [],
4978      loadedModules = new NgMap(),
4979      providerCache = {
4980        $provide: {
4981            provider: supportObject(provider),
4982            factory: supportObject(factory),
4983            service: supportObject(service),
4984            value: supportObject(value),
4985            constant: supportObject(constant),
4986            decorator: decorator
4987          }
4988      },
4989      providerInjector = (providerCache.$injector =
4990          createInternalInjector(providerCache, function(serviceName, caller) {
4991            if (angular.isString(caller)) {
4992              path.push(caller);
4993            }
4994            throw $injectorMinErr('unpr', 'Unknown provider: {0}', path.join(' <- '));
4995          })),
4996      instanceCache = {},
4997      protoInstanceInjector =
4998          createInternalInjector(instanceCache, function(serviceName, caller) {
4999            var provider = providerInjector.get(serviceName + providerSuffix, caller);
5000            return instanceInjector.invoke(
5001                provider.$get, provider, undefined, serviceName);
5002          }),
5003      instanceInjector = protoInstanceInjector;
5004
5005  providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
5006  instanceInjector.modules = providerInjector.modules = createMap();
5007  var runBlocks = loadModules(modulesToLoad);
5008  instanceInjector = protoInstanceInjector.get('$injector');
5009  instanceInjector.strictDi = strictDi;
5010  forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
5011
5012  instanceInjector.loadNewModules = function(mods) {
5013    forEach(loadModules(mods), function(fn) { if (fn) instanceInjector.invoke(fn); });
5014  };
5015
5016
5017  return instanceInjector;
5018
5019  ////////////////////////////////////
5020  // $provider
5021  ////////////////////////////////////
5022
5023  function supportObject(delegate) {
5024    return function(key, value) {
5025      if (isObject(key)) {
5026        forEach(key, reverseParams(delegate));
5027      } else {
5028        return delegate(key, value);
5029      }
5030    };
5031  }
5032
5033  function provider(name, provider_) {
5034    assertNotHasOwnProperty(name, 'service');
5035    if (isFunction(provider_) || isArray(provider_)) {
5036      provider_ = providerInjector.instantiate(provider_);
5037    }
5038    if (!provider_.$get) {
5039      throw $injectorMinErr('pget', 'Provider \'{0}\' must define $get factory method.', name);
5040    }
5041    return (providerCache[name + providerSuffix] = provider_);
5042  }
5043
5044  function enforceReturnValue(name, factory) {
5045    return /** @this */ function enforcedReturnValue() {
5046      var result = instanceInjector.invoke(factory, this);
5047      if (isUndefined(result)) {
5048        throw $injectorMinErr('undef', 'Provider \'{0}\' must return a value from $get factory method.', name);
5049      }
5050      return result;
5051    };
5052  }
5053
5054  function factory(name, factoryFn, enforce) {
5055    return provider(name, {
5056      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
5057    });
5058  }
5059
5060  function service(name, constructor) {
5061    return factory(name, ['$injector', function($injector) {
5062      return $injector.instantiate(constructor);
5063    }]);
5064  }
5065
5066  function value(name, val) { return factory(name, valueFn(val), false); }
5067
5068  function constant(name, value) {
5069    assertNotHasOwnProperty(name, 'constant');
5070    providerCache[name] = value;
5071    instanceCache[name] = value;
5072  }
5073
5074  function decorator(serviceName, decorFn) {
5075    var origProvider = providerInjector.get(serviceName + providerSuffix),
5076        orig$get = origProvider.$get;
5077
5078    origProvider.$get = function() {
5079      var origInstance = instanceInjector.invoke(orig$get, origProvider);
5080      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
5081    };
5082  }
5083
5084  ////////////////////////////////////
5085  // Module Loading
5086  ////////////////////////////////////
5087  function loadModules(modulesToLoad) {
5088    assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
5089    var runBlocks = [], moduleFn;
5090    forEach(modulesToLoad, function(module) {
5091      if (loadedModules.get(module)) return;
5092      loadedModules.set(module, true);
5093
5094      function runInvokeQueue(queue) {
5095        var i, ii;
5096        for (i = 0, ii = queue.length; i < ii; i++) {
5097          var invokeArgs = queue[i],
5098              provider = providerInjector.get(invokeArgs[0]);
5099
5100          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
5101        }
5102      }
5103
5104      try {
5105        if (isString(module)) {
5106          moduleFn = angularModule(module);
5107          instanceInjector.modules[module] = moduleFn;
5108          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
5109          runInvokeQueue(moduleFn._invokeQueue);
5110          runInvokeQueue(moduleFn._configBlocks);
5111        } else if (isFunction(module)) {
5112            runBlocks.push(providerInjector.invoke(module));
5113        } else if (isArray(module)) {
5114            runBlocks.push(providerInjector.invoke(module));
5115        } else {
5116          assertArgFn(module, 'module');
5117        }
5118      } catch (e) {
5119        if (isArray(module)) {
5120          module = module[module.length - 1];
5121        }
5122        if (e.message && e.stack && e.stack.indexOf(e.message) === -1) {
5123          // Safari & FF's stack traces don't contain error.message content
5124          // unlike those of Chrome and IE
5125          // So if stack doesn't contain message, we create a new string that contains both.
5126          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
5127          // eslint-disable-next-line no-ex-assign
5128          e = e.message + '\n' + e.stack;
5129        }
5130        throw $injectorMinErr('modulerr', 'Failed to instantiate module {0} due to:\n{1}',
5131                  module, e.stack || e.message || e);
5132      }
5133    });
5134    return runBlocks;
5135  }
5136
5137  ////////////////////////////////////
5138  // internal Injector
5139  ////////////////////////////////////
5140
5141  function createInternalInjector(cache, factory) {
5142
5143    function getService(serviceName, caller) {
5144      if (cache.hasOwnProperty(serviceName)) {
5145        if (cache[serviceName] === INSTANTIATING) {
5146          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
5147                    serviceName + ' <- ' + path.join(' <- '));
5148        }
5149        return cache[serviceName];
5150      } else {
5151        try {
5152          path.unshift(serviceName);
5153          cache[serviceName] = INSTANTIATING;
5154          cache[serviceName] = factory(serviceName, caller);
5155          return cache[serviceName];
5156        } catch (err) {
5157          if (cache[serviceName] === INSTANTIATING) {
5158            delete cache[serviceName];
5159          }
5160          throw err;
5161        } finally {
5162          path.shift();
5163        }
5164      }
5165    }
5166
5167
5168    function injectionArgs(fn, locals, serviceName) {
5169      var args = [],
5170          $inject = createInjector.$$annotate(fn, strictDi, serviceName);
5171
5172      for (var i = 0, length = $inject.length; i < length; i++) {
5173        var key = $inject[i];
5174        if (typeof key !== 'string') {
5175          throw $injectorMinErr('itkn',
5176                  'Incorrect injection token! Expected service name as string, got {0}', key);
5177        }
5178        args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
5179                                                         getService(key, serviceName));
5180      }
5181      return args;
5182    }
5183
5184    function isClass(func) {
5185      // Support: IE 9-11 only
5186      // IE 9-11 do not support classes and IE9 leaks with the code below.
5187      if (msie || typeof func !== 'function') {
5188        return false;
5189      }
5190      var result = func.$$ngIsClass;
5191      if (!isBoolean(result)) {
5192        result = func.$$ngIsClass = /^class\b/.test(stringifyFn(func));
5193      }
5194      return result;
5195    }
5196
5197    function invoke(fn, self, locals, serviceName) {
5198      if (typeof locals === 'string') {
5199        serviceName = locals;
5200        locals = null;
5201      }
5202
5203      var args = injectionArgs(fn, locals, serviceName);
5204      if (isArray(fn)) {
5205        fn = fn[fn.length - 1];
5206      }
5207
5208      if (!isClass(fn)) {
5209        // http://jsperf.com/angularjs-invoke-apply-vs-switch
5210        // #5388
5211        return fn.apply(self, args);
5212      } else {
5213        args.unshift(null);
5214        return new (Function.prototype.bind.apply(fn, args))();
5215      }
5216    }
5217
5218
5219    function instantiate(Type, locals, serviceName) {
5220      // Check if Type is annotated and use just the given function at n-1 as parameter
5221      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
5222      var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
5223      var args = injectionArgs(Type, locals, serviceName);
5224      // Empty object at position 0 is ignored for invocation with `new`, but required.
5225      args.unshift(null);
5226      return new (Function.prototype.bind.apply(ctor, args))();
5227    }
5228
5229
5230    return {
5231      invoke: invoke,
5232      instantiate: instantiate,
5233      get: getService,
5234      annotate: createInjector.$$annotate,
5235      has: function(name) {
5236        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
5237      }
5238    };
5239  }
5240}
5241
5242createInjector.$$annotate = annotate;
5243
5244/**
5245 * @ngdoc provider
5246 * @name $anchorScrollProvider
5247 * @this
5248 *
5249 * @description
5250 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
5251 * {@link ng.$location#hash $location.hash()} changes.
5252 */
5253function $AnchorScrollProvider() {
5254
5255  var autoScrollingEnabled = true;
5256
5257  /**
5258   * @ngdoc method
5259   * @name $anchorScrollProvider#disableAutoScrolling
5260   *
5261   * @description
5262   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
5263   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
5264   * Use this method to disable automatic scrolling.
5265   *
5266   * If automatic scrolling is disabled, one must explicitly call
5267   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
5268   * current hash.
5269   */
5270  this.disableAutoScrolling = function() {
5271    autoScrollingEnabled = false;
5272  };
5273
5274  /**
5275   * @ngdoc service
5276   * @name $anchorScroll
5277   * @kind function
5278   * @requires $window
5279   * @requires $location
5280   * @requires $rootScope
5281   *
5282   * @description
5283   * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
5284   * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
5285   * in the
5286   * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
5287   *
5288   * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
5289   * match any anchor whenever it changes. This can be disabled by calling
5290   * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
5291   *
5292   * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
5293   * vertical scroll-offset (either fixed or dynamic).
5294   *
5295   * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
5296   *                       {@link ng.$location#hash $location.hash()} will be used.
5297   *
5298   * @property {(number|function|jqLite)} yOffset
5299   * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
5300   * positioned elements at the top of the page, such as navbars, headers etc.
5301   *
5302   * `yOffset` can be specified in various ways:
5303   * - **number**: A fixed number of pixels to be used as offset.<br /><br />
5304   * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
5305   *   a number representing the offset (in pixels).<br /><br />
5306   * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
5307   *   the top of the page to the element's bottom will be used as offset.<br />
5308   *   **Note**: The element will be taken into account only as long as its `position` is set to
5309   *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
5310   *   their height and/or positioning according to the viewport's size.
5311   *
5312   * <br />
5313   * <div class="alert alert-warning">
5314   * In order for `yOffset` to work properly, scrolling should take place on the document's root and
5315   * not some child element.
5316   * </div>
5317   *
5318   * @example
5319     <example module="anchorScrollExample" name="anchor-scroll">
5320       <file name="index.html">
5321         <div id="scrollArea" ng-controller="ScrollController">
5322           <a ng-click="gotoBottom()">Go to bottom</a>
5323           <a id="bottom"></a> You're at the bottom!
5324         </div>
5325       </file>
5326       <file name="script.js">
5327         angular.module('anchorScrollExample', [])
5328           .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
5329             function($scope, $location, $anchorScroll) {
5330               $scope.gotoBottom = function() {
5331                 // set the location.hash to the id of
5332                 // the element you wish to scroll to.
5333                 $location.hash('bottom');
5334
5335                 // call $anchorScroll()
5336                 $anchorScroll();
5337               };
5338             }]);
5339       </file>
5340       <file name="style.css">
5341         #scrollArea {
5342           height: 280px;
5343           overflow: auto;
5344         }
5345
5346         #bottom {
5347           display: block;
5348           margin-top: 2000px;
5349         }
5350       </file>
5351     </example>
5352   *
5353   * <hr />
5354   * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
5355   * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
5356   *
5357   * @example
5358     <example module="anchorScrollOffsetExample" name="anchor-scroll-offset">
5359       <file name="index.html">
5360         <div class="fixed-header" ng-controller="headerCtrl">
5361           <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
5362             Go to anchor {{x}}
5363           </a>
5364         </div>
5365         <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
5366           Anchor {{x}} of 5
5367         </div>
5368       </file>
5369       <file name="script.js">
5370         angular.module('anchorScrollOffsetExample', [])
5371           .run(['$anchorScroll', function($anchorScroll) {
5372             $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
5373           }])
5374           .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
5375             function($anchorScroll, $location, $scope) {
5376               $scope.gotoAnchor = function(x) {
5377                 var newHash = 'anchor' + x;
5378                 if ($location.hash() !== newHash) {
5379                   // set the $location.hash to `newHash` and
5380                   // $anchorScroll will automatically scroll to it
5381                   $location.hash('anchor' + x);
5382                 } else {
5383                   // call $anchorScroll() explicitly,
5384                   // since $location.hash hasn't changed
5385                   $anchorScroll();
5386                 }
5387               };
5388             }
5389           ]);
5390       </file>
5391       <file name="style.css">
5392         body {
5393           padding-top: 50px;
5394         }
5395
5396         .anchor {
5397           border: 2px dashed DarkOrchid;
5398           padding: 10px 10px 200px 10px;
5399         }
5400
5401         .fixed-header {
5402           background-color: rgba(0, 0, 0, 0.2);
5403           height: 50px;
5404           position: fixed;
5405           top: 0; left: 0; right: 0;
5406         }
5407
5408         .fixed-header > a {
5409           display: inline-block;
5410           margin: 5px 15px;
5411         }
5412       </file>
5413     </example>
5414   */
5415  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
5416    var document = $window.document;
5417
5418    // Helper function to get first anchor from a NodeList
5419    // (using `Array#some()` instead of `angular#forEach()` since it's more performant
5420    //  and working in all supported browsers.)
5421    function getFirstAnchor(list) {
5422      var result = null;
5423      Array.prototype.some.call(list, function(element) {
5424        if (nodeName_(element) === 'a') {
5425          result = element;
5426          return true;
5427        }
5428      });
5429      return result;
5430    }
5431
5432    function getYOffset() {
5433
5434      var offset = scroll.yOffset;
5435
5436      if (isFunction(offset)) {
5437        offset = offset();
5438      } else if (isElement(offset)) {
5439        var elem = offset[0];
5440        var style = $window.getComputedStyle(elem);
5441        if (style.position !== 'fixed') {
5442          offset = 0;
5443        } else {
5444          offset = elem.getBoundingClientRect().bottom;
5445        }
5446      } else if (!isNumber(offset)) {
5447        offset = 0;
5448      }
5449
5450      return offset;
5451    }
5452
5453    function scrollTo(elem) {
5454      if (elem) {
5455        elem.scrollIntoView();
5456
5457        var offset = getYOffset();
5458
5459        if (offset) {
5460          // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
5461          // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
5462          // top of the viewport.
5463          //
5464          // IF the number of pixels from the top of `elem` to the end of the page's content is less
5465          // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
5466          // way down the page.
5467          //
5468          // This is often the case for elements near the bottom of the page.
5469          //
5470          // In such cases we do not need to scroll the whole `offset` up, just the difference between
5471          // the top of the element and the offset, which is enough to align the top of `elem` at the
5472          // desired position.
5473          var elemTop = elem.getBoundingClientRect().top;
5474          $window.scrollBy(0, elemTop - offset);
5475        }
5476      } else {
5477        $window.scrollTo(0, 0);
5478      }
5479    }
5480
5481    function scroll(hash) {
5482      // Allow numeric hashes
5483      hash = isString(hash) ? hash : isNumber(hash) ? hash.toString() : $location.hash();
5484      var elm;
5485
5486      // empty hash, scroll to the top of the page
5487      if (!hash) scrollTo(null);
5488
5489      // element with given id
5490      else if ((elm = document.getElementById(hash))) scrollTo(elm);
5491
5492      // first anchor with given name :-D
5493      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
5494
5495      // no element and hash === 'top', scroll to the top of the page
5496      else if (hash === 'top') scrollTo(null);
5497    }
5498
5499    // does not scroll when user clicks on anchor link that is currently on
5500    // (no url change, no $location.hash() change), browser native does scroll
5501    if (autoScrollingEnabled) {
5502      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
5503        function autoScrollWatchAction(newVal, oldVal) {
5504          // skip the initial scroll if $location.hash is empty
5505          if (newVal === oldVal && newVal === '') return;
5506
5507          jqLiteDocumentLoaded(function() {
5508            $rootScope.$evalAsync(scroll);
5509          });
5510        });
5511    }
5512
5513    return scroll;
5514  }];
5515}
5516
5517var $animateMinErr = minErr('$animate');
5518var ELEMENT_NODE = 1;
5519var NG_ANIMATE_CLASSNAME = 'ng-animate';
5520
5521function mergeClasses(a,b) {
5522  if (!a && !b) return '';
5523  if (!a) return b;
5524  if (!b) return a;
5525  if (isArray(a)) a = a.join(' ');
5526  if (isArray(b)) b = b.join(' ');
5527  return a + ' ' + b;
5528}
5529
5530function extractElementNode(element) {
5531  for (var i = 0; i < element.length; i++) {
5532    var elm = element[i];
5533    if (elm.nodeType === ELEMENT_NODE) {
5534      return elm;
5535    }
5536  }
5537}
5538
5539function splitClasses(classes) {
5540  if (isString(classes)) {
5541    classes = classes.split(' ');
5542  }
5543
5544  // Use createMap() to prevent class assumptions involving property names in
5545  // Object.prototype
5546  var obj = createMap();
5547  forEach(classes, function(klass) {
5548    // sometimes the split leaves empty string values
5549    // incase extra spaces were applied to the options
5550    if (klass.length) {
5551      obj[klass] = true;
5552    }
5553  });
5554  return obj;
5555}
5556
5557// if any other type of options value besides an Object value is
5558// passed into the $animate.method() animation then this helper code
5559// will be run which will ignore it. While this patch is not the
5560// greatest solution to this, a lot of existing plugins depend on
5561// $animate to either call the callback (< 1.2) or return a promise
5562// that can be changed. This helper function ensures that the options
5563// are wiped clean incase a callback function is provided.
5564function prepareAnimateOptions(options) {
5565  return isObject(options)
5566      ? options
5567      : {};
5568}
5569
5570var $$CoreAnimateJsProvider = /** @this */ function() {
5571  this.$get = noop;
5572};
5573
5574// this is prefixed with Core since it conflicts with
5575// the animateQueueProvider defined in ngAnimate/animateQueue.js
5576var $$CoreAnimateQueueProvider = /** @this */ function() {
5577  var postDigestQueue = new NgMap();
5578  var postDigestElements = [];
5579
5580  this.$get = ['$$AnimateRunner', '$rootScope',
5581       function($$AnimateRunner,   $rootScope) {
5582    return {
5583      enabled: noop,
5584      on: noop,
5585      off: noop,
5586      pin: noop,
5587
5588      push: function(element, event, options, domOperation) {
5589        if (domOperation) {
5590          domOperation();
5591        }
5592
5593        options = options || {};
5594        if (options.from) {
5595          element.css(options.from);
5596        }
5597        if (options.to) {
5598          element.css(options.to);
5599        }
5600
5601        if (options.addClass || options.removeClass) {
5602          addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
5603        }
5604
5605        var runner = new $$AnimateRunner();
5606
5607        // since there are no animations to run the runner needs to be
5608        // notified that the animation call is complete.
5609        runner.complete();
5610        return runner;
5611      }
5612    };
5613
5614
5615    function updateData(data, classes, value) {
5616      var changed = false;
5617      if (classes) {
5618        classes = isString(classes) ? classes.split(' ') :
5619                  isArray(classes) ? classes : [];
5620        forEach(classes, function(className) {
5621          if (className) {
5622            changed = true;
5623            data[className] = value;
5624          }
5625        });
5626      }
5627      return changed;
5628    }
5629
5630    function handleCSSClassChanges() {
5631      forEach(postDigestElements, function(element) {
5632        var data = postDigestQueue.get(element);
5633        if (data) {
5634          var existing = splitClasses(element.attr('class'));
5635          var toAdd = '';
5636          var toRemove = '';
5637          forEach(data, function(status, className) {
5638            var hasClass = !!existing[className];
5639            if (status !== hasClass) {
5640              if (status) {
5641                toAdd += (toAdd.length ? ' ' : '') + className;
5642              } else {
5643                toRemove += (toRemove.length ? ' ' : '') + className;
5644              }
5645            }
5646          });
5647
5648          forEach(element, function(elm) {
5649            if (toAdd) {
5650              jqLiteAddClass(elm, toAdd);
5651            }
5652            if (toRemove) {
5653              jqLiteRemoveClass(elm, toRemove);
5654            }
5655          });
5656          postDigestQueue.delete(element);
5657        }
5658      });
5659      postDigestElements.length = 0;
5660    }
5661
5662
5663    function addRemoveClassesPostDigest(element, add, remove) {
5664      var data = postDigestQueue.get(element) || {};
5665
5666      var classesAdded = updateData(data, add, true);
5667      var classesRemoved = updateData(data, remove, false);
5668
5669      if (classesAdded || classesRemoved) {
5670
5671        postDigestQueue.set(element, data);
5672        postDigestElements.push(element);
5673
5674        if (postDigestElements.length === 1) {
5675          $rootScope.$$postDigest(handleCSSClassChanges);
5676        }
5677      }
5678    }
5679  }];
5680};
5681
5682/**
5683 * @ngdoc provider
5684 * @name $animateProvider
5685 *
5686 * @description
5687 * Default implementation of $animate that doesn't perform any animations, instead just
5688 * synchronously performs DOM updates and resolves the returned runner promise.
5689 *
5690 * In order to enable animations the `ngAnimate` module has to be loaded.
5691 *
5692 * To see the functional implementation check out `src/ngAnimate/animate.js`.
5693 */
5694var $AnimateProvider = ['$provide', /** @this */ function($provide) {
5695  var provider = this;
5696  var classNameFilter = null;
5697  var customFilter = null;
5698
5699  this.$$registeredAnimations = Object.create(null);
5700
5701   /**
5702   * @ngdoc method
5703   * @name $animateProvider#register
5704   *
5705   * @description
5706   * Registers a new injectable animation factory function. The factory function produces the
5707   * animation object which contains callback functions for each event that is expected to be
5708   * animated.
5709   *
5710   *   * `eventFn`: `function(element, ... , doneFunction, options)`
5711   *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5712   *   on the type of animation additional arguments will be injected into the animation function. The
5713   *   list below explains the function signatures for the different animation methods:
5714   *
5715   *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5716   *   - addClass: function(element, addedClasses, doneFunction, options)
5717   *   - removeClass: function(element, removedClasses, doneFunction, options)
5718   *   - enter, leave, move: function(element, doneFunction, options)
5719   *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5720   *
5721   *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5722   *
5723   * ```js
5724   *   return {
5725   *     //enter, leave, move signature
5726   *     eventFn : function(element, done, options) {
5727   *       //code to run the animation
5728   *       //once complete, then run done()
5729   *       return function endFunction(wasCancelled) {
5730   *         //code to cancel the animation
5731   *       }
5732   *     }
5733   *   }
5734   * ```
5735   *
5736   * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5737   * @param {Function} factory The factory function that will be executed to return the animation
5738   *                           object.
5739   */
5740  this.register = function(name, factory) {
5741    if (name && name.charAt(0) !== '.') {
5742      throw $animateMinErr('notcsel', 'Expecting class selector starting with \'.\' got \'{0}\'.', name);
5743    }
5744
5745    var key = name + '-animation';
5746    provider.$$registeredAnimations[name.substr(1)] = key;
5747    $provide.factory(key, factory);
5748  };
5749
5750  /**
5751   * @ngdoc method
5752   * @name $animateProvider#customFilter
5753   *
5754   * @description
5755   * Sets and/or returns the custom filter function that is used to "filter" animations, i.e.
5756   * determine if an animation is allowed or not. When no filter is specified (the default), no
5757   * animation will be blocked. Setting the `customFilter` value will only allow animations for
5758   * which the filter function's return value is truthy.
5759   *
5760   * This allows to easily create arbitrarily complex rules for filtering animations, such as
5761   * allowing specific events only, or enabling animations on specific subtrees of the DOM, etc.
5762   * Filtering animations can also boost performance for low-powered devices, as well as
5763   * applications containing a lot of structural operations.
5764   *
5765   * <div class="alert alert-success">
5766   *   **Best Practice:**
5767   *   Keep the filtering function as lean as possible, because it will be called for each DOM
5768   *   action (e.g. insertion, removal, class change) performed by "animation-aware" directives.
5769   *   See {@link guide/animations#which-directives-support-animations- here} for a list of built-in
5770   *   directives that support animations.
5771   *   Performing computationally expensive or time-consuming operations on each call of the
5772   *   filtering function can make your animations sluggish.
5773   * </div>
5774   *
5775   * **Note:** If present, `customFilter` will be checked before
5776   * {@link $animateProvider#classNameFilter classNameFilter}.
5777   *
5778   * @param {Function=} filterFn - The filter function which will be used to filter all animations.
5779   *   If a falsy value is returned, no animation will be performed. The function will be called
5780   *   with the following arguments:
5781   *   - **node** `{DOMElement}` - The DOM element to be animated.
5782   *   - **event** `{String}` - The name of the animation event (e.g. `enter`, `leave`, `addClass`
5783   *     etc).
5784   *   - **options** `{Object}` - A collection of options/styles used for the animation.
5785   * @return {Function} The current filter function or `null` if there is none set.
5786   */
5787  this.customFilter = function(filterFn) {
5788    if (arguments.length === 1) {
5789      customFilter = isFunction(filterFn) ? filterFn : null;
5790    }
5791
5792    return customFilter;
5793  };
5794
5795  /**
5796   * @ngdoc method
5797   * @name $animateProvider#classNameFilter
5798   *
5799   * @description
5800   * Sets and/or returns the CSS class regular expression that is checked when performing
5801   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5802   * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5803   * When setting the `classNameFilter` value, animations will only be performed on elements
5804   * that successfully match the filter expression. This in turn can boost performance
5805   * for low-powered devices as well as applications containing a lot of structural operations.
5806   *
5807   * **Note:** If present, `classNameFilter` will be checked after
5808   * {@link $animateProvider#customFilter customFilter}. If `customFilter` is present and returns
5809   * false, `classNameFilter` will not be checked.
5810   *
5811   * @param {RegExp=} expression The className expression which will be checked against all animations
5812   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5813   */
5814  this.classNameFilter = function(expression) {
5815    if (arguments.length === 1) {
5816      classNameFilter = (expression instanceof RegExp) ? expression : null;
5817      if (classNameFilter) {
5818        var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]');
5819        if (reservedRegex.test(classNameFilter.toString())) {
5820          classNameFilter = null;
5821          throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5822        }
5823      }
5824    }
5825    return classNameFilter;
5826  };
5827
5828  this.$get = ['$$animateQueue', function($$animateQueue) {
5829    function domInsert(element, parentElement, afterElement) {
5830      // if for some reason the previous element was removed
5831      // from the dom sometime before this code runs then let's
5832      // just stick to using the parent element as the anchor
5833      if (afterElement) {
5834        var afterNode = extractElementNode(afterElement);
5835        if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5836          afterElement = null;
5837        }
5838      }
5839      if (afterElement) {
5840        afterElement.after(element);
5841      } else {
5842        parentElement.prepend(element);
5843      }
5844    }
5845
5846    /**
5847     * @ngdoc service
5848     * @name $animate
5849     * @description The $animate service exposes a series of DOM utility methods that provide support
5850     * for animation hooks. The default behavior is the application of DOM operations, however,
5851     * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5852     * to ensure that animation runs with the triggered DOM operation.
5853     *
5854     * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5855     * included and only when it is active then the animation hooks that `$animate` triggers will be
5856     * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5857     * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5858     * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5859     *
5860     * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5861     *
5862     * To learn more about enabling animation support, click here to visit the
5863     * {@link ngAnimate ngAnimate module page}.
5864     */
5865    return {
5866      // we don't call it directly since non-existant arguments may
5867      // be interpreted as null within the sub enabled function
5868
5869      /**
5870       *
5871       * @ngdoc method
5872       * @name $animate#on
5873       * @kind function
5874       * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5875       *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5876       *    is fired with the following params:
5877       *
5878       * ```js
5879       * $animate.on('enter', container,
5880       *    function callback(element, phase) {
5881       *      // cool we detected an enter animation within the container
5882       *    }
5883       * );
5884       * ```
5885       *
5886       * <div class="alert alert-warning">
5887       * **Note**: Generally, the events that are fired correspond 1:1 to `$animate` method names,
5888       * e.g. {@link ng.$animate#addClass addClass()} will fire `addClass`, and {@link ng.ngClass}
5889       * will fire `addClass` if classes are added, and `removeClass` if classes are removed.
5890       * However, there are two exceptions:
5891       *
5892       * <ul>
5893       *   <li>if both an {@link ng.$animate#addClass addClass()} and a
5894       *   {@link ng.$animate#removeClass removeClass()} action are performed during the same
5895       *   animation, the event fired will be `setClass`. This is true even for `ngClass`.</li>
5896       *   <li>an {@link ng.$animate#animate animate()} call that adds and removes classes will fire
5897       *   the `setClass` event, but if it either removes or adds classes,
5898       *   it will fire `animate` instead.</li>
5899       * </ul>
5900       *
5901       * </div>
5902       *
5903       * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5904       * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5905       *     as well as among its children
5906       * @param {Function} callback the callback function that will be fired when the listener is triggered.
5907       *
5908       * The arguments present in the callback function are:
5909       * * `element` - The captured DOM element that the animation was fired on.
5910       * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5911       * * `data` - an object with these properties:
5912       *     * addClass - `{string|null}` - space-separated CSS classes to add to the element
5913       *     * removeClass - `{string|null}` - space-separated CSS classes to remove from the element
5914       *     * from - `{Object|null}` - CSS properties & values at the beginning of the animation
5915       *     * to - `{Object|null}` - CSS properties & values at the end of the animation
5916       *
5917       * Note that the callback does not trigger a scope digest. Wrap your call into a
5918       * {@link $rootScope.Scope#$apply scope.$apply} to propagate changes to the scope.
5919       */
5920      on: $$animateQueue.on,
5921
5922      /**
5923       *
5924       * @ngdoc method
5925       * @name $animate#off
5926       * @kind function
5927       * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5928       * can be used in three different ways depending on the arguments:
5929       *
5930       * ```js
5931       * // remove all the animation event listeners listening for `enter`
5932       * $animate.off('enter');
5933       *
5934       * // remove listeners for all animation events from the container element
5935       * $animate.off(container);
5936       *
5937       * // remove all the animation event listeners listening for `enter` on the given element and its children
5938       * $animate.off('enter', container);
5939       *
5940       * // remove the event listener function provided by `callback` that is set
5941       * // to listen for `enter` on the given `container` as well as its children
5942       * $animate.off('enter', container, callback);
5943       * ```
5944       *
5945       * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
5946       * addClass, removeClass, etc...), or the container element. If it is the element, all other
5947       * arguments are ignored.
5948       * @param {DOMElement=} container the container element the event listener was placed on
5949       * @param {Function=} callback the callback function that was registered as the listener
5950       */
5951      off: $$animateQueue.off,
5952
5953      /**
5954       * @ngdoc method
5955       * @name $animate#pin
5956       * @kind function
5957       * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5958       *    outside of the DOM structure of the AngularJS application. By doing so, any animation triggered via `$animate` can be issued on the
5959       *    element despite being outside the realm of the application or within another application. Say for example if the application
5960       *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5961       *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5962       *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5963       *
5964       *    Note that this feature is only active when the `ngAnimate` module is used.
5965       *
5966       * @param {DOMElement} element the external element that will be pinned
5967       * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5968       */
5969      pin: $$animateQueue.pin,
5970
5971      /**
5972       *
5973       * @ngdoc method
5974       * @name $animate#enabled
5975       * @kind function
5976       * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5977       * function can be called in four ways:
5978       *
5979       * ```js
5980       * // returns true or false
5981       * $animate.enabled();
5982       *
5983       * // changes the enabled state for all animations
5984       * $animate.enabled(false);
5985       * $animate.enabled(true);
5986       *
5987       * // returns true or false if animations are enabled for an element
5988       * $animate.enabled(element);
5989       *
5990       * // changes the enabled state for an element and its children
5991       * $animate.enabled(element, true);
5992       * $animate.enabled(element, false);
5993       * ```
5994       *
5995       * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5996       * @param {boolean=} enabled whether or not the animations will be enabled for the element
5997       *
5998       * @return {boolean} whether or not animations are enabled
5999       */
6000      enabled: $$animateQueue.enabled,
6001
6002      /**
6003       * @ngdoc method
6004       * @name $animate#cancel
6005       * @kind function
6006       * @description Cancels the provided animation and applies the end state of the animation.
6007       * Note that this does not cancel the underlying operation, e.g. the setting of classes or
6008       * adding the element to the DOM.
6009       *
6010       * @param {animationRunner} animationRunner An animation runner returned by an $animate function.
6011       *
6012       * @example
6013        <example module="animationExample" deps="angular-animate.js" animations="true" name="animate-cancel">
6014          <file name="app.js">
6015            angular.module('animationExample', ['ngAnimate']).component('cancelExample', {
6016              templateUrl: 'template.html',
6017              controller: function($element, $animate) {
6018                this.runner = null;
6019
6020                this.addClass = function() {
6021                  this.runner = $animate.addClass($element.find('div'), 'red');
6022                  var ctrl = this;
6023                  this.runner.finally(function() {
6024                    ctrl.runner = null;
6025                  });
6026                };
6027
6028                this.removeClass = function() {
6029                  this.runner = $animate.removeClass($element.find('div'), 'red');
6030                  var ctrl = this;
6031                  this.runner.finally(function() {
6032                    ctrl.runner = null;
6033                  });
6034                };
6035
6036                this.cancel = function() {
6037                  $animate.cancel(this.runner);
6038                };
6039              }
6040            });
6041          </file>
6042          <file name="template.html">
6043            <p>
6044              <button id="add" ng-click="$ctrl.addClass()">Add</button>
6045              <button ng-click="$ctrl.removeClass()">Remove</button>
6046              <br>
6047              <button id="cancel" ng-click="$ctrl.cancel()" ng-disabled="!$ctrl.runner">Cancel</button>
6048              <br>
6049              <div id="target">CSS-Animated Text</div>
6050            </p>
6051          </file>
6052          <file name="index.html">
6053            <cancel-example></cancel-example>
6054          </file>
6055          <file name="style.css">
6056            .red-add, .red-remove {
6057              transition: all 4s cubic-bezier(0.250, 0.460, 0.450, 0.940);
6058            }
6059
6060            .red,
6061            .red-add.red-add-active {
6062              color: #FF0000;
6063              font-size: 40px;
6064            }
6065
6066            .red-remove.red-remove-active {
6067              font-size: 10px;
6068              color: black;
6069            }
6070
6071          </file>
6072        </example>
6073       */
6074      cancel: function(runner) {
6075        if (runner.cancel) {
6076          runner.cancel();
6077        }
6078      },
6079
6080      /**
6081       *
6082       * @ngdoc method
6083       * @name $animate#enter
6084       * @kind function
6085       * @description Inserts the element into the DOM either after the `after` element (if provided) or
6086       *   as the first child within the `parent` element and then triggers an animation.
6087       *   A promise is returned that will be resolved during the next digest once the animation
6088       *   has completed.
6089       *
6090       * @param {DOMElement} element the element which will be inserted into the DOM
6091       * @param {DOMElement} parent the parent element which will append the element as
6092       *   a child (so long as the after element is not present)
6093       * @param {DOMElement=} after the sibling element after which the element will be appended
6094       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6095       *   The object can have the following properties:
6096       *
6097       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6098       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6099       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6100       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6101       *
6102       * @return {Runner} the animation runner
6103       */
6104      enter: function(element, parent, after, options) {
6105        parent = parent && jqLite(parent);
6106        after = after && jqLite(after);
6107        parent = parent || after.parent();
6108        domInsert(element, parent, after);
6109        return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
6110      },
6111
6112      /**
6113       *
6114       * @ngdoc method
6115       * @name $animate#move
6116       * @kind function
6117       * @description Inserts (moves) the element into its new position in the DOM either after
6118       *   the `after` element (if provided) or as the first child within the `parent` element
6119       *   and then triggers an animation. A promise is returned that will be resolved
6120       *   during the next digest once the animation has completed.
6121       *
6122       * @param {DOMElement} element the element which will be moved into the new DOM position
6123       * @param {DOMElement} parent the parent element which will append the element as
6124       *   a child (so long as the after element is not present)
6125       * @param {DOMElement=} after the sibling element after which the element will be appended
6126       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6127       *   The object can have the following properties:
6128       *
6129       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6130       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6131       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6132       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6133       *
6134       * @return {Runner} the animation runner
6135       */
6136      move: function(element, parent, after, options) {
6137        parent = parent && jqLite(parent);
6138        after = after && jqLite(after);
6139        parent = parent || after.parent();
6140        domInsert(element, parent, after);
6141        return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
6142      },
6143
6144      /**
6145       * @ngdoc method
6146       * @name $animate#leave
6147       * @kind function
6148       * @description Triggers an animation and then removes the element from the DOM.
6149       * When the function is called a promise is returned that will be resolved during the next
6150       * digest once the animation has completed.
6151       *
6152       * @param {DOMElement} element the element which will be removed from the DOM
6153       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6154       *   The object can have the following properties:
6155       *
6156       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6157       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6158       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6159       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6160       *
6161       * @return {Runner} the animation runner
6162       */
6163      leave: function(element, options) {
6164        return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
6165          element.remove();
6166        });
6167      },
6168
6169      /**
6170       * @ngdoc method
6171       * @name $animate#addClass
6172       * @kind function
6173       *
6174       * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
6175       *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
6176       *   animation if element already contains the CSS class or if the class is removed at a later step.
6177       *   Note that class-based animations are treated differently compared to structural animations
6178       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
6179       *   depending if CSS or JavaScript animations are used.
6180       *
6181       * @param {DOMElement} element the element which the CSS classes will be applied to
6182       * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
6183       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6184       *   The object can have the following properties:
6185       *
6186       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6187       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6188       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6189       *
6190       * @return {Runner} animationRunner the animation runner
6191       */
6192      addClass: function(element, className, options) {
6193        options = prepareAnimateOptions(options);
6194        options.addClass = mergeClasses(options.addclass, className);
6195        return $$animateQueue.push(element, 'addClass', options);
6196      },
6197
6198      /**
6199       * @ngdoc method
6200       * @name $animate#removeClass
6201       * @kind function
6202       *
6203       * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
6204       *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
6205       *   animation if element does not contain the CSS class or if the class is added at a later step.
6206       *   Note that class-based animations are treated differently compared to structural animations
6207       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
6208       *   depending if CSS or JavaScript animations are used.
6209       *
6210       * @param {DOMElement} element the element which the CSS classes will be applied to
6211       * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
6212       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6213       *   The object can have the following properties:
6214       *
6215       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6216       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6217       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6218       *
6219       * @return {Runner} the animation runner
6220       */
6221      removeClass: function(element, className, options) {
6222        options = prepareAnimateOptions(options);
6223        options.removeClass = mergeClasses(options.removeClass, className);
6224        return $$animateQueue.push(element, 'removeClass', options);
6225      },
6226
6227      /**
6228       * @ngdoc method
6229       * @name $animate#setClass
6230       * @kind function
6231       *
6232       * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
6233       *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
6234       *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
6235       *    passed. Note that class-based animations are treated differently compared to structural animations
6236       *    (like enter, move and leave) since the CSS classes may be added/removed at different points
6237       *    depending if CSS or JavaScript animations are used.
6238       *
6239       * @param {DOMElement} element the element which the CSS classes will be applied to
6240       * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
6241       * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
6242       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6243       *   The object can have the following properties:
6244       *
6245       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6246       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6247       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6248       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6249       *
6250       * @return {Runner} the animation runner
6251       */
6252      setClass: function(element, add, remove, options) {
6253        options = prepareAnimateOptions(options);
6254        options.addClass = mergeClasses(options.addClass, add);
6255        options.removeClass = mergeClasses(options.removeClass, remove);
6256        return $$animateQueue.push(element, 'setClass', options);
6257      },
6258
6259      /**
6260       * @ngdoc method
6261       * @name $animate#animate
6262       * @kind function
6263       *
6264       * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
6265       * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
6266       * on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and
6267       * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
6268       * style in `to`, the style in `from` is applied immediately, and no animation is run.
6269       * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
6270       * method (or as part of the `options` parameter):
6271       *
6272       * ```js
6273       * ngModule.animation('.my-inline-animation', function() {
6274       *   return {
6275       *     animate : function(element, from, to, done, options) {
6276       *       //animation
6277       *       done();
6278       *     }
6279       *   }
6280       * });
6281       * ```
6282       *
6283       * @param {DOMElement} element the element which the CSS styles will be applied to
6284       * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
6285       * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
6286       * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
6287       *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
6288       *    (Note that if no animation is detected then this value will not be applied to the element.)
6289       * @param {object=} options an optional collection of options/styles that will be applied to the element.
6290       *   The object can have the following properties:
6291       *
6292       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
6293       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
6294       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
6295       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
6296       *
6297       * @return {Runner} the animation runner
6298       */
6299      animate: function(element, from, to, className, options) {
6300        options = prepareAnimateOptions(options);
6301        options.from = options.from ? extend(options.from, from) : from;
6302        options.to   = options.to   ? extend(options.to, to)     : to;
6303
6304        className = className || 'ng-inline-animate';
6305        options.tempClasses = mergeClasses(options.tempClasses, className);
6306        return $$animateQueue.push(element, 'animate', options);
6307      }
6308    };
6309  }];
6310}];
6311
6312var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
6313  this.$get = ['$$rAF', function($$rAF) {
6314    var waitQueue = [];
6315
6316    function waitForTick(fn) {
6317      waitQueue.push(fn);
6318      if (waitQueue.length > 1) return;
6319      $$rAF(function() {
6320        for (var i = 0; i < waitQueue.length; i++) {
6321          waitQueue[i]();
6322        }
6323        waitQueue = [];
6324      });
6325    }
6326
6327    return function() {
6328      var passed = false;
6329      waitForTick(function() {
6330        passed = true;
6331      });
6332      return function(callback) {
6333        if (passed) {
6334          callback();
6335        } else {
6336          waitForTick(callback);
6337        }
6338      };
6339    };
6340  }];
6341};
6342
6343var $$AnimateRunnerFactoryProvider = /** @this */ function() {
6344  this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
6345       function($q,   $sniffer,   $$animateAsyncRun,   $$isDocumentHidden,   $timeout) {
6346
6347    var INITIAL_STATE = 0;
6348    var DONE_PENDING_STATE = 1;
6349    var DONE_COMPLETE_STATE = 2;
6350
6351    AnimateRunner.chain = function(chain, callback) {
6352      var index = 0;
6353
6354      next();
6355      function next() {
6356        if (index === chain.length) {
6357          callback(true);
6358          return;
6359        }
6360
6361        chain[index](function(response) {
6362          if (response === false) {
6363            callback(false);
6364            return;
6365          }
6366          index++;
6367          next();
6368        });
6369      }
6370    };
6371
6372    AnimateRunner.all = function(runners, callback) {
6373      var count = 0;
6374      var status = true;
6375      forEach(runners, function(runner) {
6376        runner.done(onProgress);
6377      });
6378
6379      function onProgress(response) {
6380        status = status && response;
6381        if (++count === runners.length) {
6382          callback(status);
6383        }
6384      }
6385    };
6386
6387    function AnimateRunner(host) {
6388      this.setHost(host);
6389
6390      var rafTick = $$animateAsyncRun();
6391      var timeoutTick = function(fn) {
6392        $timeout(fn, 0, false);
6393      };
6394
6395      this._doneCallbacks = [];
6396      this._tick = function(fn) {
6397        if ($$isDocumentHidden()) {
6398          timeoutTick(fn);
6399        } else {
6400          rafTick(fn);
6401        }
6402      };
6403      this._state = 0;
6404    }
6405
6406    AnimateRunner.prototype = {
6407      setHost: function(host) {
6408        this.host = host || {};
6409      },
6410
6411      done: function(fn) {
6412        if (this._state === DONE_COMPLETE_STATE) {
6413          fn();
6414        } else {
6415          this._doneCallbacks.push(fn);
6416        }
6417      },
6418
6419      progress: noop,
6420
6421      getPromise: function() {
6422        if (!this.promise) {
6423          var self = this;
6424          this.promise = $q(function(resolve, reject) {
6425            self.done(function(status) {
6426              if (status === false) {
6427                reject();
6428              } else {
6429                resolve();
6430              }
6431            });
6432          });
6433        }
6434        return this.promise;
6435      },
6436
6437      then: function(resolveHandler, rejectHandler) {
6438        return this.getPromise().then(resolveHandler, rejectHandler);
6439      },
6440
6441      'catch': function(handler) {
6442        return this.getPromise()['catch'](handler);
6443      },
6444
6445      'finally': function(handler) {
6446        return this.getPromise()['finally'](handler);
6447      },
6448
6449      pause: function() {
6450        if (this.host.pause) {
6451          this.host.pause();
6452        }
6453      },
6454
6455      resume: function() {
6456        if (this.host.resume) {
6457          this.host.resume();
6458        }
6459      },
6460
6461      end: function() {
6462        if (this.host.end) {
6463          this.host.end();
6464        }
6465        this._resolve(true);
6466      },
6467
6468      cancel: function() {
6469        if (this.host.cancel) {
6470          this.host.cancel();
6471        }
6472        this._resolve(false);
6473      },
6474
6475      complete: function(response) {
6476        var self = this;
6477        if (self._state === INITIAL_STATE) {
6478          self._state = DONE_PENDING_STATE;
6479          self._tick(function() {
6480            self._resolve(response);
6481          });
6482        }
6483      },
6484
6485      _resolve: function(response) {
6486        if (this._state !== DONE_COMPLETE_STATE) {
6487          forEach(this._doneCallbacks, function(fn) {
6488            fn(response);
6489          });
6490          this._doneCallbacks.length = 0;
6491          this._state = DONE_COMPLETE_STATE;
6492        }
6493      }
6494    };
6495
6496    return AnimateRunner;
6497  }];
6498};
6499
6500/* exported $CoreAnimateCssProvider */
6501
6502/**
6503 * @ngdoc service
6504 * @name $animateCss
6505 * @kind object
6506 * @this
6507 *
6508 * @description
6509 * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
6510 * then the `$animateCss` service will actually perform animations.
6511 *
6512 * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
6513 */
6514var $CoreAnimateCssProvider = function() {
6515  this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
6516
6517    return function(element, initialOptions) {
6518      // all of the animation functions should create
6519      // a copy of the options data, however, if a
6520      // parent service has already created a copy then
6521      // we should stick to using that
6522      var options = initialOptions || {};
6523      if (!options.$$prepared) {
6524        options = copy(options);
6525      }
6526
6527      // there is no point in applying the styles since
6528      // there is no animation that goes on at all in
6529      // this version of $animateCss.
6530      if (options.cleanupStyles) {
6531        options.from = options.to = null;
6532      }
6533
6534      if (options.from) {
6535        element.css(options.from);
6536        options.from = null;
6537      }
6538
6539      var closed, runner = new $$AnimateRunner();
6540      return {
6541        start: run,
6542        end: run
6543      };
6544
6545      function run() {
6546        $$rAF(function() {
6547          applyAnimationContents();
6548          if (!closed) {
6549            runner.complete();
6550          }
6551          closed = true;
6552        });
6553        return runner;
6554      }
6555
6556      function applyAnimationContents() {
6557        if (options.addClass) {
6558          element.addClass(options.addClass);
6559          options.addClass = null;
6560        }
6561        if (options.removeClass) {
6562          element.removeClass(options.removeClass);
6563          options.removeClass = null;
6564        }
6565        if (options.to) {
6566          element.css(options.to);
6567          options.to = null;
6568        }
6569      }
6570    };
6571  }];
6572};
6573
6574/* global getHash: true, stripHash: false */
6575
6576function getHash(url) {
6577  var index = url.indexOf('#');
6578  return index === -1 ? '' : url.substr(index);
6579}
6580
6581function trimEmptyHash(url) {
6582  return url.replace(/#$/, '');
6583}
6584
6585/**
6586 * ! This is a private undocumented service !
6587 *
6588 * @name $browser
6589 * @requires $log
6590 * @description
6591 * This object has two goals:
6592 *
6593 * - hide all the global state in the browser caused by the window object
6594 * - abstract away all the browser specific features and inconsistencies
6595 *
6596 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
6597 * service, which can be used for convenient testing of the application without the interaction with
6598 * the real browser apis.
6599 */
6600/**
6601 * @param {object} window The global window object.
6602 * @param {object} document jQuery wrapped document.
6603 * @param {object} $log window.console or an object with the same interface.
6604 * @param {object} $sniffer $sniffer service
6605 */
6606function Browser(window, document, $log, $sniffer, $$taskTrackerFactory) {
6607  var self = this,
6608      location = window.location,
6609      history = window.history,
6610      setTimeout = window.setTimeout,
6611      clearTimeout = window.clearTimeout,
6612      pendingDeferIds = {},
6613      taskTracker = $$taskTrackerFactory($log);
6614
6615  self.isMock = false;
6616
6617  //////////////////////////////////////////////////////////////
6618  // Task-tracking API
6619  //////////////////////////////////////////////////////////////
6620
6621  // TODO(vojta): remove this temporary api
6622  self.$$completeOutstandingRequest = taskTracker.completeTask;
6623  self.$$incOutstandingRequestCount = taskTracker.incTaskCount;
6624
6625  // TODO(vojta): prefix this method with $$ ?
6626  self.notifyWhenNoOutstandingRequests = taskTracker.notifyWhenNoPendingTasks;
6627
6628  //////////////////////////////////////////////////////////////
6629  // URL API
6630  //////////////////////////////////////////////////////////////
6631
6632  var cachedState, lastHistoryState,
6633      lastBrowserUrl = location.href,
6634      baseElement = document.find('base'),
6635      pendingLocation = null,
6636      getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
6637        try {
6638          return history.state;
6639        } catch (e) {
6640          // MSIE can reportedly throw when there is no state (UNCONFIRMED).
6641        }
6642      };
6643
6644  cacheState();
6645
6646  /**
6647   * @name $browser#url
6648   *
6649   * @description
6650   * GETTER:
6651   * Without any argument, this method just returns current value of `location.href` (with a
6652   * trailing `#` stripped of if the hash is empty).
6653   *
6654   * SETTER:
6655   * With at least one argument, this method sets url to new value.
6656   * If html5 history api supported, `pushState`/`replaceState` is used, otherwise
6657   * `location.href`/`location.replace` is used.
6658   * Returns its own instance to allow chaining.
6659   *
6660   * NOTE: this api is intended for use only by the `$location` service. Please use the
6661   * {@link ng.$location $location service} to change url.
6662   *
6663   * @param {string} url New url (when used as setter)
6664   * @param {boolean=} replace Should new url replace current history record?
6665   * @param {object=} state State object to use with `pushState`/`replaceState`
6666   */
6667  self.url = function(url, replace, state) {
6668    // In modern browsers `history.state` is `null` by default; treating it separately
6669    // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
6670    // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
6671    if (isUndefined(state)) {
6672      state = null;
6673    }
6674
6675    // Android Browser BFCache causes location, history reference to become stale.
6676    if (location !== window.location) location = window.location;
6677    if (history !== window.history) history = window.history;
6678
6679    // setter
6680    if (url) {
6681      var sameState = lastHistoryState === state;
6682
6683      // Normalize the inputted URL
6684      url = urlResolve(url).href;
6685
6686      // Don't change anything if previous and current URLs and states match. This also prevents
6687      // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
6688      // See https://github.com/angular/angular.js/commit/ffb2701
6689      if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
6690        return self;
6691      }
6692      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
6693      lastBrowserUrl = url;
6694      lastHistoryState = state;
6695      // Don't use history API if only the hash changed
6696      // due to a bug in IE10/IE11 which leads
6697      // to not firing a `hashchange` nor `popstate` event
6698      // in some cases (see #9143).
6699      if ($sniffer.history && (!sameBase || !sameState)) {
6700        history[replace ? 'replaceState' : 'pushState'](state, '', url);
6701        cacheState();
6702      } else {
6703        if (!sameBase) {
6704          pendingLocation = url;
6705        }
6706        if (replace) {
6707          location.replace(url);
6708        } else if (!sameBase) {
6709          location.href = url;
6710        } else {
6711          location.hash = getHash(url);
6712        }
6713        if (location.href !== url) {
6714          pendingLocation = url;
6715        }
6716      }
6717      if (pendingLocation) {
6718        pendingLocation = url;
6719      }
6720      return self;
6721    // getter
6722    } else {
6723      // - pendingLocation is needed as browsers don't allow to read out
6724      //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
6725      //   https://openradar.appspot.com/22186109).
6726      return trimEmptyHash(pendingLocation || location.href);
6727    }
6728  };
6729
6730  /**
6731   * @name $browser#state
6732   *
6733   * @description
6734   * This method is a getter.
6735   *
6736   * Return history.state or null if history.state is undefined.
6737   *
6738   * @returns {object} state
6739   */
6740  self.state = function() {
6741    return cachedState;
6742  };
6743
6744  var urlChangeListeners = [],
6745      urlChangeInit = false;
6746
6747  function cacheStateAndFireUrlChange() {
6748    pendingLocation = null;
6749    fireStateOrUrlChange();
6750  }
6751
6752  // This variable should be used *only* inside the cacheState function.
6753  var lastCachedState = null;
6754  function cacheState() {
6755    // This should be the only place in $browser where `history.state` is read.
6756    cachedState = getCurrentState();
6757    cachedState = isUndefined(cachedState) ? null : cachedState;
6758
6759    // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
6760    if (equals(cachedState, lastCachedState)) {
6761      cachedState = lastCachedState;
6762    }
6763
6764    lastCachedState = cachedState;
6765    lastHistoryState = cachedState;
6766  }
6767
6768  function fireStateOrUrlChange() {
6769    var prevLastHistoryState = lastHistoryState;
6770    cacheState();
6771
6772    if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
6773      return;
6774    }
6775
6776    lastBrowserUrl = self.url();
6777    lastHistoryState = cachedState;
6778    forEach(urlChangeListeners, function(listener) {
6779      listener(self.url(), cachedState);
6780    });
6781  }
6782
6783  /**
6784   * @name $browser#onUrlChange
6785   *
6786   * @description
6787   * Register callback function that will be called, when url changes.
6788   *
6789   * It's only called when the url is changed from outside of AngularJS:
6790   * - user types different url into address bar
6791   * - user clicks on history (forward/back) button
6792   * - user clicks on a link
6793   *
6794   * It's not called when url is changed by $browser.url() method
6795   *
6796   * The listener gets called with new url as parameter.
6797   *
6798   * NOTE: this api is intended for use only by the $location service. Please use the
6799   * {@link ng.$location $location service} to monitor url changes in AngularJS apps.
6800   *
6801   * @param {function(string)} listener Listener function to be called when url changes.
6802   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
6803   */
6804  self.onUrlChange = function(callback) {
6805    // TODO(vojta): refactor to use node's syntax for events
6806    if (!urlChangeInit) {
6807      // We listen on both (hashchange/popstate) when available, as some browsers don't
6808      // fire popstate when user changes the address bar and don't fire hashchange when url
6809      // changed by push/replaceState
6810
6811      // html5 history api - popstate event
6812      if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
6813      // hashchange event
6814      jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
6815
6816      urlChangeInit = true;
6817    }
6818
6819    urlChangeListeners.push(callback);
6820    return callback;
6821  };
6822
6823  /**
6824   * @private
6825   * Remove popstate and hashchange handler from window.
6826   *
6827   * NOTE: this api is intended for use only by $rootScope.
6828   */
6829  self.$$applicationDestroyed = function() {
6830    jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
6831  };
6832
6833  /**
6834   * Checks whether the url has changed outside of AngularJS.
6835   * Needs to be exported to be able to check for changes that have been done in sync,
6836   * as hashchange/popstate events fire in async.
6837   */
6838  self.$$checkUrlChange = fireStateOrUrlChange;
6839
6840  //////////////////////////////////////////////////////////////
6841  // Misc API
6842  //////////////////////////////////////////////////////////////
6843
6844  /**
6845   * @name $browser#baseHref
6846   *
6847   * @description
6848   * Returns current <base href>
6849   * (always relative - without domain)
6850   *
6851   * @returns {string} The current base href
6852   */
6853  self.baseHref = function() {
6854    var href = baseElement.attr('href');
6855    return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : '';
6856  };
6857
6858  /**
6859   * @name $browser#defer
6860   * @param {function()} fn A function, who's execution should be deferred.
6861   * @param {number=} [delay=0] Number of milliseconds to defer the function execution.
6862   * @param {string=} [taskType=DEFAULT_TASK_TYPE] The type of task that is deferred.
6863   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
6864   *
6865   * @description
6866   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
6867   *
6868   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
6869   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
6870   * via `$browser.defer.flush()`.
6871   *
6872   */
6873  self.defer = function(fn, delay, taskType) {
6874    var timeoutId;
6875
6876    delay = delay || 0;
6877    taskType = taskType || taskTracker.DEFAULT_TASK_TYPE;
6878
6879    taskTracker.incTaskCount(taskType);
6880    timeoutId = setTimeout(function() {
6881      delete pendingDeferIds[timeoutId];
6882      taskTracker.completeTask(fn, taskType);
6883    }, delay);
6884    pendingDeferIds[timeoutId] = taskType;
6885
6886    return timeoutId;
6887  };
6888
6889
6890  /**
6891   * @name $browser#defer.cancel
6892   *
6893   * @description
6894   * Cancels a deferred task identified with `deferId`.
6895   *
6896   * @param {*} deferId Token returned by the `$browser.defer` function.
6897   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
6898   *                    canceled.
6899   */
6900  self.defer.cancel = function(deferId) {
6901    if (pendingDeferIds.hasOwnProperty(deferId)) {
6902      var taskType = pendingDeferIds[deferId];
6903      delete pendingDeferIds[deferId];
6904      clearTimeout(deferId);
6905      taskTracker.completeTask(noop, taskType);
6906      return true;
6907    }
6908    return false;
6909  };
6910
6911}
6912
6913/** @this */
6914function $BrowserProvider() {
6915  this.$get = ['$window', '$log', '$sniffer', '$document', '$$taskTrackerFactory',
6916       function($window,   $log,   $sniffer,   $document,   $$taskTrackerFactory) {
6917    return new Browser($window, $document, $log, $sniffer, $$taskTrackerFactory);
6918  }];
6919}
6920
6921/**
6922 * @ngdoc service
6923 * @name $cacheFactory
6924 * @this
6925 *
6926 * @description
6927 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
6928 * them.
6929 *
6930 * ```js
6931 *
6932 *  var cache = $cacheFactory('cacheId');
6933 *  expect($cacheFactory.get('cacheId')).toBe(cache);
6934 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
6935 *
6936 *  cache.put("key", "value");
6937 *  cache.put("another key", "another value");
6938 *
6939 *  // We've specified no options on creation
6940 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
6941 *
6942 * ```
6943 *
6944 *
6945 * @param {string} cacheId Name or id of the newly created cache.
6946 * @param {object=} options Options object that specifies the cache behavior. Properties:
6947 *
6948 *   - `{number=}` `capacity` — turns the cache into LRU cache.
6949 *
6950 * @returns {object} Newly created cache object with the following set of methods:
6951 *
6952 * - `{object}` `info()` — Returns id, size, and options of cache.
6953 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
6954 *   it.
6955 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
6956 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
6957 * - `{void}` `removeAll()` — Removes all cached values.
6958 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
6959 *
6960 * @example
6961   <example module="cacheExampleApp" name="cache-factory">
6962     <file name="index.html">
6963       <div ng-controller="CacheController">
6964         <input ng-model="newCacheKey" placeholder="Key">
6965         <input ng-model="newCacheValue" placeholder="Value">
6966         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
6967
6968         <p ng-if="keys.length">Cached Values</p>
6969         <div ng-repeat="key in keys">
6970           <span ng-bind="key"></span>
6971           <span>: </span>
6972           <b ng-bind="cache.get(key)"></b>
6973         </div>
6974
6975         <p>Cache Info</p>
6976         <div ng-repeat="(key, value) in cache.info()">
6977           <span ng-bind="key"></span>
6978           <span>: </span>
6979           <b ng-bind="value"></b>
6980         </div>
6981       </div>
6982     </file>
6983     <file name="script.js">
6984       angular.module('cacheExampleApp', []).
6985         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
6986           $scope.keys = [];
6987           $scope.cache = $cacheFactory('cacheId');
6988           $scope.put = function(key, value) {
6989             if (angular.isUndefined($scope.cache.get(key))) {
6990               $scope.keys.push(key);
6991             }
6992             $scope.cache.put(key, angular.isUndefined(value) ? null : value);
6993           };
6994         }]);
6995     </file>
6996     <file name="style.css">
6997       p {
6998         margin: 10px 0 3px;
6999       }
7000     </file>
7001   </example>
7002 */
7003function $CacheFactoryProvider() {
7004
7005  this.$get = function() {
7006    var caches = {};
7007
7008    function cacheFactory(cacheId, options) {
7009      if (cacheId in caches) {
7010        throw minErr('$cacheFactory')('iid', 'CacheId \'{0}\' is already taken!', cacheId);
7011      }
7012
7013      var size = 0,
7014          stats = extend({}, options, {id: cacheId}),
7015          data = createMap(),
7016          capacity = (options && options.capacity) || Number.MAX_VALUE,
7017          lruHash = createMap(),
7018          freshEnd = null,
7019          staleEnd = null;
7020
7021      /**
7022       * @ngdoc type
7023       * @name $cacheFactory.Cache
7024       *
7025       * @description
7026       * A cache object used to store and retrieve data, primarily used by
7027       * {@link $templateRequest $templateRequest} and the {@link ng.directive:script script}
7028       * directive to cache templates and other data.
7029       *
7030       * ```js
7031       *  angular.module('superCache')
7032       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
7033       *      return $cacheFactory('super-cache');
7034       *    }]);
7035       * ```
7036       *
7037       * Example test:
7038       *
7039       * ```js
7040       *  it('should behave like a cache', inject(function(superCache) {
7041       *    superCache.put('key', 'value');
7042       *    superCache.put('another key', 'another value');
7043       *
7044       *    expect(superCache.info()).toEqual({
7045       *      id: 'super-cache',
7046       *      size: 2
7047       *    });
7048       *
7049       *    superCache.remove('another key');
7050       *    expect(superCache.get('another key')).toBeUndefined();
7051       *
7052       *    superCache.removeAll();
7053       *    expect(superCache.info()).toEqual({
7054       *      id: 'super-cache',
7055       *      size: 0
7056       *    });
7057       *  }));
7058       * ```
7059       */
7060      return (caches[cacheId] = {
7061
7062        /**
7063         * @ngdoc method
7064         * @name $cacheFactory.Cache#put
7065         * @kind function
7066         *
7067         * @description
7068         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
7069         * retrieved later, and incrementing the size of the cache if the key was not already
7070         * present in the cache. If behaving like an LRU cache, it will also remove stale
7071         * entries from the set.
7072         *
7073         * It will not insert undefined values into the cache.
7074         *
7075         * @param {string} key the key under which the cached data is stored.
7076         * @param {*} value the value to store alongside the key. If it is undefined, the key
7077         *    will not be stored.
7078         * @returns {*} the value stored.
7079         */
7080        put: function(key, value) {
7081          if (isUndefined(value)) return;
7082          if (capacity < Number.MAX_VALUE) {
7083            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
7084
7085            refresh(lruEntry);
7086          }
7087
7088          if (!(key in data)) size++;
7089          data[key] = value;
7090
7091          if (size > capacity) {
7092            this.remove(staleEnd.key);
7093          }
7094
7095          return value;
7096        },
7097
7098        /**
7099         * @ngdoc method
7100         * @name $cacheFactory.Cache#get
7101         * @kind function
7102         *
7103         * @description
7104         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
7105         *
7106         * @param {string} key the key of the data to be retrieved
7107         * @returns {*} the value stored.
7108         */
7109        get: function(key) {
7110          if (capacity < Number.MAX_VALUE) {
7111            var lruEntry = lruHash[key];
7112
7113            if (!lruEntry) return;
7114
7115            refresh(lruEntry);
7116          }
7117
7118          return data[key];
7119        },
7120
7121
7122        /**
7123         * @ngdoc method
7124         * @name $cacheFactory.Cache#remove
7125         * @kind function
7126         *
7127         * @description
7128         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
7129         *
7130         * @param {string} key the key of the entry to be removed
7131         */
7132        remove: function(key) {
7133          if (capacity < Number.MAX_VALUE) {
7134            var lruEntry = lruHash[key];
7135
7136            if (!lruEntry) return;
7137
7138            if (lruEntry === freshEnd) freshEnd = lruEntry.p;
7139            if (lruEntry === staleEnd) staleEnd = lruEntry.n;
7140            link(lruEntry.n,lruEntry.p);
7141
7142            delete lruHash[key];
7143          }
7144
7145          if (!(key in data)) return;
7146
7147          delete data[key];
7148          size--;
7149        },
7150
7151
7152        /**
7153         * @ngdoc method
7154         * @name $cacheFactory.Cache#removeAll
7155         * @kind function
7156         *
7157         * @description
7158         * Clears the cache object of any entries.
7159         */
7160        removeAll: function() {
7161          data = createMap();
7162          size = 0;
7163          lruHash = createMap();
7164          freshEnd = staleEnd = null;
7165        },
7166
7167
7168        /**
7169         * @ngdoc method
7170         * @name $cacheFactory.Cache#destroy
7171         * @kind function
7172         *
7173         * @description
7174         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
7175         * removing it from the {@link $cacheFactory $cacheFactory} set.
7176         */
7177        destroy: function() {
7178          data = null;
7179          stats = null;
7180          lruHash = null;
7181          delete caches[cacheId];
7182        },
7183
7184
7185        /**
7186         * @ngdoc method
7187         * @name $cacheFactory.Cache#info
7188         * @kind function
7189         *
7190         * @description
7191         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
7192         *
7193         * @returns {object} an object with the following properties:
7194         *   <ul>
7195         *     <li>**id**: the id of the cache instance</li>
7196         *     <li>**size**: the number of entries kept in the cache instance</li>
7197         *     <li>**...**: any additional properties from the options object when creating the
7198         *       cache.</li>
7199         *   </ul>
7200         */
7201        info: function() {
7202          return extend({}, stats, {size: size});
7203        }
7204      });
7205
7206
7207      /**
7208       * makes the `entry` the freshEnd of the LRU linked list
7209       */
7210      function refresh(entry) {
7211        if (entry !== freshEnd) {
7212          if (!staleEnd) {
7213            staleEnd = entry;
7214          } else if (staleEnd === entry) {
7215            staleEnd = entry.n;
7216          }
7217
7218          link(entry.n, entry.p);
7219          link(entry, freshEnd);
7220          freshEnd = entry;
7221          freshEnd.n = null;
7222        }
7223      }
7224
7225
7226      /**
7227       * bidirectionally links two entries of the LRU linked list
7228       */
7229      function link(nextEntry, prevEntry) {
7230        if (nextEntry !== prevEntry) {
7231          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
7232          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
7233        }
7234      }
7235    }
7236
7237
7238  /**
7239   * @ngdoc method
7240   * @name $cacheFactory#info
7241   *
7242   * @description
7243   * Get information about all the caches that have been created
7244   *
7245   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
7246   */
7247    cacheFactory.info = function() {
7248      var info = {};
7249      forEach(caches, function(cache, cacheId) {
7250        info[cacheId] = cache.info();
7251      });
7252      return info;
7253    };
7254
7255
7256  /**
7257   * @ngdoc method
7258   * @name $cacheFactory#get
7259   *
7260   * @description
7261   * Get access to a cache object by the `cacheId` used when it was created.
7262   *
7263   * @param {string} cacheId Name or id of a cache to access.
7264   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
7265   */
7266    cacheFactory.get = function(cacheId) {
7267      return caches[cacheId];
7268    };
7269
7270
7271    return cacheFactory;
7272  };
7273}
7274
7275/**
7276 * @ngdoc service
7277 * @name $templateCache
7278 * @this
7279 *
7280 * @description
7281 * `$templateCache` is a {@link $cacheFactory.Cache Cache object} created by the
7282 * {@link ng.$cacheFactory $cacheFactory}.
7283 *
7284 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
7285 * can load templates directly into the cache in a `script` tag, by using {@link $templateRequest},
7286 * or by consuming the `$templateCache` service directly.
7287 *
7288 * Adding via the `script` tag:
7289 *
7290 * ```html
7291 *   <script type="text/ng-template" id="templateId.html">
7292 *     <p>This is the content of the template</p>
7293 *   </script>
7294 * ```
7295 *
7296 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
7297 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (e.g.
7298 * element with {@link ngApp} attribute), otherwise the template will be ignored.
7299 *
7300 * Adding via the `$templateCache` service:
7301 *
7302 * ```js
7303 * var myApp = angular.module('myApp', []);
7304 * myApp.run(function($templateCache) {
7305 *   $templateCache.put('templateId.html', 'This is the content of the template');
7306 * });
7307 * ```
7308 *
7309 * To retrieve the template later, simply use it in your component:
7310 * ```js
7311 * myApp.component('myComponent', {
7312 *    templateUrl: 'templateId.html'
7313 * });
7314 * ```
7315 *
7316 * or get it via the `$templateCache` service:
7317 * ```js
7318 * $templateCache.get('templateId.html')
7319 * ```
7320 *
7321 */
7322function $TemplateCacheProvider() {
7323  this.$get = ['$cacheFactory', function($cacheFactory) {
7324    return $cacheFactory('templates');
7325  }];
7326}
7327
7328/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7329 *     Any commits to this file should be reviewed with security in mind.  *
7330 *   Changes to this file can potentially create security vulnerabilities. *
7331 *          An approval from 2 Core members with history of modifying      *
7332 *                         this file is required.                          *
7333 *                                                                         *
7334 *  Does the change somehow allow for arbitrary javascript to be executed? *
7335 *    Or allows for someone to change the prototype of built-in objects?   *
7336 *     Or gives undesired access to variables like document or window?    *
7337 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7338
7339/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
7340 *
7341 * DOM-related variables:
7342 *
7343 * - "node" - DOM Node
7344 * - "element" - DOM Element or Node
7345 * - "$node" or "$element" - jqLite-wrapped node or element
7346 *
7347 *
7348 * Compiler related stuff:
7349 *
7350 * - "linkFn" - linking fn of a single directive
7351 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
7352 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
7353 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
7354 */
7355
7356
7357/**
7358 * @ngdoc service
7359 * @name $compile
7360 * @kind function
7361 *
7362 * @description
7363 * Compiles an HTML string or DOM into a template and produces a template function, which
7364 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
7365 *
7366 * The compilation is a process of walking the DOM tree and matching DOM elements to
7367 * {@link ng.$compileProvider#directive directives}.
7368 *
7369 * <div class="alert alert-warning">
7370 * **Note:** This document is an in-depth reference of all directive options.
7371 * For a gentle introduction to directives with examples of common use cases,
7372 * see the {@link guide/directive directive guide}.
7373 * </div>
7374 *
7375 * ## Comprehensive Directive API
7376 *
7377 * There are many different options for a directive.
7378 *
7379 * The difference resides in the return value of the factory function.
7380 * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
7381 * that defines the directive properties, or just the `postLink` function (all other properties will have
7382 * the default values).
7383 *
7384 * <div class="alert alert-success">
7385 * **Best Practice:** It's recommended to use the "directive definition object" form.
7386 * </div>
7387 *
7388 * Here's an example directive declared with a Directive Definition Object:
7389 *
7390 * ```js
7391 *   var myModule = angular.module(...);
7392 *
7393 *   myModule.directive('directiveName', function factory(injectables) {
7394 *     var directiveDefinitionObject = {
7395 *       {@link $compile#-priority- priority}: 0,
7396 *       {@link $compile#-template- template}: '<div></div>', // or // function(tElement, tAttrs) { ... },
7397 *       // or
7398 *       // {@link $compile#-templateurl- templateUrl}: 'directive.html', // or // function(tElement, tAttrs) { ... },
7399 *       {@link $compile#-transclude- transclude}: false,
7400 *       {@link $compile#-restrict- restrict}: 'A',
7401 *       {@link $compile#-templatenamespace- templateNamespace}: 'html',
7402 *       {@link $compile#-scope- scope}: false,
7403 *       {@link $compile#-controller- controller}: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
7404 *       {@link $compile#-controlleras- controllerAs}: 'stringIdentifier',
7405 *       {@link $compile#-bindtocontroller- bindToController}: false,
7406 *       {@link $compile#-require- require}: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
7407 *       {@link $compile#-multielement- multiElement}: false,
7408 *       {@link $compile#-compile- compile}: function compile(tElement, tAttrs, transclude) {
7409 *         return {
7410 *            {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
7411 *            {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
7412 *         }
7413 *         // or
7414 *         // return function postLink( ... ) { ... }
7415 *       },
7416 *       // or
7417 *       // {@link $compile#-link- link}: {
7418 *       //  {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
7419 *       //  {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
7420 *       // }
7421 *       // or
7422 *       // {@link $compile#-link- link}: function postLink( ... ) { ... }
7423 *     };
7424 *     return directiveDefinitionObject;
7425 *   });
7426 * ```
7427 *
7428 * <div class="alert alert-warning">
7429 * **Note:** Any unspecified options will use the default value. You can see the default values below.
7430 * </div>
7431 *
7432 * Therefore the above can be simplified as:
7433 *
7434 * ```js
7435 *   var myModule = angular.module(...);
7436 *
7437 *   myModule.directive('directiveName', function factory(injectables) {
7438 *     var directiveDefinitionObject = {
7439 *       link: function postLink(scope, iElement, iAttrs) { ... }
7440 *     };
7441 *     return directiveDefinitionObject;
7442 *     // or
7443 *     // return function postLink(scope, iElement, iAttrs) { ... }
7444 *   });
7445 * ```
7446 *
7447 * ### Life-cycle hooks
7448 * Directive controllers can provide the following methods that are called by AngularJS at points in the life-cycle of the
7449 * directive:
7450 * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
7451 *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
7452 *   this element). This is a good place to put initialization code for your controller.
7453 * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
7454 *   `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
7455 *   object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
7456 *   component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
7457 *   also be called when your bindings are initialized.
7458 * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
7459 *   changes. Any actions that you wish to take in response to the changes that you detect must be
7460 *   invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
7461 *   could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not
7462 *   be detected by AngularJS's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
7463 *   if detecting changes, you must store the previous value(s) for comparison to the current values.
7464 * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
7465 *   external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
7466 *   the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
7467 *   components will have their `$onDestroy()` hook called before child components.
7468 * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
7469 *   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
7470 *   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
7471 *   they are waiting for their template to load asynchronously and their own compilation and linking has been
7472 *   suspended until that occurs.
7473 *
7474 * #### Comparison with life-cycle hooks in the new Angular
7475 * The new Angular also uses life-cycle hooks for its components. While the AngularJS life-cycle hooks are similar there are
7476 * some differences that you should be aware of, especially when it comes to moving your code from AngularJS to Angular:
7477 *
7478 * * AngularJS hooks are prefixed with `$`, such as `$onInit`. Angular hooks are prefixed with `ng`, such as `ngOnInit`.
7479 * * AngularJS hooks can be defined on the controller prototype or added to the controller inside its constructor.
7480 *   In Angular you can only define hooks on the prototype of the Component class.
7481 * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in AngularJS than you would to
7482 *   `ngDoCheck` in Angular.
7483 * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
7484 *   propagated throughout the application.
7485 *   Angular does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
7486 *   error or do nothing depending upon the state of `enableProdMode()`.
7487 *
7488 * #### Life-cycle hook examples
7489 *
7490 * This example shows how you can check for mutations to a Date object even though the identity of the object
7491 * has not changed.
7492 *
7493 * <example name="doCheckDateExample" module="do-check-module">
7494 *   <file name="app.js">
7495 *     angular.module('do-check-module', [])
7496 *       .component('app', {
7497 *         template:
7498 *           'Month: <input ng-model="$ctrl.month" ng-change="$ctrl.updateDate()">' +
7499 *           'Date: {{ $ctrl.date }}' +
7500 *           '<test date="$ctrl.date"></test>',
7501 *         controller: function() {
7502 *           this.date = new Date();
7503 *           this.month = this.date.getMonth();
7504 *           this.updateDate = function() {
7505 *             this.date.setMonth(this.month);
7506 *           };
7507 *         }
7508 *       })
7509 *       .component('test', {
7510 *         bindings: { date: '<' },
7511 *         template:
7512 *           '<pre>{{ $ctrl.log | json }}</pre>',
7513 *         controller: function() {
7514 *           var previousValue;
7515 *           this.log = [];
7516 *           this.$doCheck = function() {
7517 *             var currentValue = this.date && this.date.valueOf();
7518 *             if (previousValue !== currentValue) {
7519 *               this.log.push('doCheck: date mutated: ' + this.date);
7520 *               previousValue = currentValue;
7521 *             }
7522 *           };
7523 *         }
7524 *       });
7525 *   </file>
7526 *   <file name="index.html">
7527 *     <app></app>
7528 *   </file>
7529 * </example>
7530 *
7531 * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
7532 * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
7533 * arrays or objects can have a negative impact on your application performance.)
7534 *
7535 * <example name="doCheckArrayExample" module="do-check-module">
7536 *   <file name="index.html">
7537 *     <div ng-init="items = []">
7538 *       <button ng-click="items.push(items.length)">Add Item</button>
7539 *       <button ng-click="items = []">Reset Items</button>
7540 *       <pre>{{ items }}</pre>
7541 *       <test items="items"></test>
7542 *     </div>
7543 *   </file>
7544 *   <file name="app.js">
7545 *      angular.module('do-check-module', [])
7546 *        .component('test', {
7547 *          bindings: { items: '<' },
7548 *          template:
7549 *            '<pre>{{ $ctrl.log | json }}</pre>',
7550 *          controller: function() {
7551 *            this.log = [];
7552 *
7553 *            this.$doCheck = function() {
7554 *              if (this.items_ref !== this.items) {
7555 *                this.log.push('doCheck: items changed');
7556 *                this.items_ref = this.items;
7557 *              }
7558 *              if (!angular.equals(this.items_clone, this.items)) {
7559 *                this.log.push('doCheck: items mutated');
7560 *                this.items_clone = angular.copy(this.items);
7561 *              }
7562 *            };
7563 *          }
7564 *        });
7565 *   </file>
7566 * </example>
7567 *
7568 *
7569 * ### Directive Definition Object
7570 *
7571 * The directive definition object provides instructions to the {@link ng.$compile
7572 * compiler}. The attributes are:
7573 *
7574 * #### `multiElement`
7575 * When this property is set to true (default is `false`), the HTML compiler will collect DOM nodes between
7576 * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
7577 * together as the directive elements. It is recommended that this feature be used on directives
7578 * which are not strictly behavioral (such as {@link ngClick}), and which
7579 * do not manipulate or replace child nodes (such as {@link ngInclude}).
7580 *
7581 * #### `priority`
7582 * When there are multiple directives defined on a single DOM element, sometimes it
7583 * is necessary to specify the order in which the directives are applied. The `priority` is used
7584 * to sort the directives before their `compile` functions get called. Priority is defined as a
7585 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
7586 * are also run in priority order, but post-link functions are run in reverse order. The order
7587 * of directives with the same priority is undefined. The default priority is `0`.
7588 *
7589 * #### `terminal`
7590 * If set to true then the current `priority` will be the last set of directives
7591 * which will execute (any directives at the current priority will still execute
7592 * as the order of execution on same `priority` is undefined). Note that expressions
7593 * and other directives used in the directive's template will also be excluded from execution.
7594 *
7595 * #### `scope`
7596 * The scope property can be `false`, `true`, or an object:
7597 *
7598 * * **`false` (default):** No scope will be created for the directive. The directive will use its
7599 * parent's scope.
7600 *
7601 * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
7602 * the directive's element. If multiple directives on the same element request a new scope,
7603 * only one new scope is created.
7604 *
7605 * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template.
7606 * The 'isolate' scope differs from normal scope in that it does not prototypically
7607 * inherit from its parent scope. This is useful when creating reusable components, which should not
7608 * accidentally read or modify data in the parent scope. Note that an isolate scope
7609 * directive without a `template` or `templateUrl` will not apply the isolate scope
7610 * to its children elements.
7611 *
7612 * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
7613 * directive's element. These local properties are useful for aliasing values for templates. The keys in
7614 * the object hash map to the name of the property on the isolate scope; the values define how the property
7615 * is bound to the parent scope, via matching attributes on the directive's element:
7616 *
7617 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
7618 *   always a string since DOM attributes are strings. If no `attr` name is specified then the
7619 *   attribute name is assumed to be the same as the local name. Given `<my-component
7620 *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
7621 *   the directive's scope property `localName` will reflect the interpolated value of `hello
7622 *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
7623 *   scope. The `name` is read from the parent scope (not the directive's scope).
7624 *
7625 * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
7626 *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
7627 *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
7628 *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
7629 *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
7630 *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
7631 *   `localModel` and vice versa. If the binding expression is non-assignable, or if the attribute
7632 *   isn't  optional and doesn't exist, an exception
7633 *   ({@link error/$compile/nonassign `$compile:nonassign`}) will be thrown upon discovering changes
7634 *   to the local value, since it will be impossible to sync them back to the parent scope.
7635 *
7636 *   By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
7637 *   method is used for tracking changes, and the equality check is based on object identity.
7638 *   However, if an object literal or an array literal is passed as the binding expression, the
7639 *   equality check is done by value (using the {@link angular.equals} function). It's also possible
7640 *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
7641 *   `$watchCollection`}: use `=*` or `=*attr`
7642 *
7643  * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
7644 *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
7645 *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
7646 *   local name.
7647 *
7648 *   For example, given `<my-component my-attr="parentModel">` and directive definition of
7649 *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
7650 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
7651 *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
7652 *   two caveats:
7653 *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
7654 *     sets the same value. That means if your bound value is an object, changes to its properties
7655 *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
7656 *     2. one-way binding watches changes to the **identity** of the parent value. That means the
7657 *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
7658 *     to the value has changed. In most cases, this should not be of concern, but can be important
7659 *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
7660 *     If you now change a property of the object in your parent scope, the change will not be
7661 *     propagated to the isolated scope, because the identity of the object on the parent scope
7662 *     has not changed. Instead you must assign a new object.
7663 *
7664 *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
7665 *   back to the parent. However, it does not make this completely impossible.
7666 *
7667 *   By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
7668 *   method is used for tracking changes, and the equality check is based on object identity.
7669 *   It's also possible to watch the evaluated value shallowly with
7670 *   {@link ng.$rootScope.Scope#$watchCollection `$watchCollection`}: use `<*` or `<*attr`
7671 *
7672 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
7673 *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
7674 *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
7675 *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
7676 *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
7677 *   via an expression to the parent scope. This can be done by passing a map of local variable names
7678 *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
7679 *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
7680 *
7681 * All 4 kinds of bindings (`@`, `=`, `<`, and `&`) can be made optional by adding `?` to the expression.
7682 * The marker must come after the mode and before the attribute name.
7683 * See the {@link error/$compile/iscp Invalid Isolate Scope Definition error} for definition examples.
7684 * This is useful to refine the interface directives provide.
7685 * One subtle difference between optional and non-optional happens **when the binding attribute is not
7686 * set**:
7687 * - the binding is optional: the property will not be defined
7688 * - the binding is not optional: the property is defined
7689 *
7690 * ```js
7691 *app.directive('testDir', function() {
7692    return {
7693      scope: {
7694        notoptional: '=',
7695        optional: '=?',
7696      },
7697      bindToController: true,
7698      controller: function() {
7699        this.$onInit = function() {
7700          console.log(this.hasOwnProperty('notoptional')) // true
7701          console.log(this.hasOwnProperty('optional')) // false
7702        }
7703      }
7704    }
7705  })
7706 *```
7707 *
7708 *
7709 * ##### Combining directives with different scope defintions
7710 *
7711 * In general it's possible to apply more than one directive to one element, but there might be limitations
7712 * depending on the type of scope required by the directives. The following points will help explain these limitations.
7713 * For simplicity only two directives are taken into account, but it is also applicable for several directives:
7714 *
7715 * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
7716 * * **child scope** + **no scope** =>  Both directives will share one single child scope
7717 * * **child scope** + **child scope** =>  Both directives will share one single child scope
7718 * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
7719 * its parent's scope
7720 * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
7721 * be applied to the same element.
7722 * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
7723 * cannot be applied to the same element.
7724 *
7725 *
7726 * #### `bindToController`
7727 * This property is used to bind scope properties directly to the controller. It can be either
7728 * `true` or an object hash with the same format as the `scope` property.
7729 *
7730 * When an isolate scope is used for a directive (see above), `bindToController: true` will
7731 * allow a component to have its properties bound to the controller, rather than to scope.
7732 *
7733 * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
7734 * properties. You can access these bindings once they have been initialized by providing a controller method called
7735 * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
7736 * initialized.
7737 *
7738 * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
7739 * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
7740 * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
7741 * scope (useful for component directives).
7742 *
7743 * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
7744 *
7745 *
7746 * #### `controller`
7747 * Controller constructor function. The controller is instantiated before the
7748 * pre-linking phase and can be accessed by other directives (see
7749 * `require` attribute). This allows the directives to communicate with each other and augment
7750 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
7751 *
7752 * * `$scope` - Current scope associated with the element
7753 * * `$element` - Current element
7754 * * `$attrs` - Current attributes object for the element
7755 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
7756 *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
7757 *    * `scope`: (optional) override the scope.
7758 *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
7759 *    * `futureParentElement` (optional):
7760 *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
7761 *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
7762 *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
7763 *          and when the `cloneLinkingFn` is passed,
7764 *          as those elements need to created and cloned in a special way when they are defined outside their
7765 *          usual containers (e.g. like `<svg>`).
7766 *        * See also the `directive.templateNamespace` property.
7767 *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
7768 *      then the default transclusion is provided.
7769 *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
7770 *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
7771 *
7772 * #### `require`
7773 * Require another directive and inject its controller as the fourth argument to the linking function. The
7774 * `require` property can be a string, an array or an object:
7775 * * a **string** containing the name of the directive to pass to the linking function
7776 * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
7777 * linking function will be an array of controllers in the same order as the names in the `require` property
7778 * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
7779 * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
7780 * controllers.
7781 *
7782 * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
7783 * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
7784 * have been constructed but before `$onInit` is called.
7785 * If the name of the required controller is the same as the local name (the key), the name can be
7786 * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.
7787 * See the {@link $compileProvider#component} helper for an example of how this can be used.
7788 * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
7789 * raised (unless no link function is specified and the required controllers are not being bound to the directive
7790 * controller, in which case error checking is skipped). The name can be prefixed with:
7791 *
7792 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
7793 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
7794 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
7795 * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
7796 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
7797 *   `null` to the `link` fn if not found.
7798 * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
7799 *   `null` to the `link` fn if not found.
7800 *
7801 *
7802 * #### `controllerAs`
7803 * Identifier name for a reference to the controller in the directive's scope.
7804 * This allows the controller to be referenced from the directive template. This is especially
7805 * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
7806 * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
7807 * `controllerAs` reference might overwrite a property that already exists on the parent scope.
7808 *
7809 *
7810 * #### `restrict`
7811 * String of subset of `EACM` which restricts the directive to a specific directive
7812 * declaration style. If omitted, the defaults (elements and attributes) are used.
7813 *
7814 * * `E` - Element name (default): `<my-directive></my-directive>`
7815 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
7816 * * `C` - Class: `<div class="my-directive: exp;"></div>`
7817 * * `M` - Comment: `<!-- directive: my-directive exp -->`
7818 *
7819 *
7820 * #### `templateNamespace`
7821 * String representing the document type used by the markup in the template.
7822 * AngularJS needs this information as those elements need to be created and cloned
7823 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
7824 *
7825 * * `html` - All root nodes in the template are HTML. Root nodes may also be
7826 *   top-level elements such as `<svg>` or `<math>`.
7827 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
7828 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
7829 *
7830 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
7831 *
7832 * #### `template`
7833 * HTML markup that may:
7834 * * Replace the contents of the directive's element (default).
7835 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
7836 * * Wrap the contents of the directive's element (if `transclude` is true).
7837 *
7838 * Value may be:
7839 *
7840 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
7841 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
7842 *   function api below) and returns a string value.
7843 *
7844 *
7845 * #### `templateUrl`
7846 * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
7847 *
7848 * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
7849 * for later when the template has been resolved.  In the meantime it will continue to compile and link
7850 * sibling and parent elements as though this element had not contained any directives.
7851 *
7852 * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
7853 * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
7854 * case when only one deeply nested directive has `templateUrl`.
7855 *
7856 * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}.
7857 *
7858 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
7859 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
7860 * a string value representing the url.  In either case, the template URL is passed through {@link
7861 * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
7862 *
7863 *
7864 * #### `replace`
7865 * <div class="alert alert-danger">
7866 * **Note:** `replace` is deprecated in AngularJS and has been removed in the new Angular (v2+).
7867 * </div>
7868 *
7869 * Specifies what the template should replace. Defaults to `false`.
7870 *
7871 * * `true` - the template will replace the directive's element.
7872 * * `false` - the template will replace the contents of the directive's element.
7873 *
7874 * The replacement process migrates all of the attributes / classes from the old element to the new
7875 * one. See the {@link guide/directive#template-expanding-directive
7876 * Directives Guide} for an example.
7877 *
7878 * There are very few scenarios where element replacement is required for the application function,
7879 * the main one being reusable custom components that are used within SVG contexts
7880 * (because SVG doesn't work with custom elements in the DOM tree).
7881 *
7882 * #### `transclude`
7883 * Extract the contents of the element where the directive appears and make it available to the directive.
7884 * The contents are compiled and provided to the directive as a **transclusion function**. See the
7885 * {@link $compile#transclusion Transclusion} section below.
7886 *
7887 *
7888 * #### `compile`
7889 *
7890 * ```js
7891 *   function compile(tElement, tAttrs, transclude) { ... }
7892 * ```
7893 *
7894 * The compile function deals with transforming the template DOM. Since most directives do not do
7895 * template transformation, it is not used often. The compile function takes the following arguments:
7896 *
7897 *   * `tElement` - template element - The element where the directive has been declared. It is
7898 *     safe to do template transformation on the element and child elements only.
7899 *
7900 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
7901 *     between all directive compile functions.
7902 *
7903 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
7904 *
7905 * <div class="alert alert-warning">
7906 * **Note:** The template instance and the link instance may be different objects if the template has
7907 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
7908 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
7909 * should be done in a linking function rather than in a compile function.
7910 * </div>
7911
7912 * <div class="alert alert-warning">
7913 * **Note:** The compile function cannot handle directives that recursively use themselves in their
7914 * own templates or compile functions. Compiling these directives results in an infinite loop and
7915 * stack overflow errors.
7916 *
7917 * This can be avoided by manually using `$compile` in the postLink function to imperatively compile
7918 * a directive's template instead of relying on automatic template compilation via `template` or
7919 * `templateUrl` declaration or manual compilation inside the compile function.
7920 * </div>
7921 *
7922 * <div class="alert alert-danger">
7923 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
7924 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
7925 *   to the link function instead.
7926 * </div>
7927
7928 * A compile function can have a return value which can be either a function or an object.
7929 *
7930 * * returning a (post-link) function - is equivalent to registering the linking function via the
7931 *   `link` property of the config object when the compile function is empty.
7932 *
7933 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
7934 *   control when a linking function should be called during the linking phase. See info about
7935 *   pre-linking and post-linking functions below.
7936 *
7937 *
7938 * #### `link`
7939 * This property is used only if the `compile` property is not defined.
7940 *
7941 * ```js
7942 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
7943 * ```
7944 *
7945 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
7946 * executed after the template has been cloned. This is where most of the directive logic will be
7947 * put.
7948 *
7949 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
7950 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
7951 *
7952 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
7953 *     manipulate the children of the element only in `postLink` function since the children have
7954 *     already been linked.
7955 *
7956 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
7957 *     between all directive linking functions.
7958 *
7959 *   * `controller` - the directive's required controller instance(s) - Instances are shared
7960 *     among all directives, which allows the directives to use the controllers as a communication
7961 *     channel. The exact value depends on the directive's `require` property:
7962 *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
7963 *       * `string`: the controller instance
7964 *       * `array`: array of controller instances
7965 *
7966 *     If a required controller cannot be found, and it is optional, the instance is `null`,
7967 *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
7968 *
7969 *     Note that you can also require the directive's own controller - it will be made available like
7970 *     any other controller.
7971 *
7972 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
7973 *     This is the same as the `$transclude` parameter of directive controllers,
7974 *     see {@link ng.$compile#-controller- the controller section for details}.
7975 *     `function([scope], cloneLinkingFn, futureParentElement)`.
7976 *
7977 * #### Pre-linking function
7978 *
7979 * Executed before the child elements are linked. Not safe to do DOM transformation since the
7980 * compiler linking function will fail to locate the correct elements for linking.
7981 *
7982 * #### Post-linking function
7983 *
7984 * Executed after the child elements are linked.
7985 *
7986 * Note that child elements that contain `templateUrl` directives will not have been compiled
7987 * and linked since they are waiting for their template to load asynchronously and their own
7988 * compilation and linking has been suspended until that occurs.
7989 *
7990 * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
7991 * for their async templates to be resolved.
7992 *
7993 *
7994 * ### Transclusion
7995 *
7996 * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
7997 * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
7998 * scope from where they were taken.
7999 *
8000 * Transclusion is used (often with {@link ngTransclude}) to insert the
8001 * original contents of a directive's element into a specified place in the template of the directive.
8002 * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
8003 * content has access to the properties on the scope from which it was taken, even if the directive
8004 * has isolated scope.
8005 * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
8006 *
8007 * This makes it possible for the widget to have private state for its template, while the transcluded
8008 * content has access to its originating scope.
8009 *
8010 * <div class="alert alert-warning">
8011 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
8012 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
8013 * Testing Transclusion Directives}.
8014 * </div>
8015 *
8016 * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
8017 * directive's element, the entire element or multiple parts of the element contents:
8018 *
8019 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
8020 * * `'element'` - transclude the whole of the directive's element including any directives on this
8021 *   element that are defined at a lower priority than this directive. When used, the `template`
8022 *   property is ignored.
8023 * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
8024 *
8025 * **Multi-slot transclusion** is declared by providing an object for the `transclude` property.
8026 *
8027 * This object is a map where the keys are the name of the slot to fill and the value is an element selector
8028 * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
8029 * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
8030 *
8031 * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}.
8032 *
8033 * If the element selector is prefixed with a `?` then that slot is optional.
8034 *
8035 * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
8036 * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
8037 *
8038 * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
8039 * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
8040 * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
8041 * injectable into the directive's controller.
8042 *
8043 *
8044 * #### Transclusion Functions
8045 *
8046 * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
8047 * function** to the directive's `link` function and `controller`. This transclusion function is a special
8048 * **linking function** that will return the compiled contents linked to a new transclusion scope.
8049 *
8050 * <div class="alert alert-info">
8051 * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
8052 * ngTransclude will deal with it for us.
8053 * </div>
8054 *
8055 * If you want to manually control the insertion and removal of the transcluded content in your directive
8056 * then you must use this transclude function. When you call a transclude function it returns a jqLite/JQuery
8057 * object that contains the compiled DOM, which is linked to the correct transclusion scope.
8058 *
8059 * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
8060 * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
8061 * content and the `scope` is the newly created transclusion scope, which the clone will be linked to.
8062 *
8063 * <div class="alert alert-info">
8064 * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
8065 * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
8066 * </div>
8067 *
8068 * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
8069 * attach function**:
8070 *
8071 * ```js
8072 * var transcludedContent, transclusionScope;
8073 *
8074 * $transclude(function(clone, scope) {
8075 *   element.append(clone);
8076 *   transcludedContent = clone;
8077 *   transclusionScope = scope;
8078 * });
8079 * ```
8080 *
8081 * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
8082 * associated transclusion scope:
8083 *
8084 * ```js
8085 * transcludedContent.remove();
8086 * transclusionScope.$destroy();
8087 * ```
8088 *
8089 * <div class="alert alert-info">
8090 * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
8091 * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
8092 * then you are also responsible for calling `$destroy` on the transclusion scope.
8093 * </div>
8094 *
8095 * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
8096 * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
8097 * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
8098 *
8099 *
8100 * #### Transclusion Scopes
8101 *
8102 * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
8103 * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
8104 * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
8105 * was taken.
8106 *
8107 * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
8108 * like this:
8109 *
8110 * ```html
8111 * <div ng-app>
8112 *   <div isolate>
8113 *     <div transclusion>
8114 *     </div>
8115 *   </div>
8116 * </div>
8117 * ```
8118 *
8119 * The `$parent` scope hierarchy will look like this:
8120 *
8121   ```
8122   - $rootScope
8123     - isolate
8124       - transclusion
8125   ```
8126 *
8127 * but the scopes will inherit prototypically from different scopes to their `$parent`.
8128 *
8129   ```
8130   - $rootScope
8131     - transclusion
8132   - isolate
8133   ```
8134 *
8135 *
8136 * ### Attributes
8137 *
8138 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
8139 * `link()` or `compile()` functions. It has a variety of uses.
8140 *
8141 * * *Accessing normalized attribute names:* Directives like `ngBind` can be expressed in many ways:
8142 *   `ng:bind`, `data-ng-bind`, or `x-ng-bind`. The attributes object allows for normalized access
8143 *   to the attributes.
8144 *
8145 * * *Directive inter-communication:* All directives share the same instance of the attributes
8146 *   object which allows the directives to use the attributes object as inter directive
8147 *   communication.
8148 *
8149 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
8150 *   allowing other directives to read the interpolated value.
8151 *
8152 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
8153 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
8154 *   the only way to easily get the actual value because during the linking phase the interpolation
8155 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
8156 *
8157 * ```js
8158 * function linkingFn(scope, elm, attrs, ctrl) {
8159 *   // get the attribute value
8160 *   console.log(attrs.ngModel);
8161 *
8162 *   // change the attribute
8163 *   attrs.$set('ngModel', 'new value');
8164 *
8165 *   // observe changes to interpolated attribute
8166 *   attrs.$observe('ngModel', function(value) {
8167 *     console.log('ngModel has changed value to ' + value);
8168 *   });
8169 * }
8170 * ```
8171 *
8172 * ## Example
8173 *
8174 * <div class="alert alert-warning">
8175 * **Note**: Typically directives are registered with `module.directive`. The example below is
8176 * to illustrate how `$compile` works.
8177 * </div>
8178 *
8179 <example module="compileExample" name="compile">
8180   <file name="index.html">
8181    <script>
8182      angular.module('compileExample', [], function($compileProvider) {
8183        // Configure new 'compile' directive by passing a directive
8184        // factory function. The factory function injects '$compile'.
8185        $compileProvider.directive('compile', function($compile) {
8186          // The directive factory creates a link function.
8187          return function(scope, element, attrs) {
8188            scope.$watch(
8189              function(scope) {
8190                // Watch the 'compile' expression for changes.
8191                return scope.$eval(attrs.compile);
8192              },
8193              function(value) {
8194                // When the 'compile' expression changes
8195                // assign it into the current DOM.
8196                element.html(value);
8197
8198                // Compile the new DOM and link it to the current scope.
8199                // NOTE: we only compile '.childNodes' so that we
8200                // don't get into an infinite loop compiling ourselves.
8201                $compile(element.contents())(scope);
8202              }
8203            );
8204          };
8205        });
8206      })
8207      .controller('GreeterController', ['$scope', function($scope) {
8208        $scope.name = 'AngularJS';
8209        $scope.html = 'Hello {{name}}';
8210      }]);
8211    </script>
8212    <div ng-controller="GreeterController">
8213      <input ng-model="name"> <br/>
8214      <textarea ng-model="html"></textarea> <br/>
8215      <div compile="html"></div>
8216    </div>
8217   </file>
8218   <file name="protractor.js" type="protractor">
8219     it('should auto compile', function() {
8220       var textarea = $('textarea');
8221       var output = $('div[compile]');
8222       // The initial state reads 'Hello AngularJS'.
8223       expect(output.getText()).toBe('Hello AngularJS');
8224       textarea.clear();
8225       textarea.sendKeys('{{name}}!');
8226       expect(output.getText()).toBe('AngularJS!');
8227     });
8228   </file>
8229 </example>
8230
8231 *
8232 *
8233 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
8234 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
8235 *
8236 * <div class="alert alert-danger">
8237 * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
8238 *   e.g. will not use the right outer scope. Please pass the transclude function as a
8239 *   `parentBoundTranscludeFn` to the link function instead.
8240 * </div>
8241 *
8242 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
8243 *                 root element(s), not their children)
8244 * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
8245 * (a DOM element/tree) to a scope. Where:
8246 *
8247 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
8248 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
8249 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
8250 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
8251 *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
8252 *
8253 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
8254 *      * `scope` - is the current scope with which the linking function is working with.
8255 *
8256 *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
8257 *  keys may be used to control linking behavior:
8258 *
8259 *      * `parentBoundTranscludeFn` - the transclude function made available to
8260 *        directives; if given, it will be passed through to the link functions of
8261 *        directives found in `element` during compilation.
8262 *      * `transcludeControllers` - an object hash with keys that map controller names
8263 *        to a hash with the key `instance`, which maps to the controller instance;
8264 *        if given, it will make the controllers available to directives on the compileNode:
8265 *        ```
8266 *        {
8267 *          parent: {
8268 *            instance: parentControllerInstance
8269 *          }
8270 *        }
8271 *        ```
8272 *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
8273 *        the cloned elements; only needed for transcludes that are allowed to contain non HTML
8274 *        elements (e.g. SVG elements). See also the `directive.controller` property.
8275 *
8276 * Calling the linking function returns the element of the template. It is either the original
8277 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
8278 *
8279 * After linking the view is not updated until after a call to `$digest`, which typically is done by
8280 * AngularJS automatically.
8281 *
8282 * If you need access to the bound view, there are two ways to do it:
8283 *
8284 * - If you are not asking the linking function to clone the template, create the DOM element(s)
8285 *   before you send them to the compiler and keep this reference around.
8286 *   ```js
8287 *     var element = angular.element('<p>{{total}}</p>');
8288 *     $compile(element)(scope);
8289 *   ```
8290 *
8291 * - if on the other hand, you need the element to be cloned, the view reference from the original
8292 *   example would not point to the clone, but rather to the original template that was cloned. In
8293 *   this case, you can access the clone either via the `cloneAttachFn` or the value returned by the
8294 *   linking function:
8295 *   ```js
8296 *     var templateElement = angular.element('<p>{{total}}</p>');
8297 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
8298 *       // Attach the clone to DOM document at the right place.
8299 *     });
8300 *
8301 *     // Now we have reference to the cloned DOM via `clonedElement`.
8302 *     // NOTE: The `clonedElement` returned by the linking function is the same as the
8303 *     //       `clonedElement` passed to `cloneAttachFn`.
8304 *   ```
8305 *
8306 *
8307 * For information on how the compiler works, see the
8308 * {@link guide/compiler AngularJS HTML Compiler} section of the Developer Guide.
8309 *
8310 * @knownIssue
8311 *
8312 * ### Double Compilation
8313 *
8314   Double compilation occurs when an already compiled part of the DOM gets
8315   compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues,
8316   and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it
8317   section on double compilation} for an in-depth explanation and ways to avoid it.
8318
8319 * @knownIssue
8320
8321   ### Issues with `replace: true`
8322 *
8323 * <div class="alert alert-danger">
8324 *   **Note**: {@link $compile#-replace- `replace: true`} is deprecated and not recommended to use,
8325 *   mainly due to the issues listed here. It has been completely removed in the new Angular.
8326 * </div>
8327 *
8328 * #### Attribute values are not merged
8329 *
8330 * When a `replace` directive encounters the same attribute on the original and the replace node,
8331 * it will simply deduplicate the attribute and join the values with a space or with a `;` in case of
8332 * the `style` attribute.
8333 * ```html
8334 * Original Node: <span class="original" style="color: red;"></span>
8335 * Replace Template: <span class="replaced" style="background: blue;"></span>
8336 * Result: <span class="original replaced" style="color: red; background: blue;"></span>
8337 * ```
8338 *
8339 * That means attributes that contain AngularJS expressions will not be merged correctly, e.g.
8340 * {@link ngShow} or {@link ngClass} will cause a {@link $parse} error:
8341 *
8342 * ```html
8343 * Original Node: <span ng-class="{'something': something}" ng-show="!condition"></span>
8344 * Replace Template: <span ng-class="{'else': else}" ng-show="otherCondition"></span>
8345 * Result: <span ng-class="{'something': something} {'else': else}" ng-show="!condition otherCondition"></span>
8346 * ```
8347 *
8348 * See issue [#5695](https://github.com/angular/angular.js/issues/5695).
8349 *
8350 * #### Directives are not deduplicated before compilation
8351 *
8352 * When the original node and the replace template declare the same directive(s), they will be
8353 * {@link guide/compiler#double-compilation-and-how-to-avoid-it compiled twice} because the compiler
8354 * does not deduplicate them. In many cases, this is not noticeable, but e.g. {@link ngModel} will
8355 * attach `$formatters` and `$parsers` twice.
8356 *
8357 * See issue [#2573](https://github.com/angular/angular.js/issues/2573).
8358 *
8359 * #### `transclude: element` in the replace template root can have unexpected effects
8360 *
8361 * When the replace template has a directive at the root node that uses
8362 * {@link $compile#-transclude- `transclude: element`}, e.g.
8363 * {@link ngIf} or {@link ngRepeat}, the DOM structure or scope inheritance can be incorrect.
8364 * See the following issues:
8365 *
8366 * - Incorrect scope on replaced element:
8367 * [#9837](https://github.com/angular/angular.js/issues/9837)
8368 * - Different DOM between `template` and `templateUrl`:
8369 * [#10612](https://github.com/angular/angular.js/issues/14326)
8370 *
8371 */
8372
8373/**
8374 * @ngdoc directive
8375 * @name ngProp
8376 * @restrict A
8377 * @element ANY
8378 *
8379 * @usage
8380 *
8381 * ```html
8382 * <ANY ng-prop-propname="expression">
8383 * </ANY>
8384 * ```
8385 *
8386 * or with uppercase letters in property (e.g. "propName"):
8387 *
8388 *
8389 * ```html
8390 * <ANY ng-prop-prop_name="expression">
8391 * </ANY>
8392 * ```
8393 *
8394 *
8395 * @description
8396 * The `ngProp` directive binds an expression to a DOM element property.
8397 * `ngProp` allows writing to arbitrary properties by including
8398 * the property name in the attribute, e.g. `ng-prop-value="'my value'"` binds 'my value' to
8399 * the `value` property.
8400 *
8401 * Usually, it's not necessary to write to properties in AngularJS, as the built-in directives
8402 * handle the most common use cases (instead of the above example, you would use {@link ngValue}).
8403 *
8404 * However, [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements)
8405 * often use custom properties to hold data, and `ngProp` can be used to provide input to these
8406 * custom elements.
8407 *
8408 * ## Binding to camelCase properties
8409 *
8410 * Since HTML attributes are case-insensitive, camelCase properties like `innerHTML` must be escaped.
8411 * AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so
8412 * `innerHTML`  must be written as `ng-prop-inner_h_t_m_l="expression"` (Note that this is just an
8413 * example, and for binding HTML {@link ngBindHtml} should be used.
8414 *
8415 * ## Security
8416 *
8417 * Binding expressions to arbitrary properties poses a security risk, as  properties like `innerHTML`
8418 * can insert potentially dangerous HTML into the application, e.g. script tags that execute
8419 * malicious code.
8420 * For this reason, `ngProp` applies Strict Contextual Escaping with the {@link ng.$sce $sce service}.
8421 * This means vulnerable properties require their content to be "trusted", based on the
8422 * context of the property. For example, the `innerHTML` is in the `HTML` context, and the
8423 * `iframe.src` property is in the `RESOURCE_URL` context, which requires that values written to
8424 * this property are trusted as a `RESOURCE_URL`.
8425 *
8426 * This can be set explicitly by calling $sce.trustAs(type, value) on the value that is
8427 * trusted before passing it to the `ng-prop-*` directive. There are exist shorthand methods for
8428 * each context type in the form of {@link ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl()} et al.
8429 *
8430 * In some cases you can also rely upon automatic sanitization of untrusted values - see below.
8431 *
8432 * Based on the context, other options may exist to mark a value as trusted / configure the behavior
8433 * of {@link ng.$sce}. For example, to restrict the `RESOURCE_URL` context to specific origins, use
8434 * the {@link $sceDelegateProvider#trustedResourceUrlList trustedResourceUrlList()}
8435 * and {@link $sceDelegateProvider#bannedResourceUrlList bannedResourceUrlList()}.
8436 *
8437 * {@link ng.$sce#what-trusted-context-types-are-supported- Find out more about the different context types}.
8438 *
8439 * ### HTML Sanitization
8440 *
8441 * By default, `$sce` will throw an error if it detects untrusted HTML content, and will not bind the
8442 * content.
8443 * However, if you include the {@link ngSanitize ngSanitize module}, it will try to sanitize the
8444 * potentially dangerous HTML, e.g. strip non-trusted tags and attributes when binding to
8445 * `innerHTML`.
8446 *
8447 * @example
8448 * ### Binding to different contexts
8449 *
8450 * <example name="ngProp" module="exampleNgProp">
8451 *   <file name="app.js">
8452 *     angular.module('exampleNgProp', [])
8453 *       .component('main', {
8454 *         templateUrl: 'main.html',
8455 *         controller: function($sce) {
8456 *           this.safeContent = '<strong>Safe content</strong>';
8457 *           this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>';
8458 *           this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent);
8459 *         }
8460 *       });
8461 *   </file>
8462 *   <file name="main.html">
8463 *     <div>
8464 *       <div class="prop-unit">
8465 *         Binding to a property without security context:
8466 *         <div class="prop-binding" ng-prop-inner_text="$ctrl.safeContent"></div>
8467 *         <span class="prop-note">innerText</span> (safeContent)
8468 *       </div>
8469 *
8470 *       <div class="prop-unit">
8471 *         "Safe" content that requires a security context will throw because the contents could potentially be dangerous ...
8472 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div>
8473 *         <span class="prop-note">innerHTML</span> (safeContent)
8474 *       </div>
8475 *
8476 *       <div class="prop-unit">
8477 *         ... so that actually dangerous content cannot be executed:
8478 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div>
8479 *         <span class="prop-note">innerHTML</span> (unsafeContent)
8480 *       </div>
8481 *
8482 *       <div class="prop-unit">
8483 *         ... but unsafe Content that has been trusted explicitly works - only do this if you are 100% sure!
8484 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div>
8485 *         <span class="prop-note">innerHTML</span> (trustedUnsafeContent)
8486 *       </div>
8487 *     </div>
8488 *   </file>
8489 *   <file name="index.html">
8490 *     <main></main>
8491 *   </file>
8492 *   <file name="styles.css">
8493 *     .prop-unit {
8494 *       margin-bottom: 10px;
8495 *     }
8496 *
8497 *     .prop-binding {
8498 *       min-height: 30px;
8499 *       border: 1px solid blue;
8500 *     }
8501 *
8502 *     .prop-note {
8503 *       font-family: Monospace;
8504 *     }
8505 *   </file>
8506 * </example>
8507 *
8508 *
8509 * @example
8510 * ### Binding to innerHTML with ngSanitize
8511 *
8512 * <example name="ngProp" module="exampleNgProp" deps="angular-sanitize.js">
8513 *   <file name="app.js">
8514 *     angular.module('exampleNgProp', ['ngSanitize'])
8515 *       .component('main', {
8516 *         templateUrl: 'main.html',
8517 *         controller: function($sce) {
8518 *           this.safeContent = '<strong>Safe content</strong>';
8519 *           this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>';
8520 *           this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent);
8521 *         }
8522 *       });
8523 *   </file>
8524 *   <file name="main.html">
8525 *     <div>
8526 *       <div class="prop-unit">
8527 *         "Safe" content will be sanitized ...
8528 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div>
8529 *         <span class="prop-note">innerHTML</span> (safeContent)
8530 *       </div>
8531 *
8532 *       <div class="prop-unit">
8533 *         ... as will dangerous content:
8534 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div>
8535 *         <span class="prop-note">innerHTML</span> (unsafeContent)
8536 *       </div>
8537 *
8538 *       <div class="prop-unit">
8539 *         ... and content that has been trusted explicitly works the same as without ngSanitize:
8540 *         <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div>
8541 *         <span class="prop-note">innerHTML</span> (trustedUnsafeContent)
8542 *       </div>
8543 *     </div>
8544 *   </file>
8545 *   <file name="index.html">
8546 *     <main></main>
8547 *   </file>
8548 *   <file name="styles.css">
8549 *     .prop-unit {
8550 *       margin-bottom: 10px;
8551 *     }
8552 *
8553 *     .prop-binding {
8554 *       min-height: 30px;
8555 *       border: 1px solid blue;
8556 *     }
8557 *
8558 *     .prop-note {
8559 *       font-family: Monospace;
8560 *     }
8561 *   </file>
8562 * </example>
8563 *
8564 */
8565
8566/** @ngdoc directive
8567 * @name ngOn
8568 * @restrict A
8569 * @element ANY
8570 *
8571 * @usage
8572 *
8573 * ```html
8574 * <ANY ng-on-eventname="expression">
8575 * </ANY>
8576 * ```
8577 *
8578 * or with uppercase letters in property (e.g. "eventName"):
8579 *
8580 *
8581 * ```html
8582 * <ANY ng-on-event_name="expression">
8583 * </ANY>
8584 * ```
8585 *
8586 * @description
8587 * The `ngOn` directive adds an event listener to a DOM element via
8588 * {@link angular.element angular.element().on()}, and evaluates an expression when the event is
8589 * fired.
8590 * `ngOn` allows adding listeners for arbitrary events by including
8591 * the event name in the attribute, e.g. `ng-on-drop="onDrop()"` executes the 'onDrop()' expression
8592 * when the `drop` event is fired.
8593 *
8594 * AngularJS provides specific directives for many events, such as {@link ngClick}, so in most
8595 * cases it is not necessary to use `ngOn`. However, AngularJS does not support all events
8596 * (e.g. the `drop` event in the example above), and new events might be introduced in later DOM
8597 * standards.
8598 *
8599 * Another use-case for `ngOn` is listening to
8600 * [custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events)
8601 * fired by
8602 * [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements).
8603 *
8604 * ## Binding to camelCase properties
8605 *
8606 * Since HTML attributes are case-insensitive, camelCase properties like `myEvent` must be escaped.
8607 * AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so
8608 * `myEvent` must be written as `ng-on-my_event="expression"`.
8609 *
8610 * @example
8611 * ### Bind to built-in DOM events
8612 *
8613 * <example name="ngOn" module="exampleNgOn">
8614 *   <file name="app.js">
8615 *     angular.module('exampleNgOn', [])
8616 *       .component('main', {
8617 *         templateUrl: 'main.html',
8618 *         controller: function() {
8619 *           this.clickCount = 0;
8620 *           this.mouseoverCount = 0;
8621 *
8622 *           this.loadingState = 0;
8623 *         }
8624 *       });
8625 *   </file>
8626 *   <file name="main.html">
8627 *     <div>
8628 *       This is equivalent to `ngClick` and `ngMouseover`:<br>
8629 *       <button
8630 *         ng-on-click="$ctrl.clickCount = $ctrl.clickCount + 1"
8631 *         ng-on-mouseover="$ctrl.mouseoverCount = $ctrl.mouseoverCount + 1">Click or mouseover</button><br>
8632 *       clickCount: {{$ctrl.clickCount}}<br>
8633 *       mouseover: {{$ctrl.mouseoverCount}}
8634 *
8635 *       <hr>
8636 *
8637 *       For the `error` and `load` event on images no built-in AngularJS directives exist:<br>
8638 *       <img src="thisimagedoesnotexist.png" ng-on-error="$ctrl.loadingState = -1" ng-on-load="$ctrl.loadingState = 1"><br>
8639 *       <div ng-switch="$ctrl.loadingState">
8640 *         <span ng-switch-when="0">Image is loading</span>
8641 *         <span ng-switch-when="-1">Image load error</span>
8642 *         <span ng-switch-when="1">Image loaded successfully</span>
8643 *       </div>
8644 *     </div>
8645 *   </file>
8646 *   <file name="index.html">
8647 *     <main></main>
8648 *   </file>
8649 * </example>
8650 *
8651 *
8652 * @example
8653 * ### Bind to custom DOM events
8654 *
8655 * <example name="ngOnCustom" module="exampleNgOn">
8656 *   <file name="app.js">
8657 *     angular.module('exampleNgOn', [])
8658 *       .component('main', {
8659 *         templateUrl: 'main.html',
8660 *         controller: function() {
8661 *           this.eventLog = '';
8662 *
8663 *           this.listener = function($event) {
8664 *             this.eventLog = 'Event with type "' + $event.type + '" fired at ' + $event.detail;
8665 *           };
8666 *         }
8667 *       })
8668 *       .component('childComponent', {
8669 *         templateUrl: 'child.html',
8670 *         controller: function($element) {
8671 *           this.fireEvent = function() {
8672 *             var event = new CustomEvent('customtype', { detail: new Date()});
8673 *
8674 *             $element[0].dispatchEvent(event);
8675 *           };
8676 *         }
8677 *       });
8678 *   </file>
8679 *   <file name="main.html">
8680 *     <child-component ng-on-customtype="$ctrl.listener($event)"></child-component><br>
8681 *     <span>Event log: {{$ctrl.eventLog}}</span>
8682 *   </file>
8683 *   <file name="child.html">
8684      <button ng-click="$ctrl.fireEvent()">Fire custom event</button>
8685 *   </file>
8686 *   <file name="index.html">
8687 *     <main></main>
8688 *   </file>
8689 * </example>
8690 */
8691
8692var $compileMinErr = minErr('$compile');
8693
8694function UNINITIALIZED_VALUE() {}
8695var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
8696
8697/**
8698 * @ngdoc provider
8699 * @name $compileProvider
8700 *
8701 * @description
8702 */
8703$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
8704/** @this */
8705function $CompileProvider($provide, $$sanitizeUriProvider) {
8706  var hasDirectives = {},
8707      Suffix = 'Directive',
8708      COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/,
8709      CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/,
8710      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
8711      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
8712
8713  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
8714  // The assumption is that future DOM event attribute names will begin with
8715  // 'on' and be composed of only English letters.
8716  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
8717  var bindingCache = createMap();
8718
8719  function parseIsolateBindings(scope, directiveName, isController) {
8720    var LOCAL_REGEXP = /^([@&]|[=<](\*?))(\??)\s*([\w$]*)$/;
8721
8722    var bindings = createMap();
8723
8724    forEach(scope, function(definition, scopeName) {
8725      definition = definition.trim();
8726
8727      if (definition in bindingCache) {
8728        bindings[scopeName] = bindingCache[definition];
8729        return;
8730      }
8731      var match = definition.match(LOCAL_REGEXP);
8732
8733      if (!match) {
8734        throw $compileMinErr('iscp',
8735            'Invalid {3} for directive \'{0}\'.' +
8736            ' Definition: {... {1}: \'{2}\' ...}',
8737            directiveName, scopeName, definition,
8738            (isController ? 'controller bindings definition' :
8739            'isolate scope definition'));
8740      }
8741
8742      bindings[scopeName] = {
8743        mode: match[1][0],
8744        collection: match[2] === '*',
8745        optional: match[3] === '?',
8746        attrName: match[4] || scopeName
8747      };
8748      if (match[4]) {
8749        bindingCache[definition] = bindings[scopeName];
8750      }
8751    });
8752
8753    return bindings;
8754  }
8755
8756  function parseDirectiveBindings(directive, directiveName) {
8757    var bindings = {
8758      isolateScope: null,
8759      bindToController: null
8760    };
8761    if (isObject(directive.scope)) {
8762      if (directive.bindToController === true) {
8763        bindings.bindToController = parseIsolateBindings(directive.scope,
8764                                                         directiveName, true);
8765        bindings.isolateScope = {};
8766      } else {
8767        bindings.isolateScope = parseIsolateBindings(directive.scope,
8768                                                     directiveName, false);
8769      }
8770    }
8771    if (isObject(directive.bindToController)) {
8772      bindings.bindToController =
8773          parseIsolateBindings(directive.bindToController, directiveName, true);
8774    }
8775    if (bindings.bindToController && !directive.controller) {
8776      // There is no controller
8777      throw $compileMinErr('noctrl',
8778            'Cannot bind to controller without directive \'{0}\'s controller.',
8779            directiveName);
8780    }
8781    return bindings;
8782  }
8783
8784  function assertValidDirectiveName(name) {
8785    var letter = name.charAt(0);
8786    if (!letter || letter !== lowercase(letter)) {
8787      throw $compileMinErr('baddir', 'Directive/Component name \'{0}\' is invalid. The first character must be a lowercase letter', name);
8788    }
8789    if (name !== name.trim()) {
8790      throw $compileMinErr('baddir',
8791            'Directive/Component name \'{0}\' is invalid. The name should not contain leading or trailing whitespaces',
8792            name);
8793    }
8794  }
8795
8796  function getDirectiveRequire(directive) {
8797    var require = directive.require || (directive.controller && directive.name);
8798
8799    if (!isArray(require) && isObject(require)) {
8800      forEach(require, function(value, key) {
8801        var match = value.match(REQUIRE_PREFIX_REGEXP);
8802        var name = value.substring(match[0].length);
8803        if (!name) require[key] = match[0] + key;
8804      });
8805    }
8806
8807    return require;
8808  }
8809
8810  function getDirectiveRestrict(restrict, name) {
8811    if (restrict && !(isString(restrict) && /[EACM]/.test(restrict))) {
8812      throw $compileMinErr('badrestrict',
8813          'Restrict property \'{0}\' of directive \'{1}\' is invalid',
8814          restrict,
8815          name);
8816    }
8817
8818    return restrict || 'EA';
8819  }
8820
8821  /**
8822   * @ngdoc method
8823   * @name $compileProvider#directive
8824   * @kind function
8825   *
8826   * @description
8827   * Register a new directive with the compiler.
8828   *
8829   * @param {string|Object} name Name of the directive in camel-case (i.e. `ngBind` which will match
8830   *    as `ng-bind`), or an object map of directives where the keys are the names and the values
8831   *    are the factories.
8832   * @param {Function|Array} directiveFactory An injectable directive factory function. See the
8833   *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
8834   * @returns {ng.$compileProvider} Self for chaining.
8835   */
8836  this.directive = function registerDirective(name, directiveFactory) {
8837    assertArg(name, 'name');
8838    assertNotHasOwnProperty(name, 'directive');
8839    if (isString(name)) {
8840      assertValidDirectiveName(name);
8841      assertArg(directiveFactory, 'directiveFactory');
8842      if (!hasDirectives.hasOwnProperty(name)) {
8843        hasDirectives[name] = [];
8844        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
8845          function($injector, $exceptionHandler) {
8846            var directives = [];
8847            forEach(hasDirectives[name], function(directiveFactory, index) {
8848              try {
8849                var directive = $injector.invoke(directiveFactory);
8850                if (isFunction(directive)) {
8851                  directive = { compile: valueFn(directive) };
8852                } else if (!directive.compile && directive.link) {
8853                  directive.compile = valueFn(directive.link);
8854                }
8855                directive.priority = directive.priority || 0;
8856                directive.index = index;
8857                directive.name = directive.name || name;
8858                directive.require = getDirectiveRequire(directive);
8859                directive.restrict = getDirectiveRestrict(directive.restrict, name);
8860                directive.$$moduleName = directiveFactory.$$moduleName;
8861                directives.push(directive);
8862              } catch (e) {
8863                $exceptionHandler(e);
8864              }
8865            });
8866            return directives;
8867          }]);
8868      }
8869      hasDirectives[name].push(directiveFactory);
8870    } else {
8871      forEach(name, reverseParams(registerDirective));
8872    }
8873    return this;
8874  };
8875
8876  /**
8877   * @ngdoc method
8878   * @name $compileProvider#component
8879   * @module ng
8880   * @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`),
8881   *    or an object map of components where the keys are the names and the values are the component definition objects.
8882   * @param {Object} options Component definition object (a simplified
8883   *    {@link ng.$compile#directive-definition-object directive definition object}),
8884   *    with the following properties (all optional):
8885   *
8886   *    - `controller` – `{(string|function()=}` – controller constructor function that should be
8887   *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
8888   *      registered controller} if passed as a string. An empty `noop` function by default.
8889   *    - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
8890   *      If present, the controller will be published to scope under the `controllerAs` name.
8891   *      If not present, this will default to be `$ctrl`.
8892   *    - `template` – `{string=|function()=}` – html template as a string or a function that
8893   *      returns an html template as a string which should be used as the contents of this component.
8894   *      Empty string by default.
8895   *
8896   *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
8897   *      the following locals:
8898   *
8899   *      - `$element` - Current element
8900   *      - `$attrs` - Current attributes object for the element
8901   *
8902   *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
8903   *      template that should be used  as the contents of this component.
8904   *
8905   *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
8906   *      the following locals:
8907   *
8908   *      - `$element` - Current element
8909   *      - `$attrs` - Current attributes object for the element
8910   *
8911   *    - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
8912   *      Component properties are always bound to the component controller and not to the scope.
8913   *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
8914   *    - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
8915   *      Disabled by default.
8916   *    - `require` - `{Object<string, string>=}` - requires the controllers of other directives and binds them to
8917   *      this component's controller. The object keys specify the property names under which the required
8918   *      controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
8919   *    - `$...` – additional properties to attach to the directive factory function and the controller
8920   *      constructor function. (This is used by the component router to annotate)
8921   *
8922   * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
8923   * @description
8924   * Register a **component definition** with the compiler. This is a shorthand for registering a special
8925   * type of directive, which represents a self-contained UI component in your application. Such components
8926   * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
8927   *
8928   * Component definitions are very simple and do not require as much configuration as defining general
8929   * directives. Component definitions usually consist only of a template and a controller backing it.
8930   *
8931   * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
8932   * `bindToController`. They always have **isolate scope** and are restricted to elements.
8933   *
8934   * Here are a few examples of how you would usually define components:
8935   *
8936   * ```js
8937   *   var myMod = angular.module(...);
8938   *   myMod.component('myComp', {
8939   *     template: '<div>My name is {{$ctrl.name}}</div>',
8940   *     controller: function() {
8941   *       this.name = 'shahar';
8942   *     }
8943   *   });
8944   *
8945   *   myMod.component('myComp', {
8946   *     template: '<div>My name is {{$ctrl.name}}</div>',
8947   *     bindings: {name: '@'}
8948   *   });
8949   *
8950   *   myMod.component('myComp', {
8951   *     templateUrl: 'views/my-comp.html',
8952   *     controller: 'MyCtrl',
8953   *     controllerAs: 'ctrl',
8954   *     bindings: {name: '@'}
8955   *   });
8956   *
8957   * ```
8958   * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
8959   *
8960   * <br />
8961   * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
8962   */
8963  this.component = function registerComponent(name, options) {
8964    if (!isString(name)) {
8965      forEach(name, reverseParams(bind(this, registerComponent)));
8966      return this;
8967    }
8968
8969    var controller = options.controller || function() {};
8970
8971    function factory($injector) {
8972      function makeInjectable(fn) {
8973        if (isFunction(fn) || isArray(fn)) {
8974          return /** @this */ function(tElement, tAttrs) {
8975            return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
8976          };
8977        } else {
8978          return fn;
8979        }
8980      }
8981
8982      var template = (!options.template && !options.templateUrl ? '' : options.template);
8983      var ddo = {
8984        controller: controller,
8985        controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
8986        template: makeInjectable(template),
8987        templateUrl: makeInjectable(options.templateUrl),
8988        transclude: options.transclude,
8989        scope: {},
8990        bindToController: options.bindings || {},
8991        restrict: 'E',
8992        require: options.require
8993      };
8994
8995      // Copy annotations (starting with $) over to the DDO
8996      forEach(options, function(val, key) {
8997        if (key.charAt(0) === '$') ddo[key] = val;
8998      });
8999
9000      return ddo;
9001    }
9002
9003    // TODO(pete) remove the following `forEach` before we release 1.6.0
9004    // The [email protected] looks for the annotations on the controller constructor
9005    // Nothing in AngularJS looks for annotations on the factory function but we can't remove
9006    // it from 1.5.x yet.
9007
9008    // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
9009    // These could be used by libraries such as the new component router
9010    forEach(options, function(val, key) {
9011      if (key.charAt(0) === '$') {
9012        factory[key] = val;
9013        // Don't try to copy over annotations to named controller
9014        if (isFunction(controller)) controller[key] = val;
9015      }
9016    });
9017
9018    factory.$inject = ['$injector'];
9019
9020    return this.directive(name, factory);
9021  };
9022
9023
9024  /**
9025   * @ngdoc method
9026   * @name $compileProvider#aHrefSanitizationTrustedUrlList
9027   * @kind function
9028   *
9029   * @description
9030   * Retrieves or overrides the default regular expression that is used for determining trusted safe
9031   * urls during a[href] sanitization.
9032   *
9033   * The sanitization is a security measure aimed at preventing XSS attacks via html links.
9034   *
9035   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
9036   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationTrustedUrlList`
9037   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
9038   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
9039   *
9040   * @param {RegExp=} regexp New regexp to trust urls with.
9041   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
9042   *    chaining otherwise.
9043   */
9044  this.aHrefSanitizationTrustedUrlList = function(regexp) {
9045    if (isDefined(regexp)) {
9046      $$sanitizeUriProvider.aHrefSanitizationTrustedUrlList(regexp);
9047      return this;
9048    } else {
9049      return $$sanitizeUriProvider.aHrefSanitizationTrustedUrlList();
9050    }
9051  };
9052
9053
9054  /**
9055   * @ngdoc method
9056   * @name $compileProvider#aHrefSanitizationWhitelist
9057   * @kind function
9058   *
9059   * @deprecated
9060   * sinceVersion="1.8.1"
9061   *
9062   * This method is deprecated. Use {@link $compileProvider#aHrefSanitizationTrustedUrlList
9063   * aHrefSanitizationTrustedUrlList} instead.
9064   */
9065  Object.defineProperty(this, 'aHrefSanitizationWhitelist', {
9066    get: function() {
9067      return this.aHrefSanitizationTrustedUrlList;
9068    },
9069    set: function(value) {
9070      this.aHrefSanitizationTrustedUrlList = value;
9071    }
9072  });
9073
9074
9075  /**
9076   * @ngdoc method
9077   * @name $compileProvider#imgSrcSanitizationTrustedUrlList
9078   * @kind function
9079   *
9080   * @description
9081   * Retrieves or overrides the default regular expression that is used for determining trusted safe
9082   * urls during img[src] sanitization.
9083   *
9084   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
9085   *
9086   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
9087   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationTrustedUrlList`
9088   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
9089   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
9090   *
9091   * @param {RegExp=} regexp New regexp to trust urls with.
9092   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
9093   *    chaining otherwise.
9094   */
9095  this.imgSrcSanitizationTrustedUrlList = function(regexp) {
9096    if (isDefined(regexp)) {
9097      $$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList(regexp);
9098      return this;
9099    } else {
9100      return $$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList();
9101    }
9102  };
9103
9104
9105  /**
9106   * @ngdoc method
9107   * @name $compileProvider#imgSrcSanitizationWhitelist
9108   * @kind function
9109   *
9110   * @deprecated
9111   * sinceVersion="1.8.1"
9112   *
9113   * This method is deprecated. Use {@link $compileProvider#imgSrcSanitizationTrustedUrlList
9114   * imgSrcSanitizationTrustedUrlList} instead.
9115   */
9116  Object.defineProperty(this, 'imgSrcSanitizationWhitelist', {
9117    get: function() {
9118      return this.imgSrcSanitizationTrustedUrlList;
9119    },
9120    set: function(value) {
9121      this.imgSrcSanitizationTrustedUrlList = value;
9122    }
9123  });
9124
9125  /**
9126   * @ngdoc method
9127   * @name  $compileProvider#debugInfoEnabled
9128   *
9129   * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
9130   * current debugInfoEnabled state
9131   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9132   *
9133   * @kind function
9134   *
9135   * @description
9136   * Call this method to enable/disable various debug runtime information in the compiler such as adding
9137   * binding information and a reference to the current scope on to DOM elements.
9138   * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
9139   * * `ng-binding` CSS class
9140   * * `ng-scope` and `ng-isolated-scope` CSS classes
9141   * * `$binding` data property containing an array of the binding expressions
9142   * * Data properties used by the {@link angular.element#methods `scope()`/`isolateScope()` methods} to return
9143   *   the element's scope.
9144   * * Placeholder comments will contain information about what directive and binding caused the placeholder.
9145   *   E.g. `<!-- ngIf: shouldShow() -->`.
9146   *
9147   * You may want to disable this in production for a significant performance boost. See
9148   * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
9149   *
9150   * The default value is true.
9151   */
9152  var debugInfoEnabled = true;
9153  this.debugInfoEnabled = function(enabled) {
9154    if (isDefined(enabled)) {
9155      debugInfoEnabled = enabled;
9156      return this;
9157    }
9158    return debugInfoEnabled;
9159  };
9160
9161  /**
9162   * @ngdoc method
9163   * @name  $compileProvider#strictComponentBindingsEnabled
9164   *
9165   * @param {boolean=} enabled update the strictComponentBindingsEnabled state if provided,
9166   * otherwise return the current strictComponentBindingsEnabled state.
9167   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9168   *
9169   * @kind function
9170   *
9171   * @description
9172   * Call this method to enable / disable the strict component bindings check. If enabled, the
9173   * compiler will enforce that all scope / controller bindings of a
9174   * {@link $compileProvider#directive directive} / {@link $compileProvider#component component}
9175   * that are not set as optional with `?`, must be provided when the directive is instantiated.
9176   * If not provided, the compiler will throw the
9177   * {@link error/$compile/missingattr $compile:missingattr error}.
9178   *
9179   * The default value is false.
9180   */
9181  var strictComponentBindingsEnabled = false;
9182  this.strictComponentBindingsEnabled = function(enabled) {
9183    if (isDefined(enabled)) {
9184      strictComponentBindingsEnabled = enabled;
9185      return this;
9186    }
9187    return strictComponentBindingsEnabled;
9188  };
9189
9190  var TTL = 10;
9191  /**
9192   * @ngdoc method
9193   * @name $compileProvider#onChangesTtl
9194   * @description
9195   *
9196   * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and
9197   * assuming that the model is unstable.
9198   *
9199   * The current default is 10 iterations.
9200   *
9201   * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result
9202   * in several iterations of calls to these hooks. However if an application needs more than the default 10
9203   * iterations to stabilize then you should investigate what is causing the model to continuously change during
9204   * the `$onChanges` hook execution.
9205   *
9206   * Increasing the TTL could have performance implications, so you should not change it without proper justification.
9207   *
9208   * @param {number} limit The number of `$onChanges` hook iterations.
9209   * @returns {number|object} the current limit (or `this` if called as a setter for chaining)
9210   */
9211  this.onChangesTtl = function(value) {
9212    if (arguments.length) {
9213      TTL = value;
9214      return this;
9215    }
9216    return TTL;
9217  };
9218
9219  var commentDirectivesEnabledConfig = true;
9220  /**
9221   * @ngdoc method
9222   * @name $compileProvider#commentDirectivesEnabled
9223   * @description
9224   *
9225   * It indicates to the compiler
9226   * whether or not directives on comments should be compiled.
9227   * Defaults to `true`.
9228   *
9229   * Calling this function with false disables the compilation of directives
9230   * on comments for the whole application.
9231   * This results in a compilation performance gain,
9232   * as the compiler doesn't have to check comments when looking for directives.
9233   * This should however only be used if you are sure that no comment directives are used in
9234   * the application (including any 3rd party directives).
9235   *
9236   * @param {boolean} enabled `false` if the compiler may ignore directives on comments
9237   * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
9238   */
9239  this.commentDirectivesEnabled = function(value) {
9240    if (arguments.length) {
9241      commentDirectivesEnabledConfig = value;
9242      return this;
9243    }
9244    return commentDirectivesEnabledConfig;
9245  };
9246
9247
9248  var cssClassDirectivesEnabledConfig = true;
9249  /**
9250   * @ngdoc method
9251   * @name $compileProvider#cssClassDirectivesEnabled
9252   * @description
9253   *
9254   * It indicates to the compiler
9255   * whether or not directives on element classes should be compiled.
9256   * Defaults to `true`.
9257   *
9258   * Calling this function with false disables the compilation of directives
9259   * on element classes for the whole application.
9260   * This results in a compilation performance gain,
9261   * as the compiler doesn't have to check element classes when looking for directives.
9262   * This should however only be used if you are sure that no class directives are used in
9263   * the application (including any 3rd party directives).
9264   *
9265   * @param {boolean} enabled `false` if the compiler may ignore directives on element classes
9266   * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
9267   */
9268  this.cssClassDirectivesEnabled = function(value) {
9269    if (arguments.length) {
9270      cssClassDirectivesEnabledConfig = value;
9271      return this;
9272    }
9273    return cssClassDirectivesEnabledConfig;
9274  };
9275
9276
9277  /**
9278   * The security context of DOM Properties.
9279   * @private
9280   */
9281  var PROP_CONTEXTS = createMap();
9282
9283  /**
9284   * @ngdoc method
9285   * @name $compileProvider#addPropertySecurityContext
9286   * @description
9287   *
9288   * Defines the security context for DOM properties bound by ng-prop-*.
9289   *
9290   * @param {string} elementName The element name or '*' to match any element.
9291   * @param {string} propertyName The DOM property name.
9292   * @param {string} ctx The {@link $sce} security context in which this value is safe for use, e.g. `$sce.URL`
9293   * @returns {object} `this` for chaining
9294   */
9295  this.addPropertySecurityContext = function(elementName, propertyName, ctx) {
9296    var key = (elementName.toLowerCase() + '|' + propertyName.toLowerCase());
9297
9298    if (key in PROP_CONTEXTS && PROP_CONTEXTS[key] !== ctx) {
9299      throw $compileMinErr('ctxoverride', 'Property context \'{0}.{1}\' already set to \'{2}\', cannot override to \'{3}\'.', elementName, propertyName, PROP_CONTEXTS[key], ctx);
9300    }
9301
9302    PROP_CONTEXTS[key] = ctx;
9303    return this;
9304  };
9305
9306  /* Default property contexts.
9307   *
9308   * Copy of https://github.com/angular/angular/blob/6.0.6/packages/compiler/src/schema/dom_security_schema.ts#L31-L58
9309   * Changing:
9310   * - SecurityContext.* => SCE_CONTEXTS/$sce.*
9311   * - STYLE => CSS
9312   * - various URL => MEDIA_URL
9313   * - *|formAction, form|action URL => RESOURCE_URL (like the attribute)
9314   */
9315  (function registerNativePropertyContexts() {
9316    function registerContext(ctx, values) {
9317      forEach(values, function(v) { PROP_CONTEXTS[v.toLowerCase()] = ctx; });
9318    }
9319
9320    registerContext(SCE_CONTEXTS.HTML, [
9321      'iframe|srcdoc',
9322      '*|innerHTML',
9323      '*|outerHTML'
9324    ]);
9325    registerContext(SCE_CONTEXTS.CSS, ['*|style']);
9326    registerContext(SCE_CONTEXTS.URL, [
9327      'area|href',       'area|ping',
9328      'a|href',          'a|ping',
9329      'blockquote|cite',
9330      'body|background',
9331      'del|cite',
9332      'input|src',
9333      'ins|cite',
9334      'q|cite'
9335    ]);
9336    registerContext(SCE_CONTEXTS.MEDIA_URL, [
9337      'audio|src',
9338      'img|src',    'img|srcset',
9339      'source|src', 'source|srcset',
9340      'track|src',
9341      'video|src',  'video|poster'
9342    ]);
9343    registerContext(SCE_CONTEXTS.RESOURCE_URL, [
9344      '*|formAction',
9345      'applet|code',      'applet|codebase',
9346      'base|href',
9347      'embed|src',
9348      'frame|src',
9349      'form|action',
9350      'head|profile',
9351      'html|manifest',
9352      'iframe|src',
9353      'link|href',
9354      'media|src',
9355      'object|codebase',  'object|data',
9356      'script|src'
9357    ]);
9358  })();
9359
9360
9361  this.$get = [
9362            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
9363            '$controller', '$rootScope', '$sce', '$animate',
9364    function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
9365             $controller,   $rootScope,   $sce,   $animate) {
9366
9367    var SIMPLE_ATTR_NAME = /^\w/;
9368    var specialAttrHolder = window.document.createElement('div');
9369
9370
9371    var commentDirectivesEnabled = commentDirectivesEnabledConfig;
9372    var cssClassDirectivesEnabled = cssClassDirectivesEnabledConfig;
9373
9374
9375    var onChangesTtl = TTL;
9376    // The onChanges hooks should all be run together in a single digest
9377    // When changes occur, the call to trigger their hooks will be added to this queue
9378    var onChangesQueue;
9379
9380    // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
9381    function flushOnChangesQueue() {
9382      try {
9383        if (!(--onChangesTtl)) {
9384          // We have hit the TTL limit so reset everything
9385          onChangesQueue = undefined;
9386          throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
9387        }
9388        // We must run this hook in an apply since the $$postDigest runs outside apply
9389        $rootScope.$apply(function() {
9390          for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
9391            try {
9392              onChangesQueue[i]();
9393            } catch (e) {
9394              $exceptionHandler(e);
9395            }
9396          }
9397          // Reset the queue to trigger a new schedule next time there is a change
9398          onChangesQueue = undefined;
9399        });
9400      } finally {
9401        onChangesTtl++;
9402      }
9403    }
9404
9405
9406    function sanitizeSrcset(value, invokeType) {
9407      if (!value) {
9408        return value;
9409      }
9410      if (!isString(value)) {
9411        throw $compileMinErr('srcset', 'Can\'t pass trusted values to `{0}`: "{1}"', invokeType, value.toString());
9412      }
9413
9414      // Such values are a bit too complex to handle automatically inside $sce.
9415      // Instead, we sanitize each of the URIs individually, which works, even dynamically.
9416
9417      // It's not possible to work around this using `$sce.trustAsMediaUrl`.
9418      // If you want to programmatically set explicitly trusted unsafe URLs, you should use
9419      // `$sce.trustAsHtml` on the whole `img` tag and inject it into the DOM using the
9420      // `ng-bind-html` directive.
9421
9422      var result = '';
9423
9424      // first check if there are spaces because it's not the same pattern
9425      var trimmedSrcset = trim(value);
9426      //                (   999x   ,|   999w   ,|   ,|,   )
9427      var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
9428      var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
9429
9430      // split srcset into tuple of uri and descriptor except for the last item
9431      var rawUris = trimmedSrcset.split(pattern);
9432
9433      // for each tuples
9434      var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
9435      for (var i = 0; i < nbrUrisWith2parts; i++) {
9436        var innerIdx = i * 2;
9437        // sanitize the uri
9438        result += $sce.getTrustedMediaUrl(trim(rawUris[innerIdx]));
9439        // add the descriptor
9440        result += ' ' + trim(rawUris[innerIdx + 1]);
9441      }
9442
9443      // split the last item into uri and descriptor
9444      var lastTuple = trim(rawUris[i * 2]).split(/\s/);
9445
9446      // sanitize the last uri
9447      result += $sce.getTrustedMediaUrl(trim(lastTuple[0]));
9448
9449      // and add the last descriptor if any
9450      if (lastTuple.length === 2) {
9451        result += (' ' + trim(lastTuple[1]));
9452      }
9453      return result;
9454    }
9455
9456
9457    function Attributes(element, attributesToCopy) {
9458      if (attributesToCopy) {
9459        var keys = Object.keys(attributesToCopy);
9460        var i, l, key;
9461
9462        for (i = 0, l = keys.length; i < l; i++) {
9463          key = keys[i];
9464          this[key] = attributesToCopy[key];
9465        }
9466      } else {
9467        this.$attr = {};
9468      }
9469
9470      this.$$element = element;
9471    }
9472
9473    Attributes.prototype = {
9474      /**
9475       * @ngdoc method
9476       * @name $compile.directive.Attributes#$normalize
9477       * @kind function
9478       *
9479       * @description
9480       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
9481       * `data-`) to its normalized, camelCase form.
9482       *
9483       * Also there is special case for Moz prefix starting with upper case letter.
9484       *
9485       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
9486       *
9487       * @param {string} name Name to normalize
9488       */
9489      $normalize: directiveNormalize,
9490
9491
9492      /**
9493       * @ngdoc method
9494       * @name $compile.directive.Attributes#$addClass
9495       * @kind function
9496       *
9497       * @description
9498       * Adds the CSS class value specified by the classVal parameter to the element. If animations
9499       * are enabled then an animation will be triggered for the class addition.
9500       *
9501       * @param {string} classVal The className value that will be added to the element
9502       */
9503      $addClass: function(classVal) {
9504        if (classVal && classVal.length > 0) {
9505          $animate.addClass(this.$$element, classVal);
9506        }
9507      },
9508
9509      /**
9510       * @ngdoc method
9511       * @name $compile.directive.Attributes#$removeClass
9512       * @kind function
9513       *
9514       * @description
9515       * Removes the CSS class value specified by the classVal parameter from the element. If
9516       * animations are enabled then an animation will be triggered for the class removal.
9517       *
9518       * @param {string} classVal The className value that will be removed from the element
9519       */
9520      $removeClass: function(classVal) {
9521        if (classVal && classVal.length > 0) {
9522          $animate.removeClass(this.$$element, classVal);
9523        }
9524      },
9525
9526      /**
9527       * @ngdoc method
9528       * @name $compile.directive.Attributes#$updateClass
9529       * @kind function
9530       *
9531       * @description
9532       * Adds and removes the appropriate CSS class values to the element based on the difference
9533       * between the new and old CSS class values (specified as newClasses and oldClasses).
9534       *
9535       * @param {string} newClasses The current CSS className value
9536       * @param {string} oldClasses The former CSS className value
9537       */
9538      $updateClass: function(newClasses, oldClasses) {
9539        var toAdd = tokenDifference(newClasses, oldClasses);
9540        if (toAdd && toAdd.length) {
9541          $animate.addClass(this.$$element, toAdd);
9542        }
9543
9544        var toRemove = tokenDifference(oldClasses, newClasses);
9545        if (toRemove && toRemove.length) {
9546          $animate.removeClass(this.$$element, toRemove);
9547        }
9548      },
9549
9550      /**
9551       * Set a normalized attribute on the element in a way such that all directives
9552       * can share the attribute. This function properly handles boolean attributes.
9553       * @param {string} key Normalized key. (ie ngAttribute)
9554       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
9555       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
9556       *     Defaults to true.
9557       * @param {string=} attrName Optional none normalized name. Defaults to key.
9558       */
9559      $set: function(key, value, writeAttr, attrName) {
9560        // TODO: decide whether or not to throw an error if "class"
9561        // is set through this function since it may cause $updateClass to
9562        // become unstable.
9563
9564        var node = this.$$element[0],
9565            booleanKey = getBooleanAttrName(node, key),
9566            aliasedKey = getAliasedAttrName(key),
9567            observer = key,
9568            nodeName;
9569
9570        if (booleanKey) {
9571          this.$$element.prop(key, value);
9572          attrName = booleanKey;
9573        } else if (aliasedKey) {
9574          this[aliasedKey] = value;
9575          observer = aliasedKey;
9576        }
9577
9578        this[key] = value;
9579
9580        // translate normalized key to actual key
9581        if (attrName) {
9582          this.$attr[key] = attrName;
9583        } else {
9584          attrName = this.$attr[key];
9585          if (!attrName) {
9586            this.$attr[key] = attrName = snake_case(key, '-');
9587          }
9588        }
9589
9590        nodeName = nodeName_(this.$$element);
9591
9592        // Sanitize img[srcset] values.
9593        if (nodeName === 'img' && key === 'srcset') {
9594          this[key] = value = sanitizeSrcset(value, '$set(\'srcset\', value)');
9595        }
9596
9597        if (writeAttr !== false) {
9598          if (value === null || isUndefined(value)) {
9599            this.$$element.removeAttr(attrName);
9600          } else {
9601            if (SIMPLE_ATTR_NAME.test(attrName)) {
9602              // jQuery skips special boolean attrs treatment in XML nodes for
9603              // historical reasons and hence AngularJS cannot freely call
9604              // `.attr(attrName, false) with such attributes. To avoid issues
9605              // in XHTML, call `removeAttr` in such cases instead.
9606              // See https://github.com/jquery/jquery/issues/4249
9607              if (booleanKey && value === false) {
9608                this.$$element.removeAttr(attrName);
9609              } else {
9610                this.$$element.attr(attrName, value);
9611              }
9612            } else {
9613              setSpecialAttr(this.$$element[0], attrName, value);
9614            }
9615          }
9616        }
9617
9618        // fire observers
9619        var $$observers = this.$$observers;
9620        if ($$observers) {
9621          forEach($$observers[observer], function(fn) {
9622            try {
9623              fn(value);
9624            } catch (e) {
9625              $exceptionHandler(e);
9626            }
9627          });
9628        }
9629      },
9630
9631
9632      /**
9633       * @ngdoc method
9634       * @name $compile.directive.Attributes#$observe
9635       * @kind function
9636       *
9637       * @description
9638       * Observes an interpolated attribute.
9639       *
9640       * The observer function will be invoked once during the next `$digest` following
9641       * compilation. The observer is then invoked whenever the interpolated value
9642       * changes.
9643       *
9644       * @param {string} key Normalized key. (ie ngAttribute) .
9645       * @param {function(interpolatedValue)} fn Function that will be called whenever
9646                the interpolated value of the attribute changes.
9647       *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
9648       *        guide} for more info.
9649       * @returns {function()} Returns a deregistration function for this observer.
9650       */
9651      $observe: function(key, fn) {
9652        var attrs = this,
9653            $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
9654            listeners = ($$observers[key] || ($$observers[key] = []));
9655
9656        listeners.push(fn);
9657        $rootScope.$evalAsync(function() {
9658          if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
9659            // no one registered attribute interpolation function, so lets call it manually
9660            fn(attrs[key]);
9661          }
9662        });
9663
9664        return function() {
9665          arrayRemove(listeners, fn);
9666        };
9667      }
9668    };
9669
9670    function setSpecialAttr(element, attrName, value) {
9671      // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
9672      // so we have to jump through some hoops to get such an attribute
9673      // https://github.com/angular/angular.js/pull/13318
9674      specialAttrHolder.innerHTML = '<span ' + attrName + '>';
9675      var attributes = specialAttrHolder.firstChild.attributes;
9676      var attribute = attributes[0];
9677      // We have to remove the attribute from its container element before we can add it to the destination element
9678      attributes.removeNamedItem(attribute.name);
9679      attribute.value = value;
9680      element.attributes.setNamedItem(attribute);
9681    }
9682
9683    function safeAddClass($element, className) {
9684      try {
9685        $element.addClass(className);
9686      } catch (e) {
9687        // ignore, since it means that we are trying to set class on
9688        // SVG element, where class name is read-only.
9689      }
9690    }
9691
9692
9693    var startSymbol = $interpolate.startSymbol(),
9694        endSymbol = $interpolate.endSymbol(),
9695        denormalizeTemplate = (startSymbol === '{{' && endSymbol  === '}}')
9696            ? identity
9697            : function denormalizeTemplate(template) {
9698              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
9699        },
9700        NG_PREFIX_BINDING = /^ng(Attr|Prop|On)([A-Z].*)$/;
9701    var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
9702
9703    compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
9704      var bindings = $element.data('$binding') || [];
9705
9706      if (isArray(binding)) {
9707        bindings = bindings.concat(binding);
9708      } else {
9709        bindings.push(binding);
9710      }
9711
9712      $element.data('$binding', bindings);
9713    } : noop;
9714
9715    compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
9716      safeAddClass($element, 'ng-binding');
9717    } : noop;
9718
9719    compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
9720      var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
9721      $element.data(dataName, scope);
9722    } : noop;
9723
9724    compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
9725      safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
9726    } : noop;
9727
9728    compile.$$createComment = function(directiveName, comment) {
9729      var content = '';
9730      if (debugInfoEnabled) {
9731        content = ' ' + (directiveName || '') + ': ';
9732        if (comment) content += comment + ' ';
9733      }
9734      return window.document.createComment(content);
9735    };
9736
9737    return compile;
9738
9739    //================================
9740
9741    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
9742                        previousCompileContext) {
9743      if (!($compileNodes instanceof jqLite)) {
9744        // jquery always rewraps, whereas we need to preserve the original selector so that we can
9745        // modify it.
9746        $compileNodes = jqLite($compileNodes);
9747      }
9748      var compositeLinkFn =
9749              compileNodes($compileNodes, transcludeFn, $compileNodes,
9750                           maxPriority, ignoreDirective, previousCompileContext);
9751      compile.$$addScopeClass($compileNodes);
9752      var namespace = null;
9753      return function publicLinkFn(scope, cloneConnectFn, options) {
9754        if (!$compileNodes) {
9755          throw $compileMinErr('multilink', 'This element has already been linked.');
9756        }
9757        assertArg(scope, 'scope');
9758
9759        if (previousCompileContext && previousCompileContext.needsNewScope) {
9760          // A parent directive did a replace and a directive on this element asked
9761          // for transclusion, which caused us to lose a layer of element on which
9762          // we could hold the new transclusion scope, so we will create it manually
9763          // here.
9764          scope = scope.$parent.$new();
9765        }
9766
9767        options = options || {};
9768        var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
9769          transcludeControllers = options.transcludeControllers,
9770          futureParentElement = options.futureParentElement;
9771
9772        // When `parentBoundTranscludeFn` is passed, it is a
9773        // `controllersBoundTransclude` function (it was previously passed
9774        // as `transclude` to directive.link) so we must unwrap it to get
9775        // its `boundTranscludeFn`
9776        if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
9777          parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
9778        }
9779
9780        if (!namespace) {
9781          namespace = detectNamespaceForChildElements(futureParentElement);
9782        }
9783        var $linkNode;
9784        if (namespace !== 'html') {
9785          // When using a directive with replace:true and templateUrl the $compileNodes
9786          // (or a child element inside of them)
9787          // might change, so we need to recreate the namespace adapted compileNodes
9788          // for call to the link function.
9789          // Note: This will already clone the nodes...
9790          $linkNode = jqLite(
9791            wrapTemplate(namespace, jqLite('<div></div>').append($compileNodes).html())
9792          );
9793        } else if (cloneConnectFn) {
9794          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
9795          // and sometimes changes the structure of the DOM.
9796          $linkNode = JQLitePrototype.clone.call($compileNodes);
9797        } else {
9798          $linkNode = $compileNodes;
9799        }
9800
9801        if (transcludeControllers) {
9802          for (var controllerName in transcludeControllers) {
9803            $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
9804          }
9805        }
9806
9807        compile.$$addScopeInfo($linkNode, scope);
9808
9809        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
9810        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
9811
9812        if (!cloneConnectFn) {
9813          $compileNodes = compositeLinkFn = null;
9814        }
9815        return $linkNode;
9816      };
9817    }
9818
9819    function detectNamespaceForChildElements(parentElement) {
9820      // TODO: Make this detect MathML as well...
9821      var node = parentElement && parentElement[0];
9822      if (!node) {
9823        return 'html';
9824      } else {
9825        return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
9826      }
9827    }
9828
9829    /**
9830     * Compile function matches each node in nodeList against the directives. Once all directives
9831     * for a particular node are collected their compile functions are executed. The compile
9832     * functions return values - the linking functions - are combined into a composite linking
9833     * function, which is the a linking function for the node.
9834     *
9835     * @param {NodeList} nodeList an array of nodes or NodeList to compile
9836     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
9837     *        scope argument is auto-generated to the new child of the transcluded parent scope.
9838     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
9839     *        the rootElement must be set the jqLite collection of the compile root. This is
9840     *        needed so that the jqLite collection items can be replaced with widgets.
9841     * @param {number=} maxPriority Max directive priority.
9842     * @returns {Function} A composite linking function of all of the matched directives or null.
9843     */
9844    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
9845                            previousCompileContext) {
9846      var linkFns = [],
9847          // `nodeList` can be either an element's `.childNodes` (live NodeList)
9848          // or a jqLite/jQuery collection or an array
9849          notLiveList = isArray(nodeList) || (nodeList instanceof jqLite),
9850          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
9851
9852
9853      for (var i = 0; i < nodeList.length; i++) {
9854        attrs = new Attributes();
9855
9856        // Support: IE 11 only
9857        // Workaround for #11781 and #14924
9858        if (msie === 11) {
9859          mergeConsecutiveTextNodes(nodeList, i, notLiveList);
9860        }
9861
9862        // We must always refer to `nodeList[i]` hereafter,
9863        // since the nodes can be replaced underneath us.
9864        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
9865                                        ignoreDirective);
9866
9867        nodeLinkFn = (directives.length)
9868            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
9869                                      null, [], [], previousCompileContext)
9870            : null;
9871
9872        if (nodeLinkFn && nodeLinkFn.scope) {
9873          compile.$$addScopeClass(attrs.$$element);
9874        }
9875
9876        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
9877                      !(childNodes = nodeList[i].childNodes) ||
9878                      !childNodes.length)
9879            ? null
9880            : compileNodes(childNodes,
9881                 nodeLinkFn ? (
9882                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
9883                     && nodeLinkFn.transclude) : transcludeFn);
9884
9885        if (nodeLinkFn || childLinkFn) {
9886          linkFns.push(i, nodeLinkFn, childLinkFn);
9887          linkFnFound = true;
9888          nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
9889        }
9890
9891        //use the previous context only for the first element in the virtual group
9892        previousCompileContext = null;
9893      }
9894
9895      // return a linking function if we have found anything, null otherwise
9896      return linkFnFound ? compositeLinkFn : null;
9897
9898      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
9899        var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
9900        var stableNodeList;
9901
9902
9903        if (nodeLinkFnFound) {
9904          // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
9905          // offsets don't get screwed up
9906          var nodeListLength = nodeList.length;
9907          stableNodeList = new Array(nodeListLength);
9908
9909          // create a sparse array by only copying the elements which have a linkFn
9910          for (i = 0; i < linkFns.length; i += 3) {
9911            idx = linkFns[i];
9912            stableNodeList[idx] = nodeList[idx];
9913          }
9914        } else {
9915          stableNodeList = nodeList;
9916        }
9917
9918        for (i = 0, ii = linkFns.length; i < ii;) {
9919          node = stableNodeList[linkFns[i++]];
9920          nodeLinkFn = linkFns[i++];
9921          childLinkFn = linkFns[i++];
9922
9923          if (nodeLinkFn) {
9924            if (nodeLinkFn.scope) {
9925              childScope = scope.$new();
9926              compile.$$addScopeInfo(jqLite(node), childScope);
9927            } else {
9928              childScope = scope;
9929            }
9930
9931            if (nodeLinkFn.transcludeOnThisElement) {
9932              childBoundTranscludeFn = createBoundTranscludeFn(
9933                  scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
9934
9935            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
9936              childBoundTranscludeFn = parentBoundTranscludeFn;
9937
9938            } else if (!parentBoundTranscludeFn && transcludeFn) {
9939              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
9940
9941            } else {
9942              childBoundTranscludeFn = null;
9943            }
9944
9945            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
9946
9947          } else if (childLinkFn) {
9948            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
9949          }
9950        }
9951      }
9952    }
9953
9954    function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) {
9955      var node = nodeList[idx];
9956      var parent = node.parentNode;
9957      var sibling;
9958
9959      if (node.nodeType !== NODE_TYPE_TEXT) {
9960        return;
9961      }
9962
9963      while (true) {
9964        sibling = parent ? node.nextSibling : nodeList[idx + 1];
9965        if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) {
9966          break;
9967        }
9968
9969        node.nodeValue = node.nodeValue + sibling.nodeValue;
9970
9971        if (sibling.parentNode) {
9972          sibling.parentNode.removeChild(sibling);
9973        }
9974        if (notLiveList && sibling === nodeList[idx + 1]) {
9975          nodeList.splice(idx + 1, 1);
9976        }
9977      }
9978    }
9979
9980    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
9981      function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
9982
9983        if (!transcludedScope) {
9984          transcludedScope = scope.$new(false, containingScope);
9985          transcludedScope.$$transcluded = true;
9986        }
9987
9988        return transcludeFn(transcludedScope, cloneFn, {
9989          parentBoundTranscludeFn: previousBoundTranscludeFn,
9990          transcludeControllers: controllers,
9991          futureParentElement: futureParentElement
9992        });
9993      }
9994
9995      // We need  to attach the transclusion slots onto the `boundTranscludeFn`
9996      // so that they are available inside the `controllersBoundTransclude` function
9997      var boundSlots = boundTranscludeFn.$$slots = createMap();
9998      for (var slotName in transcludeFn.$$slots) {
9999        if (transcludeFn.$$slots[slotName]) {
10000          boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
10001        } else {
10002          boundSlots[slotName] = null;
10003        }
10004      }
10005
10006      return boundTranscludeFn;
10007    }
10008
10009    /**
10010     * Looks for directives on the given node and adds them to the directive collection which is
10011     * sorted.
10012     *
10013     * @param node Node to search.
10014     * @param directives An array to which the directives are added to. This array is sorted before
10015     *        the function returns.
10016     * @param attrs The shared attrs object which is used to populate the normalized attributes.
10017     * @param {number=} maxPriority Max directive priority.
10018     */
10019    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
10020      var nodeType = node.nodeType,
10021          attrsMap = attrs.$attr,
10022          match,
10023          nodeName,
10024          className;
10025
10026      switch (nodeType) {
10027        case NODE_TYPE_ELEMENT: /* Element */
10028
10029          nodeName = nodeName_(node);
10030
10031          // use the node name: <directive>
10032          addDirective(directives,
10033              directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
10034
10035          // iterate over the attributes
10036          for (var attr, name, nName, value, ngPrefixMatch, nAttrs = node.attributes,
10037                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
10038            var attrStartName = false;
10039            var attrEndName = false;
10040
10041            var isNgAttr = false, isNgProp = false, isNgEvent = false;
10042            var multiElementMatch;
10043
10044            attr = nAttrs[j];
10045            name = attr.name;
10046            value = attr.value;
10047
10048            nName = directiveNormalize(name.toLowerCase());
10049
10050            // Support ng-attr-*, ng-prop-* and ng-on-*
10051            if ((ngPrefixMatch = nName.match(NG_PREFIX_BINDING))) {
10052              isNgAttr = ngPrefixMatch[1] === 'Attr';
10053              isNgProp = ngPrefixMatch[1] === 'Prop';
10054              isNgEvent = ngPrefixMatch[1] === 'On';
10055
10056              // Normalize the non-prefixed name
10057              name = name.replace(PREFIX_REGEXP, '')
10058                .toLowerCase()
10059                .substr(4 + ngPrefixMatch[1].length).replace(/_(.)/g, function(match, letter) {
10060                  return letter.toUpperCase();
10061                });
10062
10063            // Support *-start / *-end multi element directives
10064            } else if ((multiElementMatch = nName.match(MULTI_ELEMENT_DIR_RE)) && directiveIsMultiElement(multiElementMatch[1])) {
10065              attrStartName = name;
10066              attrEndName = name.substr(0, name.length - 5) + 'end';
10067              name = name.substr(0, name.length - 6);
10068            }
10069
10070            if (isNgProp || isNgEvent) {
10071              attrs[nName] = value;
10072              attrsMap[nName] = attr.name;
10073
10074              if (isNgProp) {
10075                addPropertyDirective(node, directives, nName, name);
10076              } else {
10077                addEventDirective(directives, nName, name);
10078              }
10079            } else {
10080              // Update nName for cases where a prefix was removed
10081              // NOTE: the .toLowerCase() is unnecessary and causes https://github.com/angular/angular.js/issues/16624 for ng-attr-*
10082              nName = directiveNormalize(name.toLowerCase());
10083              attrsMap[nName] = name;
10084
10085              if (isNgAttr || !attrs.hasOwnProperty(nName)) {
10086                attrs[nName] = value;
10087                if (getBooleanAttrName(node, nName)) {
10088                  attrs[nName] = true; // presence means true
10089                }
10090              }
10091
10092              addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
10093              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
10094                            attrEndName);
10095            }
10096          }
10097
10098          if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
10099            // Hidden input elements can have strange behaviour when navigating back to the page
10100            // This tells the browser not to try to cache and reinstate previous values
10101            node.setAttribute('autocomplete', 'off');
10102          }
10103
10104          // use class as directive
10105          if (!cssClassDirectivesEnabled) break;
10106          className = node.className;
10107          if (isObject(className)) {
10108              // Maybe SVGAnimatedString
10109              className = className.animVal;
10110          }
10111          if (isString(className) && className !== '') {
10112            while ((match = CLASS_DIRECTIVE_REGEXP.exec(className))) {
10113              nName = directiveNormalize(match[2]);
10114              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
10115                attrs[nName] = trim(match[3]);
10116              }
10117              className = className.substr(match.index + match[0].length);
10118            }
10119          }
10120          break;
10121        case NODE_TYPE_TEXT: /* Text Node */
10122          addTextInterpolateDirective(directives, node.nodeValue);
10123          break;
10124        case NODE_TYPE_COMMENT: /* Comment */
10125          if (!commentDirectivesEnabled) break;
10126          collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);
10127          break;
10128      }
10129
10130      directives.sort(byPriority);
10131      return directives;
10132    }
10133
10134    function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
10135      // function created because of performance, try/catch disables
10136      // the optimization of the whole function #14848
10137      try {
10138        var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
10139        if (match) {
10140          var nName = directiveNormalize(match[1]);
10141          if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
10142            attrs[nName] = trim(match[2]);
10143          }
10144        }
10145      } catch (e) {
10146        // turns out that under some circumstances IE9 throws errors when one attempts to read
10147        // comment's node value.
10148        // Just ignore it and continue. (Can't seem to reproduce in test case.)
10149      }
10150    }
10151
10152    /**
10153     * Given a node with a directive-start it collects all of the siblings until it finds
10154     * directive-end.
10155     * @param node
10156     * @param attrStart
10157     * @param attrEnd
10158     * @returns {*}
10159     */
10160    function groupScan(node, attrStart, attrEnd) {
10161      var nodes = [];
10162      var depth = 0;
10163      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
10164        do {
10165          if (!node) {
10166            throw $compileMinErr('uterdir',
10167                      'Unterminated attribute, found \'{0}\' but no matching \'{1}\' found.',
10168                      attrStart, attrEnd);
10169          }
10170          if (node.nodeType === NODE_TYPE_ELEMENT) {
10171            if (node.hasAttribute(attrStart)) depth++;
10172            if (node.hasAttribute(attrEnd)) depth--;
10173          }
10174          nodes.push(node);
10175          node = node.nextSibling;
10176        } while (depth > 0);
10177      } else {
10178        nodes.push(node);
10179      }
10180
10181      return jqLite(nodes);
10182    }
10183
10184    /**
10185     * Wrapper for linking function which converts normal linking function into a grouped
10186     * linking function.
10187     * @param linkFn
10188     * @param attrStart
10189     * @param attrEnd
10190     * @returns {Function}
10191     */
10192    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
10193      return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
10194        element = groupScan(element[0], attrStart, attrEnd);
10195        return linkFn(scope, element, attrs, controllers, transcludeFn);
10196      };
10197    }
10198
10199    /**
10200     * A function generator that is used to support both eager and lazy compilation
10201     * linking function.
10202     * @param eager
10203     * @param $compileNodes
10204     * @param transcludeFn
10205     * @param maxPriority
10206     * @param ignoreDirective
10207     * @param previousCompileContext
10208     * @returns {Function}
10209     */
10210    function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
10211      var compiled;
10212
10213      if (eager) {
10214        return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
10215      }
10216      return /** @this */ function lazyCompilation() {
10217        if (!compiled) {
10218          compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
10219
10220          // Null out all of these references in order to make them eligible for garbage collection
10221          // since this is a potentially long lived closure
10222          $compileNodes = transcludeFn = previousCompileContext = null;
10223        }
10224        return compiled.apply(this, arguments);
10225      };
10226    }
10227
10228    /**
10229     * Once the directives have been collected, their compile functions are executed. This method
10230     * is responsible for inlining directive templates as well as terminating the application
10231     * of the directives if the terminal directive has been reached.
10232     *
10233     * @param {Array} directives Array of collected directives to execute their compile function.
10234     *        this needs to be pre-sorted by priority order.
10235     * @param {Node} compileNode The raw DOM node to apply the compile functions to
10236     * @param {Object} templateAttrs The shared attribute function
10237     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
10238     *                                                  scope argument is auto-generated to the new
10239     *                                                  child of the transcluded parent scope.
10240     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
10241     *                              argument has the root jqLite array so that we can replace nodes
10242     *                              on it.
10243     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
10244     *                                           compiling the transclusion.
10245     * @param {Array.<Function>} preLinkFns
10246     * @param {Array.<Function>} postLinkFns
10247     * @param {Object} previousCompileContext Context used for previous compilation of the current
10248     *                                        node
10249     * @returns {Function} linkFn
10250     */
10251    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
10252                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
10253                                   previousCompileContext) {
10254      previousCompileContext = previousCompileContext || {};
10255
10256      var terminalPriority = -Number.MAX_VALUE,
10257          newScopeDirective = previousCompileContext.newScopeDirective,
10258          controllerDirectives = previousCompileContext.controllerDirectives,
10259          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
10260          templateDirective = previousCompileContext.templateDirective,
10261          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
10262          hasTranscludeDirective = false,
10263          hasTemplate = false,
10264          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
10265          $compileNode = templateAttrs.$$element = jqLite(compileNode),
10266          directive,
10267          directiveName,
10268          $template,
10269          replaceDirective = originalReplaceDirective,
10270          childTranscludeFn = transcludeFn,
10271          linkFn,
10272          didScanForMultipleTransclusion = false,
10273          mightHaveMultipleTransclusionError = false,
10274          directiveValue;
10275
10276      // executes all directives on the current element
10277      for (var i = 0, ii = directives.length; i < ii; i++) {
10278        directive = directives[i];
10279        var attrStart = directive.$$start;
10280        var attrEnd = directive.$$end;
10281
10282        // collect multiblock sections
10283        if (attrStart) {
10284          $compileNode = groupScan(compileNode, attrStart, attrEnd);
10285        }
10286        $template = undefined;
10287
10288        if (terminalPriority > directive.priority) {
10289          break; // prevent further processing of directives
10290        }
10291
10292        directiveValue = directive.scope;
10293
10294        if (directiveValue) {
10295
10296          // skip the check for directives with async templates, we'll check the derived sync
10297          // directive when the template arrives
10298          if (!directive.templateUrl) {
10299            if (isObject(directiveValue)) {
10300              // This directive is trying to add an isolated scope.
10301              // Check that there is no scope of any kind already
10302              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
10303                                directive, $compileNode);
10304              newIsolateScopeDirective = directive;
10305            } else {
10306              // This directive is trying to add a child scope.
10307              // Check that there is no isolated scope already
10308              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
10309                                $compileNode);
10310            }
10311          }
10312
10313          newScopeDirective = newScopeDirective || directive;
10314        }
10315
10316        directiveName = directive.name;
10317
10318        // If we encounter a condition that can result in transclusion on the directive,
10319        // then scan ahead in the remaining directives for others that may cause a multiple
10320        // transclusion error to be thrown during the compilation process.  If a matching directive
10321        // is found, then we know that when we encounter a transcluded directive, we need to eagerly
10322        // compile the `transclude` function rather than doing it lazily in order to throw
10323        // exceptions at the correct time
10324        if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
10325            || (directive.transclude && !directive.$$tlb))) {
10326                var candidateDirective;
10327
10328                for (var scanningIndex = i + 1; (candidateDirective = directives[scanningIndex++]);) {
10329                    if ((candidateDirective.transclude && !candidateDirective.$$tlb)
10330                        || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
10331                        mightHaveMultipleTransclusionError = true;
10332                        break;
10333                    }
10334                }
10335
10336                didScanForMultipleTransclusion = true;
10337        }
10338
10339        if (!directive.templateUrl && directive.controller) {
10340          controllerDirectives = controllerDirectives || createMap();
10341          assertNoDuplicate('\'' + directiveName + '\' controller',
10342              controllerDirectives[directiveName], directive, $compileNode);
10343          controllerDirectives[directiveName] = directive;
10344        }
10345
10346        directiveValue = directive.transclude;
10347
10348        if (directiveValue) {
10349          hasTranscludeDirective = true;
10350
10351          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
10352          // This option should only be used by directives that know how to safely handle element transclusion,
10353          // where the transcluded nodes are added or replaced after linking.
10354          if (!directive.$$tlb) {
10355            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
10356            nonTlbTranscludeDirective = directive;
10357          }
10358
10359          if (directiveValue === 'element') {
10360            hasElementTranscludeDirective = true;
10361            terminalPriority = directive.priority;
10362            $template = $compileNode;
10363            $compileNode = templateAttrs.$$element =
10364                jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
10365            compileNode = $compileNode[0];
10366            replaceWith(jqCollection, sliceArgs($template), compileNode);
10367
10368            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
10369                                        replaceDirective && replaceDirective.name, {
10370                                          // Don't pass in:
10371                                          // - controllerDirectives - otherwise we'll create duplicates controllers
10372                                          // - newIsolateScopeDirective or templateDirective - combining templates with
10373                                          //   element transclusion doesn't make sense.
10374                                          //
10375                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
10376                                          // on the same element more than once.
10377                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
10378                                        });
10379          } else {
10380
10381            var slots = createMap();
10382
10383            if (!isObject(directiveValue)) {
10384              $template = jqLite(jqLiteClone(compileNode)).contents();
10385            } else {
10386
10387              // We have transclusion slots,
10388              // collect them up, compile them and store their transclusion functions
10389              $template = window.document.createDocumentFragment();
10390
10391              var slotMap = createMap();
10392              var filledSlots = createMap();
10393
10394              // Parse the element selectors
10395              forEach(directiveValue, function(elementSelector, slotName) {
10396                // If an element selector starts with a ? then it is optional
10397                var optional = (elementSelector.charAt(0) === '?');
10398                elementSelector = optional ? elementSelector.substring(1) : elementSelector;
10399
10400                slotMap[elementSelector] = slotName;
10401
10402                // We explicitly assign `null` since this implies that a slot was defined but not filled.
10403                // Later when calling boundTransclusion functions with a slot name we only error if the
10404                // slot is `undefined`
10405                slots[slotName] = null;
10406
10407                // filledSlots contains `true` for all slots that are either optional or have been
10408                // filled. This is used to check that we have not missed any required slots
10409                filledSlots[slotName] = optional;
10410              });
10411
10412              // Add the matching elements into their slot
10413              forEach($compileNode.contents(), function(node) {
10414                var slotName = slotMap[directiveNormalize(nodeName_(node))];
10415                if (slotName) {
10416                  filledSlots[slotName] = true;
10417                  slots[slotName] = slots[slotName] || window.document.createDocumentFragment();
10418                  slots[slotName].appendChild(node);
10419                } else {
10420                  $template.appendChild(node);
10421                }
10422              });
10423
10424              // Check for required slots that were not filled
10425              forEach(filledSlots, function(filled, slotName) {
10426                if (!filled) {
10427                  throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
10428                }
10429              });
10430
10431              for (var slotName in slots) {
10432                if (slots[slotName]) {
10433                  // Only define a transclusion function if the slot was filled
10434                  var slotCompileNodes = jqLite(slots[slotName].childNodes);
10435                  slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slotCompileNodes, transcludeFn);
10436                }
10437              }
10438
10439              $template = jqLite($template.childNodes);
10440            }
10441
10442            $compileNode.empty(); // clear contents
10443            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
10444                undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
10445            childTranscludeFn.$$slots = slots;
10446          }
10447        }
10448
10449        if (directive.template) {
10450          hasTemplate = true;
10451          assertNoDuplicate('template', templateDirective, directive, $compileNode);
10452          templateDirective = directive;
10453
10454          directiveValue = (isFunction(directive.template))
10455              ? directive.template($compileNode, templateAttrs)
10456              : directive.template;
10457
10458          directiveValue = denormalizeTemplate(directiveValue);
10459
10460          if (directive.replace) {
10461            replaceDirective = directive;
10462            if (jqLiteIsTextNode(directiveValue)) {
10463              $template = [];
10464            } else {
10465              $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
10466            }
10467            compileNode = $template[0];
10468
10469            if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
10470              throw $compileMinErr('tplrt',
10471                  'Template for directive \'{0}\' must have exactly one root element. {1}',
10472                  directiveName, '');
10473            }
10474
10475            replaceWith(jqCollection, $compileNode, compileNode);
10476
10477            var newTemplateAttrs = {$attr: {}};
10478
10479            // combine directives from the original node and from the template:
10480            // - take the array of directives for this element
10481            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
10482            // - collect directives from the template and sort them by priority
10483            // - combine directives as: processed + template + unprocessed
10484            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
10485            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
10486
10487            if (newIsolateScopeDirective || newScopeDirective) {
10488              // The original directive caused the current element to be replaced but this element
10489              // also needs to have a new scope, so we need to tell the template directives
10490              // that they would need to get their scope from further up, if they require transclusion
10491              markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
10492            }
10493            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
10494            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
10495
10496            ii = directives.length;
10497          } else {
10498            $compileNode.html(directiveValue);
10499          }
10500        }
10501
10502        if (directive.templateUrl) {
10503          hasTemplate = true;
10504          assertNoDuplicate('template', templateDirective, directive, $compileNode);
10505          templateDirective = directive;
10506
10507          if (directive.replace) {
10508            replaceDirective = directive;
10509          }
10510
10511          // eslint-disable-next-line no-func-assign
10512          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
10513              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
10514                controllerDirectives: controllerDirectives,
10515                newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
10516                newIsolateScopeDirective: newIsolateScopeDirective,
10517                templateDirective: templateDirective,
10518                nonTlbTranscludeDirective: nonTlbTranscludeDirective
10519              });
10520          ii = directives.length;
10521        } else if (directive.compile) {
10522          try {
10523            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
10524            var context = directive.$$originalDirective || directive;
10525            if (isFunction(linkFn)) {
10526              addLinkFns(null, bind(context, linkFn), attrStart, attrEnd);
10527            } else if (linkFn) {
10528              addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd);
10529            }
10530          } catch (e) {
10531            $exceptionHandler(e, startingTag($compileNode));
10532          }
10533        }
10534
10535        if (directive.terminal) {
10536          nodeLinkFn.terminal = true;
10537          terminalPriority = Math.max(terminalPriority, directive.priority);
10538        }
10539
10540      }
10541
10542      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
10543      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
10544      nodeLinkFn.templateOnThisElement = hasTemplate;
10545      nodeLinkFn.transclude = childTranscludeFn;
10546
10547      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
10548
10549      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
10550      return nodeLinkFn;
10551
10552      ////////////////////
10553
10554      function addLinkFns(pre, post, attrStart, attrEnd) {
10555        if (pre) {
10556          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
10557          pre.require = directive.require;
10558          pre.directiveName = directiveName;
10559          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
10560            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
10561          }
10562          preLinkFns.push(pre);
10563        }
10564        if (post) {
10565          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
10566          post.require = directive.require;
10567          post.directiveName = directiveName;
10568          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
10569            post = cloneAndAnnotateFn(post, {isolateScope: true});
10570          }
10571          postLinkFns.push(post);
10572        }
10573      }
10574
10575      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
10576        var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
10577            attrs, scopeBindingInfo;
10578
10579        if (compileNode === linkNode) {
10580          attrs = templateAttrs;
10581          $element = templateAttrs.$$element;
10582        } else {
10583          $element = jqLite(linkNode);
10584          attrs = new Attributes($element, templateAttrs);
10585        }
10586
10587        controllerScope = scope;
10588        if (newIsolateScopeDirective) {
10589          isolateScope = scope.$new(true);
10590        } else if (newScopeDirective) {
10591          controllerScope = scope.$parent;
10592        }
10593
10594        if (boundTranscludeFn) {
10595          // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
10596          // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
10597          transcludeFn = controllersBoundTransclude;
10598          transcludeFn.$$boundTransclude = boundTranscludeFn;
10599          // expose the slots on the `$transclude` function
10600          transcludeFn.isSlotFilled = function(slotName) {
10601            return !!boundTranscludeFn.$$slots[slotName];
10602          };
10603        }
10604
10605        if (controllerDirectives) {
10606          elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
10607        }
10608
10609        if (newIsolateScopeDirective) {
10610          // Initialize isolate scope bindings for new isolate scope directive.
10611          compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
10612              templateDirective === newIsolateScopeDirective.$$originalDirective)));
10613          compile.$$addScopeClass($element, true);
10614          isolateScope.$$isolateBindings =
10615              newIsolateScopeDirective.$$isolateBindings;
10616          scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
10617                                        isolateScope.$$isolateBindings,
10618                                        newIsolateScopeDirective);
10619          if (scopeBindingInfo.removeWatches) {
10620            isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
10621          }
10622        }
10623
10624        // Initialize bindToController bindings
10625        for (var name in elementControllers) {
10626          var controllerDirective = controllerDirectives[name];
10627          var controller = elementControllers[name];
10628          var bindings = controllerDirective.$$bindings.bindToController;
10629
10630          controller.instance = controller();
10631          $element.data('$' + controllerDirective.name + 'Controller', controller.instance);
10632          controller.bindingInfo =
10633            initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
10634          }
10635
10636        // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
10637        forEach(controllerDirectives, function(controllerDirective, name) {
10638          var require = controllerDirective.require;
10639          if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
10640            extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
10641          }
10642        });
10643
10644        // Handle the init and destroy lifecycle hooks on all controllers that have them
10645        forEach(elementControllers, function(controller) {
10646          var controllerInstance = controller.instance;
10647          if (isFunction(controllerInstance.$onChanges)) {
10648            try {
10649              controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
10650            } catch (e) {
10651              $exceptionHandler(e);
10652            }
10653          }
10654          if (isFunction(controllerInstance.$onInit)) {
10655            try {
10656              controllerInstance.$onInit();
10657            } catch (e) {
10658              $exceptionHandler(e);
10659            }
10660          }
10661          if (isFunction(controllerInstance.$doCheck)) {
10662            controllerScope.$watch(function() { controllerInstance.$doCheck(); });
10663            controllerInstance.$doCheck();
10664          }
10665          if (isFunction(controllerInstance.$onDestroy)) {
10666            controllerScope.$on('$destroy', function callOnDestroyHook() {
10667              controllerInstance.$onDestroy();
10668            });
10669          }
10670        });
10671
10672        // PRELINKING
10673        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
10674          linkFn = preLinkFns[i];
10675          invokeLinkFn(linkFn,
10676              linkFn.isolateScope ? isolateScope : scope,
10677              $element,
10678              attrs,
10679              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
10680              transcludeFn
10681          );
10682        }
10683
10684        // RECURSION
10685        // We only pass the isolate scope, if the isolate directive has a template,
10686        // otherwise the child elements do not belong to the isolate directive.
10687        var scopeToChild = scope;
10688        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
10689          scopeToChild = isolateScope;
10690        }
10691        if (childLinkFn) {
10692          childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
10693        }
10694
10695        // POSTLINKING
10696        for (i = postLinkFns.length - 1; i >= 0; i--) {
10697          linkFn = postLinkFns[i];
10698          invokeLinkFn(linkFn,
10699              linkFn.isolateScope ? isolateScope : scope,
10700              $element,
10701              attrs,
10702              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
10703              transcludeFn
10704          );
10705        }
10706
10707        // Trigger $postLink lifecycle hooks
10708        forEach(elementControllers, function(controller) {
10709          var controllerInstance = controller.instance;
10710          if (isFunction(controllerInstance.$postLink)) {
10711            controllerInstance.$postLink();
10712          }
10713        });
10714
10715        // This is the function that is injected as `$transclude`.
10716        // Note: all arguments are optional!
10717        function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
10718          var transcludeControllers;
10719          // No scope passed in:
10720          if (!isScope(scope)) {
10721            slotName = futureParentElement;
10722            futureParentElement = cloneAttachFn;
10723            cloneAttachFn = scope;
10724            scope = undefined;
10725          }
10726
10727          if (hasElementTranscludeDirective) {
10728            transcludeControllers = elementControllers;
10729          }
10730          if (!futureParentElement) {
10731            futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
10732          }
10733          if (slotName) {
10734            // slotTranscludeFn can be one of three things:
10735            //  * a transclude function - a filled slot
10736            //  * `null` - an optional slot that was not filled
10737            //  * `undefined` - a slot that was not declared (i.e. invalid)
10738            var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
10739            if (slotTranscludeFn) {
10740              return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
10741            } else if (isUndefined(slotTranscludeFn)) {
10742              throw $compileMinErr('noslot',
10743               'No parent directive that requires a transclusion with slot name "{0}". ' +
10744               'Element: {1}',
10745               slotName, startingTag($element));
10746            }
10747          } else {
10748            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
10749          }
10750        }
10751      }
10752    }
10753
10754    function getControllers(directiveName, require, $element, elementControllers) {
10755      var value;
10756
10757      if (isString(require)) {
10758        var match = require.match(REQUIRE_PREFIX_REGEXP);
10759        var name = require.substring(match[0].length);
10760        var inheritType = match[1] || match[3];
10761        var optional = match[2] === '?';
10762
10763        //If only parents then start at the parent element
10764        if (inheritType === '^^') {
10765          $element = $element.parent();
10766        //Otherwise attempt getting the controller from elementControllers in case
10767        //the element is transcluded (and has no data) and to avoid .data if possible
10768        } else {
10769          value = elementControllers && elementControllers[name];
10770          value = value && value.instance;
10771        }
10772
10773        if (!value) {
10774          var dataName = '$' + name + 'Controller';
10775
10776          if (inheritType === '^^' && $element[0] && $element[0].nodeType === NODE_TYPE_DOCUMENT) {
10777            // inheritedData() uses the documentElement when it finds the document, so we would
10778            // require from the element itself.
10779            value = null;
10780          } else {
10781            value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
10782          }
10783        }
10784
10785        if (!value && !optional) {
10786          throw $compileMinErr('ctreq',
10787              'Controller \'{0}\', required by directive \'{1}\', can\'t be found!',
10788              name, directiveName);
10789        }
10790      } else if (isArray(require)) {
10791        value = [];
10792        for (var i = 0, ii = require.length; i < ii; i++) {
10793          value[i] = getControllers(directiveName, require[i], $element, elementControllers);
10794        }
10795      } else if (isObject(require)) {
10796        value = {};
10797        forEach(require, function(controller, property) {
10798          value[property] = getControllers(directiveName, controller, $element, elementControllers);
10799        });
10800      }
10801
10802      return value || null;
10803    }
10804
10805    function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
10806      var elementControllers = createMap();
10807      for (var controllerKey in controllerDirectives) {
10808        var directive = controllerDirectives[controllerKey];
10809        var locals = {
10810          $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
10811          $element: $element,
10812          $attrs: attrs,
10813          $transclude: transcludeFn
10814        };
10815
10816        var controller = directive.controller;
10817        if (controller === '@') {
10818          controller = attrs[directive.name];
10819        }
10820
10821        var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
10822
10823        // For directives with element transclusion the element is a comment.
10824        // In this case .data will not attach any data.
10825        // Instead, we save the controllers for the element in a local hash and attach to .data
10826        // later, once we have the actual element.
10827        elementControllers[directive.name] = controllerInstance;
10828        $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
10829      }
10830      return elementControllers;
10831    }
10832
10833    // Depending upon the context in which a directive finds itself it might need to have a new isolated
10834    // or child scope created. For instance:
10835    // * if the directive has been pulled into a template because another directive with a higher priority
10836    // asked for element transclusion
10837    // * if the directive itself asks for transclusion but it is at the root of a template and the original
10838    // element was replaced. See https://github.com/angular/angular.js/issues/12936
10839    function markDirectiveScope(directives, isolateScope, newScope) {
10840      for (var j = 0, jj = directives.length; j < jj; j++) {
10841        directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
10842      }
10843    }
10844
10845    /**
10846     * looks up the directive and decorates it with exception handling and proper parameters. We
10847     * call this the boundDirective.
10848     *
10849     * @param {string} name name of the directive to look up.
10850     * @param {string} location The directive must be found in specific format.
10851     *   String containing any of theses characters:
10852     *
10853     *   * `E`: element name
10854     *   * `A': attribute
10855     *   * `C`: class
10856     *   * `M`: comment
10857     * @returns {boolean} true if directive was added.
10858     */
10859    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
10860                          endAttrName) {
10861      if (name === ignoreDirective) return null;
10862      var match = null;
10863      if (hasDirectives.hasOwnProperty(name)) {
10864        for (var directive, directives = $injector.get(name + Suffix),
10865            i = 0, ii = directives.length; i < ii; i++) {
10866          directive = directives[i];
10867          if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
10868               directive.restrict.indexOf(location) !== -1) {
10869            if (startAttrName) {
10870              directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
10871            }
10872            if (!directive.$$bindings) {
10873              var bindings = directive.$$bindings =
10874                  parseDirectiveBindings(directive, directive.name);
10875              if (isObject(bindings.isolateScope)) {
10876                directive.$$isolateBindings = bindings.isolateScope;
10877              }
10878            }
10879            tDirectives.push(directive);
10880            match = directive;
10881          }
10882        }
10883      }
10884      return match;
10885    }
10886
10887
10888    /**
10889     * looks up the directive and returns true if it is a multi-element directive,
10890     * and therefore requires DOM nodes between -start and -end markers to be grouped
10891     * together.
10892     *
10893     * @param {string} name name of the directive to look up.
10894     * @returns true if directive was registered as multi-element.
10895     */
10896    function directiveIsMultiElement(name) {
10897      if (hasDirectives.hasOwnProperty(name)) {
10898        for (var directive, directives = $injector.get(name + Suffix),
10899            i = 0, ii = directives.length; i < ii; i++) {
10900          directive = directives[i];
10901          if (directive.multiElement) {
10902            return true;
10903          }
10904        }
10905      }
10906      return false;
10907    }
10908
10909    /**
10910     * When the element is replaced with HTML template then the new attributes
10911     * on the template need to be merged with the existing attributes in the DOM.
10912     * The desired effect is to have both of the attributes present.
10913     *
10914     * @param {object} dst destination attributes (original DOM)
10915     * @param {object} src source attributes (from the directive template)
10916     */
10917    function mergeTemplateAttributes(dst, src) {
10918      var srcAttr = src.$attr,
10919          dstAttr = dst.$attr;
10920
10921      // reapply the old attributes to the new element
10922      forEach(dst, function(value, key) {
10923        if (key.charAt(0) !== '$') {
10924          if (src[key] && src[key] !== value) {
10925            if (value.length) {
10926              value += (key === 'style' ? ';' : ' ') + src[key];
10927            } else {
10928              value = src[key];
10929            }
10930          }
10931          dst.$set(key, value, true, srcAttr[key]);
10932        }
10933      });
10934
10935      // copy the new attributes on the old attrs object
10936      forEach(src, function(value, key) {
10937        // Check if we already set this attribute in the loop above.
10938        // `dst` will never contain hasOwnProperty as DOM parser won't let it.
10939        // You will get an "InvalidCharacterError: DOM Exception 5" error if you
10940        // have an attribute like "has-own-property" or "data-has-own-property", etc.
10941        if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
10942          dst[key] = value;
10943
10944          if (key !== 'class' && key !== 'style') {
10945            dstAttr[key] = srcAttr[key];
10946          }
10947        }
10948      });
10949    }
10950
10951
10952    function compileTemplateUrl(directives, $compileNode, tAttrs,
10953        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
10954      var linkQueue = [],
10955          afterTemplateNodeLinkFn,
10956          afterTemplateChildLinkFn,
10957          beforeTemplateCompileNode = $compileNode[0],
10958          origAsyncDirective = directives.shift(),
10959          derivedSyncDirective = inherit(origAsyncDirective, {
10960            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
10961          }),
10962          templateUrl = (isFunction(origAsyncDirective.templateUrl))
10963              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
10964              : origAsyncDirective.templateUrl,
10965          templateNamespace = origAsyncDirective.templateNamespace;
10966
10967      $compileNode.empty();
10968
10969      $templateRequest(templateUrl)
10970        .then(function(content) {
10971          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
10972
10973          content = denormalizeTemplate(content);
10974
10975          if (origAsyncDirective.replace) {
10976            if (jqLiteIsTextNode(content)) {
10977              $template = [];
10978            } else {
10979              $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
10980            }
10981            compileNode = $template[0];
10982
10983            if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
10984              throw $compileMinErr('tplrt',
10985                  'Template for directive \'{0}\' must have exactly one root element. {1}',
10986                  origAsyncDirective.name, templateUrl);
10987            }
10988
10989            tempTemplateAttrs = {$attr: {}};
10990            replaceWith($rootElement, $compileNode, compileNode);
10991            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
10992
10993            if (isObject(origAsyncDirective.scope)) {
10994              // the original directive that caused the template to be loaded async required
10995              // an isolate scope
10996              markDirectiveScope(templateDirectives, true);
10997            }
10998            directives = templateDirectives.concat(directives);
10999            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
11000          } else {
11001            compileNode = beforeTemplateCompileNode;
11002            $compileNode.html(content);
11003          }
11004
11005          directives.unshift(derivedSyncDirective);
11006
11007          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
11008              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
11009              previousCompileContext);
11010          forEach($rootElement, function(node, i) {
11011            if (node === compileNode) {
11012              $rootElement[i] = $compileNode[0];
11013            }
11014          });
11015          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
11016
11017          while (linkQueue.length) {
11018            var scope = linkQueue.shift(),
11019                beforeTemplateLinkNode = linkQueue.shift(),
11020                linkRootElement = linkQueue.shift(),
11021                boundTranscludeFn = linkQueue.shift(),
11022                linkNode = $compileNode[0];
11023
11024            if (scope.$$destroyed) continue;
11025
11026            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
11027              var oldClasses = beforeTemplateLinkNode.className;
11028
11029              if (!(previousCompileContext.hasElementTranscludeDirective &&
11030                  origAsyncDirective.replace)) {
11031                // it was cloned therefore we have to clone as well.
11032                linkNode = jqLiteClone(compileNode);
11033              }
11034              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
11035
11036              // Copy in CSS classes from original node
11037              safeAddClass(jqLite(linkNode), oldClasses);
11038            }
11039            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
11040              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
11041            } else {
11042              childBoundTranscludeFn = boundTranscludeFn;
11043            }
11044            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
11045              childBoundTranscludeFn);
11046          }
11047          linkQueue = null;
11048        }).catch(function(error) {
11049          if (isError(error)) {
11050            $exceptionHandler(error);
11051          }
11052        });
11053
11054      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
11055        var childBoundTranscludeFn = boundTranscludeFn;
11056        if (scope.$$destroyed) return;
11057        if (linkQueue) {
11058          linkQueue.push(scope,
11059                         node,
11060                         rootElement,
11061                         childBoundTranscludeFn);
11062        } else {
11063          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
11064            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
11065          }
11066          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
11067        }
11068      };
11069    }
11070
11071
11072    /**
11073     * Sorting function for bound directives.
11074     */
11075    function byPriority(a, b) {
11076      var diff = b.priority - a.priority;
11077      if (diff !== 0) return diff;
11078      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
11079      return a.index - b.index;
11080    }
11081
11082    function assertNoDuplicate(what, previousDirective, directive, element) {
11083
11084      function wrapModuleNameIfDefined(moduleName) {
11085        return moduleName ?
11086          (' (module: ' + moduleName + ')') :
11087          '';
11088      }
11089
11090      if (previousDirective) {
11091        throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
11092            previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
11093            directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
11094      }
11095    }
11096
11097
11098    function addTextInterpolateDirective(directives, text) {
11099      var interpolateFn = $interpolate(text, true);
11100      if (interpolateFn) {
11101        directives.push({
11102          priority: 0,
11103          compile: function textInterpolateCompileFn(templateNode) {
11104            var templateNodeParent = templateNode.parent(),
11105                hasCompileParent = !!templateNodeParent.length;
11106
11107            // When transcluding a template that has bindings in the root
11108            // we don't have a parent and thus need to add the class during linking fn.
11109            if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
11110
11111            return function textInterpolateLinkFn(scope, node) {
11112              var parent = node.parent();
11113              if (!hasCompileParent) compile.$$addBindingClass(parent);
11114              compile.$$addBindingInfo(parent, interpolateFn.expressions);
11115              scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
11116                node[0].nodeValue = value;
11117              });
11118            };
11119          }
11120        });
11121      }
11122    }
11123
11124
11125    function wrapTemplate(type, template) {
11126      type = lowercase(type || 'html');
11127      switch (type) {
11128      case 'svg':
11129      case 'math':
11130        var wrapper = window.document.createElement('div');
11131        wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
11132        return wrapper.childNodes[0].childNodes;
11133      default:
11134        return template;
11135      }
11136    }
11137
11138
11139    function getTrustedAttrContext(nodeName, attrNormalizedName) {
11140      if (attrNormalizedName === 'srcdoc') {
11141        return $sce.HTML;
11142      }
11143      // All nodes with src attributes require a RESOURCE_URL value, except for
11144      // img and various html5 media nodes, which require the MEDIA_URL context.
11145      if (attrNormalizedName === 'src' || attrNormalizedName === 'ngSrc') {
11146        if (['img', 'video', 'audio', 'source', 'track'].indexOf(nodeName) === -1) {
11147          return $sce.RESOURCE_URL;
11148        }
11149        return $sce.MEDIA_URL;
11150      } else if (attrNormalizedName === 'xlinkHref') {
11151        // Some xlink:href are okay, most aren't
11152        if (nodeName === 'image') return $sce.MEDIA_URL;
11153        if (nodeName === 'a') return $sce.URL;
11154        return $sce.RESOURCE_URL;
11155      } else if (
11156          // Formaction
11157          (nodeName === 'form' && attrNormalizedName === 'action') ||
11158          // If relative URLs can go where they are not expected to, then
11159          // all sorts of trust issues can arise.
11160          (nodeName === 'base' && attrNormalizedName === 'href') ||
11161          // links can be stylesheets or imports, which can run script in the current origin
11162          (nodeName === 'link' && attrNormalizedName === 'href')
11163      ) {
11164        return $sce.RESOURCE_URL;
11165      } else if (nodeName === 'a' && (attrNormalizedName === 'href' ||
11166                                 attrNormalizedName === 'ngHref')) {
11167        return $sce.URL;
11168      }
11169    }
11170
11171    function getTrustedPropContext(nodeName, propNormalizedName) {
11172      var prop = propNormalizedName.toLowerCase();
11173      return PROP_CONTEXTS[nodeName + '|' + prop] || PROP_CONTEXTS['*|' + prop];
11174    }
11175
11176    function sanitizeSrcsetPropertyValue(value) {
11177      return sanitizeSrcset($sce.valueOf(value), 'ng-prop-srcset');
11178    }
11179    function addPropertyDirective(node, directives, attrName, propName) {
11180      if (EVENT_HANDLER_ATTR_REGEXP.test(propName)) {
11181        throw $compileMinErr('nodomevents', 'Property bindings for HTML DOM event properties are disallowed');
11182      }
11183
11184      var nodeName = nodeName_(node);
11185      var trustedContext = getTrustedPropContext(nodeName, propName);
11186
11187      var sanitizer = identity;
11188      // Sanitize img[srcset] + source[srcset] values.
11189      if (propName === 'srcset' && (nodeName === 'img' || nodeName === 'source')) {
11190        sanitizer = sanitizeSrcsetPropertyValue;
11191      } else if (trustedContext) {
11192        sanitizer = $sce.getTrusted.bind($sce, trustedContext);
11193      }
11194
11195      directives.push({
11196        priority: 100,
11197        compile: function ngPropCompileFn(_, attr) {
11198          var ngPropGetter = $parse(attr[attrName]);
11199          var ngPropWatch = $parse(attr[attrName], function sceValueOf(val) {
11200            // Unwrap the value to compare the actual inner safe value, not the wrapper object.
11201            return $sce.valueOf(val);
11202          });
11203
11204          return {
11205            pre: function ngPropPreLinkFn(scope, $element) {
11206              function applyPropValue() {
11207                var propValue = ngPropGetter(scope);
11208                $element[0][propName] = sanitizer(propValue);
11209              }
11210
11211              applyPropValue();
11212              scope.$watch(ngPropWatch, applyPropValue);
11213            }
11214          };
11215        }
11216      });
11217    }
11218
11219    function addEventDirective(directives, attrName, eventName) {
11220      directives.push(
11221        createEventDirective($parse, $rootScope, $exceptionHandler, attrName, eventName, /*forceAsync=*/false)
11222      );
11223    }
11224
11225    function addAttrInterpolateDirective(node, directives, value, name, isNgAttr) {
11226      var nodeName = nodeName_(node);
11227      var trustedContext = getTrustedAttrContext(nodeName, name);
11228      var mustHaveExpression = !isNgAttr;
11229      var allOrNothing = ALL_OR_NOTHING_ATTRS[name] || isNgAttr;
11230
11231      var interpolateFn = $interpolate(value, mustHaveExpression, trustedContext, allOrNothing);
11232
11233      // no interpolation found -> ignore
11234      if (!interpolateFn) return;
11235
11236      if (name === 'multiple' && nodeName === 'select') {
11237        throw $compileMinErr('selmulti',
11238            'Binding to the \'multiple\' attribute is not supported. Element: {0}',
11239            startingTag(node));
11240      }
11241
11242      if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
11243        throw $compileMinErr('nodomevents', 'Interpolations for HTML DOM event attributes are disallowed');
11244      }
11245
11246      directives.push({
11247        priority: 100,
11248        compile: function() {
11249            return {
11250              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
11251                var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
11252
11253                // If the attribute has changed since last $interpolate()ed
11254                var newValue = attr[name];
11255                if (newValue !== value) {
11256                  // we need to interpolate again since the attribute value has been updated
11257                  // (e.g. by another directive's compile function)
11258                  // ensure unset/empty values make interpolateFn falsy
11259                  interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
11260                  value = newValue;
11261                }
11262
11263                // if attribute was updated so that there is no interpolation going on we don't want to
11264                // register any observers
11265                if (!interpolateFn) return;
11266
11267                // initialize attr object so that it's ready in case we need the value for isolate
11268                // scope initialization, otherwise the value would not be available from isolate
11269                // directive's linking fn during linking phase
11270                attr[name] = interpolateFn(scope);
11271
11272                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
11273                (attr.$$observers && attr.$$observers[name].$$scope || scope).
11274                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
11275                    //special case for class attribute addition + removal
11276                    //so that class changes can tap into the animation
11277                    //hooks provided by the $animate service. Be sure to
11278                    //skip animations when the first digest occurs (when
11279                    //both the new and the old values are the same) since
11280                    //the CSS classes are the non-interpolated values
11281                    if (name === 'class' && newValue !== oldValue) {
11282                      attr.$updateClass(newValue, oldValue);
11283                    } else {
11284                      attr.$set(name, newValue);
11285                    }
11286                  });
11287              }
11288            };
11289          }
11290      });
11291    }
11292
11293
11294    /**
11295     * This is a special jqLite.replaceWith, which can replace items which
11296     * have no parents, provided that the containing jqLite collection is provided.
11297     *
11298     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
11299     *                               in the root of the tree.
11300     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
11301     *                                  the shell, but replace its DOM node reference.
11302     * @param {Node} newNode The new DOM node.
11303     */
11304    function replaceWith($rootElement, elementsToRemove, newNode) {
11305      var firstElementToRemove = elementsToRemove[0],
11306          removeCount = elementsToRemove.length,
11307          parent = firstElementToRemove.parentNode,
11308          i, ii;
11309
11310      if ($rootElement) {
11311        for (i = 0, ii = $rootElement.length; i < ii; i++) {
11312          if ($rootElement[i] === firstElementToRemove) {
11313            $rootElement[i++] = newNode;
11314            for (var j = i, j2 = j + removeCount - 1,
11315                     jj = $rootElement.length;
11316                 j < jj; j++, j2++) {
11317              if (j2 < jj) {
11318                $rootElement[j] = $rootElement[j2];
11319              } else {
11320                delete $rootElement[j];
11321              }
11322            }
11323            $rootElement.length -= removeCount - 1;
11324
11325            // If the replaced element is also the jQuery .context then replace it
11326            // .context is a deprecated jQuery api, so we should set it only when jQuery set it
11327            // http://api.jquery.com/context/
11328            if ($rootElement.context === firstElementToRemove) {
11329              $rootElement.context = newNode;
11330            }
11331            break;
11332          }
11333        }
11334      }
11335
11336      if (parent) {
11337        parent.replaceChild(newNode, firstElementToRemove);
11338      }
11339
11340      // Append all the `elementsToRemove` to a fragment. This will...
11341      // - remove them from the DOM
11342      // - allow them to still be traversed with .nextSibling
11343      // - allow a single fragment.qSA to fetch all elements being removed
11344      var fragment = window.document.createDocumentFragment();
11345      for (i = 0; i < removeCount; i++) {
11346        fragment.appendChild(elementsToRemove[i]);
11347      }
11348
11349      if (jqLite.hasData(firstElementToRemove)) {
11350        // Copy over user data (that includes AngularJS's $scope etc.). Don't copy private
11351        // data here because there's no public interface in jQuery to do that and copying over
11352        // event listeners (which is the main use of private data) wouldn't work anyway.
11353        jqLite.data(newNode, jqLite.data(firstElementToRemove));
11354
11355        // Remove $destroy event listeners from `firstElementToRemove`
11356        jqLite(firstElementToRemove).off('$destroy');
11357      }
11358
11359      // Cleanup any data/listeners on the elements and children.
11360      // This includes invoking the $destroy event on any elements with listeners.
11361      jqLite.cleanData(fragment.querySelectorAll('*'));
11362
11363      // Update the jqLite collection to only contain the `newNode`
11364      for (i = 1; i < removeCount; i++) {
11365        delete elementsToRemove[i];
11366      }
11367      elementsToRemove[0] = newNode;
11368      elementsToRemove.length = 1;
11369    }
11370
11371
11372    function cloneAndAnnotateFn(fn, annotation) {
11373      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
11374    }
11375
11376
11377    function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
11378      try {
11379        linkFn(scope, $element, attrs, controllers, transcludeFn);
11380      } catch (e) {
11381        $exceptionHandler(e, startingTag($element));
11382      }
11383    }
11384
11385    function strictBindingsCheck(attrName, directiveName) {
11386      if (strictComponentBindingsEnabled) {
11387        throw $compileMinErr('missingattr',
11388          'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!',
11389          attrName, directiveName);
11390      }
11391    }
11392
11393    // Set up $watches for isolate scope and controller bindings.
11394    function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
11395      var removeWatchCollection = [];
11396      var initialChanges = {};
11397      var changes;
11398
11399      forEach(bindings, function initializeBinding(definition, scopeName) {
11400        var attrName = definition.attrName,
11401        optional = definition.optional,
11402        mode = definition.mode, // @, =, <, or &
11403        lastValue,
11404        parentGet, parentSet, compare, removeWatch;
11405
11406        switch (mode) {
11407
11408          case '@':
11409            if (!optional && !hasOwnProperty.call(attrs, attrName)) {
11410              strictBindingsCheck(attrName, directive.name);
11411              destination[scopeName] = attrs[attrName] = undefined;
11412
11413            }
11414            removeWatch = attrs.$observe(attrName, function(value) {
11415              if (isString(value) || isBoolean(value)) {
11416                var oldValue = destination[scopeName];
11417                recordChanges(scopeName, value, oldValue);
11418                destination[scopeName] = value;
11419              }
11420            });
11421            attrs.$$observers[attrName].$$scope = scope;
11422            lastValue = attrs[attrName];
11423            if (isString(lastValue)) {
11424              // If the attribute has been provided then we trigger an interpolation to ensure
11425              // the value is there for use in the link fn
11426              destination[scopeName] = $interpolate(lastValue)(scope);
11427            } else if (isBoolean(lastValue)) {
11428              // If the attributes is one of the BOOLEAN_ATTR then AngularJS will have converted
11429              // the value to boolean rather than a string, so we special case this situation
11430              destination[scopeName] = lastValue;
11431            }
11432            initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
11433            removeWatchCollection.push(removeWatch);
11434            break;
11435
11436          case '=':
11437            if (!hasOwnProperty.call(attrs, attrName)) {
11438              if (optional) break;
11439              strictBindingsCheck(attrName, directive.name);
11440              attrs[attrName] = undefined;
11441            }
11442            if (optional && !attrs[attrName]) break;
11443
11444            parentGet = $parse(attrs[attrName]);
11445            if (parentGet.literal) {
11446              compare = equals;
11447            } else {
11448              compare = simpleCompare;
11449            }
11450            parentSet = parentGet.assign || function() {
11451              // reset the change, or we will throw this exception on every $digest
11452              lastValue = destination[scopeName] = parentGet(scope);
11453              throw $compileMinErr('nonassign',
11454                  'Expression \'{0}\' in attribute \'{1}\' used with directive \'{2}\' is non-assignable!',
11455                  attrs[attrName], attrName, directive.name);
11456            };
11457            lastValue = destination[scopeName] = parentGet(scope);
11458            var parentValueWatch = function parentValueWatch(parentValue) {
11459              if (!compare(parentValue, destination[scopeName])) {
11460                // we are out of sync and need to copy
11461                if (!compare(parentValue, lastValue)) {
11462                  // parent changed and it has precedence
11463                  destination[scopeName] = parentValue;
11464                } else {
11465                  // if the parent can be assigned then do so
11466                  parentSet(scope, parentValue = destination[scopeName]);
11467                }
11468              }
11469              lastValue = parentValue;
11470              return lastValue;
11471            };
11472            parentValueWatch.$stateful = true;
11473            if (definition.collection) {
11474              removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
11475            } else {
11476              removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
11477            }
11478            removeWatchCollection.push(removeWatch);
11479            break;
11480
11481          case '<':
11482            if (!hasOwnProperty.call(attrs, attrName)) {
11483              if (optional) break;
11484              strictBindingsCheck(attrName, directive.name);
11485              attrs[attrName] = undefined;
11486            }
11487            if (optional && !attrs[attrName]) break;
11488
11489            parentGet = $parse(attrs[attrName]);
11490            var isLiteral = parentGet.literal;
11491
11492            var initialValue = destination[scopeName] = parentGet(scope);
11493            initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
11494
11495            removeWatch = scope[definition.collection ? '$watchCollection' : '$watch'](parentGet, function parentValueWatchAction(newValue, oldValue) {
11496              if (oldValue === newValue) {
11497                if (oldValue === initialValue || (isLiteral && equals(oldValue, initialValue))) {
11498                  return;
11499                }
11500                oldValue = initialValue;
11501              }
11502              recordChanges(scopeName, newValue, oldValue);
11503              destination[scopeName] = newValue;
11504            });
11505
11506            removeWatchCollection.push(removeWatch);
11507            break;
11508
11509          case '&':
11510            if (!optional && !hasOwnProperty.call(attrs, attrName)) {
11511              strictBindingsCheck(attrName, directive.name);
11512            }
11513            // Don't assign Object.prototype method to scope
11514            parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
11515
11516            // Don't assign noop to destination if expression is not valid
11517            if (parentGet === noop && optional) break;
11518
11519            destination[scopeName] = function(locals) {
11520              return parentGet(scope, locals);
11521            };
11522            break;
11523        }
11524      });
11525
11526      function recordChanges(key, currentValue, previousValue) {
11527        if (isFunction(destination.$onChanges) && !simpleCompare(currentValue, previousValue)) {
11528          // If we have not already scheduled the top level onChangesQueue handler then do so now
11529          if (!onChangesQueue) {
11530            scope.$$postDigest(flushOnChangesQueue);
11531            onChangesQueue = [];
11532          }
11533          // If we have not already queued a trigger of onChanges for this controller then do so now
11534          if (!changes) {
11535            changes = {};
11536            onChangesQueue.push(triggerOnChangesHook);
11537          }
11538          // If the has been a change on this property already then we need to reuse the previous value
11539          if (changes[key]) {
11540            previousValue = changes[key].previousValue;
11541          }
11542          // Store this change
11543          changes[key] = new SimpleChange(previousValue, currentValue);
11544        }
11545      }
11546
11547      function triggerOnChangesHook() {
11548        destination.$onChanges(changes);
11549        // Now clear the changes so that we schedule onChanges when more changes arrive
11550        changes = undefined;
11551      }
11552
11553      return {
11554        initialChanges: initialChanges,
11555        removeWatches: removeWatchCollection.length && function removeWatches() {
11556          for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
11557            removeWatchCollection[i]();
11558          }
11559        }
11560      };
11561    }
11562  }];
11563}
11564
11565function SimpleChange(previous, current) {
11566  this.previousValue = previous;
11567  this.currentValue = current;
11568}
11569SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
11570
11571
11572var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
11573var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
11574
11575/**
11576 * Converts all accepted directives format into proper directive name.
11577 * @param name Name to normalize
11578 */
11579function directiveNormalize(name) {
11580  return name
11581    .replace(PREFIX_REGEXP, '')
11582    .replace(SPECIAL_CHARS_REGEXP, function(_, letter, offset) {
11583      return offset ? letter.toUpperCase() : letter;
11584    });
11585}
11586
11587/**
11588 * @ngdoc type
11589 * @name $compile.directive.Attributes
11590 *
11591 * @description
11592 * A shared object between directive compile / linking functions which contains normalized DOM
11593 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
11594 * needed since all of these are treated as equivalent in AngularJS:
11595 *
11596 * ```
11597 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
11598 * ```
11599 */
11600
11601/**
11602 * @ngdoc property
11603 * @name $compile.directive.Attributes#$attr
11604 *
11605 * @description
11606 * A map of DOM element attribute names to the normalized name. This is
11607 * needed to do reverse lookup from normalized name back to actual name.
11608 */
11609
11610
11611/**
11612 * @ngdoc method
11613 * @name $compile.directive.Attributes#$set
11614 * @kind function
11615 *
11616 * @description
11617 * Set DOM element attribute value.
11618 *
11619 *
11620 * @param {string} name Normalized element attribute name of the property to modify. The name is
11621 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
11622 *          property to the original name.
11623 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
11624 */
11625
11626
11627
11628/**
11629 * Closure compiler type information
11630 */
11631
11632function nodesetLinkingFn(
11633  /* angular.Scope */ scope,
11634  /* NodeList */ nodeList,
11635  /* Element */ rootElement,
11636  /* function(Function) */ boundTranscludeFn
11637) {}
11638
11639function directiveLinkingFn(
11640  /* nodesetLinkingFn */ nodesetLinkingFn,
11641  /* angular.Scope */ scope,
11642  /* Node */ node,
11643  /* Element */ rootElement,
11644  /* function(Function) */ boundTranscludeFn
11645) {}
11646
11647function tokenDifference(str1, str2) {
11648  var values = '',
11649      tokens1 = str1.split(/\s+/),
11650      tokens2 = str2.split(/\s+/);
11651
11652  outer:
11653  for (var i = 0; i < tokens1.length; i++) {
11654    var token = tokens1[i];
11655    for (var j = 0; j < tokens2.length; j++) {
11656      if (token === tokens2[j]) continue outer;
11657    }
11658    values += (values.length > 0 ? ' ' : '') + token;
11659  }
11660  return values;
11661}
11662
11663function removeComments(jqNodes) {
11664  jqNodes = jqLite(jqNodes);
11665  var i = jqNodes.length;
11666
11667  if (i <= 1) {
11668    return jqNodes;
11669  }
11670
11671  while (i--) {
11672    var node = jqNodes[i];
11673    if (node.nodeType === NODE_TYPE_COMMENT ||
11674       (node.nodeType === NODE_TYPE_TEXT && node.nodeValue.trim() === '')) {
11675         splice.call(jqNodes, i, 1);
11676    }
11677  }
11678  return jqNodes;
11679}
11680
11681var $controllerMinErr = minErr('$controller');
11682
11683
11684var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
11685function identifierForController(controller, ident) {
11686  if (ident && isString(ident)) return ident;
11687  if (isString(controller)) {
11688    var match = CNTRL_REG.exec(controller);
11689    if (match) return match[3];
11690  }
11691}
11692
11693
11694/**
11695 * @ngdoc provider
11696 * @name $controllerProvider
11697 * @this
11698 *
11699 * @description
11700 * The {@link ng.$controller $controller service} is used by AngularJS to create new
11701 * controllers.
11702 *
11703 * This provider allows controller registration via the
11704 * {@link ng.$controllerProvider#register register} method.
11705 */
11706function $ControllerProvider() {
11707  var controllers = {};
11708
11709  /**
11710   * @ngdoc method
11711   * @name $controllerProvider#has
11712   * @param {string} name Controller name to check.
11713   */
11714  this.has = function(name) {
11715    return controllers.hasOwnProperty(name);
11716  };
11717
11718  /**
11719   * @ngdoc method
11720   * @name $controllerProvider#register
11721   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
11722   *    the names and the values are the constructors.
11723   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
11724   *    annotations in the array notation).
11725   */
11726  this.register = function(name, constructor) {
11727    assertNotHasOwnProperty(name, 'controller');
11728    if (isObject(name)) {
11729      extend(controllers, name);
11730    } else {
11731      controllers[name] = constructor;
11732    }
11733  };
11734
11735  this.$get = ['$injector', function($injector) {
11736
11737    /**
11738     * @ngdoc service
11739     * @name $controller
11740     * @requires $injector
11741     *
11742     * @param {Function|string} constructor If called with a function then it's considered to be the
11743     *    controller constructor function. Otherwise it's considered to be a string which is used
11744     *    to retrieve the controller constructor using the following steps:
11745     *
11746     *    * check if a controller with given name is registered via `$controllerProvider`
11747     *    * check if evaluating the string on the current scope returns a constructor
11748     *
11749     *    The string can use the `controller as property` syntax, where the controller instance is published
11750     *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
11751     *    to work correctly.
11752     *
11753     * @param {Object} locals Injection locals for Controller.
11754     * @return {Object} Instance of given controller.
11755     *
11756     * @description
11757     * `$controller` service is responsible for instantiating controllers.
11758     *
11759     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
11760     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
11761     */
11762    return function $controller(expression, locals, later, ident) {
11763      // PRIVATE API:
11764      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
11765      //                     If true, $controller will allocate the object with the correct
11766      //                     prototype chain, but will not invoke the controller until a returned
11767      //                     callback is invoked.
11768      //   param `ident` --- An optional label which overrides the label parsed from the controller
11769      //                     expression, if any.
11770      var instance, match, constructor, identifier;
11771      later = later === true;
11772      if (ident && isString(ident)) {
11773        identifier = ident;
11774      }
11775
11776      if (isString(expression)) {
11777        match = expression.match(CNTRL_REG);
11778        if (!match) {
11779          throw $controllerMinErr('ctrlfmt',
11780            'Badly formed controller string \'{0}\'. ' +
11781            'Must match `__name__ as __id__` or `__name__`.', expression);
11782        }
11783        constructor = match[1];
11784        identifier = identifier || match[3];
11785        expression = controllers.hasOwnProperty(constructor)
11786            ? controllers[constructor]
11787            : getter(locals.$scope, constructor, true);
11788
11789        if (!expression) {
11790          throw $controllerMinErr('ctrlreg',
11791            'The controller with the name \'{0}\' is not registered.', constructor);
11792        }
11793
11794        assertArgFn(expression, constructor, true);
11795      }
11796
11797      if (later) {
11798        // Instantiate controller later:
11799        // This machinery is used to create an instance of the object before calling the
11800        // controller's constructor itself.
11801        //
11802        // This allows properties to be added to the controller before the constructor is
11803        // invoked. Primarily, this is used for isolate scope bindings in $compile.
11804        //
11805        // This feature is not intended for use by applications, and is thus not documented
11806        // publicly.
11807        // Object creation: http://jsperf.com/create-constructor/2
11808        var controllerPrototype = (isArray(expression) ?
11809          expression[expression.length - 1] : expression).prototype;
11810        instance = Object.create(controllerPrototype || null);
11811
11812        if (identifier) {
11813          addIdentifier(locals, identifier, instance, constructor || expression.name);
11814        }
11815
11816        return extend(function $controllerInit() {
11817          var result = $injector.invoke(expression, instance, locals, constructor);
11818          if (result !== instance && (isObject(result) || isFunction(result))) {
11819            instance = result;
11820            if (identifier) {
11821              // If result changed, re-assign controllerAs value to scope.
11822              addIdentifier(locals, identifier, instance, constructor || expression.name);
11823            }
11824          }
11825          return instance;
11826        }, {
11827          instance: instance,
11828          identifier: identifier
11829        });
11830      }
11831
11832      instance = $injector.instantiate(expression, locals, constructor);
11833
11834      if (identifier) {
11835        addIdentifier(locals, identifier, instance, constructor || expression.name);
11836      }
11837
11838      return instance;
11839    };
11840
11841    function addIdentifier(locals, identifier, instance, name) {
11842      if (!(locals && isObject(locals.$scope))) {
11843        throw minErr('$controller')('noscp',
11844          'Cannot export controller \'{0}\' as \'{1}\'! No $scope object provided via `locals`.',
11845          name, identifier);
11846      }
11847
11848      locals.$scope[identifier] = instance;
11849    }
11850  }];
11851}
11852
11853/**
11854 * @ngdoc service
11855 * @name $document
11856 * @requires $window
11857 * @this
11858 *
11859 * @description
11860 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
11861 *
11862 * @example
11863   <example module="documentExample" name="document">
11864     <file name="index.html">
11865       <div ng-controller="ExampleController">
11866         <p>$document title: <b ng-bind="title"></b></p>
11867         <p>window.document title: <b ng-bind="windowTitle"></b></p>
11868       </div>
11869     </file>
11870     <file name="script.js">
11871       angular.module('documentExample', [])
11872         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
11873           $scope.title = $document[0].title;
11874           $scope.windowTitle = angular.element(window.document)[0].title;
11875         }]);
11876     </file>
11877   </example>
11878 */
11879function $DocumentProvider() {
11880  this.$get = ['$window', function(window) {
11881    return jqLite(window.document);
11882  }];
11883}
11884
11885
11886/**
11887 * @private
11888 * @this
11889 * Listens for document visibility change and makes the current status accessible.
11890 */
11891function $$IsDocumentHiddenProvider() {
11892  this.$get = ['$document', '$rootScope', function($document, $rootScope) {
11893    var doc = $document[0];
11894    var hidden = doc && doc.hidden;
11895
11896    $document.on('visibilitychange', changeListener);
11897
11898    $rootScope.$on('$destroy', function() {
11899      $document.off('visibilitychange', changeListener);
11900    });
11901
11902    function changeListener() {
11903      hidden = doc.hidden;
11904    }
11905
11906    return function() {
11907      return hidden;
11908    };
11909  }];
11910}
11911
11912/**
11913 * @ngdoc service
11914 * @name $exceptionHandler
11915 * @requires ng.$log
11916 * @this
11917 *
11918 * @description
11919 * Any uncaught exception in AngularJS expressions is delegated to this service.
11920 * The default implementation simply delegates to `$log.error` which logs it into
11921 * the browser console.
11922 *
11923 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
11924 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
11925 *
11926 * ## Example:
11927 *
11928 * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught
11929 * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead
11930 * of `$log.error()`.
11931 *
11932 * ```js
11933 *   angular.
11934 *     module('exceptionOverwrite', []).
11935 *     factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
11936 *       return function myExceptionHandler(exception, cause) {
11937 *         logErrorsToBackend(exception, cause);
11938 *         $log.warn(exception, cause);
11939 *       };
11940 *     }]);
11941 * ```
11942 *
11943 * <hr />
11944 * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
11945 * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
11946 * (unless executed during a digest).
11947 *
11948 * If you wish, you can manually delegate exceptions, e.g.
11949 * `try { ... } catch(e) { $exceptionHandler(e); }`
11950 *
11951 * @param {Error} exception Exception associated with the error.
11952 * @param {string=} cause Optional information about the context in which
11953 *       the error was thrown.
11954 *
11955 */
11956function $ExceptionHandlerProvider() {
11957  this.$get = ['$log', function($log) {
11958    return function(exception, cause) {
11959      $log.error.apply($log, arguments);
11960    };
11961  }];
11962}
11963
11964var $$ForceReflowProvider = /** @this */ function() {
11965  this.$get = ['$document', function($document) {
11966    return function(domNode) {
11967      //the line below will force the browser to perform a repaint so
11968      //that all the animated elements within the animation frame will
11969      //be properly updated and drawn on screen. This is required to
11970      //ensure that the preparation animation is properly flushed so that
11971      //the active state picks up from there. DO NOT REMOVE THIS LINE.
11972      //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
11973      //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
11974      //WILL TAKE YEARS AWAY FROM YOUR LIFE.
11975      if (domNode) {
11976        if (!domNode.nodeType && domNode instanceof jqLite) {
11977          domNode = domNode[0];
11978        }
11979      } else {
11980        domNode = $document[0].body;
11981      }
11982      return domNode.offsetWidth + 1;
11983    };
11984  }];
11985};
11986
11987var APPLICATION_JSON = 'application/json';
11988var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
11989var JSON_START = /^\[|^\{(?!\{)/;
11990var JSON_ENDS = {
11991  '[': /]$/,
11992  '{': /}$/
11993};
11994var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/;
11995var $httpMinErr = minErr('$http');
11996
11997function serializeValue(v) {
11998  if (isObject(v)) {
11999    return isDate(v) ? v.toISOString() : toJson(v);
12000  }
12001  return v;
12002}
12003
12004
12005/** @this */
12006function $HttpParamSerializerProvider() {
12007  /**
12008   * @ngdoc service
12009   * @name $httpParamSerializer
12010   * @description
12011   *
12012   * Default {@link $http `$http`} params serializer that converts objects to strings
12013   * according to the following rules:
12014   *
12015   * * `{'foo': 'bar'}` results in `foo=bar`
12016   * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
12017   * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
12018   * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
12019   *
12020   * Note that serializer will sort the request parameters alphabetically.
12021   */
12022
12023  this.$get = function() {
12024    return function ngParamSerializer(params) {
12025      if (!params) return '';
12026      var parts = [];
12027      forEachSorted(params, function(value, key) {
12028        if (value === null || isUndefined(value) || isFunction(value)) return;
12029        if (isArray(value)) {
12030          forEach(value, function(v) {
12031            parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
12032          });
12033        } else {
12034          parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
12035        }
12036      });
12037
12038      return parts.join('&');
12039    };
12040  };
12041}
12042
12043/** @this */
12044function $HttpParamSerializerJQLikeProvider() {
12045  /**
12046   * @ngdoc service
12047   * @name $httpParamSerializerJQLike
12048   *
12049   * @description
12050   *
12051   * Alternative {@link $http `$http`} params serializer that follows
12052   * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
12053   * The serializer will also sort the params alphabetically.
12054   *
12055   * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
12056   *
12057   * ```js
12058   * $http({
12059   *   url: myUrl,
12060   *   method: 'GET',
12061   *   params: myParams,
12062   *   paramSerializer: '$httpParamSerializerJQLike'
12063   * });
12064   * ```
12065   *
12066   * It is also possible to set it as the default `paramSerializer` in the
12067   * {@link $httpProvider#defaults `$httpProvider`}.
12068   *
12069   * Additionally, you can inject the serializer and use it explicitly, for example to serialize
12070   * form data for submission:
12071   *
12072   * ```js
12073   * .controller(function($http, $httpParamSerializerJQLike) {
12074   *   //...
12075   *
12076   *   $http({
12077   *     url: myUrl,
12078   *     method: 'POST',
12079   *     data: $httpParamSerializerJQLike(myData),
12080   *     headers: {
12081   *       'Content-Type': 'application/x-www-form-urlencoded'
12082   *     }
12083   *   });
12084   *
12085   * });
12086   * ```
12087   *
12088   */
12089  this.$get = function() {
12090    return function jQueryLikeParamSerializer(params) {
12091      if (!params) return '';
12092      var parts = [];
12093      serialize(params, '', true);
12094      return parts.join('&');
12095
12096      function serialize(toSerialize, prefix, topLevel) {
12097        if (isArray(toSerialize)) {
12098          forEach(toSerialize, function(value, index) {
12099            serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
12100          });
12101        } else if (isObject(toSerialize) && !isDate(toSerialize)) {
12102          forEachSorted(toSerialize, function(value, key) {
12103            serialize(value, prefix +
12104                (topLevel ? '' : '[') +
12105                key +
12106                (topLevel ? '' : ']'));
12107          });
12108        } else {
12109          if (isFunction(toSerialize)) {
12110            toSerialize = toSerialize();
12111          }
12112          parts.push(encodeUriQuery(prefix) + '=' +
12113              (toSerialize == null ? '' : encodeUriQuery(serializeValue(toSerialize))));
12114        }
12115      }
12116    };
12117  };
12118}
12119
12120function defaultHttpResponseTransform(data, headers) {
12121  if (isString(data)) {
12122    // Strip json vulnerability protection prefix and trim whitespace
12123    var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
12124
12125    if (tempData) {
12126      var contentType = headers('Content-Type');
12127      var hasJsonContentType = contentType && (contentType.indexOf(APPLICATION_JSON) === 0);
12128
12129      if (hasJsonContentType || isJsonLike(tempData)) {
12130        try {
12131          data = fromJson(tempData);
12132        } catch (e) {
12133          if (!hasJsonContentType) {
12134            return data;
12135          }
12136          throw $httpMinErr('baddata', 'Data must be a valid JSON object. Received: "{0}". ' +
12137          'Parse error: "{1}"', data, e);
12138        }
12139      }
12140    }
12141  }
12142
12143  return data;
12144}
12145
12146function isJsonLike(str) {
12147    var jsonStart = str.match(JSON_START);
12148    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
12149}
12150
12151/**
12152 * Parse headers into key value object
12153 *
12154 * @param {string} headers Raw headers as a string
12155 * @returns {Object} Parsed headers as key value object
12156 */
12157function parseHeaders(headers) {
12158  var parsed = createMap(), i;
12159
12160  function fillInParsed(key, val) {
12161    if (key) {
12162      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
12163    }
12164  }
12165
12166  if (isString(headers)) {
12167    forEach(headers.split('\n'), function(line) {
12168      i = line.indexOf(':');
12169      fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
12170    });
12171  } else if (isObject(headers)) {
12172    forEach(headers, function(headerVal, headerKey) {
12173      fillInParsed(lowercase(headerKey), trim(headerVal));
12174    });
12175  }
12176
12177  return parsed;
12178}
12179
12180
12181/**
12182 * Returns a function that provides access to parsed headers.
12183 *
12184 * Headers are lazy parsed when first requested.
12185 * @see parseHeaders
12186 *
12187 * @param {(string|Object)} headers Headers to provide access to.
12188 * @returns {function(string=)} Returns a getter function which if called with:
12189 *
12190 *   - if called with an argument returns a single header value or null
12191 *   - if called with no arguments returns an object containing all headers.
12192 */
12193function headersGetter(headers) {
12194  var headersObj;
12195
12196  return function(name) {
12197    if (!headersObj) headersObj =  parseHeaders(headers);
12198
12199    if (name) {
12200      var value = headersObj[lowercase(name)];
12201      if (value === undefined) {
12202        value = null;
12203      }
12204      return value;
12205    }
12206
12207    return headersObj;
12208  };
12209}
12210
12211
12212/**
12213 * Chain all given functions
12214 *
12215 * This function is used for both request and response transforming
12216 *
12217 * @param {*} data Data to transform.
12218 * @param {function(string=)} headers HTTP headers getter fn.
12219 * @param {number} status HTTP status code of the response.
12220 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
12221 * @returns {*} Transformed data.
12222 */
12223function transformData(data, headers, status, fns) {
12224  if (isFunction(fns)) {
12225    return fns(data, headers, status);
12226  }
12227
12228  forEach(fns, function(fn) {
12229    data = fn(data, headers, status);
12230  });
12231
12232  return data;
12233}
12234
12235
12236function isSuccess(status) {
12237  return 200 <= status && status < 300;
12238}
12239
12240
12241/**
12242 * @ngdoc provider
12243 * @name $httpProvider
12244 * @this
12245 *
12246 * @description
12247 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
12248 */
12249function $HttpProvider() {
12250  /**
12251   * @ngdoc property
12252   * @name $httpProvider#defaults
12253   * @description
12254   *
12255   * Object containing default values for all {@link ng.$http $http} requests.
12256   *
12257   * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
12258   * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
12259   * by default. See {@link $http#caching $http Caching} for more information.
12260   *
12261   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
12262   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
12263   * setting default headers.
12264   *     - **`defaults.headers.common`**
12265   *     - **`defaults.headers.post`**
12266   *     - **`defaults.headers.put`**
12267   *     - **`defaults.headers.patch`**
12268   *
12269   * - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
12270   * callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
12271   * {@link $jsonpCallbacks} service. Defaults to `'callback'`.
12272   *
12273   * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
12274   *  used to the prepare string representation of request parameters (specified as an object).
12275   *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
12276   *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
12277   *
12278   * - **`defaults.transformRequest`** -
12279   * `{Array<function(data, headersGetter)>|function(data, headersGetter)}` -
12280   * An array of functions (or a single function) which are applied to the request data.
12281   * By default, this is an array with one request transformation function:
12282   *
12283   *   - If the `data` property of the request configuration object contains an object, serialize it
12284   *     into JSON format.
12285   *
12286   * - **`defaults.transformResponse`** -
12287   * `{Array<function(data, headersGetter, status)>|function(data, headersGetter, status)}` -
12288   * An array of functions (or a single function) which are applied to the response data. By default,
12289   * this is an array which applies one response transformation function that does two things:
12290   *
12291   *  - If XSRF prefix is detected, strip it
12292   *    (see {@link ng.$http#security-considerations Security Considerations in the $http docs}).
12293   *  - If the `Content-Type` is `application/json` or the response looks like JSON,
12294   *    deserialize it using a JSON parser.
12295   *
12296   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
12297   * Defaults value is `'XSRF-TOKEN'`.
12298   *
12299   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
12300   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
12301   *
12302   */
12303  var defaults = this.defaults = {
12304    // transform incoming response data
12305    transformResponse: [defaultHttpResponseTransform],
12306
12307    // transform outgoing request data
12308    transformRequest: [function(d) {
12309      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
12310    }],
12311
12312    // default headers
12313    headers: {
12314      common: {
12315        'Accept': 'application/json, text/plain, */*'
12316      },
12317      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
12318      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
12319      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
12320    },
12321
12322    xsrfCookieName: 'XSRF-TOKEN',
12323    xsrfHeaderName: 'X-XSRF-TOKEN',
12324
12325    paramSerializer: '$httpParamSerializer',
12326
12327    jsonpCallbackParam: 'callback'
12328  };
12329
12330  var useApplyAsync = false;
12331  /**
12332   * @ngdoc method
12333   * @name $httpProvider#useApplyAsync
12334   * @description
12335   *
12336   * Configure $http service to combine processing of multiple http responses received at around
12337   * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
12338   * significant performance improvement for bigger applications that make many HTTP requests
12339   * concurrently (common during application bootstrap).
12340   *
12341   * Defaults to false. If no value is specified, returns the current configured value.
12342   *
12343   * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
12344   *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
12345   *    to load and share the same digest cycle.
12346   *
12347   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
12348   *    otherwise, returns the current configured value.
12349   */
12350  this.useApplyAsync = function(value) {
12351    if (isDefined(value)) {
12352      useApplyAsync = !!value;
12353      return this;
12354    }
12355    return useApplyAsync;
12356  };
12357
12358  /**
12359   * @ngdoc property
12360   * @name $httpProvider#interceptors
12361   * @description
12362   *
12363   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
12364   * pre-processing of request or postprocessing of responses.
12365   *
12366   * These service factories are ordered by request, i.e. they are applied in the same order as the
12367   * array, on request, but reverse order, on response.
12368   *
12369   * {@link ng.$http#interceptors Interceptors detailed info}
12370   */
12371  var interceptorFactories = this.interceptors = [];
12372
12373  /**
12374   * @ngdoc property
12375   * @name $httpProvider#xsrfTrustedOrigins
12376   * @description
12377   *
12378   * Array containing URLs whose origins are trusted to receive the XSRF token. See the
12379   * {@link ng.$http#security-considerations Security Considerations} sections for more details on
12380   * XSRF.
12381   *
12382   * **Note:** An "origin" consists of the [URI scheme](https://en.wikipedia.org/wiki/URI_scheme),
12383   * the [hostname](https://en.wikipedia.org/wiki/Hostname) and the
12384   * [port number](https://en.wikipedia.org/wiki/Port_(computer_networking). For `http:` and
12385   * `https:`, the port number can be omitted if using th default ports (80 and 443 respectively).
12386   * Examples: `http://example.com`, `https://api.example.com:9876`
12387   *
12388   * <div class="alert alert-warning">
12389   *   It is not possible to trust specific URLs/paths. The `path`, `query` and `fragment` parts
12390   *   of a URL will be ignored. For example, `https://foo.com/path/bar?query=baz#fragment` will be
12391   *   treated as `https://foo.com`, meaning that **all** requests to URLs starting with
12392   *   `https://foo.com/` will include the XSRF token.
12393   * </div>
12394   *
12395   * @example
12396   *
12397   * ```js
12398   * // App served from `https://example.com/`.
12399   * angular.
12400   *   module('xsrfTrustedOriginsExample', []).
12401   *   config(['$httpProvider', function($httpProvider) {
12402   *     $httpProvider.xsrfTrustedOrigins.push('https://api.example.com');
12403   *   }]).
12404   *   run(['$http', function($http) {
12405   *     // The XSRF token will be sent.
12406   *     $http.get('https://api.example.com/preferences').then(...);
12407   *
12408   *     // The XSRF token will NOT be sent.
12409   *     $http.get('https://stats.example.com/activity').then(...);
12410   *   }]);
12411   * ```
12412   */
12413  var xsrfTrustedOrigins = this.xsrfTrustedOrigins = [];
12414
12415  /**
12416   * @ngdoc property
12417   * @name $httpProvider#xsrfWhitelistedOrigins
12418   * @description
12419   *
12420   * @deprecated
12421   * sinceVersion="1.8.1"
12422   *
12423   * This property is deprecated. Use {@link $httpProvider#xsrfTrustedOrigins xsrfTrustedOrigins}
12424   * instead.
12425   */
12426  Object.defineProperty(this, 'xsrfWhitelistedOrigins', {
12427    get: function() {
12428      return this.xsrfTrustedOrigins;
12429    },
12430    set: function(origins) {
12431      this.xsrfTrustedOrigins = origins;
12432    }
12433  });
12434
12435  this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce',
12436      function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) {
12437
12438    var defaultCache = $cacheFactory('$http');
12439
12440    /**
12441     * Make sure that default param serializer is exposed as a function
12442     */
12443    defaults.paramSerializer = isString(defaults.paramSerializer) ?
12444      $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
12445
12446    /**
12447     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
12448     * The reversal is needed so that we can build up the interception chain around the
12449     * server request.
12450     */
12451    var reversedInterceptors = [];
12452
12453    forEach(interceptorFactories, function(interceptorFactory) {
12454      reversedInterceptors.unshift(isString(interceptorFactory)
12455          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
12456    });
12457
12458    /**
12459     * A function to check request URLs against a list of allowed origins.
12460     */
12461    var urlIsAllowedOrigin = urlIsAllowedOriginFactory(xsrfTrustedOrigins);
12462
12463    /**
12464     * @ngdoc service
12465     * @kind function
12466     * @name $http
12467     * @requires ng.$httpBackend
12468     * @requires $cacheFactory
12469     * @requires $rootScope
12470     * @requires $q
12471     * @requires $injector
12472     *
12473     * @description
12474     * The `$http` service is a core AngularJS service that facilitates communication with the remote
12475     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
12476     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
12477     *
12478     * For unit testing applications that use `$http` service, see
12479     * {@link ngMock.$httpBackend $httpBackend mock}.
12480     *
12481     * For a higher level of abstraction, please check out the {@link ngResource.$resource
12482     * $resource} service.
12483     *
12484     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
12485     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
12486     * it is important to familiarize yourself with these APIs and the guarantees they provide.
12487     *
12488     *
12489     * ## General usage
12490     * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
12491     * that is used to generate an HTTP request and returns  a {@link ng.$q promise} that is
12492     * resolved (request success) or rejected (request failure) with a
12493     * {@link ng.$http#$http-returns response} object.
12494     *
12495     * ```js
12496     *   // Simple GET request example:
12497     *   $http({
12498     *     method: 'GET',
12499     *     url: '/someUrl'
12500     *   }).then(function successCallback(response) {
12501     *       // this callback will be called asynchronously
12502     *       // when the response is available
12503     *     }, function errorCallback(response) {
12504     *       // called asynchronously if an error occurs
12505     *       // or server returns response with an error status.
12506     *     });
12507     * ```
12508     *
12509     *
12510     * ## Shortcut methods
12511     *
12512     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
12513     * request data must be passed in for POST/PUT requests. An optional config can be passed as the
12514     * last argument.
12515     *
12516     * ```js
12517     *   $http.get('/someUrl', config).then(successCallback, errorCallback);
12518     *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
12519     * ```
12520     *
12521     * Complete list of shortcut methods:
12522     *
12523     * - {@link ng.$http#get $http.get}
12524     * - {@link ng.$http#head $http.head}
12525     * - {@link ng.$http#post $http.post}
12526     * - {@link ng.$http#put $http.put}
12527     * - {@link ng.$http#delete $http.delete}
12528     * - {@link ng.$http#jsonp $http.jsonp}
12529     * - {@link ng.$http#patch $http.patch}
12530     *
12531     *
12532     * ## Writing Unit Tests that use $http
12533     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
12534     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
12535     * request using trained responses.
12536     *
12537     * ```
12538     * $httpBackend.expectGET(...);
12539     * $http.get(...);
12540     * $httpBackend.flush();
12541     * ```
12542     *
12543     * ## Setting HTTP Headers
12544     *
12545     * The $http service will automatically add certain HTTP headers to all requests. These defaults
12546     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
12547     * object, which currently contains this default configuration:
12548     *
12549     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
12550     *   - <code>Accept: application/json, text/plain, \*&#65279;/&#65279;\*</code>
12551     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
12552     *   - `Content-Type: application/json`
12553     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
12554     *   - `Content-Type: application/json`
12555     *
12556     * To add or overwrite these defaults, simply add or remove a property from these configuration
12557     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
12558     * with the lowercased HTTP method name as the key, e.g.
12559     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
12560     *
12561     * The defaults can also be set at runtime via the `$http.defaults` object in the same
12562     * fashion. For example:
12563     *
12564     * ```
12565     * module.run(function($http) {
12566     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
12567     * });
12568     * ```
12569     *
12570     * In addition, you can supply a `headers` property in the config object passed when
12571     * calling `$http(config)`, which overrides the defaults without changing them globally.
12572     *
12573     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
12574     * Use the `headers` property, setting the desired header to `undefined`. For example:
12575     *
12576     * ```js
12577     * var req = {
12578     *  method: 'POST',
12579     *  url: 'http://example.com',
12580     *  headers: {
12581     *    'Content-Type': undefined
12582     *  },
12583     *  data: { test: 'test' }
12584     * }
12585     *
12586     * $http(req).then(function(){...}, function(){...});
12587     * ```
12588     *
12589     * ## Transforming Requests and Responses
12590     *
12591     * Both requests and responses can be transformed using transformation functions: `transformRequest`
12592     * and `transformResponse`. These properties can be a single function that returns
12593     * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
12594     * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
12595     *
12596     * <div class="alert alert-warning">
12597     * **Note:** AngularJS does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
12598     * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
12599     * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
12600     * function will be reflected on the scope and in any templates where the object is data-bound.
12601     * To prevent this, transform functions should have no side-effects.
12602     * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
12603     * </div>
12604     *
12605     * ### Default Transformations
12606     *
12607     * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
12608     * `defaults.transformResponse` properties. If a request does not provide its own transformations
12609     * then these will be applied.
12610     *
12611     * You can augment or replace the default transformations by modifying these properties by adding to or
12612     * replacing the array.
12613     *
12614     * AngularJS provides the following default transformations:
12615     *
12616     * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is
12617     * an array with one function that does the following:
12618     *
12619     * - If the `data` property of the request configuration object contains an object, serialize it
12620     *   into JSON format.
12621     *
12622     * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`) is
12623     * an array with one function that does the following:
12624     *
12625     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
12626     *  - If the `Content-Type` is `application/json` or the response looks like JSON,
12627   *      deserialize it using a JSON parser.
12628     *
12629     *
12630     * ### Overriding the Default Transformations Per Request
12631     *
12632     * If you wish to override the request/response transformations only for a single request then provide
12633     * `transformRequest` and/or `transformResponse` properties on the configuration object passed
12634     * into `$http`.
12635     *
12636     * Note that if you provide these properties on the config object the default transformations will be
12637     * overwritten. If you wish to augment the default transformations then you must include them in your
12638     * local transformation array.
12639     *
12640     * The following code demonstrates adding a new response transformation to be run after the default response
12641     * transformations have been run.
12642     *
12643     * ```js
12644     * function appendTransform(defaults, transform) {
12645     *
12646     *   // We can't guarantee that the default transformation is an array
12647     *   defaults = angular.isArray(defaults) ? defaults : [defaults];
12648     *
12649     *   // Append the new transformation to the defaults
12650     *   return defaults.concat(transform);
12651     * }
12652     *
12653     * $http({
12654     *   url: '...',
12655     *   method: 'GET',
12656     *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
12657     *     return doTransform(value);
12658     *   })
12659     * });
12660     * ```
12661     *
12662     *
12663     * ## Caching
12664     *
12665     * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
12666     * set the config.cache value or the default cache value to TRUE or to a cache object (created
12667     * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
12668     * precedence over the default cache value.
12669     *
12670     * In order to:
12671     *   * cache all responses - set the default cache value to TRUE or to a cache object
12672     *   * cache a specific response - set config.cache value to TRUE or to a cache object
12673     *
12674     * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
12675     * then the default `$cacheFactory("$http")` object is used.
12676     *
12677     * The default cache value can be set by updating the
12678     * {@link ng.$http#defaults `$http.defaults.cache`} property or the
12679     * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
12680     *
12681     * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
12682     * the relevant cache object. The next time the same request is made, the response is returned
12683     * from the cache without sending a request to the server.
12684     *
12685     * Take note that:
12686     *
12687     *   * Only GET and JSONP requests are cached.
12688     *   * The cache key is the request URL including search parameters; headers are not considered.
12689     *   * Cached responses are returned asynchronously, in the same way as responses from the server.
12690     *   * If multiple identical requests are made using the same cache, which is not yet populated,
12691     *     one request will be made to the server and remaining requests will return the same response.
12692     *   * A cache-control header on the response does not affect if or how responses are cached.
12693     *
12694     *
12695     * ## Interceptors
12696     *
12697     * Before you start creating interceptors, be sure to understand the
12698     * {@link ng.$q $q and deferred/promise APIs}.
12699     *
12700     * For purposes of global error handling, authentication, or any kind of synchronous or
12701     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
12702     * able to intercept requests before they are handed to the server and
12703     * responses before they are handed over to the application code that
12704     * initiated these requests. The interceptors leverage the {@link ng.$q
12705     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
12706     *
12707     * The interceptors are service factories that are registered with the `$httpProvider` by
12708     * adding them to the `$httpProvider.interceptors` array. The factory is called and
12709     * injected with dependencies (if specified) and returns the interceptor.
12710     *
12711     * There are two kinds of interceptors (and two kinds of rejection interceptors):
12712     *
12713     *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
12714     *     modify the `config` object or create a new one. The function needs to return the `config`
12715     *     object directly, or a promise containing the `config` or a new `config` object.
12716     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
12717     *     resolved with a rejection.
12718     *   * `response`: interceptors get called with http `response` object. The function is free to
12719     *     modify the `response` object or create a new one. The function needs to return the `response`
12720     *     object directly, or as a promise containing the `response` or a new `response` object.
12721     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
12722     *     resolved with a rejection.
12723     *
12724     *
12725     * ```js
12726     *   // register the interceptor as a service
12727     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
12728     *     return {
12729     *       // optional method
12730     *       'request': function(config) {
12731     *         // do something on success
12732     *         return config;
12733     *       },
12734     *
12735     *       // optional method
12736     *      'requestError': function(rejection) {
12737     *         // do something on error
12738     *         if (canRecover(rejection)) {
12739     *           return responseOrNewPromise
12740     *         }
12741     *         return $q.reject(rejection);
12742     *       },
12743     *
12744     *
12745     *
12746     *       // optional method
12747     *       'response': function(response) {
12748     *         // do something on success
12749     *         return response;
12750     *       },
12751     *
12752     *       // optional method
12753     *      'responseError': function(rejection) {
12754     *         // do something on error
12755     *         if (canRecover(rejection)) {
12756     *           return responseOrNewPromise
12757     *         }
12758     *         return $q.reject(rejection);
12759     *       }
12760     *     };
12761     *   });
12762     *
12763     *   $httpProvider.interceptors.push('myHttpInterceptor');
12764     *
12765     *
12766     *   // alternatively, register the interceptor via an anonymous factory
12767     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
12768     *     return {
12769     *      'request': function(config) {
12770     *          // same as above
12771     *       },
12772     *
12773     *       'response': function(response) {
12774     *          // same as above
12775     *       }
12776     *     };
12777     *   });
12778     * ```
12779     *
12780     * ## Security Considerations
12781     *
12782     * When designing web applications, consider security threats from:
12783     *
12784     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
12785     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
12786     *
12787     * Both server and the client must cooperate in order to eliminate these threats. AngularJS comes
12788     * pre-configured with strategies that address these issues, but for this to work backend server
12789     * cooperation is required.
12790     *
12791     * ### JSON Vulnerability Protection
12792     *
12793     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
12794     * allows third party website to turn your JSON resource URL into
12795     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
12796     * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
12797     * AngularJS will automatically strip the prefix before processing it as JSON.
12798     *
12799     * For example if your server needs to return:
12800     * ```js
12801     * ['one','two']
12802     * ```
12803     *
12804     * which is vulnerable to attack, your server can return:
12805     * ```js
12806     * )]}',
12807     * ['one','two']
12808     * ```
12809     *
12810     * AngularJS will strip the prefix, before processing the JSON.
12811     *
12812     *
12813     * ### Cross Site Request Forgery (XSRF) Protection
12814     *
12815     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
12816     * which the attacker can trick an authenticated user into unknowingly executing actions on your
12817     * website. AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the
12818     * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
12819     * header (by default `X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read
12820     * the cookie, your server can be assured that the XHR came from JavaScript running on your
12821     * domain.
12822     *
12823     * To take advantage of this, your server needs to set a token in a JavaScript readable session
12824     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
12825     * server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be
12826     * sure that only JavaScript running on your domain could have sent the request. The token must
12827     * be unique for each user and must be verifiable by the server (to prevent the JavaScript from
12828     * making up its own tokens). We recommend that the token is a digest of your site's
12829     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
12830     * for added security.
12831     *
12832     * The header will &mdash; by default &mdash; **not** be set for cross-domain requests. This
12833     * prevents unauthorized servers (e.g. malicious or compromised 3rd-party APIs) from gaining
12834     * access to your users' XSRF tokens and exposing them to Cross Site Request Forgery. If you
12835     * want to, you can trust additional origins to also receive the XSRF token, by adding them
12836     * to {@link ng.$httpProvider#xsrfTrustedOrigins xsrfTrustedOrigins}. This might be
12837     * useful, for example, if your application, served from `example.com`, needs to access your API
12838     * at `api.example.com`.
12839     * See {@link ng.$httpProvider#xsrfTrustedOrigins $httpProvider.xsrfTrustedOrigins} for
12840     * more details.
12841     *
12842     * <div class="alert alert-danger">
12843     *   **Warning**<br />
12844     *   Only trusted origins that you have control over and make sure you understand the
12845     *   implications of doing so.
12846     * </div>
12847     *
12848     * The name of the cookie and the header can be specified using the `xsrfCookieName` and
12849     * `xsrfHeaderName` properties of either `$httpProvider.defaults` at config-time,
12850     * `$http.defaults` at run-time, or the per-request config object.
12851     *
12852     * In order to prevent collisions in environments where multiple AngularJS apps share the
12853     * same domain or subdomain, we recommend that each application uses a unique cookie name.
12854     *
12855     *
12856     * @param {object} config Object describing the request to be made and how it should be
12857     *    processed. The object has following properties:
12858     *
12859     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
12860     *    - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested;
12861     *      or an object created by a call to `$sce.trustAsResourceUrl(url)`.
12862     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
12863     *      with the `paramSerializer` and appended as GET parameters.
12864     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
12865     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
12866     *      HTTP headers to send to the server. If the return value of a function is null, the
12867     *      header will not be sent. Functions accept a config object as an argument.
12868     *    - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
12869     *      To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
12870     *      The handler will be called in the context of a `$apply` block.
12871     *    - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
12872     *      object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
12873     *      The handler will be called in the context of a `$apply` block.
12874     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
12875     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
12876     *    - **transformRequest** –
12877     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
12878     *      transform function or an array of such functions. The transform function takes the http
12879     *      request body and headers and returns its transformed (typically serialized) version.
12880     *      See {@link ng.$http#overriding-the-default-transformations-per-request
12881     *      Overriding the Default Transformations}
12882     *    - **transformResponse** –
12883     *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
12884     *      transform function or an array of such functions. The transform function takes the http
12885     *      response body, headers and status and returns its transformed (typically deserialized) version.
12886     *      See {@link ng.$http#overriding-the-default-transformations-per-request
12887     *      Overriding the Default Transformations}
12888     *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
12889     *      prepare the string representation of request parameters (specified as an object).
12890     *      If specified as string, it is interpreted as function registered with the
12891     *      {@link $injector $injector}, which means you can create your own serializer
12892     *      by registering it as a {@link auto.$provide#service service}.
12893     *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
12894     *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
12895     *    - **cache** – `{boolean|Object}` – A boolean value or object created with
12896     *      {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
12897     *      See {@link $http#caching $http Caching} for more information.
12898     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
12899     *      that should abort the request when resolved.
12900     *
12901     *      A numerical timeout or a promise returned from {@link ng.$timeout $timeout}, will set
12902     *      the `xhrStatus` in the {@link $http#$http-returns response} to "timeout", and any other
12903     *      resolved promise will set it to "abort", following standard XMLHttpRequest behavior.
12904     *
12905     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
12906     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
12907     *      for more information.
12908     *    - **responseType** - `{string}` - see
12909     *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
12910     *
12911     * @returns {HttpPromise} A {@link ng.$q `Promise}` that will be resolved (request success)
12912     *   or rejected (request failure) with a response object.
12913     *
12914     *   The response object has these properties:
12915     *
12916     *   - **data** – `{string|Object}` – The response body transformed with
12917     *     the transform functions.
12918     *   - **status** – `{number}` – HTTP status code of the response.
12919     *   - **headers** – `{function([headerName])}` – Header getter function.
12920     *   - **config** – `{Object}` – The configuration object that was used
12921     *     to generate the request.
12922     *   - **statusText** – `{string}` – HTTP status text of the response.
12923     *   - **xhrStatus** – `{string}` – Status of the XMLHttpRequest
12924     *     (`complete`, `error`, `timeout` or `abort`).
12925     *
12926     *
12927     *   A response status code between 200 and 299 is considered a success status
12928     *   and will result in the success callback being called. Any response status
12929     *   code outside of that range is considered an error status and will result
12930     *   in the error callback being called.
12931     *   Also, status codes less than -1 are normalized to zero. -1 usually means
12932     *   the request was aborted, e.g. using a `config.timeout`. More information
12933     *   about the status might be available in the `xhrStatus` property.
12934     *
12935     *   Note that if the response is a redirect, XMLHttpRequest will transparently
12936     *   follow it, meaning that the outcome (success or error) will be determined
12937     *   by the final response status code.
12938     *
12939     *
12940     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
12941     *   requests. This is primarily meant to be used for debugging purposes.
12942     *
12943     *
12944     * @example
12945<example module="httpExample" name="http-service">
12946<file name="index.html">
12947  <div ng-controller="FetchController">
12948    <select ng-model="method" aria-label="Request method">
12949      <option>GET</option>
12950      <option>JSONP</option>
12951    </select>
12952    <input type="text" ng-model="url" size="80" aria-label="URL" />
12953    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
12954    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
12955    <button id="samplejsonpbtn"
12956      ng-click="updateModel('JSONP',
12957                    'https://angularjs.org/greet.php?name=Super%20Hero')">
12958      Sample JSONP
12959    </button>
12960    <button id="invalidjsonpbtn"
12961      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist')">
12962        Invalid JSONP
12963      </button>
12964    <pre>http status code: {{status}}</pre>
12965    <pre>http response data: {{data}}</pre>
12966  </div>
12967</file>
12968<file name="script.js">
12969  angular.module('httpExample', [])
12970    .config(['$sceDelegateProvider', function($sceDelegateProvider) {
12971      // We must add the JSONP endpoint that we are using to the trusted list to show that we trust it
12972      $sceDelegateProvider.trustedResourceUrlList([
12973        'self',
12974        'https://angularjs.org/**'
12975      ]);
12976    }])
12977    .controller('FetchController', ['$scope', '$http', '$templateCache',
12978      function($scope, $http, $templateCache) {
12979        $scope.method = 'GET';
12980        $scope.url = 'http-hello.html';
12981
12982        $scope.fetch = function() {
12983          $scope.code = null;
12984          $scope.response = null;
12985
12986          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
12987            then(function(response) {
12988              $scope.status = response.status;
12989              $scope.data = response.data;
12990            }, function(response) {
12991              $scope.data = response.data || 'Request failed';
12992              $scope.status = response.status;
12993          });
12994        };
12995
12996        $scope.updateModel = function(method, url) {
12997          $scope.method = method;
12998          $scope.url = url;
12999        };
13000      }]);
13001</file>
13002<file name="http-hello.html">
13003  Hello, $http!
13004</file>
13005<file name="protractor.js" type="protractor">
13006  var status = element(by.binding('status'));
13007  var data = element(by.binding('data'));
13008  var fetchBtn = element(by.id('fetchbtn'));
13009  var sampleGetBtn = element(by.id('samplegetbtn'));
13010  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
13011
13012  it('should make an xhr GET request', function() {
13013    sampleGetBtn.click();
13014    fetchBtn.click();
13015    expect(status.getText()).toMatch('200');
13016    expect(data.getText()).toMatch(/Hello, \$http!/);
13017  });
13018
13019// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
13020// it('should make a JSONP request to angularjs.org', function() {
13021//   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
13022//   sampleJsonpBtn.click();
13023//   fetchBtn.click();
13024//   expect(status.getText()).toMatch('200');
13025//   expect(data.getText()).toMatch(/Super Hero!/);
13026// });
13027
13028  it('should make JSONP request to invalid URL and invoke the error handler',
13029      function() {
13030    invalidJsonpBtn.click();
13031    fetchBtn.click();
13032    expect(status.getText()).toMatch('0');
13033    expect(data.getText()).toMatch('Request failed');
13034  });
13035</file>
13036</example>
13037     */
13038    function $http(requestConfig) {
13039
13040      if (!isObject(requestConfig)) {
13041        throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
13042      }
13043
13044      if (!isString($sce.valueOf(requestConfig.url))) {
13045        throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object.  Received: {0}', requestConfig.url);
13046      }
13047
13048      var config = extend({
13049        method: 'get',
13050        transformRequest: defaults.transformRequest,
13051        transformResponse: defaults.transformResponse,
13052        paramSerializer: defaults.paramSerializer,
13053        jsonpCallbackParam: defaults.jsonpCallbackParam
13054      }, requestConfig);
13055
13056      config.headers = mergeHeaders(requestConfig);
13057      config.method = uppercase(config.method);
13058      config.paramSerializer = isString(config.paramSerializer) ?
13059          $injector.get(config.paramSerializer) : config.paramSerializer;
13060
13061      $browser.$$incOutstandingRequestCount('$http');
13062
13063      var requestInterceptors = [];
13064      var responseInterceptors = [];
13065      var promise = $q.resolve(config);
13066
13067      // apply interceptors
13068      forEach(reversedInterceptors, function(interceptor) {
13069        if (interceptor.request || interceptor.requestError) {
13070          requestInterceptors.unshift(interceptor.request, interceptor.requestError);
13071        }
13072        if (interceptor.response || interceptor.responseError) {
13073          responseInterceptors.push(interceptor.response, interceptor.responseError);
13074        }
13075      });
13076
13077      promise = chainInterceptors(promise, requestInterceptors);
13078      promise = promise.then(serverRequest);
13079      promise = chainInterceptors(promise, responseInterceptors);
13080      promise = promise.finally(completeOutstandingRequest);
13081
13082      return promise;
13083
13084
13085      function chainInterceptors(promise, interceptors) {
13086        for (var i = 0, ii = interceptors.length; i < ii;) {
13087          var thenFn = interceptors[i++];
13088          var rejectFn = interceptors[i++];
13089
13090          promise = promise.then(thenFn, rejectFn);
13091        }
13092
13093        interceptors.length = 0;
13094
13095        return promise;
13096      }
13097
13098      function completeOutstandingRequest() {
13099        $browser.$$completeOutstandingRequest(noop, '$http');
13100      }
13101
13102      function executeHeaderFns(headers, config) {
13103        var headerContent, processedHeaders = {};
13104
13105        forEach(headers, function(headerFn, header) {
13106          if (isFunction(headerFn)) {
13107            headerContent = headerFn(config);
13108            if (headerContent != null) {
13109              processedHeaders[header] = headerContent;
13110            }
13111          } else {
13112            processedHeaders[header] = headerFn;
13113          }
13114        });
13115
13116        return processedHeaders;
13117      }
13118
13119      function mergeHeaders(config) {
13120        var defHeaders = defaults.headers,
13121            reqHeaders = extend({}, config.headers),
13122            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
13123
13124        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
13125
13126        // using for-in instead of forEach to avoid unnecessary iteration after header has been found
13127        defaultHeadersIteration:
13128        for (defHeaderName in defHeaders) {
13129          lowercaseDefHeaderName = lowercase(defHeaderName);
13130
13131          for (reqHeaderName in reqHeaders) {
13132            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
13133              continue defaultHeadersIteration;
13134            }
13135          }
13136
13137          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
13138        }
13139
13140        // execute if header value is a function for merged headers
13141        return executeHeaderFns(reqHeaders, shallowCopy(config));
13142      }
13143
13144      function serverRequest(config) {
13145        var headers = config.headers;
13146        var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
13147
13148        // strip content-type if data is undefined
13149        if (isUndefined(reqData)) {
13150          forEach(headers, function(value, header) {
13151            if (lowercase(header) === 'content-type') {
13152              delete headers[header];
13153            }
13154          });
13155        }
13156
13157        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
13158          config.withCredentials = defaults.withCredentials;
13159        }
13160
13161        // send request
13162        return sendReq(config, reqData).then(transformResponse, transformResponse);
13163      }
13164
13165      function transformResponse(response) {
13166        // make a copy since the response must be cacheable
13167        var resp = extend({}, response);
13168        resp.data = transformData(response.data, response.headers, response.status,
13169                                  config.transformResponse);
13170        return (isSuccess(response.status))
13171          ? resp
13172          : $q.reject(resp);
13173      }
13174    }
13175
13176    $http.pendingRequests = [];
13177
13178    /**
13179     * @ngdoc method
13180     * @name $http#get
13181     *
13182     * @description
13183     * Shortcut method to perform `GET` request.
13184     *
13185     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
13186     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
13187     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13188     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13189     * See {@link ng.$http#$http-returns `$http()` return value}.
13190     */
13191
13192    /**
13193     * @ngdoc method
13194     * @name $http#delete
13195     *
13196     * @description
13197     * Shortcut method to perform `DELETE` request.
13198     *
13199     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
13200     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
13201     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13202     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13203     * See {@link ng.$http#$http-returns `$http()` return value}.
13204     */
13205
13206    /**
13207     * @ngdoc method
13208     * @name $http#head
13209     *
13210     * @description
13211     * Shortcut method to perform `HEAD` request.
13212     *
13213     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
13214     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
13215     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13216     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13217     * See {@link ng.$http#$http-returns `$http()` return value}.
13218     */
13219
13220    /**
13221     * @ngdoc method
13222     * @name $http#jsonp
13223     *
13224     * @description
13225     * Shortcut method to perform `JSONP` request.
13226     *
13227     * Note that, since JSONP requests are sensitive because the response is given full access to the browser,
13228     * the url must be declared, via {@link $sce} as a trusted resource URL.
13229     * You can trust a URL by adding it to the trusted resource URL list via
13230     * {@link $sceDelegateProvider#trustedResourceUrlList  `$sceDelegateProvider.trustedResourceUrlList`} or
13231     * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
13232     *
13233     * You should avoid generating the URL for the JSONP request from user provided data.
13234     * Provide additional query parameters via `params` property of the `config` parameter, rather than
13235     * modifying the URL itself.
13236     *
13237     * JSONP requests must specify a callback to be used in the response from the server. This callback
13238     * is passed as a query parameter in the request. You must specify the name of this parameter by
13239     * setting the `jsonpCallbackParam` property on the request config object.
13240     *
13241     * ```
13242     * $http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
13243     * ```
13244     *
13245     * You can also specify a default callback parameter name in `$http.defaults.jsonpCallbackParam`.
13246     * Initially this is set to `'callback'`.
13247     *
13248     * <div class="alert alert-danger">
13249     * You can no longer use the `JSON_CALLBACK` string as a placeholder for specifying where the callback
13250     * parameter value should go.
13251     * </div>
13252     *
13253     * If you would like to customise where and how the callbacks are stored then try overriding
13254     * or decorating the {@link $jsonpCallbacks} service.
13255     *
13256     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
13257     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
13258     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13259     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13260     * See {@link ng.$http#$http-returns `$http()` return value}.
13261     */
13262    createShortMethods('get', 'delete', 'head', 'jsonp');
13263
13264    /**
13265     * @ngdoc method
13266     * @name $http#post
13267     *
13268     * @description
13269     * Shortcut method to perform `POST` request.
13270     *
13271     * @param {string} url Relative or absolute URL specifying the destination of the request
13272     * @param {*} data Request content
13273     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13274     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13275     * See {@link ng.$http#$http-returns `$http()` return value}.
13276     */
13277
13278    /**
13279     * @ngdoc method
13280     * @name $http#put
13281     *
13282     * @description
13283     * Shortcut method to perform `PUT` request.
13284     *
13285     * @param {string} url Relative or absolute URL specifying the destination of the request
13286     * @param {*} data Request content
13287     * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13288     * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13289     * See {@link ng.$http#$http-returns `$http()` return value}.
13290     */
13291
13292     /**
13293      * @ngdoc method
13294      * @name $http#patch
13295      *
13296      * @description
13297      * Shortcut method to perform `PATCH` request.
13298      *
13299      * @param {string} url Relative or absolute URL specifying the destination of the request
13300      * @param {*} data Request content
13301      * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}.
13302      * @returns {HttpPromise}  A Promise that will be resolved or rejected with a response object.
13303      * See {@link ng.$http#$http-returns `$http()` return value}.
13304      */
13305    createShortMethodsWithData('post', 'put', 'patch');
13306
13307        /**
13308         * @ngdoc property
13309         * @name $http#defaults
13310         *
13311         * @description
13312         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
13313         * default headers, withCredentials as well as request and response transformations.
13314         *
13315         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
13316         */
13317    $http.defaults = defaults;
13318
13319
13320    return $http;
13321
13322
13323    function createShortMethods(names) {
13324      forEach(arguments, function(name) {
13325        $http[name] = function(url, config) {
13326          return $http(extend({}, config || {}, {
13327            method: name,
13328            url: url
13329          }));
13330        };
13331      });
13332    }
13333
13334
13335    function createShortMethodsWithData(name) {
13336      forEach(arguments, function(name) {
13337        $http[name] = function(url, data, config) {
13338          return $http(extend({}, config || {}, {
13339            method: name,
13340            url: url,
13341            data: data
13342          }));
13343        };
13344      });
13345    }
13346
13347
13348    /**
13349     * Makes the request.
13350     *
13351     * !!! ACCESSES CLOSURE VARS:
13352     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
13353     */
13354    function sendReq(config, reqData) {
13355      var deferred = $q.defer(),
13356          promise = deferred.promise,
13357          cache,
13358          cachedResp,
13359          reqHeaders = config.headers,
13360          isJsonp = lowercase(config.method) === 'jsonp',
13361          url = config.url;
13362
13363      if (isJsonp) {
13364        // JSONP is a pretty sensitive operation where we're allowing a script to have full access to
13365        // our DOM and JS space.  So we require that the URL satisfies SCE.RESOURCE_URL.
13366        url = $sce.getTrustedResourceUrl(url);
13367      } else if (!isString(url)) {
13368        // If it is not a string then the URL must be a $sce trusted object
13369        url = $sce.valueOf(url);
13370      }
13371
13372      url = buildUrl(url, config.paramSerializer(config.params));
13373
13374      if (isJsonp) {
13375        // Check the url and add the JSONP callback placeholder
13376        url = sanitizeJsonpCallbackParam(url, config.jsonpCallbackParam);
13377      }
13378
13379      $http.pendingRequests.push(config);
13380      promise.then(removePendingReq, removePendingReq);
13381
13382      if ((config.cache || defaults.cache) && config.cache !== false &&
13383          (config.method === 'GET' || config.method === 'JSONP')) {
13384        cache = isObject(config.cache) ? config.cache
13385            : isObject(/** @type {?} */ (defaults).cache)
13386              ? /** @type {?} */ (defaults).cache
13387              : defaultCache;
13388      }
13389
13390      if (cache) {
13391        cachedResp = cache.get(url);
13392        if (isDefined(cachedResp)) {
13393          if (isPromiseLike(cachedResp)) {
13394            // cached request has already been sent, but there is no response yet
13395            cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
13396          } else {
13397            // serving from cache
13398            if (isArray(cachedResp)) {
13399              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3], cachedResp[4]);
13400            } else {
13401              resolvePromise(cachedResp, 200, {}, 'OK', 'complete');
13402            }
13403          }
13404        } else {
13405          // put the promise for the non-transformed response into cache as a placeholder
13406          cache.put(url, promise);
13407        }
13408      }
13409
13410
13411      // if we won't have the response in cache, set the xsrf headers and
13412      // send the request to the backend
13413      if (isUndefined(cachedResp)) {
13414        var xsrfValue = urlIsAllowedOrigin(config.url)
13415            ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
13416            : undefined;
13417        if (xsrfValue) {
13418          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
13419        }
13420
13421        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
13422            config.withCredentials, config.responseType,
13423            createApplyHandlers(config.eventHandlers),
13424            createApplyHandlers(config.uploadEventHandlers));
13425      }
13426
13427      return promise;
13428
13429      function createApplyHandlers(eventHandlers) {
13430        if (eventHandlers) {
13431          var applyHandlers = {};
13432          forEach(eventHandlers, function(eventHandler, key) {
13433            applyHandlers[key] = function(event) {
13434              if (useApplyAsync) {
13435                $rootScope.$applyAsync(callEventHandler);
13436              } else if ($rootScope.$$phase) {
13437                callEventHandler();
13438              } else {
13439                $rootScope.$apply(callEventHandler);
13440              }
13441
13442              function callEventHandler() {
13443                eventHandler(event);
13444              }
13445            };
13446          });
13447          return applyHandlers;
13448        }
13449      }
13450
13451
13452      /**
13453       * Callback registered to $httpBackend():
13454       *  - caches the response if desired
13455       *  - resolves the raw $http promise
13456       *  - calls $apply
13457       */
13458      function done(status, response, headersString, statusText, xhrStatus) {
13459        if (cache) {
13460          if (isSuccess(status)) {
13461            cache.put(url, [status, response, parseHeaders(headersString), statusText, xhrStatus]);
13462          } else {
13463            // remove promise from the cache
13464            cache.remove(url);
13465          }
13466        }
13467
13468        function resolveHttpPromise() {
13469          resolvePromise(response, status, headersString, statusText, xhrStatus);
13470        }
13471
13472        if (useApplyAsync) {
13473          $rootScope.$applyAsync(resolveHttpPromise);
13474        } else {
13475          resolveHttpPromise();
13476          if (!$rootScope.$$phase) $rootScope.$apply();
13477        }
13478      }
13479
13480
13481      /**
13482       * Resolves the raw $http promise.
13483       */
13484      function resolvePromise(response, status, headers, statusText, xhrStatus) {
13485        //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
13486        status = status >= -1 ? status : 0;
13487
13488        (isSuccess(status) ? deferred.resolve : deferred.reject)({
13489          data: response,
13490          status: status,
13491          headers: headersGetter(headers),
13492          config: config,
13493          statusText: statusText,
13494          xhrStatus: xhrStatus
13495        });
13496      }
13497
13498      function resolvePromiseWithResult(result) {
13499        resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText, result.xhrStatus);
13500      }
13501
13502      function removePendingReq() {
13503        var idx = $http.pendingRequests.indexOf(config);
13504        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
13505      }
13506    }
13507
13508
13509    function buildUrl(url, serializedParams) {
13510      if (serializedParams.length > 0) {
13511        url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams;
13512      }
13513      return url;
13514    }
13515
13516    function sanitizeJsonpCallbackParam(url, cbKey) {
13517      var parts = url.split('?');
13518      if (parts.length > 2) {
13519        // Throw if the url contains more than one `?` query indicator
13520        throw $httpMinErr('badjsonp', 'Illegal use more than one "?", in url, "{1}"', url);
13521      }
13522      var params = parseKeyValue(parts[1]);
13523      forEach(params, function(value, key) {
13524        if (value === 'JSON_CALLBACK') {
13525          // Throw if the url already contains a reference to JSON_CALLBACK
13526          throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url);
13527        }
13528        if (key === cbKey) {
13529          // Throw if the callback param was already provided
13530          throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', cbKey, url);
13531        }
13532      });
13533
13534      // Add in the JSON_CALLBACK callback param value
13535      url += ((url.indexOf('?') === -1) ? '?' : '&') + cbKey + '=JSON_CALLBACK';
13536
13537      return url;
13538    }
13539  }];
13540}
13541
13542/**
13543 * @ngdoc service
13544 * @name $xhrFactory
13545 * @this
13546 *
13547 * @description
13548 * Factory function used to create XMLHttpRequest objects.
13549 *
13550 * Replace or decorate this service to create your own custom XMLHttpRequest objects.
13551 *
13552 * ```
13553 * angular.module('myApp', [])
13554 * .factory('$xhrFactory', function() {
13555 *   return function createXhr(method, url) {
13556 *     return new window.XMLHttpRequest({mozSystem: true});
13557 *   };
13558 * });
13559 * ```
13560 *
13561 * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
13562 * @param {string} url URL of the request.
13563 */
13564function $xhrFactoryProvider() {
13565  this.$get = function() {
13566    return function createXhr() {
13567      return new window.XMLHttpRequest();
13568    };
13569  };
13570}
13571
13572/**
13573 * @ngdoc service
13574 * @name $httpBackend
13575 * @requires $jsonpCallbacks
13576 * @requires $document
13577 * @requires $xhrFactory
13578 * @this
13579 *
13580 * @description
13581 * HTTP backend used by the {@link ng.$http service} that delegates to
13582 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
13583 *
13584 * You should never need to use this service directly, instead use the higher-level abstractions:
13585 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
13586 *
13587 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
13588 * $httpBackend} which can be trained with responses.
13589 */
13590function $HttpBackendProvider() {
13591  this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {
13592    return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);
13593  }];
13594}
13595
13596function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
13597  // TODO(vojta): fix the signature
13598  return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
13599    url = url || $browser.url();
13600
13601    if (lowercase(method) === 'jsonp') {
13602      var callbackPath = callbacks.createCallback(url);
13603      var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {
13604        // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)
13605        var response = (status === 200) && callbacks.getResponse(callbackPath);
13606        completeRequest(callback, status, response, '', text, 'complete');
13607        callbacks.removeCallback(callbackPath);
13608      });
13609    } else {
13610
13611      var xhr = createXhr(method, url);
13612      var abortedByTimeout = false;
13613
13614      xhr.open(method, url, true);
13615      forEach(headers, function(value, key) {
13616        if (isDefined(value)) {
13617            xhr.setRequestHeader(key, value);
13618        }
13619      });
13620
13621      xhr.onload = function requestLoaded() {
13622        var statusText = xhr.statusText || '';
13623
13624        // responseText is the old-school way of retrieving response (supported by IE9)
13625        // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
13626        var response = ('response' in xhr) ? xhr.response : xhr.responseText;
13627
13628        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
13629        var status = xhr.status === 1223 ? 204 : xhr.status;
13630
13631        // fix status code when it is 0 (0 status is undocumented).
13632        // Occurs when accessing file resources or on Android 4.1 stock browser
13633        // while retrieving files from application cache.
13634        if (status === 0) {
13635          status = response ? 200 : urlResolve(url).protocol === 'file' ? 404 : 0;
13636        }
13637
13638        completeRequest(callback,
13639            status,
13640            response,
13641            xhr.getAllResponseHeaders(),
13642            statusText,
13643            'complete');
13644      };
13645
13646      var requestError = function() {
13647        // The response is always empty
13648        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
13649        completeRequest(callback, -1, null, null, '', 'error');
13650      };
13651
13652      var requestAborted = function() {
13653        completeRequest(callback, -1, null, null, '', abortedByTimeout ? 'timeout' : 'abort');
13654      };
13655
13656      var requestTimeout = function() {
13657        // The response is always empty
13658        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
13659        completeRequest(callback, -1, null, null, '', 'timeout');
13660      };
13661
13662      xhr.onerror = requestError;
13663      xhr.ontimeout = requestTimeout;
13664      xhr.onabort = requestAborted;
13665
13666      forEach(eventHandlers, function(value, key) {
13667        xhr.addEventListener(key, value);
13668      });
13669
13670      forEach(uploadEventHandlers, function(value, key) {
13671        xhr.upload.addEventListener(key, value);
13672      });
13673
13674      if (withCredentials) {
13675        xhr.withCredentials = true;
13676      }
13677
13678      if (responseType) {
13679        try {
13680          xhr.responseType = responseType;
13681        } catch (e) {
13682          // WebKit added support for the json responseType value on 09/03/2013
13683          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
13684          // known to throw when setting the value "json" as the response type. Other older
13685          // browsers implementing the responseType
13686          //
13687          // The json response type can be ignored if not supported, because JSON payloads are
13688          // parsed on the client-side regardless.
13689          if (responseType !== 'json') {
13690            throw e;
13691          }
13692        }
13693      }
13694
13695      xhr.send(isUndefined(post) ? null : post);
13696    }
13697
13698    // Since we are using xhr.abort() when a request times out, we have to set a flag that
13699    // indicates to requestAborted if the request timed out or was aborted.
13700    //
13701    // http.timeout = numerical timeout   timeout
13702    // http.timeout = $timeout            timeout
13703    // http.timeout = promise             abort
13704    // xhr.abort()                        abort (The xhr object is normally inaccessible, but
13705    //                                    can be exposed with the xhrFactory)
13706    if (timeout > 0) {
13707      var timeoutId = $browserDefer(function() {
13708        timeoutRequest('timeout');
13709      }, timeout);
13710    } else if (isPromiseLike(timeout)) {
13711      timeout.then(function() {
13712        timeoutRequest(isDefined(timeout.$$timeoutId) ? 'timeout' : 'abort');
13713      });
13714    }
13715
13716    function timeoutRequest(reason) {
13717      abortedByTimeout = reason === 'timeout';
13718      if (jsonpDone) {
13719        jsonpDone();
13720      }
13721      if (xhr) {
13722        xhr.abort();
13723      }
13724    }
13725
13726    function completeRequest(callback, status, response, headersString, statusText, xhrStatus) {
13727      // cancel timeout and subsequent timeout promise resolution
13728      if (isDefined(timeoutId)) {
13729        $browserDefer.cancel(timeoutId);
13730      }
13731      jsonpDone = xhr = null;
13732
13733      callback(status, response, headersString, statusText, xhrStatus);
13734    }
13735  };
13736
13737  function jsonpReq(url, callbackPath, done) {
13738    url = url.replace('JSON_CALLBACK', callbackPath);
13739    // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
13740    // - fetches local scripts via XHR and evals them
13741    // - adds and immediately removes script elements from the document
13742    var script = rawDocument.createElement('script'), callback = null;
13743    script.type = 'text/javascript';
13744    script.src = url;
13745    script.async = true;
13746
13747    callback = function(event) {
13748      script.removeEventListener('load', callback);
13749      script.removeEventListener('error', callback);
13750      rawDocument.body.removeChild(script);
13751      script = null;
13752      var status = -1;
13753      var text = 'unknown';
13754
13755      if (event) {
13756        if (event.type === 'load' && !callbacks.wasCalled(callbackPath)) {
13757          event = { type: 'error' };
13758        }
13759        text = event.type;
13760        status = event.type === 'error' ? 404 : 200;
13761      }
13762
13763      if (done) {
13764        done(status, text);
13765      }
13766    };
13767
13768    script.addEventListener('load', callback);
13769    script.addEventListener('error', callback);
13770    rawDocument.body.appendChild(script);
13771    return callback;
13772  }
13773}
13774
13775var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
13776$interpolateMinErr.throwNoconcat = function(text) {
13777  throw $interpolateMinErr('noconcat',
13778      'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' +
13779      'interpolations that concatenate multiple expressions when a trusted value is ' +
13780      'required.  See http://docs.angularjs.org/api/ng.$sce', text);
13781};
13782
13783$interpolateMinErr.interr = function(text, err) {
13784  return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString());
13785};
13786
13787/**
13788 * @ngdoc provider
13789 * @name $interpolateProvider
13790 * @this
13791 *
13792 * @description
13793 *
13794 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
13795 *
13796 * <div class="alert alert-danger">
13797 * This feature is sometimes used to mix different markup languages, e.g. to wrap an AngularJS
13798 * template within a Python Jinja template (or any other template language). Mixing templating
13799 * languages is **very dangerous**. The embedding template language will not safely escape AngularJS
13800 * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
13801 * security bugs!
13802 * </div>
13803 *
13804 * @example
13805<example name="custom-interpolation-markup" module="customInterpolationApp">
13806<file name="index.html">
13807<script>
13808  var customInterpolationApp = angular.module('customInterpolationApp', []);
13809
13810  customInterpolationApp.config(function($interpolateProvider) {
13811    $interpolateProvider.startSymbol('//');
13812    $interpolateProvider.endSymbol('//');
13813  });
13814
13815
13816  customInterpolationApp.controller('DemoController', function() {
13817      this.label = "This binding is brought you by // interpolation symbols.";
13818  });
13819</script>
13820<div ng-controller="DemoController as demo">
13821    //demo.label//
13822</div>
13823</file>
13824<file name="protractor.js" type="protractor">
13825  it('should interpolate binding with custom symbols', function() {
13826    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
13827  });
13828</file>
13829</example>
13830 */
13831function $InterpolateProvider() {
13832  var startSymbol = '{{';
13833  var endSymbol = '}}';
13834
13835  /**
13836   * @ngdoc method
13837   * @name $interpolateProvider#startSymbol
13838   * @description
13839   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
13840   *
13841   * @param {string=} value new value to set the starting symbol to.
13842   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
13843   */
13844  this.startSymbol = function(value) {
13845    if (value) {
13846      startSymbol = value;
13847      return this;
13848    }
13849    return startSymbol;
13850  };
13851
13852  /**
13853   * @ngdoc method
13854   * @name $interpolateProvider#endSymbol
13855   * @description
13856   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
13857   *
13858   * @param {string=} value new value to set the ending symbol to.
13859   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
13860   */
13861  this.endSymbol = function(value) {
13862    if (value) {
13863      endSymbol = value;
13864      return this;
13865    }
13866    return endSymbol;
13867  };
13868
13869
13870  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
13871    var startSymbolLength = startSymbol.length,
13872        endSymbolLength = endSymbol.length,
13873        escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
13874        escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
13875
13876    function escape(ch) {
13877      return '\\\\\\' + ch;
13878    }
13879
13880    function unescapeText(text) {
13881      return text.replace(escapedStartRegexp, startSymbol).
13882        replace(escapedEndRegexp, endSymbol);
13883    }
13884
13885    // TODO: this is the same as the constantWatchDelegate in parse.js
13886    function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
13887      var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
13888        unwatch();
13889        return constantInterp(scope);
13890      }, listener, objectEquality);
13891      return unwatch;
13892    }
13893
13894    /**
13895     * @ngdoc service
13896     * @name $interpolate
13897     * @kind function
13898     *
13899     * @requires $parse
13900     * @requires $sce
13901     *
13902     * @description
13903     *
13904     * Compiles a string with markup into an interpolation function. This service is used by the
13905     * HTML {@link ng.$compile $compile} service for data binding. See
13906     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
13907     * interpolation markup.
13908     *
13909     *
13910     * ```js
13911     *   var $interpolate = ...; // injected
13912     *   var exp = $interpolate('Hello {{name | uppercase}}!');
13913     *   expect(exp({name:'AngularJS'})).toEqual('Hello ANGULARJS!');
13914     * ```
13915     *
13916     * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
13917     * `true`, the interpolation function will return `undefined` unless all embedded expressions
13918     * evaluate to a value other than `undefined`.
13919     *
13920     * ```js
13921     *   var $interpolate = ...; // injected
13922     *   var context = {greeting: 'Hello', name: undefined };
13923     *
13924     *   // default "forgiving" mode
13925     *   var exp = $interpolate('{{greeting}} {{name}}!');
13926     *   expect(exp(context)).toEqual('Hello !');
13927     *
13928     *   // "allOrNothing" mode
13929     *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
13930     *   expect(exp(context)).toBeUndefined();
13931     *   context.name = 'AngularJS';
13932     *   expect(exp(context)).toEqual('Hello AngularJS!');
13933     * ```
13934     *
13935     * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
13936     *
13937     * #### Escaped Interpolation
13938     * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
13939     * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
13940     * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
13941     * or binding.
13942     *
13943     * This enables web-servers to prevent script injection attacks and defacing attacks, to some
13944     * degree, while also enabling code examples to work without relying on the
13945     * {@link ng.directive:ngNonBindable ngNonBindable} directive.
13946     *
13947     * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
13948     * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
13949     * interpolation start/end markers with their escaped counterparts.**
13950     *
13951     * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
13952     * output when the $interpolate service processes the text. So, for HTML elements interpolated
13953     * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
13954     * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
13955     * this is typically useful only when user-data is used in rendering a template from the server, or
13956     * when otherwise untrusted data is used by a directive.
13957     *
13958     * <example name="interpolation">
13959     *  <file name="index.html">
13960     *    <div ng-init="username='A user'">
13961     *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
13962     *        </p>
13963     *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
13964     *        application, but fails to accomplish their task, because the server has correctly
13965     *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
13966     *        characters.</p>
13967     *      <p>Instead, the result of the attempted script injection is visible, and can be removed
13968     *        from the database by an administrator.</p>
13969     *    </div>
13970     *  </file>
13971     * </example>
13972     *
13973     * @knownIssue
13974     * It is currently not possible for an interpolated expression to contain the interpolation end
13975     * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
13976     * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
13977     *
13978     * @knownIssue
13979     * All directives and components must use the standard `{{` `}}` interpolation symbols
13980     * in their templates. If you change the application interpolation symbols the {@link $compile}
13981     * service will attempt to denormalize the standard symbols to the custom symbols.
13982     * The denormalization process is not clever enough to know not to replace instances of the standard
13983     * symbols where they would not normally be treated as interpolation symbols. For example in the following
13984     * code snippet the closing braces of the literal object will get incorrectly denormalized:
13985     *
13986     * ```
13987     * <div data-context='{"context":{"id":3,"type":"page"}}">
13988     * ```
13989     *
13990     * The workaround is to ensure that such instances are separated by whitespace:
13991     * ```
13992     * <div data-context='{"context":{"id":3,"type":"page"} }">
13993     * ```
13994     *
13995     * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.
13996     *
13997     * @param {string} text The text with markup to interpolate.
13998     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
13999     *    embedded expression in order to return an interpolation function. Strings with no
14000     *    embedded expression will return null for the interpolation function.
14001     * @param {string=} trustedContext when provided, the returned function passes the interpolated
14002     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
14003     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
14004     *    provides Strict Contextual Escaping for details.
14005     * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
14006     *    unless all embedded expressions evaluate to a value other than `undefined`.
14007     * @returns {function(context)} an interpolation function which is used to compute the
14008     *    interpolated string. The function has these parameters:
14009     *
14010     * - `context`: evaluation context for all expressions embedded in the interpolated text
14011     */
14012    function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
14013      var contextAllowsConcatenation = trustedContext === $sce.URL || trustedContext === $sce.MEDIA_URL;
14014
14015      // Provide a quick exit and simplified result function for text with no interpolation
14016      if (!text.length || text.indexOf(startSymbol) === -1) {
14017        if (mustHaveExpression) return;
14018
14019        var unescapedText = unescapeText(text);
14020        if (contextAllowsConcatenation) {
14021          unescapedText = $sce.getTrusted(trustedContext, unescapedText);
14022        }
14023        var constantInterp = valueFn(unescapedText);
14024        constantInterp.exp = text;
14025        constantInterp.expressions = [];
14026        constantInterp.$$watchDelegate = constantWatchDelegate;
14027
14028        return constantInterp;
14029      }
14030
14031      allOrNothing = !!allOrNothing;
14032      var startIndex,
14033          endIndex,
14034          index = 0,
14035          expressions = [],
14036          parseFns,
14037          textLength = text.length,
14038          exp,
14039          concat = [],
14040          expressionPositions = [],
14041          singleExpression;
14042
14043
14044      while (index < textLength) {
14045        if (((startIndex = text.indexOf(startSymbol, index)) !== -1) &&
14046             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) !== -1)) {
14047          if (index !== startIndex) {
14048            concat.push(unescapeText(text.substring(index, startIndex)));
14049          }
14050          exp = text.substring(startIndex + startSymbolLength, endIndex);
14051          expressions.push(exp);
14052          index = endIndex + endSymbolLength;
14053          expressionPositions.push(concat.length);
14054          concat.push(''); // Placeholder that will get replaced with the evaluated expression.
14055        } else {
14056          // we did not find an interpolation, so we have to add the remainder to the separators array
14057          if (index !== textLength) {
14058            concat.push(unescapeText(text.substring(index)));
14059          }
14060          break;
14061        }
14062      }
14063
14064      singleExpression = concat.length === 1 && expressionPositions.length === 1;
14065      // Intercept expression if we need to stringify concatenated inputs, which may be SCE trusted
14066      // objects rather than simple strings
14067      // (we don't modify the expression if the input consists of only a single trusted input)
14068      var interceptor = contextAllowsConcatenation && singleExpression ? undefined : parseStringifyInterceptor;
14069      parseFns = expressions.map(function(exp) { return $parse(exp, interceptor); });
14070
14071      // Concatenating expressions makes it hard to reason about whether some combination of
14072      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
14073      // single expression be used for some $sce-managed secure contexts (RESOURCE_URLs mostly),
14074      // we ensure that the value that's used is assigned or constructed by some JS code somewhere
14075      // that is more testable or make it obvious that you bound the value to some user controlled
14076      // value.  This helps reduce the load when auditing for XSS issues.
14077
14078      // Note that URL and MEDIA_URL $sce contexts do not need this, since `$sce` can sanitize the values
14079      // passed to it. In that case, `$sce.getTrusted` will be called on either the single expression
14080      // or on the overall concatenated string (losing trusted types used in the mix, by design).
14081      // Both these methods will sanitize plain strings. Also, HTML could be included, but since it's
14082      // only used in srcdoc attributes, this would not be very useful.
14083
14084      if (!mustHaveExpression || expressions.length) {
14085        var compute = function(values) {
14086          for (var i = 0, ii = expressions.length; i < ii; i++) {
14087            if (allOrNothing && isUndefined(values[i])) return;
14088            concat[expressionPositions[i]] = values[i];
14089          }
14090
14091          if (contextAllowsConcatenation) {
14092            // If `singleExpression` then `concat[0]` might be a "trusted" value or `null`, rather than a string
14093            return $sce.getTrusted(trustedContext, singleExpression ? concat[0] : concat.join(''));
14094          } else if (trustedContext && concat.length > 1) {
14095            // This context does not allow more than one part, e.g. expr + string or exp + exp.
14096            $interpolateMinErr.throwNoconcat(text);
14097          }
14098          // In an unprivileged context or only one part: just concatenate and return.
14099          return concat.join('');
14100        };
14101
14102        return extend(function interpolationFn(context) {
14103            var i = 0;
14104            var ii = expressions.length;
14105            var values = new Array(ii);
14106
14107            try {
14108              for (; i < ii; i++) {
14109                values[i] = parseFns[i](context);
14110              }
14111
14112              return compute(values);
14113            } catch (err) {
14114              $exceptionHandler($interpolateMinErr.interr(text, err));
14115            }
14116
14117          }, {
14118          // all of these properties are undocumented for now
14119          exp: text, //just for compatibility with regular watchers created via $watch
14120          expressions: expressions,
14121          $$watchDelegate: function(scope, listener) {
14122            var lastValue;
14123            return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) {
14124              var currValue = compute(values);
14125              listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
14126              lastValue = currValue;
14127            });
14128          }
14129        });
14130      }
14131
14132      function parseStringifyInterceptor(value) {
14133        try {
14134          // In concatenable contexts, getTrusted comes at the end, to avoid sanitizing individual
14135          // parts of a full URL. We don't care about losing the trustedness here.
14136          // In non-concatenable contexts, where there is only one expression, this interceptor is
14137          // not applied to the expression.
14138          value = (trustedContext && !contextAllowsConcatenation) ?
14139                    $sce.getTrusted(trustedContext, value) :
14140                    $sce.valueOf(value);
14141          return allOrNothing && !isDefined(value) ? value : stringify(value);
14142        } catch (err) {
14143          $exceptionHandler($interpolateMinErr.interr(text, err));
14144        }
14145      }
14146    }
14147
14148
14149    /**
14150     * @ngdoc method
14151     * @name $interpolate#startSymbol
14152     * @description
14153     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
14154     *
14155     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
14156     * the symbol.
14157     *
14158     * @returns {string} start symbol.
14159     */
14160    $interpolate.startSymbol = function() {
14161      return startSymbol;
14162    };
14163
14164
14165    /**
14166     * @ngdoc method
14167     * @name $interpolate#endSymbol
14168     * @description
14169     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
14170     *
14171     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
14172     * the symbol.
14173     *
14174     * @returns {string} end symbol.
14175     */
14176    $interpolate.endSymbol = function() {
14177      return endSymbol;
14178    };
14179
14180    return $interpolate;
14181  }];
14182}
14183
14184var $intervalMinErr = minErr('$interval');
14185
14186/** @this */
14187function $IntervalProvider() {
14188  this.$get = ['$$intervalFactory', '$window',
14189       function($$intervalFactory,   $window) {
14190    var intervals = {};
14191    var setIntervalFn = function(tick, delay, deferred) {
14192      var id = $window.setInterval(tick, delay);
14193      intervals[id] = deferred;
14194      return id;
14195    };
14196    var clearIntervalFn = function(id) {
14197      $window.clearInterval(id);
14198      delete intervals[id];
14199    };
14200
14201    /**
14202     * @ngdoc service
14203     * @name $interval
14204     *
14205     * @description
14206     * AngularJS's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
14207     * milliseconds.
14208     *
14209     * The return value of registering an interval function is a promise. This promise will be
14210     * notified upon each tick of the interval, and will be resolved after `count` iterations, or
14211     * run indefinitely if `count` is not defined. The value of the notification will be the
14212     * number of iterations that have run.
14213     * To cancel an interval, call `$interval.cancel(promise)`.
14214     *
14215     * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
14216     * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
14217     * time.
14218     *
14219     * <div class="alert alert-warning">
14220     * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
14221     * with them.  In particular they are not automatically destroyed when a controller's scope or a
14222     * directive's element are destroyed.
14223     * You should take this into consideration and make sure to always cancel the interval at the
14224     * appropriate moment.  See the example below for more details on how and when to do this.
14225     * </div>
14226     *
14227     * @param {function()} fn A function that should be called repeatedly. If no additional arguments
14228     *   are passed (see below), the function is called with the current iteration count.
14229     * @param {number} delay Number of milliseconds between each function call.
14230     * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
14231     *   indefinitely.
14232     * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14233     *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14234     * @param {...*=} Pass additional parameters to the executed function.
14235     * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete.
14236     *
14237     * @example
14238     * <example module="intervalExample" name="interval-service">
14239     * <file name="index.html">
14240     *   <script>
14241     *     angular.module('intervalExample', [])
14242     *       .controller('ExampleController', ['$scope', '$interval',
14243     *         function($scope, $interval) {
14244     *           $scope.format = 'M/d/yy h:mm:ss a';
14245     *           $scope.blood_1 = 100;
14246     *           $scope.blood_2 = 120;
14247     *
14248     *           var stop;
14249     *           $scope.fight = function() {
14250     *             // Don't start a new fight if we are already fighting
14251     *             if ( angular.isDefined(stop) ) return;
14252     *
14253     *             stop = $interval(function() {
14254     *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
14255     *                 $scope.blood_1 = $scope.blood_1 - 3;
14256     *                 $scope.blood_2 = $scope.blood_2 - 4;
14257     *               } else {
14258     *                 $scope.stopFight();
14259     *               }
14260     *             }, 100);
14261     *           };
14262     *
14263     *           $scope.stopFight = function() {
14264     *             if (angular.isDefined(stop)) {
14265     *               $interval.cancel(stop);
14266     *               stop = undefined;
14267     *             }
14268     *           };
14269     *
14270     *           $scope.resetFight = function() {
14271     *             $scope.blood_1 = 100;
14272     *             $scope.blood_2 = 120;
14273     *           };
14274     *
14275     *           $scope.$on('$destroy', function() {
14276     *             // Make sure that the interval is destroyed too
14277     *             $scope.stopFight();
14278     *           });
14279     *         }])
14280     *       // Register the 'myCurrentTime' directive factory method.
14281     *       // We inject $interval and dateFilter service since the factory method is DI.
14282     *       .directive('myCurrentTime', ['$interval', 'dateFilter',
14283     *         function($interval, dateFilter) {
14284     *           // return the directive link function. (compile function not needed)
14285     *           return function(scope, element, attrs) {
14286     *             var format,  // date format
14287     *                 stopTime; // so that we can cancel the time updates
14288     *
14289     *             // used to update the UI
14290     *             function updateTime() {
14291     *               element.text(dateFilter(new Date(), format));
14292     *             }
14293     *
14294     *             // watch the expression, and update the UI on change.
14295     *             scope.$watch(attrs.myCurrentTime, function(value) {
14296     *               format = value;
14297     *               updateTime();
14298     *             });
14299     *
14300     *             stopTime = $interval(updateTime, 1000);
14301     *
14302     *             // listen on DOM destroy (removal) event, and cancel the next UI update
14303     *             // to prevent updating time after the DOM element was removed.
14304     *             element.on('$destroy', function() {
14305     *               $interval.cancel(stopTime);
14306     *             });
14307     *           }
14308     *         }]);
14309     *   </script>
14310     *
14311     *   <div>
14312     *     <div ng-controller="ExampleController">
14313     *       <label>Date format: <input ng-model="format"></label> <hr/>
14314     *       Current time is: <span my-current-time="format"></span>
14315     *       <hr/>
14316     *       Blood 1 : <font color='red'>{{blood_1}}</font>
14317     *       Blood 2 : <font color='red'>{{blood_2}}</font>
14318     *       <button type="button" data-ng-click="fight()">Fight</button>
14319     *       <button type="button" data-ng-click="stopFight()">StopFight</button>
14320     *       <button type="button" data-ng-click="resetFight()">resetFight</button>
14321     *     </div>
14322     *   </div>
14323     *
14324     * </file>
14325     * </example>
14326     */
14327    var interval = $$intervalFactory(setIntervalFn, clearIntervalFn);
14328
14329    /**
14330     * @ngdoc method
14331     * @name $interval#cancel
14332     *
14333     * @description
14334     * Cancels a task associated with the `promise`.
14335     *
14336     * @param {Promise=} promise returned by the `$interval` function.
14337     * @returns {boolean} Returns `true` if the task was successfully canceled.
14338     */
14339    interval.cancel = function(promise) {
14340      if (!promise) return false;
14341
14342      if (!promise.hasOwnProperty('$$intervalId')) {
14343        throw $intervalMinErr('badprom',
14344            '`$interval.cancel()` called with a promise that was not generated by `$interval()`.');
14345      }
14346
14347      if (!intervals.hasOwnProperty(promise.$$intervalId)) return false;
14348
14349      var id = promise.$$intervalId;
14350      var deferred = intervals[id];
14351
14352      // Interval cancels should not report an unhandled promise.
14353      markQExceptionHandled(deferred.promise);
14354      deferred.reject('canceled');
14355      clearIntervalFn(id);
14356
14357      return true;
14358    };
14359
14360    return interval;
14361  }];
14362}
14363
14364/** @this */
14365function $$IntervalFactoryProvider() {
14366  this.$get = ['$browser', '$q', '$$q', '$rootScope',
14367       function($browser,   $q,   $$q,   $rootScope) {
14368    return function intervalFactory(setIntervalFn, clearIntervalFn) {
14369      return function intervalFn(fn, delay, count, invokeApply) {
14370        var hasParams = arguments.length > 4,
14371            args = hasParams ? sliceArgs(arguments, 4) : [],
14372            iteration = 0,
14373            skipApply = isDefined(invokeApply) && !invokeApply,
14374            deferred = (skipApply ? $$q : $q).defer(),
14375            promise = deferred.promise;
14376
14377        count = isDefined(count) ? count : 0;
14378
14379        function callback() {
14380          if (!hasParams) {
14381            fn(iteration);
14382          } else {
14383            fn.apply(null, args);
14384          }
14385        }
14386
14387        function tick() {
14388          if (skipApply) {
14389            $browser.defer(callback);
14390          } else {
14391            $rootScope.$evalAsync(callback);
14392          }
14393          deferred.notify(iteration++);
14394
14395          if (count > 0 && iteration >= count) {
14396            deferred.resolve(iteration);
14397            clearIntervalFn(promise.$$intervalId);
14398          }
14399
14400          if (!skipApply) $rootScope.$apply();
14401        }
14402
14403        promise.$$intervalId = setIntervalFn(tick, delay, deferred, skipApply);
14404
14405        return promise;
14406      };
14407    };
14408  }];
14409}
14410
14411/**
14412 * @ngdoc service
14413 * @name $jsonpCallbacks
14414 * @requires $window
14415 * @description
14416 * This service handles the lifecycle of callbacks to handle JSONP requests.
14417 * Override this service if you wish to customise where the callbacks are stored and
14418 * how they vary compared to the requested url.
14419 */
14420var $jsonpCallbacksProvider = /** @this */ function() {
14421  this.$get = function() {
14422    var callbacks = angular.callbacks;
14423    var callbackMap = {};
14424
14425    function createCallback(callbackId) {
14426      var callback = function(data) {
14427        callback.data = data;
14428        callback.called = true;
14429      };
14430      callback.id = callbackId;
14431      return callback;
14432    }
14433
14434    return {
14435      /**
14436       * @ngdoc method
14437       * @name $jsonpCallbacks#createCallback
14438       * @param {string} url the url of the JSONP request
14439       * @returns {string} the callback path to send to the server as part of the JSONP request
14440       * @description
14441       * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback
14442       * to pass to the server, which will be used to call the callback with its payload in the JSONP response.
14443       */
14444      createCallback: function(url) {
14445        var callbackId = '_' + (callbacks.$$counter++).toString(36);
14446        var callbackPath = 'angular.callbacks.' + callbackId;
14447        var callback = createCallback(callbackId);
14448        callbackMap[callbackPath] = callbacks[callbackId] = callback;
14449        return callbackPath;
14450      },
14451      /**
14452       * @ngdoc method
14453       * @name $jsonpCallbacks#wasCalled
14454       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
14455       * @returns {boolean} whether the callback has been called, as a result of the JSONP response
14456       * @description
14457       * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the
14458       * callback that was passed in the request.
14459       */
14460      wasCalled: function(callbackPath) {
14461        return callbackMap[callbackPath].called;
14462      },
14463      /**
14464       * @ngdoc method
14465       * @name $jsonpCallbacks#getResponse
14466       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
14467       * @returns {*} the data received from the response via the registered callback
14468       * @description
14469       * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback
14470       * in the JSONP response.
14471       */
14472      getResponse: function(callbackPath) {
14473        return callbackMap[callbackPath].data;
14474      },
14475      /**
14476       * @ngdoc method
14477       * @name $jsonpCallbacks#removeCallback
14478       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
14479       * @description
14480       * {@link $httpBackend} calls this method to remove the callback after the JSONP request has
14481       * completed or timed-out.
14482       */
14483      removeCallback: function(callbackPath) {
14484        var callback = callbackMap[callbackPath];
14485        delete callbacks[callback.id];
14486        delete callbackMap[callbackPath];
14487      }
14488    };
14489  };
14490};
14491
14492/**
14493 * @ngdoc service
14494 * @name $locale
14495 *
14496 * @description
14497 * $locale service provides localization rules for various AngularJS components. As of right now the
14498 * only public api is:
14499 *
14500 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
14501 */
14502
14503/* global stripHash: true */
14504
14505var PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/,
14506    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
14507var $locationMinErr = minErr('$location');
14508
14509
14510/**
14511 * Encode path using encodeUriSegment, ignoring forward slashes
14512 *
14513 * @param {string} path Path to encode
14514 * @returns {string}
14515 */
14516function encodePath(path) {
14517  var segments = path.split('/'),
14518      i = segments.length;
14519
14520  while (i--) {
14521    // decode forward slashes to prevent them from being double encoded
14522    segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/'));
14523  }
14524
14525  return segments.join('/');
14526}
14527
14528function decodePath(path, html5Mode) {
14529  var segments = path.split('/'),
14530      i = segments.length;
14531
14532  while (i--) {
14533    segments[i] = decodeURIComponent(segments[i]);
14534    if (html5Mode) {
14535      // encode forward slashes to prevent them from being mistaken for path separators
14536      segments[i] = segments[i].replace(/\//g, '%2F');
14537    }
14538  }
14539
14540  return segments.join('/');
14541}
14542
14543function normalizePath(pathValue, searchValue, hashValue) {
14544  var search = toKeyValue(searchValue),
14545    hash = hashValue ? '#' + encodeUriSegment(hashValue) : '',
14546    path = encodePath(pathValue);
14547
14548  return path + (search ? '?' + search : '') + hash;
14549}
14550
14551function parseAbsoluteUrl(absoluteUrl, locationObj) {
14552  var parsedUrl = urlResolve(absoluteUrl);
14553
14554  locationObj.$$protocol = parsedUrl.protocol;
14555  locationObj.$$host = parsedUrl.hostname;
14556  locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
14557}
14558
14559var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
14560function parseAppUrl(url, locationObj, html5Mode) {
14561
14562  if (DOUBLE_SLASH_REGEX.test(url)) {
14563    throw $locationMinErr('badpath', 'Invalid url "{0}".', url);
14564  }
14565
14566  var prefixed = (url.charAt(0) !== '/');
14567  if (prefixed) {
14568    url = '/' + url;
14569  }
14570  var match = urlResolve(url);
14571  var path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname;
14572  locationObj.$$path = decodePath(path, html5Mode);
14573  locationObj.$$search = parseKeyValue(match.search);
14574  locationObj.$$hash = decodeURIComponent(match.hash);
14575
14576  // make sure path starts with '/';
14577  if (locationObj.$$path && locationObj.$$path.charAt(0) !== '/') {
14578    locationObj.$$path = '/' + locationObj.$$path;
14579  }
14580}
14581
14582function startsWith(str, search) {
14583  return str.slice(0, search.length) === search;
14584}
14585
14586/**
14587 *
14588 * @param {string} base
14589 * @param {string} url
14590 * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
14591 *                   the expected string.
14592 */
14593function stripBaseUrl(base, url) {
14594  if (startsWith(url, base)) {
14595    return url.substr(base.length);
14596  }
14597}
14598
14599function stripHash(url) {
14600  var index = url.indexOf('#');
14601  return index === -1 ? url : url.substr(0, index);
14602}
14603
14604function stripFile(url) {
14605  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
14606}
14607
14608/* return the server only (scheme://host:port) */
14609function serverBase(url) {
14610  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
14611}
14612
14613
14614/**
14615 * LocationHtml5Url represents a URL
14616 * This object is exposed as $location service when HTML5 mode is enabled and supported
14617 *
14618 * @constructor
14619 * @param {string} appBase application base URL
14620 * @param {string} appBaseNoFile application base URL stripped of any filename
14621 * @param {string} basePrefix URL path prefix
14622 */
14623function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
14624  this.$$html5 = true;
14625  basePrefix = basePrefix || '';
14626  parseAbsoluteUrl(appBase, this);
14627
14628
14629  /**
14630   * Parse given HTML5 (regular) URL string into properties
14631   * @param {string} url HTML5 URL
14632   * @private
14633   */
14634  this.$$parse = function(url) {
14635    var pathUrl = stripBaseUrl(appBaseNoFile, url);
14636    if (!isString(pathUrl)) {
14637      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
14638          appBaseNoFile);
14639    }
14640
14641    parseAppUrl(pathUrl, this, true);
14642
14643    if (!this.$$path) {
14644      this.$$path = '/';
14645    }
14646
14647    this.$$compose();
14648  };
14649
14650  this.$$normalizeUrl = function(url) {
14651    return appBaseNoFile + url.substr(1); // first char is always '/'
14652  };
14653
14654  this.$$parseLinkUrl = function(url, relHref) {
14655    if (relHref && relHref[0] === '#') {
14656      // special case for links to hash fragments:
14657      // keep the old url and only replace the hash fragment
14658      this.hash(relHref.slice(1));
14659      return true;
14660    }
14661    var appUrl, prevAppUrl;
14662    var rewrittenUrl;
14663
14664
14665    if (isDefined(appUrl = stripBaseUrl(appBase, url))) {
14666      prevAppUrl = appUrl;
14667      if (basePrefix && isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) {
14668        rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl);
14669      } else {
14670        rewrittenUrl = appBase + prevAppUrl;
14671      }
14672    } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) {
14673      rewrittenUrl = appBaseNoFile + appUrl;
14674    } else if (appBaseNoFile === url + '/') {
14675      rewrittenUrl = appBaseNoFile;
14676    }
14677    if (rewrittenUrl) {
14678      this.$$parse(rewrittenUrl);
14679    }
14680    return !!rewrittenUrl;
14681  };
14682}
14683
14684
14685/**
14686 * LocationHashbangUrl represents URL
14687 * This object is exposed as $location service when developer doesn't opt into html5 mode.
14688 * It also serves as the base class for html5 mode fallback on legacy browsers.
14689 *
14690 * @constructor
14691 * @param {string} appBase application base URL
14692 * @param {string} appBaseNoFile application base URL stripped of any filename
14693 * @param {string} hashPrefix hashbang prefix
14694 */
14695function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
14696
14697  parseAbsoluteUrl(appBase, this);
14698
14699
14700  /**
14701   * Parse given hashbang URL into properties
14702   * @param {string} url Hashbang URL
14703   * @private
14704   */
14705  this.$$parse = function(url) {
14706    var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url);
14707    var withoutHashUrl;
14708
14709    if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
14710
14711      // The rest of the URL starts with a hash so we have
14712      // got either a hashbang path or a plain hash fragment
14713      withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);
14714      if (isUndefined(withoutHashUrl)) {
14715        // There was no hashbang prefix so we just have a hash fragment
14716        withoutHashUrl = withoutBaseUrl;
14717      }
14718
14719    } else {
14720      // There was no hashbang path nor hash fragment:
14721      // If we are in HTML5 mode we use what is left as the path;
14722      // Otherwise we ignore what is left
14723      if (this.$$html5) {
14724        withoutHashUrl = withoutBaseUrl;
14725      } else {
14726        withoutHashUrl = '';
14727        if (isUndefined(withoutBaseUrl)) {
14728          appBase = url;
14729          /** @type {?} */ (this).replace();
14730        }
14731      }
14732    }
14733
14734    parseAppUrl(withoutHashUrl, this, false);
14735
14736    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
14737
14738    this.$$compose();
14739
14740    /*
14741     * In Windows, on an anchor node on documents loaded from
14742     * the filesystem, the browser will return a pathname
14743     * prefixed with the drive name ('/C:/path') when a
14744     * pathname without a drive is set:
14745     *  * a.setAttribute('href', '/foo')
14746     *   * a.pathname === '/C:/foo' //true
14747     *
14748     * Inside of AngularJS, we're always using pathnames that
14749     * do not include drive names for routing.
14750     */
14751    function removeWindowsDriveName(path, url, base) {
14752      /*
14753      Matches paths for file protocol on windows,
14754      such as /C:/foo/bar, and captures only /foo/bar.
14755      */
14756      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
14757
14758      var firstPathSegmentMatch;
14759
14760      //Get the relative path from the input URL.
14761      if (startsWith(url, base)) {
14762        url = url.replace(base, '');
14763      }
14764
14765      // The input URL intentionally contains a first path segment that ends with a colon.
14766      if (windowsFilePathExp.exec(url)) {
14767        return path;
14768      }
14769
14770      firstPathSegmentMatch = windowsFilePathExp.exec(path);
14771      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
14772    }
14773  };
14774
14775  this.$$normalizeUrl = function(url) {
14776    return appBase + (url ? hashPrefix + url : '');
14777  };
14778
14779  this.$$parseLinkUrl = function(url, relHref) {
14780    if (stripHash(appBase) === stripHash(url)) {
14781      this.$$parse(url);
14782      return true;
14783    }
14784    return false;
14785  };
14786}
14787
14788
14789/**
14790 * LocationHashbangUrl represents URL
14791 * This object is exposed as $location service when html5 history api is enabled but the browser
14792 * does not support it.
14793 *
14794 * @constructor
14795 * @param {string} appBase application base URL
14796 * @param {string} appBaseNoFile application base URL stripped of any filename
14797 * @param {string} hashPrefix hashbang prefix
14798 */
14799function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
14800  this.$$html5 = true;
14801  LocationHashbangUrl.apply(this, arguments);
14802
14803  this.$$parseLinkUrl = function(url, relHref) {
14804    if (relHref && relHref[0] === '#') {
14805      // special case for links to hash fragments:
14806      // keep the old url and only replace the hash fragment
14807      this.hash(relHref.slice(1));
14808      return true;
14809    }
14810
14811    var rewrittenUrl;
14812    var appUrl;
14813
14814    if (appBase === stripHash(url)) {
14815      rewrittenUrl = url;
14816    } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {
14817      rewrittenUrl = appBase + hashPrefix + appUrl;
14818    } else if (appBaseNoFile === url + '/') {
14819      rewrittenUrl = appBaseNoFile;
14820    }
14821    if (rewrittenUrl) {
14822      this.$$parse(rewrittenUrl);
14823    }
14824    return !!rewrittenUrl;
14825  };
14826
14827  this.$$normalizeUrl = function(url) {
14828    // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
14829    return appBase + hashPrefix + url;
14830  };
14831}
14832
14833
14834var locationPrototype = {
14835
14836  /**
14837   * Ensure absolute URL is initialized.
14838   * @private
14839   */
14840  $$absUrl:'',
14841
14842  /**
14843   * Are we in html5 mode?
14844   * @private
14845   */
14846  $$html5: false,
14847
14848  /**
14849   * Has any change been replacing?
14850   * @private
14851   */
14852  $$replace: false,
14853
14854  /**
14855   * Compose url and update `url` and `absUrl` property
14856   * @private
14857   */
14858  $$compose: function() {
14859    this.$$url = normalizePath(this.$$path, this.$$search, this.$$hash);
14860    this.$$absUrl = this.$$normalizeUrl(this.$$url);
14861    this.$$urlUpdatedByLocation = true;
14862  },
14863
14864  /**
14865   * @ngdoc method
14866   * @name $location#absUrl
14867   *
14868   * @description
14869   * This method is getter only.
14870   *
14871   * Return full URL representation with all segments encoded according to rules specified in
14872   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
14873   *
14874   *
14875   * ```js
14876   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
14877   * var absUrl = $location.absUrl();
14878   * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
14879   * ```
14880   *
14881   * @return {string} full URL
14882   */
14883  absUrl: locationGetter('$$absUrl'),
14884
14885  /**
14886   * @ngdoc method
14887   * @name $location#url
14888   *
14889   * @description
14890   * This method is getter / setter.
14891   *
14892   * Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
14893   *
14894   * Change path, search and hash, when called with parameter and return `$location`.
14895   *
14896   *
14897   * ```js
14898   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
14899   * var url = $location.url();
14900   * // => "/some/path?foo=bar&baz=xoxo"
14901   * ```
14902   *
14903   * @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`)
14904   * @return {string} url
14905   */
14906  url: function(url) {
14907    if (isUndefined(url)) {
14908      return this.$$url;
14909    }
14910
14911    var match = PATH_MATCH.exec(url);
14912    if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
14913    if (match[2] || match[1] || url === '') this.search(match[3] || '');
14914    this.hash(match[5] || '');
14915
14916    return this;
14917  },
14918
14919  /**
14920   * @ngdoc method
14921   * @name $location#protocol
14922   *
14923   * @description
14924   * This method is getter only.
14925   *
14926   * Return protocol of current URL.
14927   *
14928   *
14929   * ```js
14930   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
14931   * var protocol = $location.protocol();
14932   * // => "http"
14933   * ```
14934   *
14935   * @return {string} protocol of current URL
14936   */
14937  protocol: locationGetter('$$protocol'),
14938
14939  /**
14940   * @ngdoc method
14941   * @name $location#host
14942   *
14943   * @description
14944   * This method is getter only.
14945   *
14946   * Return host of current URL.
14947   *
14948   * Note: compared to the non-AngularJS version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
14949   *
14950   *
14951   * ```js
14952   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
14953   * var host = $location.host();
14954   * // => "example.com"
14955   *
14956   * // given URL http://user:[email protected]:8080/#/some/path?foo=bar&baz=xoxo
14957   * host = $location.host();
14958   * // => "example.com"
14959   * host = location.host;
14960   * // => "example.com:8080"
14961   * ```
14962   *
14963   * @return {string} host of current URL.
14964   */
14965  host: locationGetter('$$host'),
14966
14967  /**
14968   * @ngdoc method
14969   * @name $location#port
14970   *
14971   * @description
14972   * This method is getter only.
14973   *
14974   * Return port of current URL.
14975   *
14976   *
14977   * ```js
14978   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
14979   * var port = $location.port();
14980   * // => 80
14981   * ```
14982   *
14983   * @return {Number} port
14984   */
14985  port: locationGetter('$$port'),
14986
14987  /**
14988   * @ngdoc method
14989   * @name $location#path
14990   *
14991   * @description
14992   * This method is getter / setter.
14993   *
14994   * Return path of current URL when called without any parameter.
14995   *
14996   * Change path when called with parameter and return `$location`.
14997   *
14998   * Note: Path should always begin with forward slash (/), this method will add the forward slash
14999   * if it is missing.
15000   *
15001   *
15002   * ```js
15003   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
15004   * var path = $location.path();
15005   * // => "/some/path"
15006   * ```
15007   *
15008   * @param {(string|number)=} path New path
15009   * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
15010   */
15011  path: locationGetterSetter('$$path', function(path) {
15012    path = path !== null ? path.toString() : '';
15013    return path.charAt(0) === '/' ? path : '/' + path;
15014  }),
15015
15016  /**
15017   * @ngdoc method
15018   * @name $location#search
15019   *
15020   * @description
15021   * This method is getter / setter.
15022   *
15023   * Return search part (as object) of current URL when called without any parameter.
15024   *
15025   * Change search part when called with parameter and return `$location`.
15026   *
15027   *
15028   * ```js
15029   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
15030   * var searchObject = $location.search();
15031   * // => {foo: 'bar', baz: 'xoxo'}
15032   *
15033   * // set foo to 'yipee'
15034   * $location.search('foo', 'yipee');
15035   * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
15036   * ```
15037   *
15038   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
15039   * hash object.
15040   *
15041   * When called with a single argument the method acts as a setter, setting the `search` component
15042   * of `$location` to the specified value.
15043   *
15044   * If the argument is a hash object containing an array of values, these values will be encoded
15045   * as duplicate search parameters in the URL.
15046   *
15047   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
15048   * will override only a single search property.
15049   *
15050   * If `paramValue` is an array, it will override the property of the `search` component of
15051   * `$location` specified via the first argument.
15052   *
15053   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
15054   *
15055   * If `paramValue` is `true`, the property specified via the first argument will be added with no
15056   * value nor trailing equal sign.
15057   *
15058   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
15059   * one or more arguments returns `$location` object itself.
15060   */
15061  search: function(search, paramValue) {
15062    switch (arguments.length) {
15063      case 0:
15064        return this.$$search;
15065      case 1:
15066        if (isString(search) || isNumber(search)) {
15067          search = search.toString();
15068          this.$$search = parseKeyValue(search);
15069        } else if (isObject(search)) {
15070          search = copy(search, {});
15071          // remove object undefined or null properties
15072          forEach(search, function(value, key) {
15073            if (value == null) delete search[key];
15074          });
15075
15076          this.$$search = search;
15077        } else {
15078          throw $locationMinErr('isrcharg',
15079              'The first argument of the `$location#search()` call must be a string or an object.');
15080        }
15081        break;
15082      default:
15083        if (isUndefined(paramValue) || paramValue === null) {
15084          delete this.$$search[search];
15085        } else {
15086          this.$$search[search] = paramValue;
15087        }
15088    }
15089
15090    this.$$compose();
15091    return this;
15092  },
15093
15094  /**
15095   * @ngdoc method
15096   * @name $location#hash
15097   *
15098   * @description
15099   * This method is getter / setter.
15100   *
15101   * Returns the hash fragment when called without any parameters.
15102   *
15103   * Changes the hash fragment when called with a parameter and returns `$location`.
15104   *
15105   *
15106   * ```js
15107   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
15108   * var hash = $location.hash();
15109   * // => "hashValue"
15110   * ```
15111   *
15112   * @param {(string|number)=} hash New hash fragment
15113   * @return {string} hash
15114   */
15115  hash: locationGetterSetter('$$hash', function(hash) {
15116    return hash !== null ? hash.toString() : '';
15117  }),
15118
15119  /**
15120   * @ngdoc method
15121   * @name $location#replace
15122   *
15123   * @description
15124   * If called, all changes to $location during the current `$digest` will replace the current history
15125   * record, instead of adding a new one.
15126   */
15127  replace: function() {
15128    this.$$replace = true;
15129    return this;
15130  }
15131};
15132
15133forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
15134  Location.prototype = Object.create(locationPrototype);
15135
15136  /**
15137   * @ngdoc method
15138   * @name $location#state
15139   *
15140   * @description
15141   * This method is getter / setter.
15142   *
15143   * Return the history state object when called without any parameter.
15144   *
15145   * Change the history state object when called with one parameter and return `$location`.
15146   * The state object is later passed to `pushState` or `replaceState`.
15147   *
15148   * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
15149   * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
15150   * older browsers (like IE9 or Android < 4.0), don't use this method.
15151   *
15152   * @param {object=} state State object for pushState or replaceState
15153   * @return {object} state
15154   */
15155  Location.prototype.state = function(state) {
15156    if (!arguments.length) {
15157      return this.$$state;
15158    }
15159
15160    if (Location !== LocationHtml5Url || !this.$$html5) {
15161      throw $locationMinErr('nostate', 'History API state support is available only ' +
15162        'in HTML5 mode and only in browsers supporting HTML5 History API');
15163    }
15164    // The user might modify `stateObject` after invoking `$location.state(stateObject)`
15165    // but we're changing the $$state reference to $browser.state() during the $digest
15166    // so the modification window is narrow.
15167    this.$$state = isUndefined(state) ? null : state;
15168    this.$$urlUpdatedByLocation = true;
15169
15170    return this;
15171  };
15172});
15173
15174
15175function locationGetter(property) {
15176  return /** @this */ function() {
15177    return this[property];
15178  };
15179}
15180
15181
15182function locationGetterSetter(property, preprocess) {
15183  return /** @this */ function(value) {
15184    if (isUndefined(value)) {
15185      return this[property];
15186    }
15187
15188    this[property] = preprocess(value);
15189    this.$$compose();
15190
15191    return this;
15192  };
15193}
15194
15195
15196/**
15197 * @ngdoc service
15198 * @name $location
15199 *
15200 * @requires $rootElement
15201 *
15202 * @description
15203 * The $location service parses the URL in the browser address bar (based on the
15204 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
15205 * available to your application. Changes to the URL in the address bar are reflected into
15206 * $location service and changes to $location are reflected into the browser address bar.
15207 *
15208 * **The $location service:**
15209 *
15210 * - Exposes the current URL in the browser address bar, so you can
15211 *   - Watch and observe the URL.
15212 *   - Change the URL.
15213 * - Synchronizes the URL with the browser when the user
15214 *   - Changes the address bar.
15215 *   - Clicks the back or forward button (or clicks a History link).
15216 *   - Clicks on a link.
15217 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
15218 *
15219 * For more information see {@link guide/$location Developer Guide: Using $location}
15220 */
15221
15222/**
15223 * @ngdoc provider
15224 * @name $locationProvider
15225 * @this
15226 *
15227 * @description
15228 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
15229 */
15230function $LocationProvider() {
15231  var hashPrefix = '!',
15232      html5Mode = {
15233        enabled: false,
15234        requireBase: true,
15235        rewriteLinks: true
15236      };
15237
15238  /**
15239   * @ngdoc method
15240   * @name $locationProvider#hashPrefix
15241   * @description
15242   * The default value for the prefix is `'!'`.
15243   * @param {string=} prefix Prefix for hash part (containing path and search)
15244   * @returns {*} current value if used as getter or itself (chaining) if used as setter
15245   */
15246  this.hashPrefix = function(prefix) {
15247    if (isDefined(prefix)) {
15248      hashPrefix = prefix;
15249      return this;
15250    } else {
15251      return hashPrefix;
15252    }
15253  };
15254
15255  /**
15256   * @ngdoc method
15257   * @name $locationProvider#html5Mode
15258   * @description
15259   * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
15260   *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
15261   *   properties:
15262   *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
15263   *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
15264   *     support `pushState`.
15265   *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
15266   *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
15267   *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
15268   *     See the {@link guide/$location $location guide for more information}
15269   *   - **rewriteLinks** - `{boolean|string}` - (default: `true`) When html5Mode is enabled,
15270   *     enables/disables URL rewriting for relative links. If set to a string, URL rewriting will
15271   *     only happen on links with an attribute that matches the given string. For example, if set
15272   *     to `'internal-link'`, then the URL will only be rewritten for `<a internal-link>` links.
15273   *     Note that [attribute name normalization](guide/directive#normalization) does not apply
15274   *     here, so `'internalLink'` will **not** match `'internal-link'`.
15275   *
15276   * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
15277   */
15278  this.html5Mode = function(mode) {
15279    if (isBoolean(mode)) {
15280      html5Mode.enabled = mode;
15281      return this;
15282    } else if (isObject(mode)) {
15283
15284      if (isBoolean(mode.enabled)) {
15285        html5Mode.enabled = mode.enabled;
15286      }
15287
15288      if (isBoolean(mode.requireBase)) {
15289        html5Mode.requireBase = mode.requireBase;
15290      }
15291
15292      if (isBoolean(mode.rewriteLinks) || isString(mode.rewriteLinks)) {
15293        html5Mode.rewriteLinks = mode.rewriteLinks;
15294      }
15295
15296      return this;
15297    } else {
15298      return html5Mode;
15299    }
15300  };
15301
15302  /**
15303   * @ngdoc event
15304   * @name $location#$locationChangeStart
15305   * @eventType broadcast on root scope
15306   * @description
15307   * Broadcasted before a URL will change.
15308   *
15309   * This change can be prevented by calling
15310   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
15311   * details about event object. Upon successful change
15312   * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
15313   *
15314   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
15315   * the browser supports the HTML5 History API.
15316   *
15317   * @param {Object} angularEvent Synthetic event object.
15318   * @param {string} newUrl New URL
15319   * @param {string=} oldUrl URL that was before it was changed.
15320   * @param {string=} newState New history state object
15321   * @param {string=} oldState History state object that was before it was changed.
15322   */
15323
15324  /**
15325   * @ngdoc event
15326   * @name $location#$locationChangeSuccess
15327   * @eventType broadcast on root scope
15328   * @description
15329   * Broadcasted after a URL was changed.
15330   *
15331   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
15332   * the browser supports the HTML5 History API.
15333   *
15334   * @param {Object} angularEvent Synthetic event object.
15335   * @param {string} newUrl New URL
15336   * @param {string=} oldUrl URL that was before it was changed.
15337   * @param {string=} newState New history state object
15338   * @param {string=} oldState History state object that was before it was changed.
15339   */
15340
15341  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
15342      function($rootScope, $browser, $sniffer, $rootElement, $window) {
15343    var $location,
15344        LocationMode,
15345        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
15346        initialUrl = $browser.url(),
15347        appBase;
15348
15349    if (html5Mode.enabled) {
15350      if (!baseHref && html5Mode.requireBase) {
15351        throw $locationMinErr('nobase',
15352          '$location in HTML5 mode requires a <base> tag to be present!');
15353      }
15354      appBase = serverBase(initialUrl) + (baseHref || '/');
15355      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
15356    } else {
15357      appBase = stripHash(initialUrl);
15358      LocationMode = LocationHashbangUrl;
15359    }
15360    var appBaseNoFile = stripFile(appBase);
15361
15362    $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
15363    $location.$$parseLinkUrl(initialUrl, initialUrl);
15364
15365    $location.$$state = $browser.state();
15366
15367    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
15368
15369    // Determine if two URLs are equal despite potentially having different encoding/normalizing
15370    //  such as $location.absUrl() vs $browser.url()
15371    // See https://github.com/angular/angular.js/issues/16592
15372    function urlsEqual(a, b) {
15373      return a === b || urlResolve(a).href === urlResolve(b).href;
15374    }
15375
15376    function setBrowserUrlWithFallback(url, replace, state) {
15377      var oldUrl = $location.url();
15378      var oldState = $location.$$state;
15379      try {
15380        $browser.url(url, replace, state);
15381
15382        // Make sure $location.state() returns referentially identical (not just deeply equal)
15383        // state object; this makes possible quick checking if the state changed in the digest
15384        // loop. Checking deep equality would be too expensive.
15385        $location.$$state = $browser.state();
15386      } catch (e) {
15387        // Restore old values if pushState fails
15388        $location.url(oldUrl);
15389        $location.$$state = oldState;
15390
15391        throw e;
15392      }
15393    }
15394
15395    $rootElement.on('click', function(event) {
15396      var rewriteLinks = html5Mode.rewriteLinks;
15397      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
15398      // currently we open nice url link and redirect then
15399
15400      if (!rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return;
15401
15402      var elm = jqLite(event.target);
15403
15404      // traverse the DOM up to find first A tag
15405      while (nodeName_(elm[0]) !== 'a') {
15406        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
15407        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
15408      }
15409
15410      if (isString(rewriteLinks) && isUndefined(elm.attr(rewriteLinks))) return;
15411
15412      var absHref = elm.prop('href');
15413      // get the actual href attribute - see
15414      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
15415      var relHref = elm.attr('href') || elm.attr('xlink:href');
15416
15417      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
15418        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
15419        // an animation.
15420        absHref = urlResolve(absHref.animVal).href;
15421      }
15422
15423      // Ignore when url is started with javascript: or mailto:
15424      if (IGNORE_URI_REGEXP.test(absHref)) return;
15425
15426      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
15427        if ($location.$$parseLinkUrl(absHref, relHref)) {
15428          // We do a preventDefault for all urls that are part of the AngularJS application,
15429          // in html5mode and also without, so that we are able to abort navigation without
15430          // getting double entries in the location history.
15431          event.preventDefault();
15432          // update location manually
15433          if ($location.absUrl() !== $browser.url()) {
15434            $rootScope.$apply();
15435          }
15436        }
15437      }
15438    });
15439
15440
15441    // rewrite hashbang url <> html5 url
15442    if ($location.absUrl() !== initialUrl) {
15443      $browser.url($location.absUrl(), true);
15444    }
15445
15446    var initializing = true;
15447
15448    // update $location when $browser url changes
15449    $browser.onUrlChange(function(newUrl, newState) {
15450
15451      if (!startsWith(newUrl, appBaseNoFile)) {
15452        // If we are navigating outside of the app then force a reload
15453        $window.location.href = newUrl;
15454        return;
15455      }
15456
15457      $rootScope.$evalAsync(function() {
15458        var oldUrl = $location.absUrl();
15459        var oldState = $location.$$state;
15460        var defaultPrevented;
15461        $location.$$parse(newUrl);
15462        $location.$$state = newState;
15463
15464        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
15465            newState, oldState).defaultPrevented;
15466
15467        // if the location was changed by a `$locationChangeStart` handler then stop
15468        // processing this location change
15469        if ($location.absUrl() !== newUrl) return;
15470
15471        if (defaultPrevented) {
15472          $location.$$parse(oldUrl);
15473          $location.$$state = oldState;
15474          setBrowserUrlWithFallback(oldUrl, false, oldState);
15475        } else {
15476          initializing = false;
15477          afterLocationChange(oldUrl, oldState);
15478        }
15479      });
15480      if (!$rootScope.$$phase) $rootScope.$digest();
15481    });
15482
15483    // update browser
15484    $rootScope.$watch(function $locationWatch() {
15485      if (initializing || $location.$$urlUpdatedByLocation) {
15486        $location.$$urlUpdatedByLocation = false;
15487
15488        var oldUrl = $browser.url();
15489        var newUrl = $location.absUrl();
15490        var oldState = $browser.state();
15491        var currentReplace = $location.$$replace;
15492        var urlOrStateChanged = !urlsEqual(oldUrl, newUrl) ||
15493          ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
15494
15495        if (initializing || urlOrStateChanged) {
15496          initializing = false;
15497
15498          $rootScope.$evalAsync(function() {
15499            var newUrl = $location.absUrl();
15500            var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
15501                $location.$$state, oldState).defaultPrevented;
15502
15503            // if the location was changed by a `$locationChangeStart` handler then stop
15504            // processing this location change
15505            if ($location.absUrl() !== newUrl) return;
15506
15507            if (defaultPrevented) {
15508              $location.$$parse(oldUrl);
15509              $location.$$state = oldState;
15510            } else {
15511              if (urlOrStateChanged) {
15512                setBrowserUrlWithFallback(newUrl, currentReplace,
15513                                          oldState === $location.$$state ? null : $location.$$state);
15514              }
15515              afterLocationChange(oldUrl, oldState);
15516            }
15517          });
15518        }
15519      }
15520
15521      $location.$$replace = false;
15522
15523      // we don't need to return anything because $evalAsync will make the digest loop dirty when
15524      // there is a change
15525    });
15526
15527    return $location;
15528
15529    function afterLocationChange(oldUrl, oldState) {
15530      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
15531        $location.$$state, oldState);
15532    }
15533}];
15534}
15535
15536/**
15537 * @ngdoc service
15538 * @name $log
15539 * @requires $window
15540 *
15541 * @description
15542 * Simple service for logging. Default implementation safely writes the message
15543 * into the browser's console (if present).
15544 *
15545 * The main purpose of this service is to simplify debugging and troubleshooting.
15546 *
15547 * To reveal the location of the calls to `$log` in the JavaScript console,
15548 * you can "blackbox" the AngularJS source in your browser:
15549 *
15550 * [Mozilla description of blackboxing](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Black_box_a_source).
15551 * [Chrome description of blackboxing](https://developer.chrome.com/devtools/docs/blackboxing).
15552 *
15553 * Note: Not all browsers support blackboxing.
15554 *
15555 * The default is to log `debug` messages. You can use
15556 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
15557 *
15558 * @example
15559   <example module="logExample" name="log-service">
15560     <file name="script.js">
15561       angular.module('logExample', [])
15562         .controller('LogController', ['$scope', '$log', function($scope, $log) {
15563           $scope.$log = $log;
15564           $scope.message = 'Hello World!';
15565         }]);
15566     </file>
15567     <file name="index.html">
15568       <div ng-controller="LogController">
15569         <p>Reload this page with open console, enter text and hit the log button...</p>
15570         <label>Message:
15571         <input type="text" ng-model="message" /></label>
15572         <button ng-click="$log.log(message)">log</button>
15573         <button ng-click="$log.warn(message)">warn</button>
15574         <button ng-click="$log.info(message)">info</button>
15575         <button ng-click="$log.error(message)">error</button>
15576         <button ng-click="$log.debug(message)">debug</button>
15577       </div>
15578     </file>
15579   </example>
15580 */
15581
15582/**
15583 * @ngdoc provider
15584 * @name $logProvider
15585 * @this
15586 *
15587 * @description
15588 * Use the `$logProvider` to configure how the application logs messages
15589 */
15590function $LogProvider() {
15591  var debug = true,
15592      self = this;
15593
15594  /**
15595   * @ngdoc method
15596   * @name $logProvider#debugEnabled
15597   * @description
15598   * @param {boolean=} flag enable or disable debug level messages
15599   * @returns {*} current value if used as getter or itself (chaining) if used as setter
15600   */
15601  this.debugEnabled = function(flag) {
15602    if (isDefined(flag)) {
15603      debug = flag;
15604      return this;
15605    } else {
15606      return debug;
15607    }
15608  };
15609
15610  this.$get = ['$window', function($window) {
15611    // Support: IE 9-11, Edge 12-14+
15612    // IE/Edge display errors in such a way that it requires the user to click in 4 places
15613    // to see the stack trace. There is no way to feature-detect it so there's a chance
15614    // of the user agent sniffing to go wrong but since it's only about logging, this shouldn't
15615    // break apps. Other browsers display errors in a sensible way and some of them map stack
15616    // traces along source maps if available so it makes sense to let browsers display it
15617    // as they want.
15618    var formatStackTrace = msie || /\bEdge\//.test($window.navigator && $window.navigator.userAgent);
15619
15620    return {
15621      /**
15622       * @ngdoc method
15623       * @name $log#log
15624       *
15625       * @description
15626       * Write a log message
15627       */
15628      log: consoleLog('log'),
15629
15630      /**
15631       * @ngdoc method
15632       * @name $log#info
15633       *
15634       * @description
15635       * Write an information message
15636       */
15637      info: consoleLog('info'),
15638
15639      /**
15640       * @ngdoc method
15641       * @name $log#warn
15642       *
15643       * @description
15644       * Write a warning message
15645       */
15646      warn: consoleLog('warn'),
15647
15648      /**
15649       * @ngdoc method
15650       * @name $log#error
15651       *
15652       * @description
15653       * Write an error message
15654       */
15655      error: consoleLog('error'),
15656
15657      /**
15658       * @ngdoc method
15659       * @name $log#debug
15660       *
15661       * @description
15662       * Write a debug message
15663       */
15664      debug: (function() {
15665        var fn = consoleLog('debug');
15666
15667        return function() {
15668          if (debug) {
15669            fn.apply(self, arguments);
15670          }
15671        };
15672      })()
15673    };
15674
15675    function formatError(arg) {
15676      if (isError(arg)) {
15677        if (arg.stack && formatStackTrace) {
15678          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
15679              ? 'Error: ' + arg.message + '\n' + arg.stack
15680              : arg.stack;
15681        } else if (arg.sourceURL) {
15682          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
15683        }
15684      }
15685      return arg;
15686    }
15687
15688    function consoleLog(type) {
15689      var console = $window.console || {},
15690          logFn = console[type] || console.log || noop;
15691
15692      return function() {
15693        var args = [];
15694        forEach(arguments, function(arg) {
15695          args.push(formatError(arg));
15696        });
15697        // Support: IE 9 only
15698        // console methods don't inherit from Function.prototype in IE 9 so we can't
15699        // call `logFn.apply(console, args)` directly.
15700        return Function.prototype.apply.call(logFn, console, args);
15701      };
15702    }
15703  }];
15704}
15705
15706/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15707 *     Any commits to this file should be reviewed with security in mind.  *
15708 *   Changes to this file can potentially create security vulnerabilities. *
15709 *          An approval from 2 Core members with history of modifying      *
15710 *                         this file is required.                          *
15711 *                                                                         *
15712 *  Does the change somehow allow for arbitrary javascript to be executed? *
15713 *    Or allows for someone to change the prototype of built-in objects?   *
15714 *     Or gives undesired access to variables likes document or window?    *
15715 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15716
15717var $parseMinErr = minErr('$parse');
15718
15719var objectValueOf = {}.constructor.prototype.valueOf;
15720
15721// Sandboxing AngularJS Expressions
15722// ------------------------------
15723// AngularJS expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by
15724// various means such as obtaining a reference to native JS functions like the Function constructor.
15725//
15726// As an example, consider the following AngularJS expression:
15727//
15728//   {}.toString.constructor('alert("evil JS code")')
15729//
15730// It is important to realize that if you create an expression from a string that contains user provided
15731// content then it is possible that your application contains a security vulnerability to an XSS style attack.
15732//
15733// See https://docs.angularjs.org/guide/security
15734
15735
15736function getStringValue(name) {
15737  // Property names must be strings. This means that non-string objects cannot be used
15738  // as keys in an object. Any non-string object, including a number, is typecasted
15739  // into a string via the toString method.
15740  // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
15741  //
15742  // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
15743  // to a string. It's not always possible. If `name` is an object and its `toString` method is
15744  // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
15745  //
15746  // TypeError: Cannot convert object to primitive value
15747  //
15748  // For performance reasons, we don't catch this error here and allow it to propagate up the call
15749  // stack. Note that you'll get the same error in JavaScript if you try to access a property using
15750  // such a 'broken' object as a key.
15751  return name + '';
15752}
15753
15754
15755var OPERATORS = createMap();
15756forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
15757var ESCAPE = {'n':'\n', 'f':'\f', 'r':'\r', 't':'\t', 'v':'\v', '\'':'\'', '"':'"'};
15758
15759
15760/////////////////////////////////////////
15761
15762
15763/**
15764 * @constructor
15765 */
15766var Lexer = function Lexer(options) {
15767  this.options = options;
15768};
15769
15770Lexer.prototype = {
15771  constructor: Lexer,
15772
15773  lex: function(text) {
15774    this.text = text;
15775    this.index = 0;
15776    this.tokens = [];
15777
15778    while (this.index < this.text.length) {
15779      var ch = this.text.charAt(this.index);
15780      if (ch === '"' || ch === '\'') {
15781        this.readString(ch);
15782      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
15783        this.readNumber();
15784      } else if (this.isIdentifierStart(this.peekMultichar())) {
15785        this.readIdent();
15786      } else if (this.is(ch, '(){}[].,;:?')) {
15787        this.tokens.push({index: this.index, text: ch});
15788        this.index++;
15789      } else if (this.isWhitespace(ch)) {
15790        this.index++;
15791      } else {
15792        var ch2 = ch + this.peek();
15793        var ch3 = ch2 + this.peek(2);
15794        var op1 = OPERATORS[ch];
15795        var op2 = OPERATORS[ch2];
15796        var op3 = OPERATORS[ch3];
15797        if (op1 || op2 || op3) {
15798          var token = op3 ? ch3 : (op2 ? ch2 : ch);
15799          this.tokens.push({index: this.index, text: token, operator: true});
15800          this.index += token.length;
15801        } else {
15802          this.throwError('Unexpected next character ', this.index, this.index + 1);
15803        }
15804      }
15805    }
15806    return this.tokens;
15807  },
15808
15809  is: function(ch, chars) {
15810    return chars.indexOf(ch) !== -1;
15811  },
15812
15813  peek: function(i) {
15814    var num = i || 1;
15815    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
15816  },
15817
15818  isNumber: function(ch) {
15819    return ('0' <= ch && ch <= '9') && typeof ch === 'string';
15820  },
15821
15822  isWhitespace: function(ch) {
15823    // IE treats non-breaking space as \u00A0
15824    return (ch === ' ' || ch === '\r' || ch === '\t' ||
15825            ch === '\n' || ch === '\v' || ch === '\u00A0');
15826  },
15827
15828  isIdentifierStart: function(ch) {
15829    return this.options.isIdentifierStart ?
15830        this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
15831        this.isValidIdentifierStart(ch);
15832  },
15833
15834  isValidIdentifierStart: function(ch) {
15835    return ('a' <= ch && ch <= 'z' ||
15836            'A' <= ch && ch <= 'Z' ||
15837            '_' === ch || ch === '$');
15838  },
15839
15840  isIdentifierContinue: function(ch) {
15841    return this.options.isIdentifierContinue ?
15842        this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
15843        this.isValidIdentifierContinue(ch);
15844  },
15845
15846  isValidIdentifierContinue: function(ch, cp) {
15847    return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
15848  },
15849
15850  codePointAt: function(ch) {
15851    if (ch.length === 1) return ch.charCodeAt(0);
15852    // eslint-disable-next-line no-bitwise
15853    return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
15854  },
15855
15856  peekMultichar: function() {
15857    var ch = this.text.charAt(this.index);
15858    var peek = this.peek();
15859    if (!peek) {
15860      return ch;
15861    }
15862    var cp1 = ch.charCodeAt(0);
15863    var cp2 = peek.charCodeAt(0);
15864    if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
15865      return ch + peek;
15866    }
15867    return ch;
15868  },
15869
15870  isExpOperator: function(ch) {
15871    return (ch === '-' || ch === '+' || this.isNumber(ch));
15872  },
15873
15874  throwError: function(error, start, end) {
15875    end = end || this.index;
15876    var colStr = (isDefined(start)
15877            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
15878            : ' ' + end);
15879    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
15880        error, colStr, this.text);
15881  },
15882
15883  readNumber: function() {
15884    var number = '';
15885    var start = this.index;
15886    while (this.index < this.text.length) {
15887      var ch = lowercase(this.text.charAt(this.index));
15888      if (ch === '.' || this.isNumber(ch)) {
15889        number += ch;
15890      } else {
15891        var peekCh = this.peek();
15892        if (ch === 'e' && this.isExpOperator(peekCh)) {
15893          number += ch;
15894        } else if (this.isExpOperator(ch) &&
15895            peekCh && this.isNumber(peekCh) &&
15896            number.charAt(number.length - 1) === 'e') {
15897          number += ch;
15898        } else if (this.isExpOperator(ch) &&
15899            (!peekCh || !this.isNumber(peekCh)) &&
15900            number.charAt(number.length - 1) === 'e') {
15901          this.throwError('Invalid exponent');
15902        } else {
15903          break;
15904        }
15905      }
15906      this.index++;
15907    }
15908    this.tokens.push({
15909      index: start,
15910      text: number,
15911      constant: true,
15912      value: Number(number)
15913    });
15914  },
15915
15916  readIdent: function() {
15917    var start = this.index;
15918    this.index += this.peekMultichar().length;
15919    while (this.index < this.text.length) {
15920      var ch = this.peekMultichar();
15921      if (!this.isIdentifierContinue(ch)) {
15922        break;
15923      }
15924      this.index += ch.length;
15925    }
15926    this.tokens.push({
15927      index: start,
15928      text: this.text.slice(start, this.index),
15929      identifier: true
15930    });
15931  },
15932
15933  readString: function(quote) {
15934    var start = this.index;
15935    this.index++;
15936    var string = '';
15937    var rawString = quote;
15938    var escape = false;
15939    while (this.index < this.text.length) {
15940      var ch = this.text.charAt(this.index);
15941      rawString += ch;
15942      if (escape) {
15943        if (ch === 'u') {
15944          var hex = this.text.substring(this.index + 1, this.index + 5);
15945          if (!hex.match(/[\da-f]{4}/i)) {
15946            this.throwError('Invalid unicode escape [\\u' + hex + ']');
15947          }
15948          this.index += 4;
15949          string += String.fromCharCode(parseInt(hex, 16));
15950        } else {
15951          var rep = ESCAPE[ch];
15952          string = string + (rep || ch);
15953        }
15954        escape = false;
15955      } else if (ch === '\\') {
15956        escape = true;
15957      } else if (ch === quote) {
15958        this.index++;
15959        this.tokens.push({
15960          index: start,
15961          text: rawString,
15962          constant: true,
15963          value: string
15964        });
15965        return;
15966      } else {
15967        string += ch;
15968      }
15969      this.index++;
15970    }
15971    this.throwError('Unterminated quote', start);
15972  }
15973};
15974
15975var AST = function AST(lexer, options) {
15976  this.lexer = lexer;
15977  this.options = options;
15978};
15979
15980AST.Program = 'Program';
15981AST.ExpressionStatement = 'ExpressionStatement';
15982AST.AssignmentExpression = 'AssignmentExpression';
15983AST.ConditionalExpression = 'ConditionalExpression';
15984AST.LogicalExpression = 'LogicalExpression';
15985AST.BinaryExpression = 'BinaryExpression';
15986AST.UnaryExpression = 'UnaryExpression';
15987AST.CallExpression = 'CallExpression';
15988AST.MemberExpression = 'MemberExpression';
15989AST.Identifier = 'Identifier';
15990AST.Literal = 'Literal';
15991AST.ArrayExpression = 'ArrayExpression';
15992AST.Property = 'Property';
15993AST.ObjectExpression = 'ObjectExpression';
15994AST.ThisExpression = 'ThisExpression';
15995AST.LocalsExpression = 'LocalsExpression';
15996
15997// Internal use only
15998AST.NGValueParameter = 'NGValueParameter';
15999
16000AST.prototype = {
16001  ast: function(text) {
16002    this.text = text;
16003    this.tokens = this.lexer.lex(text);
16004
16005    var value = this.program();
16006
16007    if (this.tokens.length !== 0) {
16008      this.throwError('is an unexpected token', this.tokens[0]);
16009    }
16010
16011    return value;
16012  },
16013
16014  program: function() {
16015    var body = [];
16016    while (true) {
16017      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
16018        body.push(this.expressionStatement());
16019      if (!this.expect(';')) {
16020        return { type: AST.Program, body: body};
16021      }
16022    }
16023  },
16024
16025  expressionStatement: function() {
16026    return { type: AST.ExpressionStatement, expression: this.filterChain() };
16027  },
16028
16029  filterChain: function() {
16030    var left = this.expression();
16031    while (this.expect('|')) {
16032      left = this.filter(left);
16033    }
16034    return left;
16035  },
16036
16037  expression: function() {
16038    return this.assignment();
16039  },
16040
16041  assignment: function() {
16042    var result = this.ternary();
16043    if (this.expect('=')) {
16044      if (!isAssignable(result)) {
16045        throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
16046      }
16047
16048      result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
16049    }
16050    return result;
16051  },
16052
16053  ternary: function() {
16054    var test = this.logicalOR();
16055    var alternate;
16056    var consequent;
16057    if (this.expect('?')) {
16058      alternate = this.expression();
16059      if (this.consume(':')) {
16060        consequent = this.expression();
16061        return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
16062      }
16063    }
16064    return test;
16065  },
16066
16067  logicalOR: function() {
16068    var left = this.logicalAND();
16069    while (this.expect('||')) {
16070      left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
16071    }
16072    return left;
16073  },
16074
16075  logicalAND: function() {
16076    var left = this.equality();
16077    while (this.expect('&&')) {
16078      left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
16079    }
16080    return left;
16081  },
16082
16083  equality: function() {
16084    var left = this.relational();
16085    var token;
16086    while ((token = this.expect('==','!=','===','!=='))) {
16087      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
16088    }
16089    return left;
16090  },
16091
16092  relational: function() {
16093    var left = this.additive();
16094    var token;
16095    while ((token = this.expect('<', '>', '<=', '>='))) {
16096      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
16097    }
16098    return left;
16099  },
16100
16101  additive: function() {
16102    var left = this.multiplicative();
16103    var token;
16104    while ((token = this.expect('+','-'))) {
16105      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
16106    }
16107    return left;
16108  },
16109
16110  multiplicative: function() {
16111    var left = this.unary();
16112    var token;
16113    while ((token = this.expect('*','/','%'))) {
16114      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
16115    }
16116    return left;
16117  },
16118
16119  unary: function() {
16120    var token;
16121    if ((token = this.expect('+', '-', '!'))) {
16122      return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
16123    } else {
16124      return this.primary();
16125    }
16126  },
16127
16128  primary: function() {
16129    var primary;
16130    if (this.expect('(')) {
16131      primary = this.filterChain();
16132      this.consume(')');
16133    } else if (this.expect('[')) {
16134      primary = this.arrayDeclaration();
16135    } else if (this.expect('{')) {
16136      primary = this.object();
16137    } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
16138      primary = copy(this.selfReferential[this.consume().text]);
16139    } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
16140      primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
16141    } else if (this.peek().identifier) {
16142      primary = this.identifier();
16143    } else if (this.peek().constant) {
16144      primary = this.constant();
16145    } else {
16146      this.throwError('not a primary expression', this.peek());
16147    }
16148
16149    var next;
16150    while ((next = this.expect('(', '[', '.'))) {
16151      if (next.text === '(') {
16152        primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
16153        this.consume(')');
16154      } else if (next.text === '[') {
16155        primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
16156        this.consume(']');
16157      } else if (next.text === '.') {
16158        primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
16159      } else {
16160        this.throwError('IMPOSSIBLE');
16161      }
16162    }
16163    return primary;
16164  },
16165
16166  filter: function(baseExpression) {
16167    var args = [baseExpression];
16168    var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
16169
16170    while (this.expect(':')) {
16171      args.push(this.expression());
16172    }
16173
16174    return result;
16175  },
16176
16177  parseArguments: function() {
16178    var args = [];
16179    if (this.peekToken().text !== ')') {
16180      do {
16181        args.push(this.filterChain());
16182      } while (this.expect(','));
16183    }
16184    return args;
16185  },
16186
16187  identifier: function() {
16188    var token = this.consume();
16189    if (!token.identifier) {
16190      this.throwError('is not a valid identifier', token);
16191    }
16192    return { type: AST.Identifier, name: token.text };
16193  },
16194
16195  constant: function() {
16196    // TODO check that it is a constant
16197    return { type: AST.Literal, value: this.consume().value };
16198  },
16199
16200  arrayDeclaration: function() {
16201    var elements = [];
16202    if (this.peekToken().text !== ']') {
16203      do {
16204        if (this.peek(']')) {
16205          // Support trailing commas per ES5.1.
16206          break;
16207        }
16208        elements.push(this.expression());
16209      } while (this.expect(','));
16210    }
16211    this.consume(']');
16212
16213    return { type: AST.ArrayExpression, elements: elements };
16214  },
16215
16216  object: function() {
16217    var properties = [], property;
16218    if (this.peekToken().text !== '}') {
16219      do {
16220        if (this.peek('}')) {
16221          // Support trailing commas per ES5.1.
16222          break;
16223        }
16224        property = {type: AST.Property, kind: 'init'};
16225        if (this.peek().constant) {
16226          property.key = this.constant();
16227          property.computed = false;
16228          this.consume(':');
16229          property.value = this.expression();
16230        } else if (this.peek().identifier) {
16231          property.key = this.identifier();
16232          property.computed = false;
16233          if (this.peek(':')) {
16234            this.consume(':');
16235            property.value = this.expression();
16236          } else {
16237            property.value = property.key;
16238          }
16239        } else if (this.peek('[')) {
16240          this.consume('[');
16241          property.key = this.expression();
16242          this.consume(']');
16243          property.computed = true;
16244          this.consume(':');
16245          property.value = this.expression();
16246        } else {
16247          this.throwError('invalid key', this.peek());
16248        }
16249        properties.push(property);
16250      } while (this.expect(','));
16251    }
16252    this.consume('}');
16253
16254    return {type: AST.ObjectExpression, properties: properties };
16255  },
16256
16257  throwError: function(msg, token) {
16258    throw $parseMinErr('syntax',
16259        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
16260          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
16261  },
16262
16263  consume: function(e1) {
16264    if (this.tokens.length === 0) {
16265      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
16266    }
16267
16268    var token = this.expect(e1);
16269    if (!token) {
16270      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
16271    }
16272    return token;
16273  },
16274
16275  peekToken: function() {
16276    if (this.tokens.length === 0) {
16277      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
16278    }
16279    return this.tokens[0];
16280  },
16281
16282  peek: function(e1, e2, e3, e4) {
16283    return this.peekAhead(0, e1, e2, e3, e4);
16284  },
16285
16286  peekAhead: function(i, e1, e2, e3, e4) {
16287    if (this.tokens.length > i) {
16288      var token = this.tokens[i];
16289      var t = token.text;
16290      if (t === e1 || t === e2 || t === e3 || t === e4 ||
16291          (!e1 && !e2 && !e3 && !e4)) {
16292        return token;
16293      }
16294    }
16295    return false;
16296  },
16297
16298  expect: function(e1, e2, e3, e4) {
16299    var token = this.peek(e1, e2, e3, e4);
16300    if (token) {
16301      this.tokens.shift();
16302      return token;
16303    }
16304    return false;
16305  },
16306
16307  selfReferential: {
16308    'this': {type: AST.ThisExpression },
16309    '$locals': {type: AST.LocalsExpression }
16310  }
16311};
16312
16313function ifDefined(v, d) {
16314  return typeof v !== 'undefined' ? v : d;
16315}
16316
16317function plusFn(l, r) {
16318  if (typeof l === 'undefined') return r;
16319  if (typeof r === 'undefined') return l;
16320  return l + r;
16321}
16322
16323function isStateless($filter, filterName) {
16324  var fn = $filter(filterName);
16325  return !fn.$stateful;
16326}
16327
16328var PURITY_ABSOLUTE = 1;
16329var PURITY_RELATIVE = 2;
16330
16331// Detect nodes which could depend on non-shallow state of objects
16332function isPure(node, parentIsPure) {
16333  switch (node.type) {
16334    // Computed members might invoke a stateful toString()
16335    case AST.MemberExpression:
16336      if (node.computed) {
16337        return false;
16338      }
16339      break;
16340
16341    // Unary always convert to primative
16342    case AST.UnaryExpression:
16343      return PURITY_ABSOLUTE;
16344
16345    // The binary + operator can invoke a stateful toString().
16346    case AST.BinaryExpression:
16347      return node.operator !== '+' ? PURITY_ABSOLUTE : false;
16348
16349    // Functions / filters probably read state from within objects
16350    case AST.CallExpression:
16351      return false;
16352  }
16353
16354  return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure;
16355}
16356
16357function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
16358  var allConstants;
16359  var argsToWatch;
16360  var isStatelessFilter;
16361
16362  var astIsPure = ast.isPure = isPure(ast, parentIsPure);
16363
16364  switch (ast.type) {
16365  case AST.Program:
16366    allConstants = true;
16367    forEach(ast.body, function(expr) {
16368      findConstantAndWatchExpressions(expr.expression, $filter, astIsPure);
16369      allConstants = allConstants && expr.expression.constant;
16370    });
16371    ast.constant = allConstants;
16372    break;
16373  case AST.Literal:
16374    ast.constant = true;
16375    ast.toWatch = [];
16376    break;
16377  case AST.UnaryExpression:
16378    findConstantAndWatchExpressions(ast.argument, $filter, astIsPure);
16379    ast.constant = ast.argument.constant;
16380    ast.toWatch = ast.argument.toWatch;
16381    break;
16382  case AST.BinaryExpression:
16383    findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
16384    findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
16385    ast.constant = ast.left.constant && ast.right.constant;
16386    ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
16387    break;
16388  case AST.LogicalExpression:
16389    findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
16390    findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
16391    ast.constant = ast.left.constant && ast.right.constant;
16392    ast.toWatch = ast.constant ? [] : [ast];
16393    break;
16394  case AST.ConditionalExpression:
16395    findConstantAndWatchExpressions(ast.test, $filter, astIsPure);
16396    findConstantAndWatchExpressions(ast.alternate, $filter, astIsPure);
16397    findConstantAndWatchExpressions(ast.consequent, $filter, astIsPure);
16398    ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
16399    ast.toWatch = ast.constant ? [] : [ast];
16400    break;
16401  case AST.Identifier:
16402    ast.constant = false;
16403    ast.toWatch = [ast];
16404    break;
16405  case AST.MemberExpression:
16406    findConstantAndWatchExpressions(ast.object, $filter, astIsPure);
16407    if (ast.computed) {
16408      findConstantAndWatchExpressions(ast.property, $filter, astIsPure);
16409    }
16410    ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
16411    ast.toWatch = ast.constant ? [] : [ast];
16412    break;
16413  case AST.CallExpression:
16414    isStatelessFilter = ast.filter ? isStateless($filter, ast.callee.name) : false;
16415    allConstants = isStatelessFilter;
16416    argsToWatch = [];
16417    forEach(ast.arguments, function(expr) {
16418      findConstantAndWatchExpressions(expr, $filter, astIsPure);
16419      allConstants = allConstants && expr.constant;
16420      argsToWatch.push.apply(argsToWatch, expr.toWatch);
16421    });
16422    ast.constant = allConstants;
16423    ast.toWatch = isStatelessFilter ? argsToWatch : [ast];
16424    break;
16425  case AST.AssignmentExpression:
16426    findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
16427    findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
16428    ast.constant = ast.left.constant && ast.right.constant;
16429    ast.toWatch = [ast];
16430    break;
16431  case AST.ArrayExpression:
16432    allConstants = true;
16433    argsToWatch = [];
16434    forEach(ast.elements, function(expr) {
16435      findConstantAndWatchExpressions(expr, $filter, astIsPure);
16436      allConstants = allConstants && expr.constant;
16437      argsToWatch.push.apply(argsToWatch, expr.toWatch);
16438    });
16439    ast.constant = allConstants;
16440    ast.toWatch = argsToWatch;
16441    break;
16442  case AST.ObjectExpression:
16443    allConstants = true;
16444    argsToWatch = [];
16445    forEach(ast.properties, function(property) {
16446      findConstantAndWatchExpressions(property.value, $filter, astIsPure);
16447      allConstants = allConstants && property.value.constant;
16448      argsToWatch.push.apply(argsToWatch, property.value.toWatch);
16449      if (property.computed) {
16450        //`{[key]: value}` implicitly does `key.toString()` which may be non-pure
16451        findConstantAndWatchExpressions(property.key, $filter, /*parentIsPure=*/false);
16452        allConstants = allConstants && property.key.constant;
16453        argsToWatch.push.apply(argsToWatch, property.key.toWatch);
16454      }
16455    });
16456    ast.constant = allConstants;
16457    ast.toWatch = argsToWatch;
16458    break;
16459  case AST.ThisExpression:
16460    ast.constant = false;
16461    ast.toWatch = [];
16462    break;
16463  case AST.LocalsExpression:
16464    ast.constant = false;
16465    ast.toWatch = [];
16466    break;
16467  }
16468}
16469
16470function getInputs(body) {
16471  if (body.length !== 1) return;
16472  var lastExpression = body[0].expression;
16473  var candidate = lastExpression.toWatch;
16474  if (candidate.length !== 1) return candidate;
16475  return candidate[0] !== lastExpression ? candidate : undefined;
16476}
16477
16478function isAssignable(ast) {
16479  return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
16480}
16481
16482function assignableAST(ast) {
16483  if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
16484    return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
16485  }
16486}
16487
16488function isLiteral(ast) {
16489  return ast.body.length === 0 ||
16490      ast.body.length === 1 && (
16491      ast.body[0].expression.type === AST.Literal ||
16492      ast.body[0].expression.type === AST.ArrayExpression ||
16493      ast.body[0].expression.type === AST.ObjectExpression);
16494}
16495
16496function isConstant(ast) {
16497  return ast.constant;
16498}
16499
16500function ASTCompiler($filter) {
16501  this.$filter = $filter;
16502}
16503
16504ASTCompiler.prototype = {
16505  compile: function(ast) {
16506    var self = this;
16507    this.state = {
16508      nextId: 0,
16509      filters: {},
16510      fn: {vars: [], body: [], own: {}},
16511      assign: {vars: [], body: [], own: {}},
16512      inputs: []
16513    };
16514    findConstantAndWatchExpressions(ast, self.$filter);
16515    var extra = '';
16516    var assignable;
16517    this.stage = 'assign';
16518    if ((assignable = assignableAST(ast))) {
16519      this.state.computing = 'assign';
16520      var result = this.nextId();
16521      this.recurse(assignable, result);
16522      this.return_(result);
16523      extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
16524    }
16525    var toWatch = getInputs(ast.body);
16526    self.stage = 'inputs';
16527    forEach(toWatch, function(watch, key) {
16528      var fnKey = 'fn' + key;
16529      self.state[fnKey] = {vars: [], body: [], own: {}};
16530      self.state.computing = fnKey;
16531      var intoId = self.nextId();
16532      self.recurse(watch, intoId);
16533      self.return_(intoId);
16534      self.state.inputs.push({name: fnKey, isPure: watch.isPure});
16535      watch.watchId = key;
16536    });
16537    this.state.computing = 'fn';
16538    this.stage = 'main';
16539    this.recurse(ast);
16540    var fnString =
16541      // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
16542      // This is a workaround for this until we do a better job at only removing the prefix only when we should.
16543      '"' + this.USE + ' ' + this.STRICT + '";\n' +
16544      this.filterPrefix() +
16545      'var fn=' + this.generateFunction('fn', 's,l,a,i') +
16546      extra +
16547      this.watchFns() +
16548      'return fn;';
16549
16550    // eslint-disable-next-line no-new-func
16551    var fn = (new Function('$filter',
16552        'getStringValue',
16553        'ifDefined',
16554        'plus',
16555        fnString))(
16556          this.$filter,
16557          getStringValue,
16558          ifDefined,
16559          plusFn);
16560    this.state = this.stage = undefined;
16561    return fn;
16562  },
16563
16564  USE: 'use',
16565
16566  STRICT: 'strict',
16567
16568  watchFns: function() {
16569    var result = [];
16570    var inputs = this.state.inputs;
16571    var self = this;
16572    forEach(inputs, function(input) {
16573      result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's'));
16574      if (input.isPure) {
16575        result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';');
16576      }
16577    });
16578    if (inputs.length) {
16579      result.push('fn.inputs=[' + inputs.map(function(i) { return i.name; }).join(',') + '];');
16580    }
16581    return result.join('');
16582  },
16583
16584  generateFunction: function(name, params) {
16585    return 'function(' + params + '){' +
16586        this.varsPrefix(name) +
16587        this.body(name) +
16588        '};';
16589  },
16590
16591  filterPrefix: function() {
16592    var parts = [];
16593    var self = this;
16594    forEach(this.state.filters, function(id, filter) {
16595      parts.push(id + '=$filter(' + self.escape(filter) + ')');
16596    });
16597    if (parts.length) return 'var ' + parts.join(',') + ';';
16598    return '';
16599  },
16600
16601  varsPrefix: function(section) {
16602    return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
16603  },
16604
16605  body: function(section) {
16606    return this.state[section].body.join('');
16607  },
16608
16609  recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
16610    var left, right, self = this, args, expression, computed;
16611    recursionFn = recursionFn || noop;
16612    if (!skipWatchIdCheck && isDefined(ast.watchId)) {
16613      intoId = intoId || this.nextId();
16614      this.if_('i',
16615        this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
16616        this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
16617      );
16618      return;
16619    }
16620    switch (ast.type) {
16621    case AST.Program:
16622      forEach(ast.body, function(expression, pos) {
16623        self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
16624        if (pos !== ast.body.length - 1) {
16625          self.current().body.push(right, ';');
16626        } else {
16627          self.return_(right);
16628        }
16629      });
16630      break;
16631    case AST.Literal:
16632      expression = this.escape(ast.value);
16633      this.assign(intoId, expression);
16634      recursionFn(intoId || expression);
16635      break;
16636    case AST.UnaryExpression:
16637      this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
16638      expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
16639      this.assign(intoId, expression);
16640      recursionFn(expression);
16641      break;
16642    case AST.BinaryExpression:
16643      this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
16644      this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
16645      if (ast.operator === '+') {
16646        expression = this.plus(left, right);
16647      } else if (ast.operator === '-') {
16648        expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
16649      } else {
16650        expression = '(' + left + ')' + ast.operator + '(' + right + ')';
16651      }
16652      this.assign(intoId, expression);
16653      recursionFn(expression);
16654      break;
16655    case AST.LogicalExpression:
16656      intoId = intoId || this.nextId();
16657      self.recurse(ast.left, intoId);
16658      self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
16659      recursionFn(intoId);
16660      break;
16661    case AST.ConditionalExpression:
16662      intoId = intoId || this.nextId();
16663      self.recurse(ast.test, intoId);
16664      self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
16665      recursionFn(intoId);
16666      break;
16667    case AST.Identifier:
16668      intoId = intoId || this.nextId();
16669      if (nameId) {
16670        nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
16671        nameId.computed = false;
16672        nameId.name = ast.name;
16673      }
16674      self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
16675        function() {
16676          self.if_(self.stage === 'inputs' || 's', function() {
16677            if (create && create !== 1) {
16678              self.if_(
16679                self.isNull(self.nonComputedMember('s', ast.name)),
16680                self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
16681            }
16682            self.assign(intoId, self.nonComputedMember('s', ast.name));
16683          });
16684        }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
16685        );
16686      recursionFn(intoId);
16687      break;
16688    case AST.MemberExpression:
16689      left = nameId && (nameId.context = this.nextId()) || this.nextId();
16690      intoId = intoId || this.nextId();
16691      self.recurse(ast.object, left, undefined, function() {
16692        self.if_(self.notNull(left), function() {
16693          if (ast.computed) {
16694            right = self.nextId();
16695            self.recurse(ast.property, right);
16696            self.getStringValue(right);
16697            if (create && create !== 1) {
16698              self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
16699            }
16700            expression = self.computedMember(left, right);
16701            self.assign(intoId, expression);
16702            if (nameId) {
16703              nameId.computed = true;
16704              nameId.name = right;
16705            }
16706          } else {
16707            if (create && create !== 1) {
16708              self.if_(self.isNull(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
16709            }
16710            expression = self.nonComputedMember(left, ast.property.name);
16711            self.assign(intoId, expression);
16712            if (nameId) {
16713              nameId.computed = false;
16714              nameId.name = ast.property.name;
16715            }
16716          }
16717        }, function() {
16718          self.assign(intoId, 'undefined');
16719        });
16720        recursionFn(intoId);
16721      }, !!create);
16722      break;
16723    case AST.CallExpression:
16724      intoId = intoId || this.nextId();
16725      if (ast.filter) {
16726        right = self.filter(ast.callee.name);
16727        args = [];
16728        forEach(ast.arguments, function(expr) {
16729          var argument = self.nextId();
16730          self.recurse(expr, argument);
16731          args.push(argument);
16732        });
16733        expression = right + '(' + args.join(',') + ')';
16734        self.assign(intoId, expression);
16735        recursionFn(intoId);
16736      } else {
16737        right = self.nextId();
16738        left = {};
16739        args = [];
16740        self.recurse(ast.callee, right, left, function() {
16741          self.if_(self.notNull(right), function() {
16742            forEach(ast.arguments, function(expr) {
16743              self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
16744                args.push(argument);
16745              });
16746            });
16747            if (left.name) {
16748              expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
16749            } else {
16750              expression = right + '(' + args.join(',') + ')';
16751            }
16752            self.assign(intoId, expression);
16753          }, function() {
16754            self.assign(intoId, 'undefined');
16755          });
16756          recursionFn(intoId);
16757        });
16758      }
16759      break;
16760    case AST.AssignmentExpression:
16761      right = this.nextId();
16762      left = {};
16763      this.recurse(ast.left, undefined, left, function() {
16764        self.if_(self.notNull(left.context), function() {
16765          self.recurse(ast.right, right);
16766          expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
16767          self.assign(intoId, expression);
16768          recursionFn(intoId || expression);
16769        });
16770      }, 1);
16771      break;
16772    case AST.ArrayExpression:
16773      args = [];
16774      forEach(ast.elements, function(expr) {
16775        self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
16776          args.push(argument);
16777        });
16778      });
16779      expression = '[' + args.join(',') + ']';
16780      this.assign(intoId, expression);
16781      recursionFn(intoId || expression);
16782      break;
16783    case AST.ObjectExpression:
16784      args = [];
16785      computed = false;
16786      forEach(ast.properties, function(property) {
16787        if (property.computed) {
16788          computed = true;
16789        }
16790      });
16791      if (computed) {
16792        intoId = intoId || this.nextId();
16793        this.assign(intoId, '{}');
16794        forEach(ast.properties, function(property) {
16795          if (property.computed) {
16796            left = self.nextId();
16797            self.recurse(property.key, left);
16798          } else {
16799            left = property.key.type === AST.Identifier ?
16800                       property.key.name :
16801                       ('' + property.key.value);
16802          }
16803          right = self.nextId();
16804          self.recurse(property.value, right);
16805          self.assign(self.member(intoId, left, property.computed), right);
16806        });
16807      } else {
16808        forEach(ast.properties, function(property) {
16809          self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) {
16810            args.push(self.escape(
16811                property.key.type === AST.Identifier ? property.key.name :
16812                  ('' + property.key.value)) +
16813                ':' + expr);
16814          });
16815        });
16816        expression = '{' + args.join(',') + '}';
16817        this.assign(intoId, expression);
16818      }
16819      recursionFn(intoId || expression);
16820      break;
16821    case AST.ThisExpression:
16822      this.assign(intoId, 's');
16823      recursionFn(intoId || 's');
16824      break;
16825    case AST.LocalsExpression:
16826      this.assign(intoId, 'l');
16827      recursionFn(intoId || 'l');
16828      break;
16829    case AST.NGValueParameter:
16830      this.assign(intoId, 'v');
16831      recursionFn(intoId || 'v');
16832      break;
16833    }
16834  },
16835
16836  getHasOwnProperty: function(element, property) {
16837    var key = element + '.' + property;
16838    var own = this.current().own;
16839    if (!own.hasOwnProperty(key)) {
16840      own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
16841    }
16842    return own[key];
16843  },
16844
16845  assign: function(id, value) {
16846    if (!id) return;
16847    this.current().body.push(id, '=', value, ';');
16848    return id;
16849  },
16850
16851  filter: function(filterName) {
16852    if (!this.state.filters.hasOwnProperty(filterName)) {
16853      this.state.filters[filterName] = this.nextId(true);
16854    }
16855    return this.state.filters[filterName];
16856  },
16857
16858  ifDefined: function(id, defaultValue) {
16859    return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
16860  },
16861
16862  plus: function(left, right) {
16863    return 'plus(' + left + ',' + right + ')';
16864  },
16865
16866  return_: function(id) {
16867    this.current().body.push('return ', id, ';');
16868  },
16869
16870  if_: function(test, alternate, consequent) {
16871    if (test === true) {
16872      alternate();
16873    } else {
16874      var body = this.current().body;
16875      body.push('if(', test, '){');
16876      alternate();
16877      body.push('}');
16878      if (consequent) {
16879        body.push('else{');
16880        consequent();
16881        body.push('}');
16882      }
16883    }
16884  },
16885
16886  not: function(expression) {
16887    return '!(' + expression + ')';
16888  },
16889
16890  isNull: function(expression) {
16891    return expression + '==null';
16892  },
16893
16894  notNull: function(expression) {
16895    return expression + '!=null';
16896  },
16897
16898  nonComputedMember: function(left, right) {
16899    var SAFE_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
16900    var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
16901    if (SAFE_IDENTIFIER.test(right)) {
16902      return left + '.' + right;
16903    } else {
16904      return left  + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
16905    }
16906  },
16907
16908  computedMember: function(left, right) {
16909    return left + '[' + right + ']';
16910  },
16911
16912  member: function(left, right, computed) {
16913    if (computed) return this.computedMember(left, right);
16914    return this.nonComputedMember(left, right);
16915  },
16916
16917  getStringValue: function(item) {
16918    this.assign(item, 'getStringValue(' + item + ')');
16919  },
16920
16921  lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
16922    var self = this;
16923    return function() {
16924      self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
16925    };
16926  },
16927
16928  lazyAssign: function(id, value) {
16929    var self = this;
16930    return function() {
16931      self.assign(id, value);
16932    };
16933  },
16934
16935  stringEscapeRegex: /[^ a-zA-Z0-9]/g,
16936
16937  stringEscapeFn: function(c) {
16938    return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
16939  },
16940
16941  escape: function(value) {
16942    if (isString(value)) return '\'' + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + '\'';
16943    if (isNumber(value)) return value.toString();
16944    if (value === true) return 'true';
16945    if (value === false) return 'false';
16946    if (value === null) return 'null';
16947    if (typeof value === 'undefined') return 'undefined';
16948
16949    throw $parseMinErr('esc', 'IMPOSSIBLE');
16950  },
16951
16952  nextId: function(skip, init) {
16953    var id = 'v' + (this.state.nextId++);
16954    if (!skip) {
16955      this.current().vars.push(id + (init ? '=' + init : ''));
16956    }
16957    return id;
16958  },
16959
16960  current: function() {
16961    return this.state[this.state.computing];
16962  }
16963};
16964
16965
16966function ASTInterpreter($filter) {
16967  this.$filter = $filter;
16968}
16969
16970ASTInterpreter.prototype = {
16971  compile: function(ast) {
16972    var self = this;
16973    findConstantAndWatchExpressions(ast, self.$filter);
16974    var assignable;
16975    var assign;
16976    if ((assignable = assignableAST(ast))) {
16977      assign = this.recurse(assignable);
16978    }
16979    var toWatch = getInputs(ast.body);
16980    var inputs;
16981    if (toWatch) {
16982      inputs = [];
16983      forEach(toWatch, function(watch, key) {
16984        var input = self.recurse(watch);
16985        input.isPure = watch.isPure;
16986        watch.input = input;
16987        inputs.push(input);
16988        watch.watchId = key;
16989      });
16990    }
16991    var expressions = [];
16992    forEach(ast.body, function(expression) {
16993      expressions.push(self.recurse(expression.expression));
16994    });
16995    var fn = ast.body.length === 0 ? noop :
16996             ast.body.length === 1 ? expressions[0] :
16997             function(scope, locals) {
16998               var lastValue;
16999               forEach(expressions, function(exp) {
17000                 lastValue = exp(scope, locals);
17001               });
17002               return lastValue;
17003             };
17004    if (assign) {
17005      fn.assign = function(scope, value, locals) {
17006        return assign(scope, locals, value);
17007      };
17008    }
17009    if (inputs) {
17010      fn.inputs = inputs;
17011    }
17012    return fn;
17013  },
17014
17015  recurse: function(ast, context, create) {
17016    var left, right, self = this, args;
17017    if (ast.input) {
17018      return this.inputs(ast.input, ast.watchId);
17019    }
17020    switch (ast.type) {
17021    case AST.Literal:
17022      return this.value(ast.value, context);
17023    case AST.UnaryExpression:
17024      right = this.recurse(ast.argument);
17025      return this['unary' + ast.operator](right, context);
17026    case AST.BinaryExpression:
17027      left = this.recurse(ast.left);
17028      right = this.recurse(ast.right);
17029      return this['binary' + ast.operator](left, right, context);
17030    case AST.LogicalExpression:
17031      left = this.recurse(ast.left);
17032      right = this.recurse(ast.right);
17033      return this['binary' + ast.operator](left, right, context);
17034    case AST.ConditionalExpression:
17035      return this['ternary?:'](
17036        this.recurse(ast.test),
17037        this.recurse(ast.alternate),
17038        this.recurse(ast.consequent),
17039        context
17040      );
17041    case AST.Identifier:
17042      return self.identifier(ast.name, context, create);
17043    case AST.MemberExpression:
17044      left = this.recurse(ast.object, false, !!create);
17045      if (!ast.computed) {
17046        right = ast.property.name;
17047      }
17048      if (ast.computed) right = this.recurse(ast.property);
17049      return ast.computed ?
17050        this.computedMember(left, right, context, create) :
17051        this.nonComputedMember(left, right, context, create);
17052    case AST.CallExpression:
17053      args = [];
17054      forEach(ast.arguments, function(expr) {
17055        args.push(self.recurse(expr));
17056      });
17057      if (ast.filter) right = this.$filter(ast.callee.name);
17058      if (!ast.filter) right = this.recurse(ast.callee, true);
17059      return ast.filter ?
17060        function(scope, locals, assign, inputs) {
17061          var values = [];
17062          for (var i = 0; i < args.length; ++i) {
17063            values.push(args[i](scope, locals, assign, inputs));
17064          }
17065          var value = right.apply(undefined, values, inputs);
17066          return context ? {context: undefined, name: undefined, value: value} : value;
17067        } :
17068        function(scope, locals, assign, inputs) {
17069          var rhs = right(scope, locals, assign, inputs);
17070          var value;
17071          if (rhs.value != null) {
17072            var values = [];
17073            for (var i = 0; i < args.length; ++i) {
17074              values.push(args[i](scope, locals, assign, inputs));
17075            }
17076            value = rhs.value.apply(rhs.context, values);
17077          }
17078          return context ? {value: value} : value;
17079        };
17080    case AST.AssignmentExpression:
17081      left = this.recurse(ast.left, true, 1);
17082      right = this.recurse(ast.right);
17083      return function(scope, locals, assign, inputs) {
17084        var lhs = left(scope, locals, assign, inputs);
17085        var rhs = right(scope, locals, assign, inputs);
17086        lhs.context[lhs.name] = rhs;
17087        return context ? {value: rhs} : rhs;
17088      };
17089    case AST.ArrayExpression:
17090      args = [];
17091      forEach(ast.elements, function(expr) {
17092        args.push(self.recurse(expr));
17093      });
17094      return function(scope, locals, assign, inputs) {
17095        var value = [];
17096        for (var i = 0; i < args.length; ++i) {
17097          value.push(args[i](scope, locals, assign, inputs));
17098        }
17099        return context ? {value: value} : value;
17100      };
17101    case AST.ObjectExpression:
17102      args = [];
17103      forEach(ast.properties, function(property) {
17104        if (property.computed) {
17105          args.push({key: self.recurse(property.key),
17106                     computed: true,
17107                     value: self.recurse(property.value)
17108          });
17109        } else {
17110          args.push({key: property.key.type === AST.Identifier ?
17111                          property.key.name :
17112                          ('' + property.key.value),
17113                     computed: false,
17114                     value: self.recurse(property.value)
17115          });
17116        }
17117      });
17118      return function(scope, locals, assign, inputs) {
17119        var value = {};
17120        for (var i = 0; i < args.length; ++i) {
17121          if (args[i].computed) {
17122            value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs);
17123          } else {
17124            value[args[i].key] = args[i].value(scope, locals, assign, inputs);
17125          }
17126        }
17127        return context ? {value: value} : value;
17128      };
17129    case AST.ThisExpression:
17130      return function(scope) {
17131        return context ? {value: scope} : scope;
17132      };
17133    case AST.LocalsExpression:
17134      return function(scope, locals) {
17135        return context ? {value: locals} : locals;
17136      };
17137    case AST.NGValueParameter:
17138      return function(scope, locals, assign) {
17139        return context ? {value: assign} : assign;
17140      };
17141    }
17142  },
17143
17144  'unary+': function(argument, context) {
17145    return function(scope, locals, assign, inputs) {
17146      var arg = argument(scope, locals, assign, inputs);
17147      if (isDefined(arg)) {
17148        arg = +arg;
17149      } else {
17150        arg = 0;
17151      }
17152      return context ? {value: arg} : arg;
17153    };
17154  },
17155  'unary-': function(argument, context) {
17156    return function(scope, locals, assign, inputs) {
17157      var arg = argument(scope, locals, assign, inputs);
17158      if (isDefined(arg)) {
17159        arg = -arg;
17160      } else {
17161        arg = -0;
17162      }
17163      return context ? {value: arg} : arg;
17164    };
17165  },
17166  'unary!': function(argument, context) {
17167    return function(scope, locals, assign, inputs) {
17168      var arg = !argument(scope, locals, assign, inputs);
17169      return context ? {value: arg} : arg;
17170    };
17171  },
17172  'binary+': function(left, right, context) {
17173    return function(scope, locals, assign, inputs) {
17174      var lhs = left(scope, locals, assign, inputs);
17175      var rhs = right(scope, locals, assign, inputs);
17176      var arg = plusFn(lhs, rhs);
17177      return context ? {value: arg} : arg;
17178    };
17179  },
17180  'binary-': function(left, right, context) {
17181    return function(scope, locals, assign, inputs) {
17182      var lhs = left(scope, locals, assign, inputs);
17183      var rhs = right(scope, locals, assign, inputs);
17184      var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
17185      return context ? {value: arg} : arg;
17186    };
17187  },
17188  'binary*': function(left, right, context) {
17189    return function(scope, locals, assign, inputs) {
17190      var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
17191      return context ? {value: arg} : arg;
17192    };
17193  },
17194  'binary/': function(left, right, context) {
17195    return function(scope, locals, assign, inputs) {
17196      var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
17197      return context ? {value: arg} : arg;
17198    };
17199  },
17200  'binary%': function(left, right, context) {
17201    return function(scope, locals, assign, inputs) {
17202      var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
17203      return context ? {value: arg} : arg;
17204    };
17205  },
17206  'binary===': function(left, right, context) {
17207    return function(scope, locals, assign, inputs) {
17208      var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
17209      return context ? {value: arg} : arg;
17210    };
17211  },
17212  'binary!==': function(left, right, context) {
17213    return function(scope, locals, assign, inputs) {
17214      var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
17215      return context ? {value: arg} : arg;
17216    };
17217  },
17218  'binary==': function(left, right, context) {
17219    return function(scope, locals, assign, inputs) {
17220      // eslint-disable-next-line eqeqeq
17221      var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
17222      return context ? {value: arg} : arg;
17223    };
17224  },
17225  'binary!=': function(left, right, context) {
17226    return function(scope, locals, assign, inputs) {
17227      // eslint-disable-next-line eqeqeq
17228      var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
17229      return context ? {value: arg} : arg;
17230    };
17231  },
17232  'binary<': function(left, right, context) {
17233    return function(scope, locals, assign, inputs) {
17234      var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
17235      return context ? {value: arg} : arg;
17236    };
17237  },
17238  'binary>': function(left, right, context) {
17239    return function(scope, locals, assign, inputs) {
17240      var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
17241      return context ? {value: arg} : arg;
17242    };
17243  },
17244  'binary<=': function(left, right, context) {
17245    return function(scope, locals, assign, inputs) {
17246      var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
17247      return context ? {value: arg} : arg;
17248    };
17249  },
17250  'binary>=': function(left, right, context) {
17251    return function(scope, locals, assign, inputs) {
17252      var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
17253      return context ? {value: arg} : arg;
17254    };
17255  },
17256  'binary&&': function(left, right, context) {
17257    return function(scope, locals, assign, inputs) {
17258      var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
17259      return context ? {value: arg} : arg;
17260    };
17261  },
17262  'binary||': function(left, right, context) {
17263    return function(scope, locals, assign, inputs) {
17264      var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
17265      return context ? {value: arg} : arg;
17266    };
17267  },
17268  'ternary?:': function(test, alternate, consequent, context) {
17269    return function(scope, locals, assign, inputs) {
17270      var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
17271      return context ? {value: arg} : arg;
17272    };
17273  },
17274  value: function(value, context) {
17275    return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
17276  },
17277  identifier: function(name, context, create) {
17278    return function(scope, locals, assign, inputs) {
17279      var base = locals && (name in locals) ? locals : scope;
17280      if (create && create !== 1 && base && base[name] == null) {
17281        base[name] = {};
17282      }
17283      var value = base ? base[name] : undefined;
17284      if (context) {
17285        return {context: base, name: name, value: value};
17286      } else {
17287        return value;
17288      }
17289    };
17290  },
17291  computedMember: function(left, right, context, create) {
17292    return function(scope, locals, assign, inputs) {
17293      var lhs = left(scope, locals, assign, inputs);
17294      var rhs;
17295      var value;
17296      if (lhs != null) {
17297        rhs = right(scope, locals, assign, inputs);
17298        rhs = getStringValue(rhs);
17299        if (create && create !== 1) {
17300          if (lhs && !(lhs[rhs])) {
17301            lhs[rhs] = {};
17302          }
17303        }
17304        value = lhs[rhs];
17305      }
17306      if (context) {
17307        return {context: lhs, name: rhs, value: value};
17308      } else {
17309        return value;
17310      }
17311    };
17312  },
17313  nonComputedMember: function(left, right, context, create) {
17314    return function(scope, locals, assign, inputs) {
17315      var lhs = left(scope, locals, assign, inputs);
17316      if (create && create !== 1) {
17317        if (lhs && lhs[right] == null) {
17318          lhs[right] = {};
17319        }
17320      }
17321      var value = lhs != null ? lhs[right] : undefined;
17322      if (context) {
17323        return {context: lhs, name: right, value: value};
17324      } else {
17325        return value;
17326      }
17327    };
17328  },
17329  inputs: function(input, watchId) {
17330    return function(scope, value, locals, inputs) {
17331      if (inputs) return inputs[watchId];
17332      return input(scope, value, locals);
17333    };
17334  }
17335};
17336
17337/**
17338 * @constructor
17339 */
17340function Parser(lexer, $filter, options) {
17341  this.ast = new AST(lexer, options);
17342  this.astCompiler = options.csp ? new ASTInterpreter($filter) :
17343                                   new ASTCompiler($filter);
17344}
17345
17346Parser.prototype = {
17347  constructor: Parser,
17348
17349  parse: function(text) {
17350    var ast = this.getAst(text);
17351    var fn = this.astCompiler.compile(ast.ast);
17352    fn.literal = isLiteral(ast.ast);
17353    fn.constant = isConstant(ast.ast);
17354    fn.oneTime = ast.oneTime;
17355    return fn;
17356  },
17357
17358  getAst: function(exp) {
17359    var oneTime = false;
17360    exp = exp.trim();
17361
17362    if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
17363      oneTime = true;
17364      exp = exp.substring(2);
17365    }
17366    return {
17367      ast: this.ast.ast(exp),
17368      oneTime: oneTime
17369    };
17370  }
17371};
17372
17373function getValueOf(value) {
17374  return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
17375}
17376
17377///////////////////////////////////
17378
17379/**
17380 * @ngdoc service
17381 * @name $parse
17382 * @kind function
17383 *
17384 * @description
17385 *
17386 * Converts AngularJS {@link guide/expression expression} into a function.
17387 *
17388 * ```js
17389 *   var getter = $parse('user.name');
17390 *   var setter = getter.assign;
17391 *   var context = {user:{name:'AngularJS'}};
17392 *   var locals = {user:{name:'local'}};
17393 *
17394 *   expect(getter(context)).toEqual('AngularJS');
17395 *   setter(context, 'newValue');
17396 *   expect(context.user.name).toEqual('newValue');
17397 *   expect(getter(context, locals)).toEqual('local');
17398 * ```
17399 *
17400 *
17401 * @param {string} expression String expression to compile.
17402 * @returns {function(context, locals)} a function which represents the compiled expression:
17403 *
17404 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17405 *      are evaluated against (typically a scope object).
17406 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17407 *      `context`.
17408 *
17409 *    The returned function also has the following properties:
17410 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
17411 *        literal.
17412 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
17413 *        constant literals.
17414 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
17415 *        set to a function to change its value on the given context.
17416 *
17417 */
17418
17419
17420/**
17421 * @ngdoc provider
17422 * @name $parseProvider
17423 * @this
17424 *
17425 * @description
17426 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
17427 *  service.
17428 */
17429function $ParseProvider() {
17430  var cache = createMap();
17431  var literals = {
17432    'true': true,
17433    'false': false,
17434    'null': null,
17435    'undefined': undefined
17436  };
17437  var identStart, identContinue;
17438
17439  /**
17440   * @ngdoc method
17441   * @name $parseProvider#addLiteral
17442   * @description
17443   *
17444   * Configure $parse service to add literal values that will be present as literal at expressions.
17445   *
17446   * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
17447   * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
17448   *
17449   **/
17450  this.addLiteral = function(literalName, literalValue) {
17451    literals[literalName] = literalValue;
17452  };
17453
17454 /**
17455  * @ngdoc method
17456  * @name $parseProvider#setIdentifierFns
17457  *
17458  * @description
17459  *
17460  * Allows defining the set of characters that are allowed in AngularJS expressions. The function
17461  * `identifierStart` will get called to know if a given character is a valid character to be the
17462  * first character for an identifier. The function `identifierContinue` will get called to know if
17463  * a given character is a valid character to be a follow-up identifier character. The functions
17464  * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
17465  * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
17466  * mind that the `string` parameter can be two characters long depending on the character
17467  * representation. It is expected for the function to return `true` or `false`, whether that
17468  * character is allowed or not.
17469  *
17470  * Since this function will be called extensively, keep the implementation of these functions fast,
17471  * as the performance of these functions have a direct impact on the expressions parsing speed.
17472  *
17473  * @param {function=} identifierStart The function that will decide whether the given character is
17474  *   a valid identifier start character.
17475  * @param {function=} identifierContinue The function that will decide whether the given character is
17476  *   a valid identifier continue character.
17477  */
17478  this.setIdentifierFns = function(identifierStart, identifierContinue) {
17479    identStart = identifierStart;
17480    identContinue = identifierContinue;
17481    return this;
17482  };
17483
17484  this.$get = ['$filter', function($filter) {
17485    var noUnsafeEval = csp().noUnsafeEval;
17486    var $parseOptions = {
17487          csp: noUnsafeEval,
17488          literals: copy(literals),
17489          isIdentifierStart: isFunction(identStart) && identStart,
17490          isIdentifierContinue: isFunction(identContinue) && identContinue
17491        };
17492    $parse.$$getAst = $$getAst;
17493    return $parse;
17494
17495    function $parse(exp, interceptorFn) {
17496      var parsedExpression, cacheKey;
17497
17498      switch (typeof exp) {
17499        case 'string':
17500          exp = exp.trim();
17501          cacheKey = exp;
17502
17503          parsedExpression = cache[cacheKey];
17504
17505          if (!parsedExpression) {
17506            var lexer = new Lexer($parseOptions);
17507            var parser = new Parser(lexer, $filter, $parseOptions);
17508            parsedExpression = parser.parse(exp);
17509
17510            cache[cacheKey] = addWatchDelegate(parsedExpression);
17511          }
17512          return addInterceptor(parsedExpression, interceptorFn);
17513
17514        case 'function':
17515          return addInterceptor(exp, interceptorFn);
17516
17517        default:
17518          return addInterceptor(noop, interceptorFn);
17519      }
17520    }
17521
17522    function $$getAst(exp) {
17523      var lexer = new Lexer($parseOptions);
17524      var parser = new Parser(lexer, $filter, $parseOptions);
17525      return parser.getAst(exp).ast;
17526    }
17527
17528    function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) {
17529
17530      if (newValue == null || oldValueOfValue == null) { // null/undefined
17531        return newValue === oldValueOfValue;
17532      }
17533
17534      if (typeof newValue === 'object') {
17535
17536        // attempt to convert the value to a primitive type
17537        // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
17538        //             be cheaply dirty-checked
17539        newValue = getValueOf(newValue);
17540
17541        if (typeof newValue === 'object' && !compareObjectIdentity) {
17542          // objects/arrays are not supported - deep-watching them would be too expensive
17543          return false;
17544        }
17545
17546        // fall-through to the primitive equality check
17547      }
17548
17549      //Primitive or NaN
17550      // eslint-disable-next-line no-self-compare
17551      return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
17552    }
17553
17554    function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
17555      var inputExpressions = parsedExpression.inputs;
17556      var lastResult;
17557
17558      if (inputExpressions.length === 1) {
17559        var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
17560        inputExpressions = inputExpressions[0];
17561        return scope.$watch(function expressionInputWatch(scope) {
17562          var newInputValue = inputExpressions(scope);
17563          if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, inputExpressions.isPure)) {
17564            lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
17565            oldInputValueOf = newInputValue && getValueOf(newInputValue);
17566          }
17567          return lastResult;
17568        }, listener, objectEquality, prettyPrintExpression);
17569      }
17570
17571      var oldInputValueOfValues = [];
17572      var oldInputValues = [];
17573      for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
17574        oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
17575        oldInputValues[i] = null;
17576      }
17577
17578      return scope.$watch(function expressionInputsWatch(scope) {
17579        var changed = false;
17580
17581        for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
17582          var newInputValue = inputExpressions[i](scope);
17583          if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], inputExpressions[i].isPure))) {
17584            oldInputValues[i] = newInputValue;
17585            oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
17586          }
17587        }
17588
17589        if (changed) {
17590          lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
17591        }
17592
17593        return lastResult;
17594      }, listener, objectEquality, prettyPrintExpression);
17595    }
17596
17597    function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
17598      var isDone = parsedExpression.literal ? isAllDefined : isDefined;
17599      var unwatch, lastValue;
17600
17601      var exp = parsedExpression.$$intercepted || parsedExpression;
17602      var post = parsedExpression.$$interceptor || identity;
17603
17604      var useInputs = parsedExpression.inputs && !exp.inputs;
17605
17606      // Propagate the literal/inputs/constant attributes
17607      // ... but not oneTime since we are handling it
17608      oneTimeWatch.literal = parsedExpression.literal;
17609      oneTimeWatch.constant = parsedExpression.constant;
17610      oneTimeWatch.inputs = parsedExpression.inputs;
17611
17612      // Allow other delegates to run on this wrapped expression
17613      addWatchDelegate(oneTimeWatch);
17614
17615      unwatch = scope.$watch(oneTimeWatch, listener, objectEquality, prettyPrintExpression);
17616
17617      return unwatch;
17618
17619      function unwatchIfDone() {
17620        if (isDone(lastValue)) {
17621          unwatch();
17622        }
17623      }
17624
17625      function oneTimeWatch(scope, locals, assign, inputs) {
17626        lastValue = useInputs && inputs ? inputs[0] : exp(scope, locals, assign, inputs);
17627        if (isDone(lastValue)) {
17628          scope.$$postDigest(unwatchIfDone);
17629        }
17630        return post(lastValue);
17631      }
17632    }
17633
17634    function isAllDefined(value) {
17635      var allDefined = true;
17636      forEach(value, function(val) {
17637        if (!isDefined(val)) allDefined = false;
17638      });
17639      return allDefined;
17640    }
17641
17642    function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
17643      var unwatch = scope.$watch(function constantWatch(scope) {
17644        unwatch();
17645        return parsedExpression(scope);
17646      }, listener, objectEquality);
17647      return unwatch;
17648    }
17649
17650    function addWatchDelegate(parsedExpression) {
17651      if (parsedExpression.constant) {
17652        parsedExpression.$$watchDelegate = constantWatchDelegate;
17653      } else if (parsedExpression.oneTime) {
17654        parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
17655      } else if (parsedExpression.inputs) {
17656        parsedExpression.$$watchDelegate = inputsWatchDelegate;
17657      }
17658
17659      return parsedExpression;
17660    }
17661
17662    function chainInterceptors(first, second) {
17663      function chainedInterceptor(value) {
17664        return second(first(value));
17665      }
17666      chainedInterceptor.$stateful = first.$stateful || second.$stateful;
17667      chainedInterceptor.$$pure = first.$$pure && second.$$pure;
17668
17669      return chainedInterceptor;
17670    }
17671
17672    function addInterceptor(parsedExpression, interceptorFn) {
17673      if (!interceptorFn) return parsedExpression;
17674
17675      // Extract any existing interceptors out of the parsedExpression
17676      // to ensure the original parsedExpression is always the $$intercepted
17677      if (parsedExpression.$$interceptor) {
17678        interceptorFn = chainInterceptors(parsedExpression.$$interceptor, interceptorFn);
17679        parsedExpression = parsedExpression.$$intercepted;
17680      }
17681
17682      var useInputs = false;
17683
17684      var fn = function interceptedExpression(scope, locals, assign, inputs) {
17685        var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
17686        return interceptorFn(value);
17687      };
17688
17689      // Maintain references to the interceptor/intercepted
17690      fn.$$intercepted = parsedExpression;
17691      fn.$$interceptor = interceptorFn;
17692
17693      // Propagate the literal/oneTime/constant attributes
17694      fn.literal = parsedExpression.literal;
17695      fn.oneTime = parsedExpression.oneTime;
17696      fn.constant = parsedExpression.constant;
17697
17698      // Treat the interceptor like filters.
17699      // If it is not $stateful then only watch its inputs.
17700      // If the expression itself has no inputs then use the full expression as an input.
17701      if (!interceptorFn.$stateful) {
17702        useInputs = !parsedExpression.inputs;
17703        fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
17704
17705        if (!interceptorFn.$$pure) {
17706          fn.inputs = fn.inputs.map(function(e) {
17707              // Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a
17708              // non-pure interceptor function.
17709              if (e.isPure === PURITY_RELATIVE) {
17710                return function depurifier(s) { return e(s); };
17711              }
17712              return e;
17713            });
17714        }
17715      }
17716
17717      return addWatchDelegate(fn);
17718    }
17719  }];
17720}
17721
17722/**
17723 * @ngdoc service
17724 * @name $q
17725 * @requires $rootScope
17726 *
17727 * @description
17728 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
17729 * when they are done processing.
17730 *
17731 * This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred
17732 * objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
17733 *
17734 * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
17735 * implementations, and the other which resembles ES6 (ES2015) promises to some degree.
17736 *
17737 * ## $q constructor
17738 *
17739 * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
17740 * function as the first argument. This is similar to the native Promise implementation from ES6,
17741 * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
17742 *
17743 * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
17744 * available yet.
17745 *
17746 * It can be used like so:
17747 *
17748 * ```js
17749 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
17750 *   // are available in the current lexical scope (they could have been injected or passed in).
17751 *
17752 *   function asyncGreet(name) {
17753 *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
17754 *     return $q(function(resolve, reject) {
17755 *       setTimeout(function() {
17756 *         if (okToGreet(name)) {
17757 *           resolve('Hello, ' + name + '!');
17758 *         } else {
17759 *           reject('Greeting ' + name + ' is not allowed.');
17760 *         }
17761 *       }, 1000);
17762 *     });
17763 *   }
17764 *
17765 *   var promise = asyncGreet('Robin Hood');
17766 *   promise.then(function(greeting) {
17767 *     alert('Success: ' + greeting);
17768 *   }, function(reason) {
17769 *     alert('Failed: ' + reason);
17770 *   });
17771 * ```
17772 *
17773 * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
17774 *
17775 * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
17776 *
17777 * However, the more traditional CommonJS-style usage is still available, and documented below.
17778 *
17779 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
17780 * interface for interacting with an object that represents the result of an action that is
17781 * performed asynchronously, and may or may not be finished at any given point in time.
17782 *
17783 * From the perspective of dealing with error handling, deferred and promise APIs are to
17784 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
17785 *
17786 * ```js
17787 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
17788 *   // are available in the current lexical scope (they could have been injected or passed in).
17789 *
17790 *   function asyncGreet(name) {
17791 *     var deferred = $q.defer();
17792 *
17793 *     setTimeout(function() {
17794 *       deferred.notify('About to greet ' + name + '.');
17795 *
17796 *       if (okToGreet(name)) {
17797 *         deferred.resolve('Hello, ' + name + '!');
17798 *       } else {
17799 *         deferred.reject('Greeting ' + name + ' is not allowed.');
17800 *       }
17801 *     }, 1000);
17802 *
17803 *     return deferred.promise;
17804 *   }
17805 *
17806 *   var promise = asyncGreet('Robin Hood');
17807 *   promise.then(function(greeting) {
17808 *     alert('Success: ' + greeting);
17809 *   }, function(reason) {
17810 *     alert('Failed: ' + reason);
17811 *   }, function(update) {
17812 *     alert('Got notification: ' + update);
17813 *   });
17814 * ```
17815 *
17816 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
17817 * comes in the way of guarantees that promise and deferred APIs make, see
17818 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
17819 *
17820 * Additionally the promise api allows for composition that is very hard to do with the
17821 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
17822 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
17823 * section on serial or parallel joining of promises.
17824 *
17825 * ## The Deferred API
17826 *
17827 * A new instance of deferred is constructed by calling `$q.defer()`.
17828 *
17829 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
17830 * that can be used for signaling the successful or unsuccessful completion, as well as the status
17831 * of the task.
17832 *
17833 * **Methods**
17834 *
17835 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
17836 *   constructed via `$q.reject`, the promise will be rejected instead.
17837 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
17838 *   resolving it with a rejection constructed via `$q.reject`.
17839 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
17840 *   multiple times before the promise is either resolved or rejected.
17841 *
17842 * **Properties**
17843 *
17844 * - promise – `{Promise}` – promise object associated with this deferred.
17845 *
17846 *
17847 * ## The Promise API
17848 *
17849 * A new promise instance is created when a deferred instance is created and can be retrieved by
17850 * calling `deferred.promise`.
17851 *
17852 * The purpose of the promise object is to allow for interested parties to get access to the result
17853 * of the deferred task when it completes.
17854 *
17855 * **Methods**
17856 *
17857 * - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or
17858 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
17859 *   as soon as the result is available. The callbacks are called with a single argument: the result
17860 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
17861 *   provide a progress indication, before the promise is resolved or rejected.
17862 *
17863 *   This method *returns a new promise* which is resolved or rejected via the return value of the
17864 *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
17865 *   with the value which is resolved in that promise using
17866 *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
17867 *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
17868 *   resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
17869 *   arguments are optional.
17870 *
17871 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
17872 *
17873 * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
17874 *   but to do so without modifying the final value. This is useful to release resources or do some
17875 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
17876 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
17877 *   more information.
17878 *
17879 * ## Chaining promises
17880 *
17881 * Because calling the `then` method of a promise returns a new derived promise, it is easily
17882 * possible to create a chain of promises:
17883 *
17884 * ```js
17885 *   promiseB = promiseA.then(function(result) {
17886 *     return result + 1;
17887 *   });
17888 *
17889 *   // promiseB will be resolved immediately after promiseA is resolved and its value
17890 *   // will be the result of promiseA incremented by 1
17891 * ```
17892 *
17893 * It is possible to create chains of any length and since a promise can be resolved with another
17894 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
17895 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
17896 * $http's response interceptors.
17897 *
17898 *
17899 * ## Differences between Kris Kowal's Q and $q
17900 *
17901 *  There are two main differences:
17902 *
17903 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
17904 *   mechanism in AngularJS, which means faster propagation of resolution or rejection into your
17905 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
17906 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
17907 *   all the important functionality needed for common async tasks.
17908 *
17909 * ## Testing
17910 *
17911 *  ```js
17912 *    it('should simulate promise', inject(function($q, $rootScope) {
17913 *      var deferred = $q.defer();
17914 *      var promise = deferred.promise;
17915 *      var resolvedValue;
17916 *
17917 *      promise.then(function(value) { resolvedValue = value; });
17918 *      expect(resolvedValue).toBeUndefined();
17919 *
17920 *      // Simulate resolving of promise
17921 *      deferred.resolve(123);
17922 *      // Note that the 'then' function does not get called synchronously.
17923 *      // This is because we want the promise API to always be async, whether or not
17924 *      // it got called synchronously or asynchronously.
17925 *      expect(resolvedValue).toBeUndefined();
17926 *
17927 *      // Propagate promise resolution to 'then' functions using $apply().
17928 *      $rootScope.$apply();
17929 *      expect(resolvedValue).toEqual(123);
17930 *    }));
17931 *  ```
17932 *
17933 * @param {function(function, function)} resolver Function which is responsible for resolving or
17934 *   rejecting the newly created promise. The first parameter is a function which resolves the
17935 *   promise, the second parameter is a function which rejects the promise.
17936 *
17937 * @returns {Promise} The newly created promise.
17938 */
17939/**
17940 * @ngdoc provider
17941 * @name $qProvider
17942 * @this
17943 *
17944 * @description
17945 */
17946function $QProvider() {
17947  var errorOnUnhandledRejections = true;
17948  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
17949    return qFactory(function(callback) {
17950      $rootScope.$evalAsync(callback);
17951    }, $exceptionHandler, errorOnUnhandledRejections);
17952  }];
17953
17954  /**
17955   * @ngdoc method
17956   * @name $qProvider#errorOnUnhandledRejections
17957   * @kind function
17958   *
17959   * @description
17960   * Retrieves or overrides whether to generate an error when a rejected promise is not handled.
17961   * This feature is enabled by default.
17962   *
17963   * @param {boolean=} value Whether to generate an error when a rejected promise is not handled.
17964   * @returns {boolean|ng.$qProvider} Current value when called without a new value or self for
17965   *    chaining otherwise.
17966   */
17967  this.errorOnUnhandledRejections = function(value) {
17968    if (isDefined(value)) {
17969      errorOnUnhandledRejections = value;
17970      return this;
17971    } else {
17972      return errorOnUnhandledRejections;
17973    }
17974  };
17975}
17976
17977/** @this */
17978function $$QProvider() {
17979  var errorOnUnhandledRejections = true;
17980  this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
17981    return qFactory(function(callback) {
17982      $browser.defer(callback);
17983    }, $exceptionHandler, errorOnUnhandledRejections);
17984  }];
17985
17986  this.errorOnUnhandledRejections = function(value) {
17987    if (isDefined(value)) {
17988      errorOnUnhandledRejections = value;
17989      return this;
17990    } else {
17991      return errorOnUnhandledRejections;
17992    }
17993  };
17994}
17995
17996/**
17997 * Constructs a promise manager.
17998 *
17999 * @param {function(function)} nextTick Function for executing functions in the next turn.
18000 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
18001 *     debugging purposes.
18002 * @param {boolean=} errorOnUnhandledRejections Whether an error should be generated on unhandled
18003 *     promises rejections.
18004 * @returns {object} Promise manager.
18005 */
18006function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
18007  var $qMinErr = minErr('$q', TypeError);
18008  var queueSize = 0;
18009  var checkQueue = [];
18010
18011  /**
18012   * @ngdoc method
18013   * @name ng.$q#defer
18014   * @kind function
18015   *
18016   * @description
18017   * Creates a `Deferred` object which represents a task which will finish in the future.
18018   *
18019   * @returns {Deferred} Returns a new instance of deferred.
18020   */
18021  function defer() {
18022    return new Deferred();
18023  }
18024
18025  function Deferred() {
18026    var promise = this.promise = new Promise();
18027    //Non prototype methods necessary to support unbound execution :/
18028    this.resolve = function(val) { resolvePromise(promise, val); };
18029    this.reject = function(reason) { rejectPromise(promise, reason); };
18030    this.notify = function(progress) { notifyPromise(promise, progress); };
18031  }
18032
18033
18034  function Promise() {
18035    this.$$state = { status: 0 };
18036  }
18037
18038  extend(Promise.prototype, {
18039    then: function(onFulfilled, onRejected, progressBack) {
18040      if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
18041        return this;
18042      }
18043      var result = new Promise();
18044
18045      this.$$state.pending = this.$$state.pending || [];
18046      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
18047      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
18048
18049      return result;
18050    },
18051
18052    'catch': function(callback) {
18053      return this.then(null, callback);
18054    },
18055
18056    'finally': function(callback, progressBack) {
18057      return this.then(function(value) {
18058        return handleCallback(value, resolve, callback);
18059      }, function(error) {
18060        return handleCallback(error, reject, callback);
18061      }, progressBack);
18062    }
18063  });
18064
18065  function processQueue(state) {
18066    var fn, promise, pending;
18067
18068    pending = state.pending;
18069    state.processScheduled = false;
18070    state.pending = undefined;
18071    try {
18072      for (var i = 0, ii = pending.length; i < ii; ++i) {
18073        markQStateExceptionHandled(state);
18074        promise = pending[i][0];
18075        fn = pending[i][state.status];
18076        try {
18077          if (isFunction(fn)) {
18078            resolvePromise(promise, fn(state.value));
18079          } else if (state.status === 1) {
18080            resolvePromise(promise, state.value);
18081          } else {
18082            rejectPromise(promise, state.value);
18083          }
18084        } catch (e) {
18085          rejectPromise(promise, e);
18086          // This error is explicitly marked for being passed to the $exceptionHandler
18087          if (e && e.$$passToExceptionHandler === true) {
18088            exceptionHandler(e);
18089          }
18090        }
18091      }
18092    } finally {
18093      --queueSize;
18094      if (errorOnUnhandledRejections && queueSize === 0) {
18095        nextTick(processChecks);
18096      }
18097    }
18098  }
18099
18100  function processChecks() {
18101    // eslint-disable-next-line no-unmodified-loop-condition
18102    while (!queueSize && checkQueue.length) {
18103      var toCheck = checkQueue.shift();
18104      if (!isStateExceptionHandled(toCheck)) {
18105        markQStateExceptionHandled(toCheck);
18106        var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
18107        if (isError(toCheck.value)) {
18108          exceptionHandler(toCheck.value, errorMessage);
18109        } else {
18110          exceptionHandler(errorMessage);
18111        }
18112      }
18113    }
18114  }
18115
18116  function scheduleProcessQueue(state) {
18117    if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !isStateExceptionHandled(state)) {
18118      if (queueSize === 0 && checkQueue.length === 0) {
18119        nextTick(processChecks);
18120      }
18121      checkQueue.push(state);
18122    }
18123    if (state.processScheduled || !state.pending) return;
18124    state.processScheduled = true;
18125    ++queueSize;
18126    nextTick(function() { processQueue(state); });
18127  }
18128
18129  function resolvePromise(promise, val) {
18130    if (promise.$$state.status) return;
18131    if (val === promise) {
18132      $$reject(promise, $qMinErr(
18133        'qcycle',
18134        'Expected promise to be resolved with value other than itself \'{0}\'',
18135        val));
18136    } else {
18137      $$resolve(promise, val);
18138    }
18139
18140  }
18141
18142  function $$resolve(promise, val) {
18143    var then;
18144    var done = false;
18145    try {
18146      if (isObject(val) || isFunction(val)) then = val.then;
18147      if (isFunction(then)) {
18148        promise.$$state.status = -1;
18149        then.call(val, doResolve, doReject, doNotify);
18150      } else {
18151        promise.$$state.value = val;
18152        promise.$$state.status = 1;
18153        scheduleProcessQueue(promise.$$state);
18154      }
18155    } catch (e) {
18156      doReject(e);
18157    }
18158
18159    function doResolve(val) {
18160      if (done) return;
18161      done = true;
18162      $$resolve(promise, val);
18163    }
18164    function doReject(val) {
18165      if (done) return;
18166      done = true;
18167      $$reject(promise, val);
18168    }
18169    function doNotify(progress) {
18170      notifyPromise(promise, progress);
18171    }
18172  }
18173
18174  function rejectPromise(promise, reason) {
18175    if (promise.$$state.status) return;
18176    $$reject(promise, reason);
18177  }
18178
18179  function $$reject(promise, reason) {
18180    promise.$$state.value = reason;
18181    promise.$$state.status = 2;
18182    scheduleProcessQueue(promise.$$state);
18183  }
18184
18185  function notifyPromise(promise, progress) {
18186    var callbacks = promise.$$state.pending;
18187
18188    if ((promise.$$state.status <= 0) && callbacks && callbacks.length) {
18189      nextTick(function() {
18190        var callback, result;
18191        for (var i = 0, ii = callbacks.length; i < ii; i++) {
18192          result = callbacks[i][0];
18193          callback = callbacks[i][3];
18194          try {
18195            notifyPromise(result, isFunction(callback) ? callback(progress) : progress);
18196          } catch (e) {
18197            exceptionHandler(e);
18198          }
18199        }
18200      });
18201    }
18202  }
18203
18204  /**
18205   * @ngdoc method
18206   * @name $q#reject
18207   * @kind function
18208   *
18209   * @description
18210   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
18211   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
18212   * a promise chain, you don't need to worry about it.
18213   *
18214   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
18215   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
18216   * a promise error callback and you want to forward the error to the promise derived from the
18217   * current promise, you have to "rethrow" the error by returning a rejection constructed via
18218   * `reject`.
18219   *
18220   * ```js
18221   *   promiseB = promiseA.then(function(result) {
18222   *     // success: do something and resolve promiseB
18223   *     //          with the old or a new result
18224   *     return result;
18225   *   }, function(reason) {
18226   *     // error: handle the error if possible and
18227   *     //        resolve promiseB with newPromiseOrValue,
18228   *     //        otherwise forward the rejection to promiseB
18229   *     if (canHandle(reason)) {
18230   *      // handle the error and recover
18231   *      return newPromiseOrValue;
18232   *     }
18233   *     return $q.reject(reason);
18234   *   });
18235   * ```
18236   *
18237   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
18238   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
18239   */
18240  function reject(reason) {
18241    var result = new Promise();
18242    rejectPromise(result, reason);
18243    return result;
18244  }
18245
18246  function handleCallback(value, resolver, callback) {
18247    var callbackOutput = null;
18248    try {
18249      if (isFunction(callback)) callbackOutput = callback();
18250    } catch (e) {
18251      return reject(e);
18252    }
18253    if (isPromiseLike(callbackOutput)) {
18254      return callbackOutput.then(function() {
18255        return resolver(value);
18256      }, reject);
18257    } else {
18258      return resolver(value);
18259    }
18260  }
18261
18262  /**
18263   * @ngdoc method
18264   * @name $q#when
18265   * @kind function
18266   *
18267   * @description
18268   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
18269   * This is useful when you are dealing with an object that might or might not be a promise, or if
18270   * the promise comes from a source that can't be trusted.
18271   *
18272   * @param {*} value Value or a promise
18273   * @param {Function=} successCallback
18274   * @param {Function=} errorCallback
18275   * @param {Function=} progressCallback
18276   * @returns {Promise} Returns a promise of the passed value or promise
18277   */
18278
18279
18280  function when(value, callback, errback, progressBack) {
18281    var result = new Promise();
18282    resolvePromise(result, value);
18283    return result.then(callback, errback, progressBack);
18284  }
18285
18286  /**
18287   * @ngdoc method
18288   * @name $q#resolve
18289   * @kind function
18290   *
18291   * @description
18292   * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
18293   *
18294   * @param {*} value Value or a promise
18295   * @param {Function=} successCallback
18296   * @param {Function=} errorCallback
18297   * @param {Function=} progressCallback
18298   * @returns {Promise} Returns a promise of the passed value or promise
18299   */
18300  var resolve = when;
18301
18302  /**
18303   * @ngdoc method
18304   * @name $q#all
18305   * @kind function
18306   *
18307   * @description
18308   * Combines multiple promises into a single promise that is resolved when all of the input
18309   * promises are resolved.
18310   *
18311   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
18312   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
18313   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
18314   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
18315   *   with the same rejection value.
18316   */
18317
18318  function all(promises) {
18319    var result = new Promise(),
18320        counter = 0,
18321        results = isArray(promises) ? [] : {};
18322
18323    forEach(promises, function(promise, key) {
18324      counter++;
18325      when(promise).then(function(value) {
18326        results[key] = value;
18327        if (!(--counter)) resolvePromise(result, results);
18328      }, function(reason) {
18329        rejectPromise(result, reason);
18330      });
18331    });
18332
18333    if (counter === 0) {
18334      resolvePromise(result, results);
18335    }
18336
18337    return result;
18338  }
18339
18340  /**
18341   * @ngdoc method
18342   * @name $q#race
18343   * @kind function
18344   *
18345   * @description
18346   * Returns a promise that resolves or rejects as soon as one of those promises
18347   * resolves or rejects, with the value or reason from that promise.
18348   *
18349   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
18350   * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
18351   * resolves or rejects, with the value or reason from that promise.
18352   */
18353
18354  function race(promises) {
18355    var deferred = defer();
18356
18357    forEach(promises, function(promise) {
18358      when(promise).then(deferred.resolve, deferred.reject);
18359    });
18360
18361    return deferred.promise;
18362  }
18363
18364  function $Q(resolver) {
18365    if (!isFunction(resolver)) {
18366      throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver);
18367    }
18368
18369    var promise = new Promise();
18370
18371    function resolveFn(value) {
18372      resolvePromise(promise, value);
18373    }
18374
18375    function rejectFn(reason) {
18376      rejectPromise(promise, reason);
18377    }
18378
18379    resolver(resolveFn, rejectFn);
18380
18381    return promise;
18382  }
18383
18384  // Let's make the instanceof operator work for promises, so that
18385  // `new $q(fn) instanceof $q` would evaluate to true.
18386  $Q.prototype = Promise.prototype;
18387
18388  $Q.defer = defer;
18389  $Q.reject = reject;
18390  $Q.when = when;
18391  $Q.resolve = resolve;
18392  $Q.all = all;
18393  $Q.race = race;
18394
18395  return $Q;
18396}
18397
18398function isStateExceptionHandled(state) {
18399  return !!state.pur;
18400}
18401function markQStateExceptionHandled(state) {
18402  state.pur = true;
18403}
18404function markQExceptionHandled(q) {
18405  // Built-in `$q` promises will always have a `$$state` property. This check is to allow
18406  // overwriting `$q` with a different promise library (e.g. Bluebird + angular-bluebird-promises).
18407  // (Currently, this is the only method that might be called with a promise, even if it is not
18408  // created by the built-in `$q`.)
18409  if (q.$$state) {
18410    markQStateExceptionHandled(q.$$state);
18411  }
18412}
18413
18414/** @this */
18415function $$RAFProvider() { //rAF
18416  this.$get = ['$window', '$timeout', function($window, $timeout) {
18417    var requestAnimationFrame = $window.requestAnimationFrame ||
18418                                $window.webkitRequestAnimationFrame;
18419
18420    var cancelAnimationFrame = $window.cancelAnimationFrame ||
18421                               $window.webkitCancelAnimationFrame ||
18422                               $window.webkitCancelRequestAnimationFrame;
18423
18424    var rafSupported = !!requestAnimationFrame;
18425    var raf = rafSupported
18426      ? function(fn) {
18427          var id = requestAnimationFrame(fn);
18428          return function() {
18429            cancelAnimationFrame(id);
18430          };
18431        }
18432      : function(fn) {
18433          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
18434          return function() {
18435            $timeout.cancel(timer);
18436          };
18437        };
18438
18439    raf.supported = rafSupported;
18440
18441    return raf;
18442  }];
18443}
18444
18445/**
18446 * DESIGN NOTES
18447 *
18448 * The design decisions behind the scope are heavily favored for speed and memory consumption.
18449 *
18450 * The typical use of scope is to watch the expressions, which most of the time return the same
18451 * value as last time so we optimize the operation.
18452 *
18453 * Closures construction is expensive in terms of speed as well as memory:
18454 *   - No closures, instead use prototypical inheritance for API
18455 *   - Internal state needs to be stored on scope directly, which means that private state is
18456 *     exposed as $$____ properties
18457 *
18458 * Loop operations are optimized by using while(count--) { ... }
18459 *   - This means that in order to keep the same order of execution as addition we have to add
18460 *     items to the array at the beginning (unshift) instead of at the end (push)
18461 *
18462 * Child scopes are created and removed often
18463 *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
18464 *
18465 * There are fewer watches than observers. This is why you don't want the observer to be implemented
18466 * in the same way as watch. Watch requires return of the initialization function which is expensive
18467 * to construct.
18468 */
18469
18470
18471/**
18472 * @ngdoc provider
18473 * @name $rootScopeProvider
18474 * @description
18475 *
18476 * Provider for the $rootScope service.
18477 */
18478
18479/**
18480 * @ngdoc method
18481 * @name $rootScopeProvider#digestTtl
18482 * @description
18483 *
18484 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
18485 * assuming that the model is unstable.
18486 *
18487 * The current default is 10 iterations.
18488 *
18489 * In complex applications it's possible that the dependencies between `$watch`s will result in
18490 * several digest iterations. However if an application needs more than the default 10 digest
18491 * iterations for its model to stabilize then you should investigate what is causing the model to
18492 * continuously change during the digest.
18493 *
18494 * Increasing the TTL could have performance implications, so you should not change it without
18495 * proper justification.
18496 *
18497 * @param {number} limit The number of digest iterations.
18498 */
18499
18500
18501/**
18502 * @ngdoc service
18503 * @name $rootScope
18504 * @this
18505 *
18506 * @description
18507 *
18508 * Every application has a single root {@link ng.$rootScope.Scope scope}.
18509 * All other scopes are descendant scopes of the root scope. Scopes provide separation
18510 * between the model and the view, via a mechanism for watching the model for changes.
18511 * They also provide event emission/broadcast and subscription facility. See the
18512 * {@link guide/scope developer guide on scopes}.
18513 */
18514function $RootScopeProvider() {
18515  var TTL = 10;
18516  var $rootScopeMinErr = minErr('$rootScope');
18517  var lastDirtyWatch = null;
18518  var applyAsyncId = null;
18519
18520  this.digestTtl = function(value) {
18521    if (arguments.length) {
18522      TTL = value;
18523    }
18524    return TTL;
18525  };
18526
18527  function createChildScopeClass(parent) {
18528    function ChildScope() {
18529      this.$$watchers = this.$$nextSibling =
18530          this.$$childHead = this.$$childTail = null;
18531      this.$$listeners = {};
18532      this.$$listenerCount = {};
18533      this.$$watchersCount = 0;
18534      this.$id = nextUid();
18535      this.$$ChildScope = null;
18536      this.$$suspended = false;
18537    }
18538    ChildScope.prototype = parent;
18539    return ChildScope;
18540  }
18541
18542  this.$get = ['$exceptionHandler', '$parse', '$browser',
18543      function($exceptionHandler, $parse, $browser) {
18544
18545    function destroyChildScope($event) {
18546        $event.currentScope.$$destroyed = true;
18547    }
18548
18549    function cleanUpScope($scope) {
18550
18551      // Support: IE 9 only
18552      if (msie === 9) {
18553        // There is a memory leak in IE9 if all child scopes are not disconnected
18554        // completely when a scope is destroyed. So this code will recurse up through
18555        // all this scopes children
18556        //
18557        // See issue https://github.com/angular/angular.js/issues/10706
18558        if ($scope.$$childHead) {
18559          cleanUpScope($scope.$$childHead);
18560        }
18561        if ($scope.$$nextSibling) {
18562          cleanUpScope($scope.$$nextSibling);
18563        }
18564      }
18565
18566      // The code below works around IE9 and V8's memory leaks
18567      //
18568      // See:
18569      // - https://code.google.com/p/v8/issues/detail?id=2073#c26
18570      // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
18571      // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
18572
18573      $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
18574          $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
18575    }
18576
18577    /**
18578     * @ngdoc type
18579     * @name $rootScope.Scope
18580     *
18581     * @description
18582     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
18583     * {@link auto.$injector $injector}. Child scopes are created using the
18584     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
18585     * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
18586     * an in-depth introduction and usage examples.
18587     *
18588     *
18589     * ## Inheritance
18590     * A scope can inherit from a parent scope, as in this example:
18591     * ```js
18592         var parent = $rootScope;
18593         var child = parent.$new();
18594
18595         parent.salutation = "Hello";
18596         expect(child.salutation).toEqual('Hello');
18597
18598         child.salutation = "Welcome";
18599         expect(child.salutation).toEqual('Welcome');
18600         expect(parent.salutation).toEqual('Hello');
18601     * ```
18602     *
18603     * When interacting with `Scope` in tests, additional helper methods are available on the
18604     * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
18605     * details.
18606     *
18607     *
18608     * @param {Object.<string, function()>=} providers Map of service factory which need to be
18609     *                                       provided for the current scope. Defaults to {@link ng}.
18610     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
18611     *                              append/override services provided by `providers`. This is handy
18612     *                              when unit-testing and having the need to override a default
18613     *                              service.
18614     * @returns {Object} Newly created scope.
18615     *
18616     */
18617    function Scope() {
18618      this.$id = nextUid();
18619      this.$$phase = this.$parent = this.$$watchers =
18620                     this.$$nextSibling = this.$$prevSibling =
18621                     this.$$childHead = this.$$childTail = null;
18622      this.$root = this;
18623      this.$$destroyed = false;
18624      this.$$suspended = false;
18625      this.$$listeners = {};
18626      this.$$listenerCount = {};
18627      this.$$watchersCount = 0;
18628      this.$$isolateBindings = null;
18629    }
18630
18631    /**
18632     * @ngdoc property
18633     * @name $rootScope.Scope#$id
18634     *
18635     * @description
18636     * Unique scope ID (monotonically increasing) useful for debugging.
18637     */
18638
18639     /**
18640      * @ngdoc property
18641      * @name $rootScope.Scope#$parent
18642      *
18643      * @description
18644      * Reference to the parent scope.
18645      */
18646
18647      /**
18648       * @ngdoc property
18649       * @name $rootScope.Scope#$root
18650       *
18651       * @description
18652       * Reference to the root scope.
18653       */
18654
18655    Scope.prototype = {
18656      constructor: Scope,
18657      /**
18658       * @ngdoc method
18659       * @name $rootScope.Scope#$new
18660       * @kind function
18661       *
18662       * @description
18663       * Creates a new child {@link ng.$rootScope.Scope scope}.
18664       *
18665       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
18666       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
18667       *
18668       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
18669       * desired for the scope and its child scopes to be permanently detached from the parent and
18670       * thus stop participating in model change detection and listener notification by invoking.
18671       *
18672       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
18673       *         parent scope. The scope is isolated, as it can not see parent scope properties.
18674       *         When creating widgets, it is useful for the widget to not accidentally read parent
18675       *         state.
18676       *
18677       * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
18678       *                              of the newly created scope. Defaults to `this` scope if not provided.
18679       *                              This is used when creating a transclude scope to correctly place it
18680       *                              in the scope hierarchy while maintaining the correct prototypical
18681       *                              inheritance.
18682       *
18683       * @returns {Object} The newly created child scope.
18684       *
18685       */
18686      $new: function(isolate, parent) {
18687        var child;
18688
18689        parent = parent || this;
18690
18691        if (isolate) {
18692          child = new Scope();
18693          child.$root = this.$root;
18694        } else {
18695          // Only create a child scope class if somebody asks for one,
18696          // but cache it to allow the VM to optimize lookups.
18697          if (!this.$$ChildScope) {
18698            this.$$ChildScope = createChildScopeClass(this);
18699          }
18700          child = new this.$$ChildScope();
18701        }
18702        child.$parent = parent;
18703        child.$$prevSibling = parent.$$childTail;
18704        if (parent.$$childHead) {
18705          parent.$$childTail.$$nextSibling = child;
18706          parent.$$childTail = child;
18707        } else {
18708          parent.$$childHead = parent.$$childTail = child;
18709        }
18710
18711        // When the new scope is not isolated or we inherit from `this`, and
18712        // the parent scope is destroyed, the property `$$destroyed` is inherited
18713        // prototypically. In all other cases, this property needs to be set
18714        // when the parent scope is destroyed.
18715        // The listener needs to be added after the parent is set
18716        if (isolate || parent !== this) child.$on('$destroy', destroyChildScope);
18717
18718        return child;
18719      },
18720
18721      /**
18722       * @ngdoc method
18723       * @name $rootScope.Scope#$watch
18724       * @kind function
18725       *
18726       * @description
18727       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
18728       *
18729       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
18730       *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
18731       *   its value when executed multiple times with the same input because it may be executed multiple
18732       *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
18733       *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).)
18734       * - The `listener` is called only when the value from the current `watchExpression` and the
18735       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
18736       *   see below). Inequality is determined according to reference inequality,
18737       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
18738       *    via the `!==` Javascript operator, unless `objectEquality == true`
18739       *   (see next point)
18740       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
18741       *   according to the {@link angular.equals} function. To save the value of the object for
18742       *   later comparison, the {@link angular.copy} function is used. This therefore means that
18743       *   watching complex objects will have adverse memory and performance implications.
18744       * - This should not be used to watch for changes in objects that are (or contain)
18745       *   [File](https://developer.mozilla.org/docs/Web/API/File) objects due to limitations with {@link angular.copy `angular.copy`}.
18746       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
18747       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
18748       *   iteration limit is 10 to prevent an infinite loop deadlock.
18749       *
18750       *
18751       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
18752       * you can register a `watchExpression` function with no `listener`. (Be prepared for
18753       * multiple calls to your `watchExpression` because it will execute multiple times in a
18754       * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
18755       *
18756       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
18757       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
18758       * watcher. In rare cases, this is undesirable because the listener is called when the result
18759       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
18760       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
18761       * listener was called due to initialization.
18762       *
18763       *
18764       *
18765       * @example
18766       * ```js
18767           // let's assume that scope was dependency injected as the $rootScope
18768           var scope = $rootScope;
18769           scope.name = 'misko';
18770           scope.counter = 0;
18771
18772           expect(scope.counter).toEqual(0);
18773           scope.$watch('name', function(newValue, oldValue) {
18774             scope.counter = scope.counter + 1;
18775           });
18776           expect(scope.counter).toEqual(0);
18777
18778           scope.$digest();
18779           // the listener is always called during the first $digest loop after it was registered
18780           expect(scope.counter).toEqual(1);
18781
18782           scope.$digest();
18783           // but now it will not be called unless the value changes
18784           expect(scope.counter).toEqual(1);
18785
18786           scope.name = 'adam';
18787           scope.$digest();
18788           expect(scope.counter).toEqual(2);
18789
18790
18791
18792           // Using a function as a watchExpression
18793           var food;
18794           scope.foodCounter = 0;
18795           expect(scope.foodCounter).toEqual(0);
18796           scope.$watch(
18797             // This function returns the value being watched. It is called for each turn of the $digest loop
18798             function() { return food; },
18799             // This is the change listener, called when the value returned from the above function changes
18800             function(newValue, oldValue) {
18801               if ( newValue !== oldValue ) {
18802                 // Only increment the counter if the value changed
18803                 scope.foodCounter = scope.foodCounter + 1;
18804               }
18805             }
18806           );
18807           // No digest has been run so the counter will be zero
18808           expect(scope.foodCounter).toEqual(0);
18809
18810           // Run the digest but since food has not changed count will still be zero
18811           scope.$digest();
18812           expect(scope.foodCounter).toEqual(0);
18813
18814           // Update food and run digest.  Now the counter will increment
18815           food = 'cheeseburger';
18816           scope.$digest();
18817           expect(scope.foodCounter).toEqual(1);
18818
18819       * ```
18820       *
18821       *
18822       *
18823       * @param {(function()|string)} watchExpression Expression that is evaluated on each
18824       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
18825       *    a call to the `listener`.
18826       *
18827       *    - `string`: Evaluated as {@link guide/expression expression}
18828       *    - `function(scope)`: called with current `scope` as a parameter.
18829       * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
18830       *    of `watchExpression` changes.
18831       *
18832       *    - `newVal` contains the current value of the `watchExpression`
18833       *    - `oldVal` contains the previous value of the `watchExpression`
18834       *    - `scope` refers to the current scope
18835       * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
18836       *     comparing for reference equality.
18837       * @returns {function()} Returns a deregistration function for this listener.
18838       */
18839      $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
18840        var get = $parse(watchExp);
18841        var fn = isFunction(listener) ? listener : noop;
18842
18843        if (get.$$watchDelegate) {
18844          return get.$$watchDelegate(this, fn, objectEquality, get, watchExp);
18845        }
18846        var scope = this,
18847            array = scope.$$watchers,
18848            watcher = {
18849              fn: fn,
18850              last: initWatchVal,
18851              get: get,
18852              exp: prettyPrintExpression || watchExp,
18853              eq: !!objectEquality
18854            };
18855
18856        lastDirtyWatch = null;
18857
18858        if (!array) {
18859          array = scope.$$watchers = [];
18860          array.$$digestWatchIndex = -1;
18861        }
18862        // we use unshift since we use a while loop in $digest for speed.
18863        // the while loop reads in reverse order.
18864        array.unshift(watcher);
18865        array.$$digestWatchIndex++;
18866        incrementWatchersCount(this, 1);
18867
18868        return function deregisterWatch() {
18869          var index = arrayRemove(array, watcher);
18870          if (index >= 0) {
18871            incrementWatchersCount(scope, -1);
18872            if (index < array.$$digestWatchIndex) {
18873              array.$$digestWatchIndex--;
18874            }
18875          }
18876          lastDirtyWatch = null;
18877        };
18878      },
18879
18880      /**
18881       * @ngdoc method
18882       * @name $rootScope.Scope#$watchGroup
18883       * @kind function
18884       *
18885       * @description
18886       * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
18887       * If any one expression in the collection changes the `listener` is executed.
18888       *
18889       * - The items in the `watchExpressions` array are observed via the standard `$watch` operation. Their return
18890       *   values are examined for changes on every call to `$digest`.
18891       * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
18892       *
18893       * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
18894       * watched using {@link ng.$rootScope.Scope#$watch $watch()}
18895       *
18896       * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
18897       *    expression in `watchExpressions` changes
18898       *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
18899       *    those of `watchExpression`
18900       *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
18901       *    those of `watchExpression`
18902       *    The `scope` refers to the current scope.
18903       * @returns {function()} Returns a de-registration function for all listeners.
18904       */
18905      $watchGroup: function(watchExpressions, listener) {
18906        var oldValues = new Array(watchExpressions.length);
18907        var newValues = new Array(watchExpressions.length);
18908        var deregisterFns = [];
18909        var self = this;
18910        var changeReactionScheduled = false;
18911        var firstRun = true;
18912
18913        if (!watchExpressions.length) {
18914          // No expressions means we call the listener ASAP
18915          var shouldCall = true;
18916          self.$evalAsync(function() {
18917            if (shouldCall) listener(newValues, newValues, self);
18918          });
18919          return function deregisterWatchGroup() {
18920            shouldCall = false;
18921          };
18922        }
18923
18924        if (watchExpressions.length === 1) {
18925          // Special case size of one
18926          return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
18927            newValues[0] = value;
18928            oldValues[0] = oldValue;
18929            listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
18930          });
18931        }
18932
18933        forEach(watchExpressions, function(expr, i) {
18934          var unwatchFn = self.$watch(expr, function watchGroupSubAction(value) {
18935            newValues[i] = value;
18936            if (!changeReactionScheduled) {
18937              changeReactionScheduled = true;
18938              self.$evalAsync(watchGroupAction);
18939            }
18940          });
18941          deregisterFns.push(unwatchFn);
18942        });
18943
18944        function watchGroupAction() {
18945          changeReactionScheduled = false;
18946
18947          try {
18948            if (firstRun) {
18949              firstRun = false;
18950              listener(newValues, newValues, self);
18951            } else {
18952              listener(newValues, oldValues, self);
18953            }
18954          } finally {
18955            for (var i = 0; i < watchExpressions.length; i++) {
18956              oldValues[i] = newValues[i];
18957            }
18958          }
18959        }
18960
18961        return function deregisterWatchGroup() {
18962          while (deregisterFns.length) {
18963            deregisterFns.shift()();
18964          }
18965        };
18966      },
18967
18968
18969      /**
18970       * @ngdoc method
18971       * @name $rootScope.Scope#$watchCollection
18972       * @kind function
18973       *
18974       * @description
18975       * Shallow watches the properties of an object and fires whenever any of the properties change
18976       * (for arrays, this implies watching the array items; for object maps, this implies watching
18977       * the properties). If a change is detected, the `listener` callback is fired.
18978       *
18979       * - The `obj` collection is observed via standard $watch operation and is examined on every
18980       *   call to $digest() to see if any items have been added, removed, or moved.
18981       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
18982       *   adding, removing, and moving items belonging to an object or array.
18983       *
18984       *
18985       * @example
18986       * ```js
18987          $scope.names = ['igor', 'matias', 'misko', 'james'];
18988          $scope.dataCount = 4;
18989
18990          $scope.$watchCollection('names', function(newNames, oldNames) {
18991            $scope.dataCount = newNames.length;
18992          });
18993
18994          expect($scope.dataCount).toEqual(4);
18995          $scope.$digest();
18996
18997          //still at 4 ... no changes
18998          expect($scope.dataCount).toEqual(4);
18999
19000          $scope.names.pop();
19001          $scope.$digest();
19002
19003          //now there's been a change
19004          expect($scope.dataCount).toEqual(3);
19005       * ```
19006       *
19007       *
19008       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
19009       *    expression value should evaluate to an object or an array which is observed on each
19010       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
19011       *    collection will trigger a call to the `listener`.
19012       *
19013       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
19014       *    when a change is detected.
19015       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
19016       *    - The `oldCollection` object is a copy of the former collection data.
19017       *      Due to performance considerations, the`oldCollection` value is computed only if the
19018       *      `listener` function declares two or more arguments.
19019       *    - The `scope` argument refers to the current scope.
19020       *
19021       * @returns {function()} Returns a de-registration function for this listener. When the
19022       *    de-registration function is executed, the internal watch operation is terminated.
19023       */
19024      $watchCollection: function(obj, listener) {
19025        // Mark the interceptor as
19026        // ... $$pure when literal since the instance will change when any input changes
19027        $watchCollectionInterceptor.$$pure = $parse(obj).literal;
19028        // ... $stateful when non-literal since we must read the state of the collection
19029        $watchCollectionInterceptor.$stateful = !$watchCollectionInterceptor.$$pure;
19030
19031        var self = this;
19032        // the current value, updated on each dirty-check run
19033        var newValue;
19034        // a shallow copy of the newValue from the last dirty-check run,
19035        // updated to match newValue during dirty-check run
19036        var oldValue;
19037        // a shallow copy of the newValue from when the last change happened
19038        var veryOldValue;
19039        // only track veryOldValue if the listener is asking for it
19040        var trackVeryOldValue = (listener.length > 1);
19041        var changeDetected = 0;
19042        var changeDetector = $parse(obj, $watchCollectionInterceptor);
19043        var internalArray = [];
19044        var internalObject = {};
19045        var initRun = true;
19046        var oldLength = 0;
19047
19048        function $watchCollectionInterceptor(_value) {
19049          newValue = _value;
19050          var newLength, key, bothNaN, newItem, oldItem;
19051
19052          // If the new value is undefined, then return undefined as the watch may be a one-time watch
19053          if (isUndefined(newValue)) return;
19054
19055          if (!isObject(newValue)) { // if primitive
19056            if (oldValue !== newValue) {
19057              oldValue = newValue;
19058              changeDetected++;
19059            }
19060          } else if (isArrayLike(newValue)) {
19061            if (oldValue !== internalArray) {
19062              // we are transitioning from something which was not an array into array.
19063              oldValue = internalArray;
19064              oldLength = oldValue.length = 0;
19065              changeDetected++;
19066            }
19067
19068            newLength = newValue.length;
19069
19070            if (oldLength !== newLength) {
19071              // if lengths do not match we need to trigger change notification
19072              changeDetected++;
19073              oldValue.length = oldLength = newLength;
19074            }
19075            // copy the items to oldValue and look for changes.
19076            for (var i = 0; i < newLength; i++) {
19077              oldItem = oldValue[i];
19078              newItem = newValue[i];
19079
19080              // eslint-disable-next-line no-self-compare
19081              bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
19082              if (!bothNaN && (oldItem !== newItem)) {
19083                changeDetected++;
19084                oldValue[i] = newItem;
19085              }
19086            }
19087          } else {
19088            if (oldValue !== internalObject) {
19089              // we are transitioning from something which was not an object into object.
19090              oldValue = internalObject = {};
19091              oldLength = 0;
19092              changeDetected++;
19093            }
19094            // copy the items to oldValue and look for changes.
19095            newLength = 0;
19096            for (key in newValue) {
19097              if (hasOwnProperty.call(newValue, key)) {
19098                newLength++;
19099                newItem = newValue[key];
19100                oldItem = oldValue[key];
19101
19102                if (key in oldValue) {
19103                  // eslint-disable-next-line no-self-compare
19104                  bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
19105                  if (!bothNaN && (oldItem !== newItem)) {
19106                    changeDetected++;
19107                    oldValue[key] = newItem;
19108                  }
19109                } else {
19110                  oldLength++;
19111                  oldValue[key] = newItem;
19112                  changeDetected++;
19113                }
19114              }
19115            }
19116            if (oldLength > newLength) {
19117              // we used to have more keys, need to find them and destroy them.
19118              changeDetected++;
19119              for (key in oldValue) {
19120                if (!hasOwnProperty.call(newValue, key)) {
19121                  oldLength--;
19122                  delete oldValue[key];
19123                }
19124              }
19125            }
19126          }
19127          return changeDetected;
19128        }
19129
19130        function $watchCollectionAction() {
19131          if (initRun) {
19132            initRun = false;
19133            listener(newValue, newValue, self);
19134          } else {
19135            listener(newValue, veryOldValue, self);
19136          }
19137
19138          // make a copy for the next time a collection is changed
19139          if (trackVeryOldValue) {
19140            if (!isObject(newValue)) {
19141              //primitive
19142              veryOldValue = newValue;
19143            } else if (isArrayLike(newValue)) {
19144              veryOldValue = new Array(newValue.length);
19145              for (var i = 0; i < newValue.length; i++) {
19146                veryOldValue[i] = newValue[i];
19147              }
19148            } else { // if object
19149              veryOldValue = {};
19150              for (var key in newValue) {
19151                if (hasOwnProperty.call(newValue, key)) {
19152                  veryOldValue[key] = newValue[key];
19153                }
19154              }
19155            }
19156          }
19157        }
19158
19159        return this.$watch(changeDetector, $watchCollectionAction);
19160      },
19161
19162      /**
19163       * @ngdoc method
19164       * @name $rootScope.Scope#$digest
19165       * @kind function
19166       *
19167       * @description
19168       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
19169       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
19170       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
19171       * until no more listeners are firing. This means that it is possible to get into an infinite
19172       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
19173       * iterations exceeds 10.
19174       *
19175       * Usually, you don't call `$digest()` directly in
19176       * {@link ng.directive:ngController controllers} or in
19177       * {@link ng.$compileProvider#directive directives}.
19178       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
19179       * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
19180       *
19181       * If you want to be notified whenever `$digest()` is called,
19182       * you can register a `watchExpression` function with
19183       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
19184       *
19185       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
19186       *
19187       * @example
19188       * ```js
19189           var scope = ...;
19190           scope.name = 'misko';
19191           scope.counter = 0;
19192
19193           expect(scope.counter).toEqual(0);
19194           scope.$watch('name', function(newValue, oldValue) {
19195             scope.counter = scope.counter + 1;
19196           });
19197           expect(scope.counter).toEqual(0);
19198
19199           scope.$digest();
19200           // the listener is always called during the first $digest loop after it was registered
19201           expect(scope.counter).toEqual(1);
19202
19203           scope.$digest();
19204           // but now it will not be called unless the value changes
19205           expect(scope.counter).toEqual(1);
19206
19207           scope.name = 'adam';
19208           scope.$digest();
19209           expect(scope.counter).toEqual(2);
19210       * ```
19211       *
19212       */
19213      $digest: function() {
19214        var watch, value, last, fn, get,
19215            watchers,
19216            dirty, ttl = TTL,
19217            next, current, target = asyncQueue.length ? $rootScope : this,
19218            watchLog = [],
19219            logIdx, asyncTask;
19220
19221        beginPhase('$digest');
19222        // Check for changes to browser url that happened in sync before the call to $digest
19223        $browser.$$checkUrlChange();
19224
19225        if (this === $rootScope && applyAsyncId !== null) {
19226          // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
19227          // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
19228          $browser.defer.cancel(applyAsyncId);
19229          flushApplyAsync();
19230        }
19231
19232        lastDirtyWatch = null;
19233
19234        do { // "while dirty" loop
19235          dirty = false;
19236          current = target;
19237
19238          // It's safe for asyncQueuePosition to be a local variable here because this loop can't
19239          // be reentered recursively. Calling $digest from a function passed to $evalAsync would
19240          // lead to a '$digest already in progress' error.
19241          for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {
19242            try {
19243              asyncTask = asyncQueue[asyncQueuePosition];
19244              fn = asyncTask.fn;
19245              fn(asyncTask.scope, asyncTask.locals);
19246            } catch (e) {
19247              $exceptionHandler(e);
19248            }
19249            lastDirtyWatch = null;
19250          }
19251          asyncQueue.length = 0;
19252
19253          traverseScopesLoop:
19254          do { // "traverse the scopes" loop
19255            if ((watchers = !current.$$suspended && current.$$watchers)) {
19256              // process our watches
19257              watchers.$$digestWatchIndex = watchers.length;
19258              while (watchers.$$digestWatchIndex--) {
19259                try {
19260                  watch = watchers[watchers.$$digestWatchIndex];
19261                  // Most common watches are on primitives, in which case we can short
19262                  // circuit it with === operator, only when === fails do we use .equals
19263                  if (watch) {
19264                    get = watch.get;
19265                    if ((value = get(current)) !== (last = watch.last) &&
19266                        !(watch.eq
19267                            ? equals(value, last)
19268                            : (isNumberNaN(value) && isNumberNaN(last)))) {
19269                      dirty = true;
19270                      lastDirtyWatch = watch;
19271                      watch.last = watch.eq ? copy(value, null) : value;
19272                      fn = watch.fn;
19273                      fn(value, ((last === initWatchVal) ? value : last), current);
19274                      if (ttl < 5) {
19275                        logIdx = 4 - ttl;
19276                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
19277                        watchLog[logIdx].push({
19278                          msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
19279                          newVal: value,
19280                          oldVal: last
19281                        });
19282                      }
19283                    } else if (watch === lastDirtyWatch) {
19284                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
19285                      // have already been tested.
19286                      dirty = false;
19287                      break traverseScopesLoop;
19288                    }
19289                  }
19290                } catch (e) {
19291                  $exceptionHandler(e);
19292                }
19293              }
19294            }
19295
19296            // Insanity Warning: scope depth-first traversal
19297            // yes, this code is a bit crazy, but it works and we have tests to prove it!
19298            // this piece should be kept in sync with the traversal in $broadcast
19299            // (though it differs due to having the extra check for $$suspended and does not
19300            // check $$listenerCount)
19301            if (!(next = ((!current.$$suspended && current.$$watchersCount && current.$$childHead) ||
19302                (current !== target && current.$$nextSibling)))) {
19303              while (current !== target && !(next = current.$$nextSibling)) {
19304                current = current.$parent;
19305              }
19306            }
19307          } while ((current = next));
19308
19309          // `break traverseScopesLoop;` takes us to here
19310
19311          if ((dirty || asyncQueue.length) && !(ttl--)) {
19312            clearPhase();
19313            throw $rootScopeMinErr('infdig',
19314                '{0} $digest() iterations reached. Aborting!\n' +
19315                'Watchers fired in the last 5 iterations: {1}',
19316                TTL, watchLog);
19317          }
19318
19319        } while (dirty || asyncQueue.length);
19320
19321        clearPhase();
19322
19323        // postDigestQueuePosition isn't local here because this loop can be reentered recursively.
19324        while (postDigestQueuePosition < postDigestQueue.length) {
19325          try {
19326            postDigestQueue[postDigestQueuePosition++]();
19327          } catch (e) {
19328            $exceptionHandler(e);
19329          }
19330        }
19331        postDigestQueue.length = postDigestQueuePosition = 0;
19332
19333        // Check for changes to browser url that happened during the $digest
19334        // (for which no event is fired; e.g. via `history.pushState()`)
19335        $browser.$$checkUrlChange();
19336      },
19337
19338      /**
19339       * @ngdoc method
19340       * @name $rootScope.Scope#$suspend
19341       * @kind function
19342       *
19343       * @description
19344       * Suspend watchers of this scope subtree so that they will not be invoked during digest.
19345       *
19346       * This can be used to optimize your application when you know that running those watchers
19347       * is redundant.
19348       *
19349       * **Warning**
19350       *
19351       * Suspending scopes from the digest cycle can have unwanted and difficult to debug results.
19352       * Only use this approach if you are confident that you know what you are doing and have
19353       * ample tests to ensure that bindings get updated as you expect.
19354       *
19355       * Some of the things to consider are:
19356       *
19357       * * Any external event on a directive/component will not trigger a digest while the hosting
19358       *   scope is suspended - even if the event handler calls `$apply()` or `$rootScope.$digest()`.
19359       * * Transcluded content exists on a scope that inherits from outside a directive but exists
19360       *   as a child of the directive's containing scope. If the containing scope is suspended the
19361       *   transcluded scope will also be suspended, even if the scope from which the transcluded
19362       *   scope inherits is not suspended.
19363       * * Multiple directives trying to manage the suspended status of a scope can confuse each other:
19364       *    * A call to `$suspend()` on an already suspended scope is a no-op.
19365       *    * A call to `$resume()` on a non-suspended scope is a no-op.
19366       *    * If two directives suspend a scope, then one of them resumes the scope, the scope will no
19367       *      longer be suspended. This could result in the other directive believing a scope to be
19368       *      suspended when it is not.
19369       * * If a parent scope is suspended then all its descendants will be also excluded from future
19370       *   digests whether or not they have been suspended themselves. Note that this also applies to
19371       *   isolate child scopes.
19372       * * Calling `$digest()` directly on a descendant of a suspended scope will still run the watchers
19373       *   for that scope and its descendants. When digesting we only check whether the current scope is
19374       *   locally suspended, rather than checking whether it has a suspended ancestor.
19375       * * Calling `$resume()` on a scope that has a suspended ancestor will not cause the scope to be
19376       *   included in future digests until all its ancestors have been resumed.
19377       * * Resolved promises, e.g. from explicit `$q` deferreds and `$http` calls, trigger `$apply()`
19378       *   against the `$rootScope` and so will still trigger a global digest even if the promise was
19379       *   initiated by a component that lives on a suspended scope.
19380       */
19381      $suspend: function() {
19382        this.$$suspended = true;
19383      },
19384
19385      /**
19386       * @ngdoc method
19387       * @name $rootScope.Scope#$isSuspended
19388       * @kind function
19389       *
19390       * @description
19391       * Call this method to determine if this scope has been explicitly suspended. It will not
19392       * tell you whether an ancestor has been suspended.
19393       * To determine if this scope will be excluded from a digest triggered at the $rootScope,
19394       * for example, you must check all its ancestors:
19395       *
19396       * ```
19397       * function isExcludedFromDigest(scope) {
19398       *   while(scope) {
19399       *     if (scope.$isSuspended()) return true;
19400       *     scope = scope.$parent;
19401       *   }
19402       *   return false;
19403       * ```
19404       *
19405       * Be aware that a scope may not be included in digests if it has a suspended ancestor,
19406       * even if `$isSuspended()` returns false.
19407       *
19408       * @returns true if the current scope has been suspended.
19409       */
19410      $isSuspended: function() {
19411        return this.$$suspended;
19412      },
19413
19414      /**
19415       * @ngdoc method
19416       * @name $rootScope.Scope#$resume
19417       * @kind function
19418       *
19419       * @description
19420       * Resume watchers of this scope subtree in case it was suspended.
19421       *
19422       * See {@link $rootScope.Scope#$suspend} for information about the dangers of using this approach.
19423       */
19424      $resume: function() {
19425        this.$$suspended = false;
19426      },
19427
19428      /**
19429       * @ngdoc event
19430       * @name $rootScope.Scope#$destroy
19431       * @eventType broadcast on scope being destroyed
19432       *
19433       * @description
19434       * Broadcasted when a scope and its children are being destroyed.
19435       *
19436       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
19437       * clean up DOM bindings before an element is removed from the DOM.
19438       */
19439
19440      /**
19441       * @ngdoc method
19442       * @name $rootScope.Scope#$destroy
19443       * @kind function
19444       *
19445       * @description
19446       * Removes the current scope (and all of its children) from the parent scope. Removal implies
19447       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
19448       * propagate to the current scope and its children. Removal also implies that the current
19449       * scope is eligible for garbage collection.
19450       *
19451       * The `$destroy()` is usually used by directives such as
19452       * {@link ng.directive:ngRepeat ngRepeat} for managing the
19453       * unrolling of the loop.
19454       *
19455       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
19456       * Application code can register a `$destroy` event handler that will give it a chance to
19457       * perform any necessary cleanup.
19458       *
19459       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
19460       * clean up DOM bindings before an element is removed from the DOM.
19461       */
19462      $destroy: function() {
19463        // We can't destroy a scope that has been already destroyed.
19464        if (this.$$destroyed) return;
19465        var parent = this.$parent;
19466
19467        this.$broadcast('$destroy');
19468        this.$$destroyed = true;
19469
19470        if (this === $rootScope) {
19471          //Remove handlers attached to window when $rootScope is removed
19472          $browser.$$applicationDestroyed();
19473        }
19474
19475        incrementWatchersCount(this, -this.$$watchersCount);
19476        for (var eventName in this.$$listenerCount) {
19477          decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
19478        }
19479
19480        // sever all the references to parent scopes (after this cleanup, the current scope should
19481        // not be retained by any of our references and should be eligible for garbage collection)
19482        if (parent && parent.$$childHead === this) parent.$$childHead = this.$$nextSibling;
19483        if (parent && parent.$$childTail === this) parent.$$childTail = this.$$prevSibling;
19484        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
19485        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
19486
19487        // Disable listeners, watchers and apply/digest methods
19488        this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
19489        this.$on = this.$watch = this.$watchGroup = function() { return noop; };
19490        this.$$listeners = {};
19491
19492        // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
19493        this.$$nextSibling = null;
19494        cleanUpScope(this);
19495      },
19496
19497      /**
19498       * @ngdoc method
19499       * @name $rootScope.Scope#$eval
19500       * @kind function
19501       *
19502       * @description
19503       * Executes the `expression` on the current scope and returns the result. Any exceptions in
19504       * the expression are propagated (uncaught). This is useful when evaluating AngularJS
19505       * expressions.
19506       *
19507       * @example
19508       * ```js
19509           var scope = ng.$rootScope.Scope();
19510           scope.a = 1;
19511           scope.b = 2;
19512
19513           expect(scope.$eval('a+b')).toEqual(3);
19514           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
19515       * ```
19516       *
19517       * @param {(string|function())=} expression An AngularJS expression to be executed.
19518       *
19519       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
19520       *    - `function(scope)`: execute the function with the current `scope` parameter.
19521       *
19522       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
19523       * @returns {*} The result of evaluating the expression.
19524       */
19525      $eval: function(expr, locals) {
19526        return $parse(expr)(this, locals);
19527      },
19528
19529      /**
19530       * @ngdoc method
19531       * @name $rootScope.Scope#$evalAsync
19532       * @kind function
19533       *
19534       * @description
19535       * Executes the expression on the current scope at a later point in time.
19536       *
19537       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
19538       * that:
19539       *
19540       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
19541       *     rendering).
19542       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
19543       *     `expression` execution.
19544       *
19545       * Any exceptions from the execution of the expression are forwarded to the
19546       * {@link ng.$exceptionHandler $exceptionHandler} service.
19547       *
19548       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
19549       * will be scheduled. However, it is encouraged to always call code that changes the model
19550       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
19551       *
19552       * @param {(string|function())=} expression An AngularJS expression to be executed.
19553       *
19554       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
19555       *    - `function(scope)`: execute the function with the current `scope` parameter.
19556       *
19557       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
19558       */
19559      $evalAsync: function(expr, locals) {
19560        // if we are outside of an $digest loop and this is the first time we are scheduling async
19561        // task also schedule async auto-flush
19562        if (!$rootScope.$$phase && !asyncQueue.length) {
19563          $browser.defer(function() {
19564            if (asyncQueue.length) {
19565              $rootScope.$digest();
19566            }
19567          }, null, '$evalAsync');
19568        }
19569
19570        asyncQueue.push({scope: this, fn: $parse(expr), locals: locals});
19571      },
19572
19573      $$postDigest: function(fn) {
19574        postDigestQueue.push(fn);
19575      },
19576
19577      /**
19578       * @ngdoc method
19579       * @name $rootScope.Scope#$apply
19580       * @kind function
19581       *
19582       * @description
19583       * `$apply()` is used to execute an expression in AngularJS from outside of the AngularJS
19584       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
19585       * Because we are calling into the AngularJS framework we need to perform proper scope life
19586       * cycle of {@link ng.$exceptionHandler exception handling},
19587       * {@link ng.$rootScope.Scope#$digest executing watches}.
19588       *
19589       * **Life cycle: Pseudo-Code of `$apply()`**
19590       *
19591       * ```js
19592           function $apply(expr) {
19593             try {
19594               return $eval(expr);
19595             } catch (e) {
19596               $exceptionHandler(e);
19597             } finally {
19598               $root.$digest();
19599             }
19600           }
19601       * ```
19602       *
19603       *
19604       * Scope's `$apply()` method transitions through the following stages:
19605       *
19606       * 1. The {@link guide/expression expression} is executed using the
19607       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
19608       * 2. Any exceptions from the execution of the expression are forwarded to the
19609       *    {@link ng.$exceptionHandler $exceptionHandler} service.
19610       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
19611       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
19612       *
19613       *
19614       * @param {(string|function())=} exp An AngularJS expression to be executed.
19615       *
19616       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
19617       *    - `function(scope)`: execute the function with current `scope` parameter.
19618       *
19619       * @returns {*} The result of evaluating the expression.
19620       */
19621      $apply: function(expr) {
19622        try {
19623          beginPhase('$apply');
19624          try {
19625            return this.$eval(expr);
19626          } finally {
19627            clearPhase();
19628          }
19629        } catch (e) {
19630          $exceptionHandler(e);
19631        } finally {
19632          try {
19633            $rootScope.$digest();
19634          } catch (e) {
19635            $exceptionHandler(e);
19636            // eslint-disable-next-line no-unsafe-finally
19637            throw e;
19638          }
19639        }
19640      },
19641
19642      /**
19643       * @ngdoc method
19644       * @name $rootScope.Scope#$applyAsync
19645       * @kind function
19646       *
19647       * @description
19648       * Schedule the invocation of $apply to occur at a later time. The actual time difference
19649       * varies across browsers, but is typically around ~10 milliseconds.
19650       *
19651       * This can be used to queue up multiple expressions which need to be evaluated in the same
19652       * digest.
19653       *
19654       * @param {(string|function())=} exp An AngularJS expression to be executed.
19655       *
19656       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
19657       *    - `function(scope)`: execute the function with current `scope` parameter.
19658       */
19659      $applyAsync: function(expr) {
19660        var scope = this;
19661        if (expr) {
19662          applyAsyncQueue.push($applyAsyncExpression);
19663        }
19664        expr = $parse(expr);
19665        scheduleApplyAsync();
19666
19667        function $applyAsyncExpression() {
19668          scope.$eval(expr);
19669        }
19670      },
19671
19672      /**
19673       * @ngdoc method
19674       * @name $rootScope.Scope#$on
19675       * @kind function
19676       *
19677       * @description
19678       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
19679       * discussion of event life cycle.
19680       *
19681       * The event listener function format is: `function(event, args...)`. The `event` object
19682       * passed into the listener has the following attributes:
19683       *
19684       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
19685       *     `$broadcast`-ed.
19686       *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
19687       *     event propagates through the scope hierarchy, this property is set to null.
19688       *   - `name` - `{string}`: name of the event.
19689       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
19690       *     further event propagation (available only for events that were `$emit`-ed).
19691       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
19692       *     to true.
19693       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
19694       *
19695       * @param {string} name Event name to listen on.
19696       * @param {function(event, ...args)} listener Function to call when the event is emitted.
19697       * @returns {function()} Returns a deregistration function for this listener.
19698       */
19699      $on: function(name, listener) {
19700        var namedListeners = this.$$listeners[name];
19701        if (!namedListeners) {
19702          this.$$listeners[name] = namedListeners = [];
19703        }
19704        namedListeners.push(listener);
19705
19706        var current = this;
19707        do {
19708          if (!current.$$listenerCount[name]) {
19709            current.$$listenerCount[name] = 0;
19710          }
19711          current.$$listenerCount[name]++;
19712        } while ((current = current.$parent));
19713
19714        var self = this;
19715        return function() {
19716          var indexOfListener = namedListeners.indexOf(listener);
19717          if (indexOfListener !== -1) {
19718            // Use delete in the hope of the browser deallocating the memory for the array entry,
19719            // while not shifting the array indexes of other listeners.
19720            // See issue https://github.com/angular/angular.js/issues/16135
19721            delete namedListeners[indexOfListener];
19722            decrementListenerCount(self, 1, name);
19723          }
19724        };
19725      },
19726
19727
19728      /**
19729       * @ngdoc method
19730       * @name $rootScope.Scope#$emit
19731       * @kind function
19732       *
19733       * @description
19734       * Dispatches an event `name` upwards through the scope hierarchy notifying the
19735       * registered {@link ng.$rootScope.Scope#$on} listeners.
19736       *
19737       * The event life cycle starts at the scope on which `$emit` was called. All
19738       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
19739       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
19740       * registered listeners along the way. The event will stop propagating if one of the listeners
19741       * cancels it.
19742       *
19743       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
19744       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
19745       *
19746       * @param {string} name Event name to emit.
19747       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
19748       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
19749       */
19750      $emit: function(name, args) {
19751        var empty = [],
19752            namedListeners,
19753            scope = this,
19754            stopPropagation = false,
19755            event = {
19756              name: name,
19757              targetScope: scope,
19758              stopPropagation: function() {stopPropagation = true;},
19759              preventDefault: function() {
19760                event.defaultPrevented = true;
19761              },
19762              defaultPrevented: false
19763            },
19764            listenerArgs = concat([event], arguments, 1),
19765            i, length;
19766
19767        do {
19768          namedListeners = scope.$$listeners[name] || empty;
19769          event.currentScope = scope;
19770          for (i = 0, length = namedListeners.length; i < length; i++) {
19771
19772            // if listeners were deregistered, defragment the array
19773            if (!namedListeners[i]) {
19774              namedListeners.splice(i, 1);
19775              i--;
19776              length--;
19777              continue;
19778            }
19779            try {
19780              //allow all listeners attached to the current scope to run
19781              namedListeners[i].apply(null, listenerArgs);
19782            } catch (e) {
19783              $exceptionHandler(e);
19784            }
19785          }
19786          //if any listener on the current scope stops propagation, prevent bubbling
19787          if (stopPropagation) {
19788            break;
19789          }
19790          //traverse upwards
19791          scope = scope.$parent;
19792        } while (scope);
19793
19794        event.currentScope = null;
19795
19796        return event;
19797      },
19798
19799
19800      /**
19801       * @ngdoc method
19802       * @name $rootScope.Scope#$broadcast
19803       * @kind function
19804       *
19805       * @description
19806       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
19807       * registered {@link ng.$rootScope.Scope#$on} listeners.
19808       *
19809       * The event life cycle starts at the scope on which `$broadcast` was called. All
19810       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
19811       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
19812       * scope and calls all registered listeners along the way. The event cannot be canceled.
19813       *
19814       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
19815       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
19816       *
19817       * @param {string} name Event name to broadcast.
19818       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
19819       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
19820       */
19821      $broadcast: function(name, args) {
19822        var target = this,
19823            current = target,
19824            next = target,
19825            event = {
19826              name: name,
19827              targetScope: target,
19828              preventDefault: function() {
19829                event.defaultPrevented = true;
19830              },
19831              defaultPrevented: false
19832            };
19833
19834        if (!target.$$listenerCount[name]) return event;
19835
19836        var listenerArgs = concat([event], arguments, 1),
19837            listeners, i, length;
19838
19839        //down while you can, then up and next sibling or up and next sibling until back at root
19840        while ((current = next)) {
19841          event.currentScope = current;
19842          listeners = current.$$listeners[name] || [];
19843          for (i = 0, length = listeners.length; i < length; i++) {
19844            // if listeners were deregistered, defragment the array
19845            if (!listeners[i]) {
19846              listeners.splice(i, 1);
19847              i--;
19848              length--;
19849              continue;
19850            }
19851
19852            try {
19853              listeners[i].apply(null, listenerArgs);
19854            } catch (e) {
19855              $exceptionHandler(e);
19856            }
19857          }
19858
19859          // Insanity Warning: scope depth-first traversal
19860          // yes, this code is a bit crazy, but it works and we have tests to prove it!
19861          // this piece should be kept in sync with the traversal in $digest
19862          // (though it differs due to having the extra check for $$listenerCount and
19863          // does not check $$suspended)
19864          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
19865              (current !== target && current.$$nextSibling)))) {
19866            while (current !== target && !(next = current.$$nextSibling)) {
19867              current = current.$parent;
19868            }
19869          }
19870        }
19871
19872        event.currentScope = null;
19873        return event;
19874      }
19875    };
19876
19877    var $rootScope = new Scope();
19878
19879    //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
19880    var asyncQueue = $rootScope.$$asyncQueue = [];
19881    var postDigestQueue = $rootScope.$$postDigestQueue = [];
19882    var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
19883
19884    var postDigestQueuePosition = 0;
19885
19886    return $rootScope;
19887
19888
19889    function beginPhase(phase) {
19890      if ($rootScope.$$phase) {
19891        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
19892      }
19893
19894      $rootScope.$$phase = phase;
19895    }
19896
19897    function clearPhase() {
19898      $rootScope.$$phase = null;
19899    }
19900
19901    function incrementWatchersCount(current, count) {
19902      do {
19903        current.$$watchersCount += count;
19904      } while ((current = current.$parent));
19905    }
19906
19907    function decrementListenerCount(current, count, name) {
19908      do {
19909        current.$$listenerCount[name] -= count;
19910
19911        if (current.$$listenerCount[name] === 0) {
19912          delete current.$$listenerCount[name];
19913        }
19914      } while ((current = current.$parent));
19915    }
19916
19917    /**
19918     * function used as an initial value for watchers.
19919     * because it's unique we can easily tell it apart from other values
19920     */
19921    function initWatchVal() {}
19922
19923    function flushApplyAsync() {
19924      while (applyAsyncQueue.length) {
19925        try {
19926          applyAsyncQueue.shift()();
19927        } catch (e) {
19928          $exceptionHandler(e);
19929        }
19930      }
19931      applyAsyncId = null;
19932    }
19933
19934    function scheduleApplyAsync() {
19935      if (applyAsyncId === null) {
19936        applyAsyncId = $browser.defer(function() {
19937          $rootScope.$apply(flushApplyAsync);
19938        }, null, '$applyAsync');
19939      }
19940    }
19941  }];
19942}
19943
19944/**
19945 * @ngdoc service
19946 * @name $rootElement
19947 *
19948 * @description
19949 * The root element of AngularJS application. This is either the element where {@link
19950 * ng.directive:ngApp ngApp} was declared or the element passed into
19951 * {@link angular.bootstrap}. The element represents the root element of application. It is also the
19952 * location where the application's {@link auto.$injector $injector} service gets
19953 * published, and can be retrieved using `$rootElement.injector()`.
19954 */
19955
19956
19957// the implementation is in angular.bootstrap
19958
19959/**
19960 * @this
19961 * @description
19962 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
19963 */
19964function $$SanitizeUriProvider() {
19965
19966  var aHrefSanitizationTrustedUrlList = /^\s*(https?|s?ftp|mailto|tel|file):/,
19967    imgSrcSanitizationTrustedUrlList = /^\s*((https?|ftp|file|blob):|data:image\/)/;
19968
19969  /**
19970   * @description
19971   * Retrieves or overrides the default regular expression that is used for determining trusted safe
19972   * urls during a[href] sanitization.
19973   *
19974   * The sanitization is a security measure aimed at prevent XSS attacks via HTML anchor links.
19975   *
19976   * Any url due to be assigned to an `a[href]` attribute via interpolation is marked as requiring
19977   * the $sce.URL security context. When interpolation occurs a call is made to `$sce.trustAsUrl(url)`
19978   * which in turn may call `$$sanitizeUri(url, isMedia)` to sanitize the potentially malicious URL.
19979   *
19980   * If the URL matches the `aHrefSanitizationTrustedUrlList` regular expression, it is returned unchanged.
19981   *
19982   * If there is no match the URL is returned prefixed with `'unsafe:'` to ensure that when it is written
19983   * to the DOM it is inactive and potentially malicious code will not be executed.
19984   *
19985   * @param {RegExp=} regexp New regexp to trust urls with.
19986   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
19987   *    chaining otherwise.
19988   */
19989  this.aHrefSanitizationTrustedUrlList = function(regexp) {
19990    if (isDefined(regexp)) {
19991      aHrefSanitizationTrustedUrlList = regexp;
19992      return this;
19993    }
19994    return aHrefSanitizationTrustedUrlList;
19995  };
19996
19997
19998  /**
19999   * @description
20000   * Retrieves or overrides the default regular expression that is used for determining trusted safe
20001   * urls during img[src] sanitization.
20002   *
20003   * The sanitization is a security measure aimed at prevent XSS attacks via HTML image src links.
20004   *
20005   * Any URL due to be assigned to an `img[src]` attribute via interpolation is marked as requiring
20006   * the $sce.MEDIA_URL security context. When interpolation occurs a call is made to
20007   * `$sce.trustAsMediaUrl(url)` which in turn may call `$$sanitizeUri(url, isMedia)` to sanitize
20008   * the potentially malicious URL.
20009   *
20010   * If the URL matches the `imgSrcSanitizationTrustedUrlList` regular expression, it is returned
20011   * unchanged.
20012   *
20013   * If there is no match the URL is returned prefixed with `'unsafe:'` to ensure that when it is written
20014   * to the DOM it is inactive and potentially malicious code will not be executed.
20015   *
20016   * @param {RegExp=} regexp New regexp to trust urls with.
20017   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
20018   *    chaining otherwise.
20019   */
20020  this.imgSrcSanitizationTrustedUrlList = function(regexp) {
20021    if (isDefined(regexp)) {
20022      imgSrcSanitizationTrustedUrlList = regexp;
20023      return this;
20024    }
20025    return imgSrcSanitizationTrustedUrlList;
20026  };
20027
20028  this.$get = function() {
20029    return function sanitizeUri(uri, isMediaUrl) {
20030      // if (!uri) return uri;
20031      var regex = isMediaUrl ? imgSrcSanitizationTrustedUrlList : aHrefSanitizationTrustedUrlList;
20032      var normalizedVal = urlResolve(uri && uri.trim()).href;
20033      if (normalizedVal !== '' && !normalizedVal.match(regex)) {
20034        return 'unsafe:' + normalizedVal;
20035      }
20036      return uri;
20037    };
20038  };
20039}
20040
20041/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
20042 *     Any commits to this file should be reviewed with security in mind.  *
20043 *   Changes to this file can potentially create security vulnerabilities. *
20044 *          An approval from 2 Core members with history of modifying      *
20045 *                         this file is required.                          *
20046 *                                                                         *
20047 *  Does the change somehow allow for arbitrary javascript to be executed? *
20048 *    Or allows for someone to change the prototype of built-in objects?   *
20049 *     Or gives undesired access to variables likes document or window?    *
20050 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
20051
20052/* exported $SceProvider, $SceDelegateProvider */
20053
20054var $sceMinErr = minErr('$sce');
20055
20056var SCE_CONTEXTS = {
20057  // HTML is used when there's HTML rendered (e.g. ng-bind-html, iframe srcdoc binding).
20058  HTML: 'html',
20059
20060  // Style statements or stylesheets. Currently unused in AngularJS.
20061  CSS: 'css',
20062
20063  // An URL used in a context where it refers to the source of media, which are not expected to be run
20064  // as scripts, such as an image, audio, video, etc.
20065  MEDIA_URL: 'mediaUrl',
20066
20067  // An URL used in a context where it does not refer to a resource that loads code.
20068  // A value that can be trusted as a URL can also trusted as a MEDIA_URL.
20069  URL: 'url',
20070
20071  // RESOURCE_URL is a subtype of URL used where the referred-to resource could be interpreted as
20072  // code. (e.g. ng-include, script src binding, templateUrl)
20073  // A value that can be trusted as a RESOURCE_URL, can also trusted as a URL and a MEDIA_URL.
20074  RESOURCE_URL: 'resourceUrl',
20075
20076  // Script. Currently unused in AngularJS.
20077  JS: 'js'
20078};
20079
20080// Helper functions follow.
20081
20082var UNDERSCORE_LOWERCASE_REGEXP = /_([a-z])/g;
20083
20084function snakeToCamel(name) {
20085  return name
20086    .replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace);
20087}
20088
20089function adjustMatcher(matcher) {
20090  if (matcher === 'self') {
20091    return matcher;
20092  } else if (isString(matcher)) {
20093    // Strings match exactly except for 2 wildcards - '*' and '**'.
20094    // '*' matches any character except those from the set ':/.?&'.
20095    // '**' matches any character (like .* in a RegExp).
20096    // More than 2 *'s raises an error as it's ill defined.
20097    if (matcher.indexOf('***') > -1) {
20098      throw $sceMinErr('iwcard',
20099          'Illegal sequence *** in string matcher.  String: {0}', matcher);
20100    }
20101    matcher = escapeForRegexp(matcher).
20102                  replace(/\\\*\\\*/g, '.*').
20103                  replace(/\\\*/g, '[^:/.?&;]*');
20104    return new RegExp('^' + matcher + '$');
20105  } else if (isRegExp(matcher)) {
20106    // The only other type of matcher allowed is a Regexp.
20107    // Match entire URL / disallow partial matches.
20108    // Flags are reset (i.e. no global, ignoreCase or multiline)
20109    return new RegExp('^' + matcher.source + '$');
20110  } else {
20111    throw $sceMinErr('imatcher',
20112        'Matchers may only be "self", string patterns or RegExp objects');
20113  }
20114}
20115
20116
20117function adjustMatchers(matchers) {
20118  var adjustedMatchers = [];
20119  if (isDefined(matchers)) {
20120    forEach(matchers, function(matcher) {
20121      adjustedMatchers.push(adjustMatcher(matcher));
20122    });
20123  }
20124  return adjustedMatchers;
20125}
20126
20127
20128/**
20129 * @ngdoc service
20130 * @name $sceDelegate
20131 * @kind function
20132 *
20133 * @description
20134 *
20135 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
20136 * Contextual Escaping (SCE)} services to AngularJS.
20137 *
20138 * For an overview of this service and the functionnality it provides in AngularJS, see the main
20139 * page for {@link ng.$sce SCE}. The current page is targeted for developers who need to alter how
20140 * SCE works in their application, which shouldn't be needed in most cases.
20141 *
20142 * <div class="alert alert-danger">
20143 * AngularJS strongly relies on contextual escaping for the security of bindings: disabling or
20144 * modifying this might cause cross site scripting (XSS) vulnerabilities. For libraries owners,
20145 * changes to this service will also influence users, so be extra careful and document your changes.
20146 * </div>
20147 *
20148 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
20149 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
20150 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
20151 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
20152 * work because `$sce` delegates to `$sceDelegate` for these operations.
20153 *
20154 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
20155 *
20156 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
20157 * can override it completely to change the behavior of `$sce`, the common case would
20158 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
20159 * your own trusted and banned resource lists for trusting URLs used for loading AngularJS resources
20160 * such as templates.  Refer {@link ng.$sceDelegateProvider#trustedResourceUrlList
20161 * $sceDelegateProvider.trustedResourceUrlList} and {@link
20162 * ng.$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList}
20163 */
20164
20165/**
20166 * @ngdoc provider
20167 * @name $sceDelegateProvider
20168 * @this
20169 *
20170 * @description
20171 *
20172 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
20173 * $sceDelegate service}, used as a delegate for {@link ng.$sce Strict Contextual Escaping (SCE)}.
20174 *
20175 * The `$sceDelegateProvider` allows one to get/set the `trustedResourceUrlList` and
20176 * `bannedResourceUrlList` used to ensure that the URLs used for sourcing AngularJS templates and
20177 * other script-running URLs are safe (all places that use the `$sce.RESOURCE_URL` context). See
20178 * {@link ng.$sceDelegateProvider#trustedResourceUrlList
20179 * $sceDelegateProvider.trustedResourceUrlList} and
20180 * {@link ng.$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList},
20181 *
20182 * For the general details about this service in AngularJS, read the main page for {@link ng.$sce
20183 * Strict Contextual Escaping (SCE)}.
20184 *
20185 * **Example**:  Consider the following case. <a name="example"></a>
20186 *
20187 * - your app is hosted at url `http://myapp.example.com/`
20188 * - but some of your templates are hosted on other domains you control such as
20189 *   `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc.
20190 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
20191 *
20192 * Here is what a secure configuration for this scenario might look like:
20193 *
20194 * ```
20195 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
20196 *    $sceDelegateProvider.trustedResourceUrlList([
20197 *      // Allow same origin resource loads.
20198 *      'self',
20199 *      // Allow loading from our assets domain.  Notice the difference between * and **.
20200 *      'http://srv*.assets.example.com/**'
20201 *    ]);
20202 *
20203 *    // The banned resource URL list overrides the trusted resource URL list so the open redirect
20204 *    // here is blocked.
20205 *    $sceDelegateProvider.bannedResourceUrlList([
20206 *      'http://myapp.example.com/clickThru**'
20207 *    ]);
20208 *  });
20209 * ```
20210 * Note that an empty trusted resource URL list will block every resource URL from being loaded, and will require
20211 * you to manually mark each one as trusted with `$sce.trustAsResourceUrl`. However, templates
20212 * requested by {@link ng.$templateRequest $templateRequest} that are present in
20213 * {@link ng.$templateCache $templateCache} will not go through this check. If you have a mechanism
20214 * to populate your templates in that cache at config time, then it is a good idea to remove 'self'
20215 * from the trusted resource URL lsit. This helps to mitigate the security impact of certain types
20216 * of issues, like for instance attacker-controlled `ng-includes`.
20217 */
20218
20219function $SceDelegateProvider() {
20220  this.SCE_CONTEXTS = SCE_CONTEXTS;
20221
20222  // Resource URLs can also be trusted by policy.
20223  var trustedResourceUrlList = ['self'],
20224      bannedResourceUrlList = [];
20225
20226  /**
20227   * @ngdoc method
20228   * @name $sceDelegateProvider#trustedResourceUrlList
20229   * @kind function
20230   *
20231   * @param {Array=} trustedResourceUrlList When provided, replaces the trustedResourceUrlList with
20232   *     the value provided.  This must be an array or null.  A snapshot of this array is used so
20233   *     further changes to the array are ignored.
20234   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
20235   *     allowed in this array.
20236   *
20237   * @return {Array} The currently set trusted resource URL array.
20238   *
20239   * @description
20240   * Sets/Gets the list trusted of resource URLs.
20241   *
20242   * The **default value** when no `trustedResourceUrlList` has been explicitly set is `['self']`
20243   * allowing only same origin resource requests.
20244   *
20245   * <div class="alert alert-warning">
20246   * **Note:** the default `trustedResourceUrlList` of 'self' is not recommended if your app shares
20247   * its origin with other apps! It is a good idea to limit it to only your application's directory.
20248   * </div>
20249   */
20250  this.trustedResourceUrlList = function(value) {
20251    if (arguments.length) {
20252      trustedResourceUrlList = adjustMatchers(value);
20253    }
20254    return trustedResourceUrlList;
20255  };
20256
20257  /**
20258   * @ngdoc method
20259   * @name $sceDelegateProvider#resourceUrlWhitelist
20260   * @kind function
20261   *
20262   * @deprecated
20263   * sinceVersion="1.8.1"
20264   *
20265   * This method is deprecated. Use {@link $sceDelegateProvider#trustedResourceUrlList
20266   * trustedResourceUrlList} instead.
20267   */
20268  Object.defineProperty(this, 'resourceUrlWhitelist', {
20269    get: function() {
20270      return this.trustedResourceUrlList;
20271    },
20272    set: function(value) {
20273      this.trustedResourceUrlList = value;
20274    }
20275  });
20276
20277  /**
20278   * @ngdoc method
20279   * @name $sceDelegateProvider#bannedResourceUrlList
20280   * @kind function
20281   *
20282   * @param {Array=} bannedResourceUrlList When provided, replaces the `bannedResourceUrlList` with
20283   *     the value provided. This must be an array or null. A snapshot of this array is used so
20284   *     further changes to the array are ignored.</p><p>
20285   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
20286   *     allowed in this array.</p><p>
20287   *     The typical usage for the `bannedResourceUrlList` is to **block
20288   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
20289   *     these would otherwise be trusted but actually return content from the redirected domain.
20290   *     </p><p>
20291   *     Finally, **the banned resource URL list overrides the trusted resource URL list** and has
20292   *     the final say.
20293   *
20294   * @return {Array} The currently set `bannedResourceUrlList` array.
20295   *
20296   * @description
20297   * Sets/Gets the `bannedResourceUrlList` of trusted resource URLs.
20298   *
20299   * The **default value** when no trusted resource URL list has been explicitly set is the empty
20300   * array (i.e. there is no `bannedResourceUrlList`.)
20301   */
20302  this.bannedResourceUrlList = function(value) {
20303    if (arguments.length) {
20304      bannedResourceUrlList = adjustMatchers(value);
20305    }
20306    return bannedResourceUrlList;
20307  };
20308
20309  /**
20310   * @ngdoc method
20311   * @name $sceDelegateProvider#resourceUrlBlacklist
20312   * @kind function
20313   *
20314   * @deprecated
20315   * sinceVersion="1.8.1"
20316   *
20317   * This method is deprecated. Use {@link $sceDelegateProvider#bannedResourceUrlList
20318   * bannedResourceUrlList} instead.
20319   */
20320  Object.defineProperty(this, 'resourceUrlBlacklist', {
20321    get: function() {
20322      return this.bannedResourceUrlList;
20323    },
20324    set: function(value) {
20325      this.bannedResourceUrlList = value;
20326    }
20327  });
20328
20329  this.$get = ['$injector', '$$sanitizeUri', function($injector, $$sanitizeUri) {
20330
20331    var htmlSanitizer = function htmlSanitizer(html) {
20332      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
20333    };
20334
20335    if ($injector.has('$sanitize')) {
20336      htmlSanitizer = $injector.get('$sanitize');
20337    }
20338
20339
20340    function matchUrl(matcher, parsedUrl) {
20341      if (matcher === 'self') {
20342        return urlIsSameOrigin(parsedUrl) || urlIsSameOriginAsBaseUrl(parsedUrl);
20343      } else {
20344        // definitely a regex.  See adjustMatchers()
20345        return !!matcher.exec(parsedUrl.href);
20346      }
20347    }
20348
20349    function isResourceUrlAllowedByPolicy(url) {
20350      var parsedUrl = urlResolve(url.toString());
20351      var i, n, allowed = false;
20352      // Ensure that at least one item from the trusted resource URL list allows this url.
20353      for (i = 0, n = trustedResourceUrlList.length; i < n; i++) {
20354        if (matchUrl(trustedResourceUrlList[i], parsedUrl)) {
20355          allowed = true;
20356          break;
20357        }
20358      }
20359      if (allowed) {
20360        // Ensure that no item from the banned resource URL list has blocked this url.
20361        for (i = 0, n = bannedResourceUrlList.length; i < n; i++) {
20362          if (matchUrl(bannedResourceUrlList[i], parsedUrl)) {
20363            allowed = false;
20364            break;
20365          }
20366        }
20367      }
20368      return allowed;
20369    }
20370
20371    function generateHolderType(Base) {
20372      var holderType = function TrustedValueHolderType(trustedValue) {
20373        this.$$unwrapTrustedValue = function() {
20374          return trustedValue;
20375        };
20376      };
20377      if (Base) {
20378        holderType.prototype = new Base();
20379      }
20380      holderType.prototype.valueOf = function sceValueOf() {
20381        return this.$$unwrapTrustedValue();
20382      };
20383      holderType.prototype.toString = function sceToString() {
20384        return this.$$unwrapTrustedValue().toString();
20385      };
20386      return holderType;
20387    }
20388
20389    var trustedValueHolderBase = generateHolderType(),
20390        byType = {};
20391
20392    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
20393    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
20394    byType[SCE_CONTEXTS.MEDIA_URL] = generateHolderType(trustedValueHolderBase);
20395    byType[SCE_CONTEXTS.URL] = generateHolderType(byType[SCE_CONTEXTS.MEDIA_URL]);
20396    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
20397    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
20398
20399    /**
20400     * @ngdoc method
20401     * @name $sceDelegate#trustAs
20402     *
20403     * @description
20404     * Returns a trusted representation of the parameter for the specified context. This trusted
20405     * object will later on be used as-is, without any security check, by bindings or directives
20406     * that require this security context.
20407     * For instance, marking a string as trusted for the `$sce.HTML` context will entirely bypass
20408     * the potential `$sanitize` call in corresponding `$sce.HTML` bindings or directives, such as
20409     * `ng-bind-html`. Note that in most cases you won't need to call this function: if you have the
20410     * sanitizer loaded, passing the value itself will render all the HTML that does not pose a
20411     * security risk.
20412     *
20413     * See {@link ng.$sceDelegate#getTrusted getTrusted} for the function that will consume those
20414     * trusted values, and {@link ng.$sce $sce} for general documentation about strict contextual
20415     * escaping.
20416     *
20417     * @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`,
20418     *     `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`.
20419     *
20420     * @param {*} value The value that should be considered trusted.
20421     * @return {*} A trusted representation of value, that can be used in the given context.
20422     */
20423    function trustAs(type, trustedValue) {
20424      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
20425      if (!Constructor) {
20426        throw $sceMinErr('icontext',
20427            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
20428            type, trustedValue);
20429      }
20430      if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
20431        return trustedValue;
20432      }
20433      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
20434      // mutable objects, we ensure here that the value passed in is actually a string.
20435      if (typeof trustedValue !== 'string') {
20436        throw $sceMinErr('itype',
20437            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
20438            type);
20439      }
20440      return new Constructor(trustedValue);
20441    }
20442
20443    /**
20444     * @ngdoc method
20445     * @name $sceDelegate#valueOf
20446     *
20447     * @description
20448     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
20449     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
20450     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
20451     *
20452     * If the passed parameter is not a value that had been returned by {@link
20453     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, it must be returned as-is.
20454     *
20455     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
20456     *     call or anything else.
20457     * @return {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
20458     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
20459     *     `value` unchanged.
20460     */
20461    function valueOf(maybeTrusted) {
20462      if (maybeTrusted instanceof trustedValueHolderBase) {
20463        return maybeTrusted.$$unwrapTrustedValue();
20464      } else {
20465        return maybeTrusted;
20466      }
20467    }
20468
20469    /**
20470     * @ngdoc method
20471     * @name $sceDelegate#getTrusted
20472     *
20473     * @description
20474     * Given an object and a security context in which to assign it, returns a value that's safe to
20475     * use in this context, which was represented by the parameter. To do so, this function either
20476     * unwraps the safe type it has been given (for instance, a {@link ng.$sceDelegate#trustAs
20477     * `$sceDelegate.trustAs`} result), or it might try to sanitize the value given, depending on
20478     * the context and sanitizer availablility.
20479     *
20480     * The contexts that can be sanitized are $sce.MEDIA_URL, $sce.URL and $sce.HTML. The first two are available
20481     * by default, and the third one relies on the `$sanitize` service (which may be loaded through
20482     * the `ngSanitize` module). Furthermore, for $sce.RESOURCE_URL context, a plain string may be
20483     * accepted if the resource url policy defined by {@link ng.$sceDelegateProvider#trustedResourceUrlList
20484     * `$sceDelegateProvider.trustedResourceUrlList`} and {@link ng.$sceDelegateProvider#bannedResourceUrlList
20485     * `$sceDelegateProvider.bannedResourceUrlList`} accepts that resource.
20486     *
20487     * This function will throw if the safe type isn't appropriate for this context, or if the
20488     * value given cannot be accepted in the context (which might be caused by sanitization not
20489     * being available, or the value not being recognized as safe).
20490     *
20491     * <div class="alert alert-danger">
20492     * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
20493     * (XSS) vulnerability in your application.
20494     * </div>
20495     *
20496     * @param {string} type The context in which this value is to be used (such as `$sce.HTML`).
20497     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
20498     *     `$sceDelegate.trustAs`} call, or anything else (which will not be considered trusted.)
20499     * @return {*} A version of the value that's safe to use in the given context, or throws an
20500     *     exception if this is impossible.
20501     */
20502    function getTrusted(type, maybeTrusted) {
20503      if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
20504        return maybeTrusted;
20505      }
20506      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
20507      // If maybeTrusted is a trusted class instance or subclass instance, then unwrap and return
20508      // as-is.
20509      if (constructor && maybeTrusted instanceof constructor) {
20510        return maybeTrusted.$$unwrapTrustedValue();
20511      }
20512
20513      // If maybeTrusted is a trusted class instance but not of the correct trusted type
20514      // then unwrap it and allow it to pass through to the rest of the checks
20515      if (isFunction(maybeTrusted.$$unwrapTrustedValue)) {
20516        maybeTrusted = maybeTrusted.$$unwrapTrustedValue();
20517      }
20518
20519      // If we get here, then we will either sanitize the value or throw an exception.
20520      if (type === SCE_CONTEXTS.MEDIA_URL || type === SCE_CONTEXTS.URL) {
20521        // we attempt to sanitize non-resource URLs
20522        return $$sanitizeUri(maybeTrusted.toString(), type === SCE_CONTEXTS.MEDIA_URL);
20523      } else if (type === SCE_CONTEXTS.RESOURCE_URL) {
20524        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
20525          return maybeTrusted;
20526        } else {
20527          throw $sceMinErr('insecurl',
20528              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
20529              maybeTrusted.toString());
20530        }
20531      } else if (type === SCE_CONTEXTS.HTML) {
20532        // htmlSanitizer throws its own error when no sanitizer is available.
20533        return htmlSanitizer(maybeTrusted);
20534      }
20535      // Default error when the $sce service has no way to make the input safe.
20536      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
20537    }
20538
20539    return { trustAs: trustAs,
20540             getTrusted: getTrusted,
20541             valueOf: valueOf };
20542  }];
20543}
20544
20545
20546/**
20547 * @ngdoc provider
20548 * @name $sceProvider
20549 * @this
20550 *
20551 * @description
20552 *
20553 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
20554 * -   enable/disable Strict Contextual Escaping (SCE) in a module
20555 * -   override the default implementation with a custom delegate
20556 *
20557 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
20558 */
20559
20560/**
20561 * @ngdoc service
20562 * @name $sce
20563 * @kind function
20564 *
20565 * @description
20566 *
20567 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
20568 *
20569 * ## Strict Contextual Escaping
20570 *
20571 * Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render
20572 * trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and
20573 * (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
20574 *
20575 * ### Overview
20576 *
20577 * To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in
20578 * HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically
20579 * run security checks on them (sanitizations, trusted URL resource, depending on context), or throw
20580 * when it cannot guarantee the security of the result. That behavior depends strongly on contexts:
20581 * HTML can be sanitized, but template URLs cannot, for instance.
20582 *
20583 * To illustrate this, consider the `ng-bind-html` directive. It renders its value directly as HTML:
20584 * we call that the *context*. When given an untrusted input, AngularJS will attempt to sanitize it
20585 * before rendering if a sanitizer is available, and throw otherwise. To bypass sanitization and
20586 * render the input as-is, you will need to mark it as trusted for that context before attempting
20587 * to bind it.
20588 *
20589 * As of version 1.2, AngularJS ships with SCE enabled by default.
20590 *
20591 * ### In practice
20592 *
20593 * Here's an example of a binding in a privileged context:
20594 *
20595 * ```
20596 * <input ng-model="userHtml" aria-label="User input">
20597 * <div ng-bind-html="userHtml"></div>
20598 * ```
20599 *
20600 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
20601 * disabled, this application allows the user to render arbitrary HTML into the DIV, which would
20602 * be an XSS security bug. In a more realistic example, one may be rendering user comments, blog
20603 * articles, etc. via bindings. (HTML is just one example of a context where rendering user
20604 * controlled input creates security vulnerabilities.)
20605 *
20606 * For the case of HTML, you might use a library, either on the client side, or on the server side,
20607 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
20608 *
20609 * How would you ensure that every place that used these types of bindings was bound to a value that
20610 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
20611 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
20612 * properties/fields and forgot to update the binding to the sanitized value?
20613 *
20614 * To be secure by default, AngularJS makes sure bindings go through that sanitization, or
20615 * any similar validation process, unless there's a good reason to trust the given value in this
20616 * context.  That trust is formalized with a function call. This means that as a developer, you
20617 * can assume all untrusted bindings are safe. Then, to audit your code for binding security issues,
20618 * you just need to ensure the values you mark as trusted indeed are safe - because they were
20619 * received from your server, sanitized by your library, etc. You can organize your codebase to
20620 * help with this - perhaps allowing only the files in a specific directory to do this.
20621 * Ensuring that the internal API exposed by that code doesn't markup arbitrary values as safe then
20622 * becomes a more manageable task.
20623 *
20624 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
20625 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
20626 * build the trusted versions of your values.
20627 *
20628 * ### How does it work?
20629 *
20630 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
20631 * $sce.getTrusted(context, value)} rather than to the value directly.  Think of this function as
20632 * a way to enforce the required security context in your data sink. Directives use {@link
20633 * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs
20634 * the {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. Also,
20635 * when binding without directives, AngularJS will understand the context of your bindings
20636 * automatically.
20637 *
20638 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
20639 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
20640 * simplified):
20641 *
20642 * ```
20643 * var ngBindHtmlDirective = ['$sce', function($sce) {
20644 *   return function(scope, element, attr) {
20645 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
20646 *       element.html(value || '');
20647 *     });
20648 *   };
20649 * }];
20650 * ```
20651 *
20652 * ### Impact on loading templates
20653 *
20654 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
20655 * `templateUrl`'s specified by {@link guide/directive directives}.
20656 *
20657 * By default, AngularJS only loads templates from the same domain and protocol as the application
20658 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
20659 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
20660 * protocols, you may either add them to the {@link ng.$sceDelegateProvider#trustedResourceUrlList
20661 * trustedResourceUrlList} or {@link ng.$sce#trustAsResourceUrl wrap them} into trusted values.
20662 *
20663 * *Please note*:
20664 * The browser's
20665 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
20666 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
20667 * policy apply in addition to this and may further restrict whether the template is successfully
20668 * loaded.  This means that without the right CORS policy, loading templates from a different domain
20669 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
20670 * browsers.
20671 *
20672 * ### This feels like too much overhead
20673 *
20674 * It's important to remember that SCE only applies to interpolation expressions.
20675 *
20676 * If your expressions are constant literals, they're automatically trusted and you don't need to
20677 * call `$sce.trustAs` on them (e.g.
20678 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works (remember to include the
20679 * `ngSanitize` module). The `$sceDelegate` will also use the `$sanitize` service if it is available
20680 * when binding untrusted values to `$sce.HTML` context.
20681 * AngularJS provides an implementation in `angular-sanitize.js`, and if you
20682 * wish to use it, you will also need to depend on the {@link ngSanitize `ngSanitize`} module in
20683 * your application.
20684 *
20685 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
20686 * templates in `ng-include` from your application's domain without having to even know about SCE.
20687 * It blocks loading templates from other domains or loading templates over http from an https
20688 * served document.  You can change these by setting your own custom {@link
20689 * ng.$sceDelegateProvider#trustedResourceUrlList trusted resource URL list} and {@link
20690 * ng.$sceDelegateProvider#bannedResourceUrlList banned resource URL list} for matching such URLs.
20691 *
20692 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
20693 * application that's secure and can be audited to verify that with much more ease than bolting
20694 * security onto an application later.
20695 *
20696 * <a name="contexts"></a>
20697 * ### What trusted context types are supported?
20698 *
20699 * | Context             | Notes          |
20700 * |---------------------|----------------|
20701 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
20702 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
20703 * | `$sce.MEDIA_URL`    | For URLs that are safe to render as media. Is automatically converted from string by sanitizing when needed. |
20704 * | `$sce.URL`          | For URLs that are safe to follow as links. Is automatically converted from string by sanitizing when needed. Note that `$sce.URL` makes a stronger statement about the URL than `$sce.MEDIA_URL` does and therefore contexts requiring values trusted for `$sce.URL` can be used anywhere that values trusted for `$sce.MEDIA_URL` are required.|
20705 * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` or `$sce.MEDIA_URL` do and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` or `$sce.MEDIA_URL` are required. <br><br> The {@link $sceDelegateProvider#trustedResourceUrlList $sceDelegateProvider#trustedResourceUrlList()} and {@link $sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider#bannedResourceUrlList()} can be used to restrict trusted origins for `RESOURCE_URL` |
20706 * | `$sce.JS`           | For JavaScript that is safe to execute in your application's context.  Currently unused.  Feel free to use it in your own directives. |
20707 *
20708 *
20709 * <div class="alert alert-warning">
20710 * Be aware that, before AngularJS 1.7.0, `a[href]` and `img[src]` used to sanitize their
20711 * interpolated values directly rather than rely upon {@link ng.$sce#getTrusted `$sce.getTrusted`}.
20712 *
20713 * **As of 1.7.0, this is no longer the case.**
20714 *
20715 * Now such interpolations are marked as requiring `$sce.URL` (for `a[href]`) or `$sce.MEDIA_URL`
20716 * (for `img[src]`), so that the sanitization happens (via `$sce.getTrusted...`) when the `$interpolate`
20717 * service evaluates the expressions.
20718 * </div>
20719 *
20720 * There are no CSS or JS context bindings in AngularJS currently, so their corresponding `$sce.trustAs`
20721 * functions aren't useful yet. This might evolve.
20722 *
20723 * ### Format of items in {@link ng.$sceDelegateProvider#trustedResourceUrlList trustedResourceUrlList}/{@link ng.$sceDelegateProvider#bannedResourceUrlList bannedResourceUrlList} <a name="resourceUrlPatternItem"></a>
20724 *
20725 *  Each element in these arrays must be one of the following:
20726 *
20727 *  - **'self'**
20728 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
20729 *      domain** as the application document using the **same protocol**.
20730 *  - **String** (except the special value `'self'`)
20731 *    - The string is matched against the full *normalized / absolute URL* of the resource
20732 *      being tested (substring matches are not good enough.)
20733 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
20734 *      match themselves.
20735 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
20736 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
20737 *      for matching resource URL lists.
20738 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
20739 *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
20740 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
20741 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
20742 *      http://foo.example.com/templates/**).
20743 *  - **RegExp** (*see caveat below*)
20744 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
20745 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
20746 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
20747 *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
20748 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
20749 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
20750 *      is highly recommended to use the string patterns and only fall back to regular expressions
20751 *      as a last resort.
20752 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
20753 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
20754 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
20755 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
20756 *    - If you are generating your JavaScript from some other templating engine (not
20757 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
20758 *      remember to escape your regular expression (and be aware that you might need more than
20759 *      one level of escaping depending on your templating engine and the way you interpolated
20760 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
20761 *      enough before coding your own.  E.g. Ruby has
20762 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
20763 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
20764 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
20765 *      Closure library's [goog.string.regExpEscape(s)](
20766 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
20767 *
20768 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
20769 *
20770 * ### Show me an example using SCE.
20771 *
20772 * <example module="mySceApp" deps="angular-sanitize.js" name="sce-service">
20773 * <file name="index.html">
20774 *   <div ng-controller="AppController as myCtrl">
20775 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
20776 *     <b>User comments</b><br>
20777 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
20778 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
20779 *     exploit.
20780 *     <div class="well">
20781 *       <div ng-repeat="userComment in myCtrl.userComments">
20782 *         <b>{{userComment.name}}</b>:
20783 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
20784 *         <br>
20785 *       </div>
20786 *     </div>
20787 *   </div>
20788 * </file>
20789 *
20790 * <file name="script.js">
20791 *   angular.module('mySceApp', ['ngSanitize'])
20792 *     .controller('AppController', ['$http', '$templateCache', '$sce',
20793 *       function AppController($http, $templateCache, $sce) {
20794 *         var self = this;
20795 *         $http.get('test_data.json', {cache: $templateCache}).then(function(response) {
20796 *           self.userComments = response.data;
20797 *         });
20798 *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
20799 *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
20800 *             'sanitization.&quot;">Hover over this text.</span>');
20801 *       }]);
20802 * </file>
20803 *
20804 * <file name="test_data.json">
20805 * [
20806 *   { "name": "Alice",
20807 *     "htmlComment":
20808 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
20809 *   },
20810 *   { "name": "Bob",
20811 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
20812 *   }
20813 * ]
20814 * </file>
20815 *
20816 * <file name="protractor.js" type="protractor">
20817 *   describe('SCE doc demo', function() {
20818 *     it('should sanitize untrusted values', function() {
20819 *       expect(element.all(by.css('.htmlComment')).first().getAttribute('innerHTML'))
20820 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
20821 *     });
20822 *
20823 *     it('should NOT sanitize explicitly trusted values', function() {
20824 *       expect(element(by.id('explicitlyTrustedHtml')).getAttribute('innerHTML')).toBe(
20825 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
20826 *           'sanitization.&quot;">Hover over this text.</span>');
20827 *     });
20828 *   });
20829 * </file>
20830 * </example>
20831 *
20832 *
20833 *
20834 * ## Can I disable SCE completely?
20835 *
20836 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
20837 * for little coding overhead.  It will be much harder to take an SCE disabled application and
20838 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
20839 * for cases where you have a lot of existing code that was written before SCE was introduced and
20840 * you're migrating them a module at a time. Also do note that this is an app-wide setting, so if
20841 * you are writing a library, you will cause security bugs applications using it.
20842 *
20843 * That said, here's how you can completely disable SCE:
20844 *
20845 * ```
20846 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
20847 *   // Completely disable SCE.  For demonstration purposes only!
20848 *   // Do not use in new projects or libraries.
20849 *   $sceProvider.enabled(false);
20850 * });
20851 * ```
20852 *
20853 */
20854
20855function $SceProvider() {
20856  var enabled = true;
20857
20858  /**
20859   * @ngdoc method
20860   * @name $sceProvider#enabled
20861   * @kind function
20862   *
20863   * @param {boolean=} value If provided, then enables/disables SCE application-wide.
20864   * @return {boolean} True if SCE is enabled, false otherwise.
20865   *
20866   * @description
20867   * Enables/disables SCE and returns the current value.
20868   */
20869  this.enabled = function(value) {
20870    if (arguments.length) {
20871      enabled = !!value;
20872    }
20873    return enabled;
20874  };
20875
20876
20877  /* Design notes on the default implementation for SCE.
20878   *
20879   * The API contract for the SCE delegate
20880   * -------------------------------------
20881   * The SCE delegate object must provide the following 3 methods:
20882   *
20883   * - trustAs(contextEnum, value)
20884   *     This method is used to tell the SCE service that the provided value is OK to use in the
20885   *     contexts specified by contextEnum.  It must return an object that will be accepted by
20886   *     getTrusted() for a compatible contextEnum and return this value.
20887   *
20888   * - valueOf(value)
20889   *     For values that were not produced by trustAs(), return them as is.  For values that were
20890   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
20891   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
20892   *     such a value.
20893   *
20894   * - getTrusted(contextEnum, value)
20895   *     This function should return the value that is safe to use in the context specified by
20896   *     contextEnum or throw and exception otherwise.
20897   *
20898   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
20899   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
20900   * instance, an implementation could maintain a registry of all trusted objects by context.  In
20901   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
20902   * return the same object passed in if it was found in the registry under a compatible context or
20903   * throw an exception otherwise.  An implementation might only wrap values some of the time based
20904   * on some criteria.  getTrusted() might return a value and not throw an exception for special
20905   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
20906   *
20907   *
20908   * A note on the inheritance model for SCE contexts
20909   * ------------------------------------------------
20910   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
20911   * is purely an implementation details.
20912   *
20913   * The contract is simply this:
20914   *
20915   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
20916   *     will also succeed.
20917   *
20918   * Inheritance happens to capture this in a natural way. In some future, we may not use
20919   * inheritance anymore. That is OK because no code outside of sce.js and sceSpecs.js would need to
20920   * be aware of this detail.
20921   */
20922
20923  this.$get = ['$parse', '$sceDelegate', function(
20924                $parse,   $sceDelegate) {
20925    // Support: IE 9-11 only
20926    // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
20927    // the "expression(javascript expression)" syntax which is insecure.
20928    if (enabled && msie < 8) {
20929      throw $sceMinErr('iequirks',
20930        'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
20931        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
20932        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
20933    }
20934
20935    var sce = shallowCopy(SCE_CONTEXTS);
20936
20937    /**
20938     * @ngdoc method
20939     * @name $sce#isEnabled
20940     * @kind function
20941     *
20942     * @return {Boolean} True if SCE is enabled, false otherwise.  If you want to set the value, you
20943     *     have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
20944     *
20945     * @description
20946     * Returns a boolean indicating if SCE is enabled.
20947     */
20948    sce.isEnabled = function() {
20949      return enabled;
20950    };
20951    sce.trustAs = $sceDelegate.trustAs;
20952    sce.getTrusted = $sceDelegate.getTrusted;
20953    sce.valueOf = $sceDelegate.valueOf;
20954
20955    if (!enabled) {
20956      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
20957      sce.valueOf = identity;
20958    }
20959
20960    /**
20961     * @ngdoc method
20962     * @name $sce#parseAs
20963     *
20964     * @description
20965     * Converts AngularJS {@link guide/expression expression} into a function.  This is like {@link
20966     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
20967     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
20968     * *result*)}
20969     *
20970     * @param {string} type The SCE context in which this result will be used.
20971     * @param {string} expression String expression to compile.
20972     * @return {function(context, locals)} A function which represents the compiled expression:
20973     *
20974     *    * `context` – `{object}` – an object against which any expressions embedded in the
20975     *      strings are evaluated against (typically a scope object).
20976     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
20977     *      in `context`.
20978     */
20979    sce.parseAs = function sceParseAs(type, expr) {
20980      var parsed = $parse(expr);
20981      if (parsed.literal && parsed.constant) {
20982        return parsed;
20983      } else {
20984        return $parse(expr, function(value) {
20985          return sce.getTrusted(type, value);
20986        });
20987      }
20988    };
20989
20990    /**
20991     * @ngdoc method
20992     * @name $sce#trustAs
20993     *
20994     * @description
20995     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, returns a
20996     * wrapped object that represents your value, and the trust you have in its safety for the given
20997     * context. AngularJS can then use that value as-is in bindings of the specified secure context.
20998     * This is used in bindings for `ng-bind-html`, `ng-include`, and most `src` attribute
20999     * interpolations. See {@link ng.$sce $sce} for strict contextual escaping.
21000     *
21001     * @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`,
21002     *     `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`.
21003     *
21004     * @param {*} value The value that that should be considered trusted.
21005     * @return {*} A wrapped version of value that can be used as a trusted variant of your `value`
21006     *     in the context you specified.
21007     */
21008
21009    /**
21010     * @ngdoc method
21011     * @name $sce#trustAsHtml
21012     *
21013     * @description
21014     * Shorthand method.  `$sce.trustAsHtml(value)` →
21015     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
21016     *
21017     * @param {*} value The value to mark as trusted for `$sce.HTML` context.
21018     * @return {*} A wrapped version of value that can be used as a trusted variant of your `value`
21019     *     in `$sce.HTML` context (like `ng-bind-html`).
21020     */
21021
21022    /**
21023     * @ngdoc method
21024     * @name $sce#trustAsCss
21025     *
21026     * @description
21027     * Shorthand method.  `$sce.trustAsCss(value)` →
21028     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.CSS, value)`}
21029     *
21030     * @param {*} value The value to mark as trusted for `$sce.CSS` context.
21031     * @return {*} A wrapped version of value that can be used as a trusted variant
21032     *     of your `value` in `$sce.CSS` context. This context is currently unused, so there are
21033     *     almost no reasons to use this function so far.
21034     */
21035
21036    /**
21037     * @ngdoc method
21038     * @name $sce#trustAsUrl
21039     *
21040     * @description
21041     * Shorthand method.  `$sce.trustAsUrl(value)` →
21042     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
21043     *
21044     * @param {*} value The value to mark as trusted for `$sce.URL` context.
21045     * @return {*} A wrapped version of value that can be used as a trusted variant of your `value`
21046     *     in `$sce.URL` context. That context is currently unused, so there are almost no reasons
21047     *     to use this function so far.
21048     */
21049
21050    /**
21051     * @ngdoc method
21052     * @name $sce#trustAsResourceUrl
21053     *
21054     * @description
21055     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
21056     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
21057     *
21058     * @param {*} value The value to mark as trusted for `$sce.RESOURCE_URL` context.
21059     * @return {*} A wrapped version of value that can be used as a trusted variant of your `value`
21060     *     in `$sce.RESOURCE_URL` context (template URLs in `ng-include`, most `src` attribute
21061     *     bindings, ...)
21062     */
21063
21064    /**
21065     * @ngdoc method
21066     * @name $sce#trustAsJs
21067     *
21068     * @description
21069     * Shorthand method.  `$sce.trustAsJs(value)` →
21070     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
21071     *
21072     * @param {*} value The value to mark as trusted for `$sce.JS` context.
21073     * @return {*} A wrapped version of value that can be used as a trusted variant of your `value`
21074     *     in `$sce.JS` context. That context is currently unused, so there are almost no reasons to
21075     *     use this function so far.
21076     */
21077
21078    /**
21079     * @ngdoc method
21080     * @name $sce#getTrusted
21081     *
21082     * @description
21083     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
21084     * takes any input, and either returns a value that's safe to use in the specified context,
21085     * or throws an exception. This function is aware of trusted values created by the `trustAs`
21086     * function and its shorthands, and when contexts are appropriate, returns the unwrapped value
21087     * as-is. Finally, this function can also throw when there is no way to turn `maybeTrusted` in a
21088     * safe value (e.g., no sanitization is available or possible.)
21089     *
21090     * @param {string} type The context in which this value is to be used.
21091     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs
21092     *     `$sce.trustAs`} call, or anything else (which will not be considered trusted.)
21093     * @return {*} A version of the value that's safe to use in the given context, or throws an
21094     *     exception if this is impossible.
21095     */
21096
21097    /**
21098     * @ngdoc method
21099     * @name $sce#getTrustedHtml
21100     *
21101     * @description
21102     * Shorthand method.  `$sce.getTrustedHtml(value)` →
21103     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
21104     *
21105     * @param {*} value The value to pass to `$sce.getTrusted`.
21106     * @return {*} The return value of `$sce.getTrusted($sce.HTML, value)`
21107     */
21108
21109    /**
21110     * @ngdoc method
21111     * @name $sce#getTrustedCss
21112     *
21113     * @description
21114     * Shorthand method.  `$sce.getTrustedCss(value)` →
21115     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
21116     *
21117     * @param {*} value The value to pass to `$sce.getTrusted`.
21118     * @return {*} The return value of `$sce.getTrusted($sce.CSS, value)`
21119     */
21120
21121    /**
21122     * @ngdoc method
21123     * @name $sce#getTrustedUrl
21124     *
21125     * @description
21126     * Shorthand method.  `$sce.getTrustedUrl(value)` →
21127     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
21128     *
21129     * @param {*} value The value to pass to `$sce.getTrusted`.
21130     * @return {*} The return value of `$sce.getTrusted($sce.URL, value)`
21131     */
21132
21133    /**
21134     * @ngdoc method
21135     * @name $sce#getTrustedResourceUrl
21136     *
21137     * @description
21138     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
21139     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
21140     *
21141     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
21142     * @return {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
21143     */
21144
21145    /**
21146     * @ngdoc method
21147     * @name $sce#getTrustedJs
21148     *
21149     * @description
21150     * Shorthand method.  `$sce.getTrustedJs(value)` →
21151     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
21152     *
21153     * @param {*} value The value to pass to `$sce.getTrusted`.
21154     * @return {*} The return value of `$sce.getTrusted($sce.JS, value)`
21155     */
21156
21157    /**
21158     * @ngdoc method
21159     * @name $sce#parseAsHtml
21160     *
21161     * @description
21162     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
21163     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
21164     *
21165     * @param {string} expression String expression to compile.
21166     * @return {function(context, locals)} A function which represents the compiled expression:
21167     *
21168     *    * `context` – `{object}` – an object against which any expressions embedded in the
21169     *      strings are evaluated against (typically a scope object).
21170     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
21171     *      in `context`.
21172     */
21173
21174    /**
21175     * @ngdoc method
21176     * @name $sce#parseAsCss
21177     *
21178     * @description
21179     * Shorthand method.  `$sce.parseAsCss(value)` →
21180     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
21181     *
21182     * @param {string} expression String expression to compile.
21183     * @return {function(context, locals)} A function which represents the compiled expression:
21184     *
21185     *    * `context` – `{object}` – an object against which any expressions embedded in the
21186     *      strings are evaluated against (typically a scope object).
21187     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
21188     *      in `context`.
21189     */
21190
21191    /**
21192     * @ngdoc method
21193     * @name $sce#parseAsUrl
21194     *
21195     * @description
21196     * Shorthand method.  `$sce.parseAsUrl(value)` →
21197     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
21198     *
21199     * @param {string} expression String expression to compile.
21200     * @return {function(context, locals)} A function which represents the compiled expression:
21201     *
21202     *    * `context` – `{object}` – an object against which any expressions embedded in the
21203     *      strings are evaluated against (typically a scope object).
21204     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
21205     *      in `context`.
21206     */
21207
21208    /**
21209     * @ngdoc method
21210     * @name $sce#parseAsResourceUrl
21211     *
21212     * @description
21213     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
21214     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
21215     *
21216     * @param {string} expression String expression to compile.
21217     * @return {function(context, locals)} A function which represents the compiled expression:
21218     *
21219     *    * `context` – `{object}` – an object against which any expressions embedded in the
21220     *      strings are evaluated against (typically a scope object).
21221     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
21222     *      in `context`.
21223     */
21224
21225    /**
21226     * @ngdoc method
21227     * @name $sce#parseAsJs
21228     *
21229     * @description
21230     * Shorthand method.  `$sce.parseAsJs(value)` →
21231     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
21232     *
21233     * @param {string} expression String expression to compile.
21234     * @return {function(context, locals)} A function which represents the compiled expression:
21235     *
21236     *    * `context` – `{object}` – an object against which any expressions embedded in the
21237     *      strings are evaluated against (typically a scope object).
21238     *    * `locals` – `{object=}` – local variables context object, useful for overriding values
21239     *      in `context`.
21240     */
21241
21242    // Shorthand delegations.
21243    var parse = sce.parseAs,
21244        getTrusted = sce.getTrusted,
21245        trustAs = sce.trustAs;
21246
21247    forEach(SCE_CONTEXTS, function(enumValue, name) {
21248      var lName = lowercase(name);
21249      sce[snakeToCamel('parse_as_' + lName)] = function(expr) {
21250        return parse(enumValue, expr);
21251      };
21252      sce[snakeToCamel('get_trusted_' + lName)] = function(value) {
21253        return getTrusted(enumValue, value);
21254      };
21255      sce[snakeToCamel('trust_as_' + lName)] = function(value) {
21256        return trustAs(enumValue, value);
21257      };
21258    });
21259
21260    return sce;
21261  }];
21262}
21263
21264/* exported $SnifferProvider */
21265
21266/**
21267 * !!! This is an undocumented "private" service !!!
21268 *
21269 * @name $sniffer
21270 * @requires $window
21271 * @requires $document
21272 * @this
21273 *
21274 * @property {boolean} history Does the browser support html5 history api ?
21275 * @property {boolean} transitions Does the browser support CSS transition events ?
21276 * @property {boolean} animations Does the browser support CSS animation events ?
21277 *
21278 * @description
21279 * This is very simple implementation of testing browser's features.
21280 */
21281function $SnifferProvider() {
21282  this.$get = ['$window', '$document', function($window, $document) {
21283    var eventSupport = {},
21284        // Chrome Packaged Apps are not allowed to access `history.pushState`.
21285        // If not sandboxed, they can be detected by the presence of `chrome.app.runtime`
21286        // (see https://developer.chrome.com/apps/api_index). If sandboxed, they can be detected by
21287        // the presence of an extension runtime ID and the absence of other Chrome runtime APIs
21288        // (see https://developer.chrome.com/apps/manifest/sandbox).
21289        // (NW.js apps have access to Chrome APIs, but do support `history`.)
21290        isNw = $window.nw && $window.nw.process,
21291        isChromePackagedApp =
21292            !isNw &&
21293            $window.chrome &&
21294            ($window.chrome.app && $window.chrome.app.runtime ||
21295                !$window.chrome.app && $window.chrome.runtime && $window.chrome.runtime.id),
21296        hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,
21297        android =
21298          toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
21299        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
21300        document = $document[0] || {},
21301        bodyStyle = document.body && document.body.style,
21302        transitions = false,
21303        animations = false;
21304
21305    if (bodyStyle) {
21306      // Support: Android <5, Blackberry Browser 10, default Chrome in Android 4.4.x
21307      // Mentioned browsers need a -webkit- prefix for transitions & animations.
21308      transitions = !!('transition' in bodyStyle || 'webkitTransition' in bodyStyle);
21309      animations = !!('animation' in bodyStyle || 'webkitAnimation' in bodyStyle);
21310    }
21311
21312
21313    return {
21314      // Android has history.pushState, but it does not update location correctly
21315      // so let's not use the history API at all.
21316      // http://code.google.com/p/android/issues/detail?id=17471
21317      // https://github.com/angular/angular.js/issues/904
21318
21319      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
21320      // so let's not use the history API also
21321      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
21322      history: !!(hasHistoryPushState && !(android < 4) && !boxee),
21323      hasEvent: function(event) {
21324        // Support: IE 9-11 only
21325        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
21326        // it. In particular the event is not fired when backspace or delete key are pressed or
21327        // when cut operation is performed.
21328        // IE10+ implements 'input' event but it erroneously fires under various situations,
21329        // e.g. when placeholder changes, or a form is focused.
21330        if (event === 'input' && msie) return false;
21331
21332        if (isUndefined(eventSupport[event])) {
21333          var divElm = document.createElement('div');
21334          eventSupport[event] = 'on' + event in divElm;
21335        }
21336
21337        return eventSupport[event];
21338      },
21339      csp: csp(),
21340      transitions: transitions,
21341      animations: animations,
21342      android: android
21343    };
21344  }];
21345}
21346
21347/**
21348 * ! This is a private undocumented service !
21349 *
21350 * @name $$taskTrackerFactory
21351 * @description
21352 * A function to create `TaskTracker` instances.
21353 *
21354 * A `TaskTracker` can keep track of pending tasks (grouped by type) and can notify interested
21355 * parties when all pending tasks (or tasks of a specific type) have been completed.
21356 *
21357 * @param {$log} log - A logger instance (such as `$log`). Used to log error during callback
21358 *     execution.
21359 *
21360 * @this
21361 */
21362function $$TaskTrackerFactoryProvider() {
21363  this.$get = valueFn(function(log) { return new TaskTracker(log); });
21364}
21365
21366function TaskTracker(log) {
21367  var self = this;
21368  var taskCounts = {};
21369  var taskCallbacks = [];
21370
21371  var ALL_TASKS_TYPE = self.ALL_TASKS_TYPE = '$$all$$';
21372  var DEFAULT_TASK_TYPE = self.DEFAULT_TASK_TYPE = '$$default$$';
21373
21374  /**
21375   * Execute the specified function and decrement the appropriate `taskCounts` counter.
21376   * If the counter reaches 0, all corresponding `taskCallbacks` are executed.
21377   *
21378   * @param {Function} fn - The function to execute.
21379   * @param {string=} [taskType=DEFAULT_TASK_TYPE] - The type of task that is being completed.
21380   */
21381  self.completeTask = completeTask;
21382
21383  /**
21384   * Increase the task count for the specified task type (or the default task type if non is
21385   * specified).
21386   *
21387   * @param {string=} [taskType=DEFAULT_TASK_TYPE] - The type of task whose count will be increased.
21388   */
21389  self.incTaskCount = incTaskCount;
21390
21391  /**
21392   * Execute the specified callback when all pending tasks have been completed.
21393   *
21394   * If there are no pending tasks, the callback is executed immediately. You can optionally limit
21395   * the tasks that will be waited for to a specific type, by passing a `taskType`.
21396   *
21397   * @param {function} callback - The function to call when there are no pending tasks.
21398   * @param {string=} [taskType=ALL_TASKS_TYPE] - The type of tasks that will be waited for.
21399   */
21400  self.notifyWhenNoPendingTasks = notifyWhenNoPendingTasks;
21401
21402  function completeTask(fn, taskType) {
21403    taskType = taskType || DEFAULT_TASK_TYPE;
21404
21405    try {
21406      fn();
21407    } finally {
21408      decTaskCount(taskType);
21409
21410      var countForType = taskCounts[taskType];
21411      var countForAll = taskCounts[ALL_TASKS_TYPE];
21412
21413      // If at least one of the queues (`ALL_TASKS_TYPE` or `taskType`) is empty, run callbacks.
21414      if (!countForAll || !countForType) {
21415        var getNextCallback = !countForAll ? getLastCallback : getLastCallbackForType;
21416        var nextCb;
21417
21418        while ((nextCb = getNextCallback(taskType))) {
21419          try {
21420            nextCb();
21421          } catch (e) {
21422            log.error(e);
21423          }
21424        }
21425      }
21426    }
21427  }
21428
21429  function decTaskCount(taskType) {
21430    taskType = taskType || DEFAULT_TASK_TYPE;
21431    if (taskCounts[taskType]) {
21432      taskCounts[taskType]--;
21433      taskCounts[ALL_TASKS_TYPE]--;
21434    }
21435  }
21436
21437  function getLastCallback() {
21438    var cbInfo = taskCallbacks.pop();
21439    return cbInfo && cbInfo.cb;
21440  }
21441
21442  function getLastCallbackForType(taskType) {
21443    for (var i = taskCallbacks.length - 1; i >= 0; --i) {
21444      var cbInfo = taskCallbacks[i];
21445      if (cbInfo.type === taskType) {
21446        taskCallbacks.splice(i, 1);
21447        return cbInfo.cb;
21448      }
21449    }
21450  }
21451
21452  function incTaskCount(taskType) {
21453    taskType = taskType || DEFAULT_TASK_TYPE;
21454    taskCounts[taskType] = (taskCounts[taskType] || 0) + 1;
21455    taskCounts[ALL_TASKS_TYPE] = (taskCounts[ALL_TASKS_TYPE] || 0) + 1;
21456  }
21457
21458  function notifyWhenNoPendingTasks(callback, taskType) {
21459    taskType = taskType || ALL_TASKS_TYPE;
21460    if (!taskCounts[taskType]) {
21461      callback();
21462    } else {
21463      taskCallbacks.push({type: taskType, cb: callback});
21464    }
21465  }
21466}
21467
21468var $templateRequestMinErr = minErr('$templateRequest');
21469
21470/**
21471 * @ngdoc provider
21472 * @name $templateRequestProvider
21473 * @this
21474 *
21475 * @description
21476 * Used to configure the options passed to the {@link $http} service when making a template request.
21477 *
21478 * For example, it can be used for specifying the "Accept" header that is sent to the server, when
21479 * requesting a template.
21480 */
21481function $TemplateRequestProvider() {
21482
21483  var httpOptions;
21484
21485  /**
21486   * @ngdoc method
21487   * @name $templateRequestProvider#httpOptions
21488   * @description
21489   * The options to be passed to the {@link $http} service when making the request.
21490   * You can use this to override options such as the "Accept" header for template requests.
21491   *
21492   * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
21493   * options if not overridden here.
21494   *
21495   * @param {string=} value new value for the {@link $http} options.
21496   * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
21497   */
21498  this.httpOptions = function(val) {
21499    if (val) {
21500      httpOptions = val;
21501      return this;
21502    }
21503    return httpOptions;
21504  };
21505
21506  /**
21507   * @ngdoc service
21508   * @name $templateRequest
21509   *
21510   * @description
21511   * The `$templateRequest` service runs security checks then downloads the provided template using
21512   * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
21513   * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
21514   * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
21515   * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
21516   * when `tpl` is of type string and `$templateCache` has the matching entry.
21517   *
21518   * If you want to pass custom options to the `$http` service, such as setting the Accept header you
21519   * can configure this via {@link $templateRequestProvider#httpOptions}.
21520   *
21521   * `$templateRequest` is used internally by {@link $compile}, {@link ngRoute.$route}, and directives such
21522   * as {@link ngInclude} to download and cache templates.
21523   *
21524   * 3rd party modules should use `$templateRequest` if their services or directives are loading
21525   * templates.
21526   *
21527   * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
21528   * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
21529   *
21530   * @return {Promise} a promise for the HTTP response data of the given URL.
21531   *
21532   * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
21533   */
21534  this.$get = ['$exceptionHandler', '$templateCache', '$http', '$q', '$sce',
21535    function($exceptionHandler, $templateCache, $http, $q, $sce) {
21536
21537      function handleRequestFn(tpl, ignoreRequestError) {
21538        handleRequestFn.totalPendingRequests++;
21539
21540        // We consider the template cache holds only trusted templates, so
21541        // there's no need to go through adding the template again to the trusted
21542        // resources for keys that already are included in there. This also makes
21543        // AngularJS accept any script directive, no matter its name. However, we
21544        // still need to unwrap trusted types.
21545        if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {
21546          tpl = $sce.getTrustedResourceUrl(tpl);
21547        }
21548
21549        var transformResponse = $http.defaults && $http.defaults.transformResponse;
21550
21551        if (isArray(transformResponse)) {
21552          transformResponse = transformResponse.filter(function(transformer) {
21553            return transformer !== defaultHttpResponseTransform;
21554          });
21555        } else if (transformResponse === defaultHttpResponseTransform) {
21556          transformResponse = null;
21557        }
21558
21559        return $http.get(tpl, extend({
21560            cache: $templateCache,
21561            transformResponse: transformResponse
21562          }, httpOptions))
21563          .finally(function() {
21564            handleRequestFn.totalPendingRequests--;
21565          })
21566          .then(function(response) {
21567            return $templateCache.put(tpl, response.data);
21568          }, handleError);
21569
21570        function handleError(resp) {
21571          if (!ignoreRequestError) {
21572            resp = $templateRequestMinErr('tpload',
21573                'Failed to load template: {0} (HTTP status: {1} {2})',
21574                tpl, resp.status, resp.statusText);
21575
21576            $exceptionHandler(resp);
21577          }
21578
21579          return $q.reject(resp);
21580        }
21581      }
21582
21583      handleRequestFn.totalPendingRequests = 0;
21584
21585      return handleRequestFn;
21586    }
21587  ];
21588}
21589
21590/** @this */
21591function $$TestabilityProvider() {
21592  this.$get = ['$rootScope', '$browser', '$location',
21593       function($rootScope,   $browser,   $location) {
21594
21595    /**
21596     * @name $testability
21597     *
21598     * @description
21599     * The private $$testability service provides a collection of methods for use when debugging
21600     * or by automated test and debugging tools.
21601     */
21602    var testability = {};
21603
21604    /**
21605     * @name $$testability#findBindings
21606     *
21607     * @description
21608     * Returns an array of elements that are bound (via ng-bind or {{}})
21609     * to expressions matching the input.
21610     *
21611     * @param {Element} element The element root to search from.
21612     * @param {string} expression The binding expression to match.
21613     * @param {boolean} opt_exactMatch If true, only returns exact matches
21614     *     for the expression. Filters and whitespace are ignored.
21615     */
21616    testability.findBindings = function(element, expression, opt_exactMatch) {
21617      var bindings = element.getElementsByClassName('ng-binding');
21618      var matches = [];
21619      forEach(bindings, function(binding) {
21620        var dataBinding = angular.element(binding).data('$binding');
21621        if (dataBinding) {
21622          forEach(dataBinding, function(bindingName) {
21623            if (opt_exactMatch) {
21624              var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
21625              if (matcher.test(bindingName)) {
21626                matches.push(binding);
21627              }
21628            } else {
21629              if (bindingName.indexOf(expression) !== -1) {
21630                matches.push(binding);
21631              }
21632            }
21633          });
21634        }
21635      });
21636      return matches;
21637    };
21638
21639    /**
21640     * @name $$testability#findModels
21641     *
21642     * @description
21643     * Returns an array of elements that are two-way found via ng-model to
21644     * expressions matching the input.
21645     *
21646     * @param {Element} element The element root to search from.
21647     * @param {string} expression The model expression to match.
21648     * @param {boolean} opt_exactMatch If true, only returns exact matches
21649     *     for the expression.
21650     */
21651    testability.findModels = function(element, expression, opt_exactMatch) {
21652      var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
21653      for (var p = 0; p < prefixes.length; ++p) {
21654        var attributeEquals = opt_exactMatch ? '=' : '*=';
21655        var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
21656        var elements = element.querySelectorAll(selector);
21657        if (elements.length) {
21658          return elements;
21659        }
21660      }
21661    };
21662
21663    /**
21664     * @name $$testability#getLocation
21665     *
21666     * @description
21667     * Shortcut for getting the location in a browser agnostic way. Returns
21668     *     the path, search, and hash. (e.g. /path?a=b#hash)
21669     */
21670    testability.getLocation = function() {
21671      return $location.url();
21672    };
21673
21674    /**
21675     * @name $$testability#setLocation
21676     *
21677     * @description
21678     * Shortcut for navigating to a location without doing a full page reload.
21679     *
21680     * @param {string} url The location url (path, search and hash,
21681     *     e.g. /path?a=b#hash) to go to.
21682     */
21683    testability.setLocation = function(url) {
21684      if (url !== $location.url()) {
21685        $location.url(url);
21686        $rootScope.$digest();
21687      }
21688    };
21689
21690    /**
21691     * @name $$testability#whenStable
21692     *
21693     * @description
21694     * Calls the callback when all pending tasks are completed.
21695     *
21696     * Types of tasks waited for include:
21697     * - Pending timeouts (via {@link $timeout}).
21698     * - Pending HTTP requests (via {@link $http}).
21699     * - In-progress route transitions (via {@link $route}).
21700     * - Pending tasks scheduled via {@link $rootScope#$applyAsync}.
21701     * - Pending tasks scheduled via {@link $rootScope#$evalAsync}.
21702     *   These include tasks scheduled via `$evalAsync()` indirectly (such as {@link $q} promises).
21703     *
21704     * @param {function} callback
21705     */
21706    testability.whenStable = function(callback) {
21707      $browser.notifyWhenNoOutstandingRequests(callback);
21708    };
21709
21710    return testability;
21711  }];
21712}
21713
21714var $timeoutMinErr = minErr('$timeout');
21715
21716/** @this */
21717function $TimeoutProvider() {
21718  this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
21719       function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
21720
21721    var deferreds = {};
21722
21723
21724    /**
21725     * @ngdoc service
21726     * @name $timeout
21727     *
21728     * @description
21729     * AngularJS's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
21730     * block and delegates any exceptions to
21731     * {@link ng.$exceptionHandler $exceptionHandler} service.
21732     *
21733     * The return value of calling `$timeout` is a promise, which will be resolved when
21734     * the delay has passed and the timeout function, if provided, is executed.
21735     *
21736     * To cancel a timeout request, call `$timeout.cancel(promise)`.
21737     *
21738     * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
21739     * synchronously flush the queue of deferred functions.
21740     *
21741     * If you only want a promise that will be resolved after some specified delay
21742     * then you can call `$timeout` without the `fn` function.
21743     *
21744     * @param {function()=} fn A function, whose execution should be delayed.
21745     * @param {number=} [delay=0] Delay in milliseconds.
21746     * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
21747     *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
21748     * @param {...*=} Pass additional parameters to the executed function.
21749     * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
21750     *   will be resolved with the return value of the `fn` function.
21751     *
21752     */
21753    function timeout(fn, delay, invokeApply) {
21754      if (!isFunction(fn)) {
21755        invokeApply = delay;
21756        delay = fn;
21757        fn = noop;
21758      }
21759
21760      var args = sliceArgs(arguments, 3),
21761          skipApply = (isDefined(invokeApply) && !invokeApply),
21762          deferred = (skipApply ? $$q : $q).defer(),
21763          promise = deferred.promise,
21764          timeoutId;
21765
21766      timeoutId = $browser.defer(function() {
21767        try {
21768          deferred.resolve(fn.apply(null, args));
21769        } catch (e) {
21770          deferred.reject(e);
21771          $exceptionHandler(e);
21772        } finally {
21773          delete deferreds[promise.$$timeoutId];
21774        }
21775
21776        if (!skipApply) $rootScope.$apply();
21777      }, delay, '$timeout');
21778
21779      promise.$$timeoutId = timeoutId;
21780      deferreds[timeoutId] = deferred;
21781
21782      return promise;
21783    }
21784
21785
21786    /**
21787     * @ngdoc method
21788     * @name $timeout#cancel
21789     *
21790     * @description
21791     * Cancels a task associated with the `promise`. As a result of this, the promise will be
21792     * resolved with a rejection.
21793     *
21794     * @param {Promise=} promise Promise returned by the `$timeout` function.
21795     * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
21796     *   canceled.
21797     */
21798    timeout.cancel = function(promise) {
21799      if (!promise) return false;
21800
21801      if (!promise.hasOwnProperty('$$timeoutId')) {
21802        throw $timeoutMinErr('badprom',
21803            '`$timeout.cancel()` called with a promise that was not generated by `$timeout()`.');
21804      }
21805
21806      if (!deferreds.hasOwnProperty(promise.$$timeoutId)) return false;
21807
21808      var id = promise.$$timeoutId;
21809      var deferred = deferreds[id];
21810
21811      // Timeout cancels should not report an unhandled promise.
21812      markQExceptionHandled(deferred.promise);
21813      deferred.reject('canceled');
21814      delete deferreds[id];
21815
21816      return $browser.defer.cancel(id);
21817    };
21818
21819    return timeout;
21820  }];
21821}
21822
21823// NOTE:  The usage of window and document instead of $window and $document here is
21824// deliberate.  This service depends on the specific behavior of anchor nodes created by the
21825// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
21826// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
21827// doesn't know about mocked locations and resolves URLs to the real document - which is
21828// exactly the behavior needed here.  There is little value is mocking these out for this
21829// service.
21830var urlParsingNode = window.document.createElement('a');
21831var originUrl = urlResolve(window.location.href);
21832var baseUrlParsingNode;
21833
21834urlParsingNode.href = 'http://[::1]';
21835
21836// Support: IE 9-11 only, Edge 16-17 only (fixed in 18 Preview)
21837// IE/Edge don't wrap IPv6 addresses' hostnames in square brackets
21838// when parsed out of an anchor element.
21839var ipv6InBrackets = urlParsingNode.hostname === '[::1]';
21840
21841/**
21842 *
21843 * Implementation Notes for non-IE browsers
21844 * ----------------------------------------
21845 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
21846 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
21847 * URL will be resolved into an absolute URL in the context of the application document.
21848 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
21849 * properties are all populated to reflect the normalized URL.  This approach has wide
21850 * compatibility - Safari 1+, Mozilla 1+ etc.  See
21851 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
21852 *
21853 * Implementation Notes for IE
21854 * ---------------------------
21855 * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
21856 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
21857 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
21858 * work around that by performing the parsing in a 2nd step by taking a previously normalized
21859 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
21860 * properties such as protocol, hostname, port, etc.
21861 *
21862 * References:
21863 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
21864 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
21865 *   http://url.spec.whatwg.org/#urlutils
21866 *   https://github.com/angular/angular.js/pull/2902
21867 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
21868 *
21869 * @kind function
21870 * @param {string|object} url The URL to be parsed. If `url` is not a string, it will be returned
21871 *     unchanged.
21872 * @description Normalizes and parses a URL.
21873 * @returns {object} Returns the normalized URL as a dictionary.
21874 *
21875 *   | member name   | Description                                                            |
21876 *   |---------------|------------------------------------------------------------------------|
21877 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
21878 *   | protocol      | The protocol without the trailing colon                                |
21879 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
21880 *   | search        | The search params, minus the question mark                             |
21881 *   | hash          | The hash string, minus the hash symbol                                 |
21882 *   | hostname      | The hostname                                                           |
21883 *   | port          | The port, without ":"                                                  |
21884 *   | pathname      | The pathname, beginning with "/"                                       |
21885 *
21886 */
21887function urlResolve(url) {
21888  if (!isString(url)) return url;
21889
21890  var href = url;
21891
21892  // Support: IE 9-11 only
21893  if (msie) {
21894    // Normalize before parse.  Refer Implementation Notes on why this is
21895    // done in two steps on IE.
21896    urlParsingNode.setAttribute('href', href);
21897    href = urlParsingNode.href;
21898  }
21899
21900  urlParsingNode.setAttribute('href', href);
21901
21902  var hostname = urlParsingNode.hostname;
21903
21904  if (!ipv6InBrackets && hostname.indexOf(':') > -1) {
21905    hostname = '[' + hostname + ']';
21906  }
21907
21908  return {
21909    href: urlParsingNode.href,
21910    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
21911    host: urlParsingNode.host,
21912    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
21913    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
21914    hostname: hostname,
21915    port: urlParsingNode.port,
21916    pathname: (urlParsingNode.pathname.charAt(0) === '/')
21917      ? urlParsingNode.pathname
21918      : '/' + urlParsingNode.pathname
21919  };
21920}
21921
21922/**
21923 * Parse a request URL and determine whether this is a same-origin request as the application
21924 * document.
21925 *
21926 * @param {string|object} requestUrl The url of the request as a string that will be resolved
21927 * or a parsed URL object.
21928 * @returns {boolean} Whether the request is for the same origin as the application document.
21929 */
21930function urlIsSameOrigin(requestUrl) {
21931  return urlsAreSameOrigin(requestUrl, originUrl);
21932}
21933
21934/**
21935 * Parse a request URL and determine whether it is same-origin as the current document base URL.
21936 *
21937 * Note: The base URL is usually the same as the document location (`location.href`) but can
21938 * be overriden by using the `<base>` tag.
21939 *
21940 * @param {string|object} requestUrl The url of the request as a string that will be resolved
21941 * or a parsed URL object.
21942 * @returns {boolean} Whether the URL is same-origin as the document base URL.
21943 */
21944function urlIsSameOriginAsBaseUrl(requestUrl) {
21945  return urlsAreSameOrigin(requestUrl, getBaseUrl());
21946}
21947
21948/**
21949 * Create a function that can check a URL's origin against a list of allowed/trusted origins.
21950 * The current location's origin is implicitly trusted.
21951 *
21952 * @param {string[]} trustedOriginUrls - A list of URLs (strings), whose origins are trusted.
21953 *
21954 * @returns {Function} - A function that receives a URL (string or parsed URL object) and returns
21955 *     whether it is of an allowed origin.
21956 */
21957function urlIsAllowedOriginFactory(trustedOriginUrls) {
21958  var parsedAllowedOriginUrls = [originUrl].concat(trustedOriginUrls.map(urlResolve));
21959
21960  /**
21961   * Check whether the specified URL (string or parsed URL object) has an origin that is allowed
21962   * based on a list of trusted-origin URLs. The current location's origin is implicitly
21963   * trusted.
21964   *
21965   * @param {string|Object} requestUrl - The URL to be checked (provided as a string that will be
21966   *     resolved or a parsed URL object).
21967   *
21968   * @returns {boolean} - Whether the specified URL is of an allowed origin.
21969   */
21970  return function urlIsAllowedOrigin(requestUrl) {
21971    var parsedUrl = urlResolve(requestUrl);
21972    return parsedAllowedOriginUrls.some(urlsAreSameOrigin.bind(null, parsedUrl));
21973  };
21974}
21975
21976/**
21977 * Determine if two URLs share the same origin.
21978 *
21979 * @param {string|Object} url1 - First URL to compare as a string or a normalized URL in the form of
21980 *     a dictionary object returned by `urlResolve()`.
21981 * @param {string|object} url2 - Second URL to compare as a string or a normalized URL in the form
21982 *     of a dictionary object returned by `urlResolve()`.
21983 *
21984 * @returns {boolean} - True if both URLs have the same origin, and false otherwise.
21985 */
21986function urlsAreSameOrigin(url1, url2) {
21987  url1 = urlResolve(url1);
21988  url2 = urlResolve(url2);
21989
21990  return (url1.protocol === url2.protocol &&
21991          url1.host === url2.host);
21992}
21993
21994/**
21995 * Returns the current document base URL.
21996 * @returns {string}
21997 */
21998function getBaseUrl() {
21999  if (window.document.baseURI) {
22000    return window.document.baseURI;
22001  }
22002
22003  // `document.baseURI` is available everywhere except IE
22004  if (!baseUrlParsingNode) {
22005    baseUrlParsingNode = window.document.createElement('a');
22006    baseUrlParsingNode.href = '.';
22007
22008    // Work-around for IE bug described in Implementation Notes. The fix in `urlResolve()` is not
22009    // suitable here because we need to track changes to the base URL.
22010    baseUrlParsingNode = baseUrlParsingNode.cloneNode(false);
22011  }
22012  return baseUrlParsingNode.href;
22013}
22014
22015/**
22016 * @ngdoc service
22017 * @name $window
22018 * @this
22019 *
22020 * @description
22021 * A reference to the browser's `window` object. While `window`
22022 * is globally available in JavaScript, it causes testability problems, because
22023 * it is a global variable. In AngularJS we always refer to it through the
22024 * `$window` service, so it may be overridden, removed or mocked for testing.
22025 *
22026 * Expressions, like the one defined for the `ngClick` directive in the example
22027 * below, are evaluated with respect to the current scope.  Therefore, there is
22028 * no risk of inadvertently coding in a dependency on a global value in such an
22029 * expression.
22030 *
22031 * @example
22032   <example module="windowExample" name="window-service">
22033     <file name="index.html">
22034       <script>
22035         angular.module('windowExample', [])
22036           .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
22037             $scope.greeting = 'Hello, World!';
22038             $scope.doGreeting = function(greeting) {
22039               $window.alert(greeting);
22040             };
22041           }]);
22042       </script>
22043       <div ng-controller="ExampleController">
22044         <input type="text" ng-model="greeting" aria-label="greeting" />
22045         <button ng-click="doGreeting(greeting)">ALERT</button>
22046       </div>
22047     </file>
22048     <file name="protractor.js" type="protractor">
22049      it('should display the greeting in the input box', function() {
22050       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
22051       // If we click the button it will block the test runner
22052       // element(':button').click();
22053      });
22054     </file>
22055   </example>
22056 */
22057function $WindowProvider() {
22058  this.$get = valueFn(window);
22059}
22060
22061/**
22062 * @name $$cookieReader
22063 * @requires $document
22064 *
22065 * @description
22066 * This is a private service for reading cookies used by $http and ngCookies
22067 *
22068 * @return {Object} a key/value map of the current cookies
22069 */
22070function $$CookieReader($document) {
22071  var rawDocument = $document[0] || {};
22072  var lastCookies = {};
22073  var lastCookieString = '';
22074
22075  function safeGetCookie(rawDocument) {
22076    try {
22077      return rawDocument.cookie || '';
22078    } catch (e) {
22079      return '';
22080    }
22081  }
22082
22083  function safeDecodeURIComponent(str) {
22084    try {
22085      return decodeURIComponent(str);
22086    } catch (e) {
22087      return str;
22088    }
22089  }
22090
22091  return function() {
22092    var cookieArray, cookie, i, index, name;
22093    var currentCookieString = safeGetCookie(rawDocument);
22094
22095    if (currentCookieString !== lastCookieString) {
22096      lastCookieString = currentCookieString;
22097      cookieArray = lastCookieString.split('; ');
22098      lastCookies = {};
22099
22100      for (i = 0; i < cookieArray.length; i++) {
22101        cookie = cookieArray[i];
22102        index = cookie.indexOf('=');
22103        if (index > 0) { //ignore nameless cookies
22104          name = safeDecodeURIComponent(cookie.substring(0, index));
22105          // the first value that is seen for a cookie is the most
22106          // specific one.  values for the same cookie name that
22107          // follow are for less specific paths.
22108          if (isUndefined(lastCookies[name])) {
22109            lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
22110          }
22111        }
22112      }
22113    }
22114    return lastCookies;
22115  };
22116}
22117
22118$$CookieReader.$inject = ['$document'];
22119
22120/** @this */
22121function $$CookieReaderProvider() {
22122  this.$get = $$CookieReader;
22123}
22124
22125/* global currencyFilter: true,
22126 dateFilter: true,
22127 filterFilter: true,
22128 jsonFilter: true,
22129 limitToFilter: true,
22130 lowercaseFilter: true,
22131 numberFilter: true,
22132 orderByFilter: true,
22133 uppercaseFilter: true,
22134 */
22135
22136/**
22137 * @ngdoc provider
22138 * @name $filterProvider
22139 * @description
22140 *
22141 * Filters are just functions which transform input to an output. However filters need to be
22142 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
22143 * annotated with dependencies and is responsible for creating a filter function.
22144 *
22145 * <div class="alert alert-warning">
22146 * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`.
22147 * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
22148 * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
22149 * (`myapp_subsection_filterx`).
22150 * </div>
22151 *
22152 * ```js
22153 *   // Filter registration
22154 *   function MyModule($provide, $filterProvider) {
22155 *     // create a service to demonstrate injection (not always needed)
22156 *     $provide.value('greet', function(name){
22157 *       return 'Hello ' + name + '!';
22158 *     });
22159 *
22160 *     // register a filter factory which uses the
22161 *     // greet service to demonstrate DI.
22162 *     $filterProvider.register('greet', function(greet){
22163 *       // return the filter function which uses the greet service
22164 *       // to generate salutation
22165 *       return function(text) {
22166 *         // filters need to be forgiving so check input validity
22167 *         return text && greet(text) || text;
22168 *       };
22169 *     });
22170 *   }
22171 * ```
22172 *
22173 * The filter function is registered with the `$injector` under the filter name suffix with
22174 * `Filter`.
22175 *
22176 * ```js
22177 *   it('should be the same instance', inject(
22178 *     function($filterProvider) {
22179 *       $filterProvider.register('reverse', function(){
22180 *         return ...;
22181 *       });
22182 *     },
22183 *     function($filter, reverseFilter) {
22184 *       expect($filter('reverse')).toBe(reverseFilter);
22185 *     });
22186 * ```
22187 *
22188 *
22189 * For more information about how AngularJS filters work, and how to create your own filters, see
22190 * {@link guide/filter Filters} in the AngularJS Developer Guide.
22191 */
22192
22193/**
22194 * @ngdoc service
22195 * @name $filter
22196 * @kind function
22197 * @description
22198 * Filters are used for formatting data displayed to the user.
22199 *
22200 * They can be used in view templates, controllers or services. AngularJS comes
22201 * with a collection of [built-in filters](api/ng/filter), but it is easy to
22202 * define your own as well.
22203 *
22204 * The general syntax in templates is as follows:
22205 *
22206 * ```html
22207 * {{ expression [| filter_name[:parameter_value] ... ] }}
22208 * ```
22209 *
22210 * @param {String} name Name of the filter function to retrieve
22211 * @return {Function} the filter function
22212 * @example
22213   <example name="$filter" module="filterExample">
22214     <file name="index.html">
22215       <div ng-controller="MainCtrl">
22216        <h3>{{ originalText }}</h3>
22217        <h3>{{ filteredText }}</h3>
22218       </div>
22219     </file>
22220
22221     <file name="script.js">
22222      angular.module('filterExample', [])
22223      .controller('MainCtrl', function($scope, $filter) {
22224        $scope.originalText = 'hello';
22225        $scope.filteredText = $filter('uppercase')($scope.originalText);
22226      });
22227     </file>
22228   </example>
22229  */
22230$FilterProvider.$inject = ['$provide'];
22231/** @this */
22232function $FilterProvider($provide) {
22233  var suffix = 'Filter';
22234
22235  /**
22236   * @ngdoc method
22237   * @name $filterProvider#register
22238   * @param {string|Object} name Name of the filter function, or an object map of filters where
22239   *    the keys are the filter names and the values are the filter factories.
22240   *
22241   *    <div class="alert alert-warning">
22242   *    **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`.
22243   *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
22244   *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
22245   *    (`myapp_subsection_filterx`).
22246   *    </div>
22247    * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
22248   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
22249   *    of the registered filter instances.
22250   */
22251  function register(name, factory) {
22252    if (isObject(name)) {
22253      var filters = {};
22254      forEach(name, function(filter, key) {
22255        filters[key] = register(key, filter);
22256      });
22257      return filters;
22258    } else {
22259      return $provide.factory(name + suffix, factory);
22260    }
22261  }
22262  this.register = register;
22263
22264  this.$get = ['$injector', function($injector) {
22265    return function(name) {
22266      return $injector.get(name + suffix);
22267    };
22268  }];
22269
22270  ////////////////////////////////////////
22271
22272  /* global
22273    currencyFilter: false,
22274    dateFilter: false,
22275    filterFilter: false,
22276    jsonFilter: false,
22277    limitToFilter: false,
22278    lowercaseFilter: false,
22279    numberFilter: false,
22280    orderByFilter: false,
22281    uppercaseFilter: false
22282  */
22283
22284  register('currency', currencyFilter);
22285  register('date', dateFilter);
22286  register('filter', filterFilter);
22287  register('json', jsonFilter);
22288  register('limitTo', limitToFilter);
22289  register('lowercase', lowercaseFilter);
22290  register('number', numberFilter);
22291  register('orderBy', orderByFilter);
22292  register('uppercase', uppercaseFilter);
22293}
22294
22295/**
22296 * @ngdoc filter
22297 * @name filter
22298 * @kind function
22299 *
22300 * @description
22301 * Selects a subset of items from `array` and returns it as a new array.
22302 *
22303 * @param {Array} array The source array.
22304 * <div class="alert alert-info">
22305 *   **Note**: If the array contains objects that reference themselves, filtering is not possible.
22306 * </div>
22307 * @param {string|Object|function()} expression The predicate to be used for selecting items from
22308 *   `array`.
22309 *
22310 *   Can be one of:
22311 *
22312 *   - `string`: The string is used for matching against the contents of the `array`. All strings or
22313 *     objects with string properties in `array` that match this string will be returned. This also
22314 *     applies to nested object properties.
22315 *     The predicate can be negated by prefixing the string with `!`.
22316 *
22317 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
22318 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
22319 *     which have property `name` containing "M" and property `phone` containing "1". A special
22320 *     property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
22321 *     against any property of the object or its nested object properties. That's equivalent to the
22322 *     simple substring match with a `string` as described above. The special property name can be
22323 *     overwritten, using the `anyPropertyKey` parameter.
22324 *     The predicate can be negated by prefixing the string with `!`.
22325 *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
22326 *     not containing "M".
22327 *
22328 *     Note that a named property will match properties on the same level only, while the special
22329 *     `$` property will match properties on the same level or deeper. E.g. an array item like
22330 *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
22331 *     **will** be matched by `{$: 'John'}`.
22332 *
22333 *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
22334 *     The function is called for each element of the array, with the element, its index, and
22335 *     the entire array itself as arguments.
22336 *
22337 *     The final result is an array of those elements that the predicate returned true for.
22338 *
22339 * @param {function(actual, expected)|true|false} [comparator] Comparator which is used in
22340 *     determining if values retrieved using `expression` (when it is not a function) should be
22341 *     considered a match based on the expected value (from the filter expression) and actual
22342 *     value (from the object in the array).
22343 *
22344 *   Can be one of:
22345 *
22346 *   - `function(actual, expected)`:
22347 *     The function will be given the object value and the predicate value to compare and
22348 *     should return true if both values should be considered equal.
22349 *
22350 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
22351 *     This is essentially strict comparison of expected and actual.
22352 *
22353 *   - `false`: A short hand for a function which will look for a substring match in a case
22354 *     insensitive way. Primitive values are converted to strings. Objects are not compared against
22355 *     primitives, unless they have a custom `toString` method (e.g. `Date` objects).
22356 *
22357 *
22358 *   Defaults to `false`.
22359 *
22360 * @param {string} [anyPropertyKey] The special property name that matches against any property.
22361 *     By default `$`.
22362 *
22363 * @example
22364   <example name="filter-filter">
22365     <file name="index.html">
22366       <div ng-init="friends = [{name:'John', phone:'555-1276'},
22367                                {name:'Mary', phone:'800-BIG-MARY'},
22368                                {name:'Mike', phone:'555-4321'},
22369                                {name:'Adam', phone:'555-5678'},
22370                                {name:'Julie', phone:'555-8765'},
22371                                {name:'Juliette', phone:'555-5678'}]"></div>
22372
22373       <label>Search: <input ng-model="searchText"></label>
22374       <table id="searchTextResults">
22375         <tr><th>Name</th><th>Phone</th></tr>
22376         <tr ng-repeat="friend in friends | filter:searchText">
22377           <td>{{friend.name}}</td>
22378           <td>{{friend.phone}}</td>
22379         </tr>
22380       </table>
22381       <hr>
22382       <label>Any: <input ng-model="search.$"></label> <br>
22383       <label>Name only <input ng-model="search.name"></label><br>
22384       <label>Phone only <input ng-model="search.phone"></label><br>
22385       <label>Equality <input type="checkbox" ng-model="strict"></label><br>
22386       <table id="searchObjResults">
22387         <tr><th>Name</th><th>Phone</th></tr>
22388         <tr ng-repeat="friendObj in friends | filter:search:strict">
22389           <td>{{friendObj.name}}</td>
22390           <td>{{friendObj.phone}}</td>
22391         </tr>
22392       </table>
22393     </file>
22394     <file name="protractor.js" type="protractor">
22395       var expectFriendNames = function(expectedNames, key) {
22396         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
22397           arr.forEach(function(wd, i) {
22398             expect(wd.getText()).toMatch(expectedNames[i]);
22399           });
22400         });
22401       };
22402
22403       it('should search across all fields when filtering with a string', function() {
22404         var searchText = element(by.model('searchText'));
22405         searchText.clear();
22406         searchText.sendKeys('m');
22407         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
22408
22409         searchText.clear();
22410         searchText.sendKeys('76');
22411         expectFriendNames(['John', 'Julie'], 'friend');
22412       });
22413
22414       it('should search in specific fields when filtering with a predicate object', function() {
22415         var searchAny = element(by.model('search.$'));
22416         searchAny.clear();
22417         searchAny.sendKeys('i');
22418         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
22419       });
22420       it('should use a equal comparison when comparator is true', function() {
22421         var searchName = element(by.model('search.name'));
22422         var strict = element(by.model('strict'));
22423         searchName.clear();
22424         searchName.sendKeys('Julie');
22425         strict.click();
22426         expectFriendNames(['Julie'], 'friendObj');
22427       });
22428     </file>
22429   </example>
22430 */
22431
22432function filterFilter() {
22433  return function(array, expression, comparator, anyPropertyKey) {
22434    if (!isArrayLike(array)) {
22435      if (array == null) {
22436        return array;
22437      } else {
22438        throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
22439      }
22440    }
22441
22442    anyPropertyKey = anyPropertyKey || '$';
22443    var expressionType = getTypeForFilter(expression);
22444    var predicateFn;
22445    var matchAgainstAnyProp;
22446
22447    switch (expressionType) {
22448      case 'function':
22449        predicateFn = expression;
22450        break;
22451      case 'boolean':
22452      case 'null':
22453      case 'number':
22454      case 'string':
22455        matchAgainstAnyProp = true;
22456        // falls through
22457      case 'object':
22458        predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);
22459        break;
22460      default:
22461        return array;
22462    }
22463
22464    return Array.prototype.filter.call(array, predicateFn);
22465  };
22466}
22467
22468// Helper functions for `filterFilter`
22469function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {
22470  var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);
22471  var predicateFn;
22472
22473  if (comparator === true) {
22474    comparator = equals;
22475  } else if (!isFunction(comparator)) {
22476    comparator = function(actual, expected) {
22477      if (isUndefined(actual)) {
22478        // No substring matching against `undefined`
22479        return false;
22480      }
22481      if ((actual === null) || (expected === null)) {
22482        // No substring matching against `null`; only match against `null`
22483        return actual === expected;
22484      }
22485      if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
22486        // Should not compare primitives against objects, unless they have custom `toString` method
22487        return false;
22488      }
22489
22490      actual = lowercase('' + actual);
22491      expected = lowercase('' + expected);
22492      return actual.indexOf(expected) !== -1;
22493    };
22494  }
22495
22496  predicateFn = function(item) {
22497    if (shouldMatchPrimitives && !isObject(item)) {
22498      return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);
22499    }
22500    return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);
22501  };
22502
22503  return predicateFn;
22504}
22505
22506function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {
22507  var actualType = getTypeForFilter(actual);
22508  var expectedType = getTypeForFilter(expected);
22509
22510  if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
22511    return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);
22512  } else if (isArray(actual)) {
22513    // In case `actual` is an array, consider it a match
22514    // if ANY of it's items matches `expected`
22515    return actual.some(function(item) {
22516      return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);
22517    });
22518  }
22519
22520  switch (actualType) {
22521    case 'object':
22522      var key;
22523      if (matchAgainstAnyProp) {
22524        for (key in actual) {
22525          // Under certain, rare, circumstances, key may not be a string and `charAt` will be undefined
22526          // See: https://github.com/angular/angular.js/issues/15644
22527          if (key.charAt && (key.charAt(0) !== '$') &&
22528              deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
22529            return true;
22530          }
22531        }
22532        return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);
22533      } else if (expectedType === 'object') {
22534        for (key in expected) {
22535          var expectedVal = expected[key];
22536          if (isFunction(expectedVal) || isUndefined(expectedVal)) {
22537            continue;
22538          }
22539
22540          var matchAnyProperty = key === anyPropertyKey;
22541          var actualVal = matchAnyProperty ? actual : actual[key];
22542          if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {
22543            return false;
22544          }
22545        }
22546        return true;
22547      } else {
22548        return comparator(actual, expected);
22549      }
22550    case 'function':
22551      return false;
22552    default:
22553      return comparator(actual, expected);
22554  }
22555}
22556
22557// Used for easily differentiating between `null` and actual `object`
22558function getTypeForFilter(val) {
22559  return (val === null) ? 'null' : typeof val;
22560}
22561
22562var MAX_DIGITS = 22;
22563var DECIMAL_SEP = '.';
22564var ZERO_CHAR = '0';
22565
22566/**
22567 * @ngdoc filter
22568 * @name currency
22569 * @kind function
22570 *
22571 * @description
22572 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
22573 * symbol for current locale is used.
22574 *
22575 * @param {number} amount Input to filter.
22576 * @param {string=} symbol Currency symbol or identifier to be displayed.
22577 * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
22578 * @returns {string} Formatted number.
22579 *
22580 *
22581 * @example
22582   <example module="currencyExample" name="currency-filter">
22583     <file name="index.html">
22584       <script>
22585         angular.module('currencyExample', [])
22586           .controller('ExampleController', ['$scope', function($scope) {
22587             $scope.amount = 1234.56;
22588           }]);
22589       </script>
22590       <div ng-controller="ExampleController">
22591         <input type="number" ng-model="amount" aria-label="amount"> <br>
22592         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
22593         custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span><br>
22594         no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
22595       </div>
22596     </file>
22597     <file name="protractor.js" type="protractor">
22598       it('should init with 1234.56', function() {
22599         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
22600         expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
22601         expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
22602       });
22603       it('should update', function() {
22604         if (browser.params.browser === 'safari') {
22605           // Safari does not understand the minus key. See
22606           // https://github.com/angular/protractor/issues/481
22607           return;
22608         }
22609         element(by.model('amount')).clear();
22610         element(by.model('amount')).sendKeys('-1234');
22611         expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
22612         expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
22613         expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
22614       });
22615     </file>
22616   </example>
22617 */
22618currencyFilter.$inject = ['$locale'];
22619function currencyFilter($locale) {
22620  var formats = $locale.NUMBER_FORMATS;
22621  return function(amount, currencySymbol, fractionSize) {
22622    if (isUndefined(currencySymbol)) {
22623      currencySymbol = formats.CURRENCY_SYM;
22624    }
22625
22626    if (isUndefined(fractionSize)) {
22627      fractionSize = formats.PATTERNS[1].maxFrac;
22628    }
22629
22630    // If the currency symbol is empty, trim whitespace around the symbol
22631    var currencySymbolRe = !currencySymbol ? /\s*\u00A4\s*/g : /\u00A4/g;
22632
22633    // if null or undefined pass it through
22634    return (amount == null)
22635        ? amount
22636        : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
22637            replace(currencySymbolRe, currencySymbol);
22638  };
22639}
22640
22641/**
22642 * @ngdoc filter
22643 * @name number
22644 * @kind function
22645 *
22646 * @description
22647 * Formats a number as text.
22648 *
22649 * If the input is null or undefined, it will just be returned.
22650 * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
22651 * If the input is not a number an empty string is returned.
22652 *
22653 *
22654 * @param {number|string} number Number to format.
22655 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
22656 * If this is not provided then the fraction size is computed from the current locale's number
22657 * formatting pattern. In the case of the default locale, it will be 3.
22658 * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
22659 *                   locale (e.g., in the en_US locale it will have "." as the decimal separator and
22660 *                   include "," group separators after each third digit).
22661 *
22662 * @example
22663   <example module="numberFilterExample" name="number-filter">
22664     <file name="index.html">
22665       <script>
22666         angular.module('numberFilterExample', [])
22667           .controller('ExampleController', ['$scope', function($scope) {
22668             $scope.val = 1234.56789;
22669           }]);
22670       </script>
22671       <div ng-controller="ExampleController">
22672         <label>Enter number: <input ng-model='val'></label><br>
22673         Default formatting: <span id='number-default'>{{val | number}}</span><br>
22674         No fractions: <span>{{val | number:0}}</span><br>
22675         Negative number: <span>{{-val | number:4}}</span>
22676       </div>
22677     </file>
22678     <file name="protractor.js" type="protractor">
22679       it('should format numbers', function() {
22680         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
22681         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
22682         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
22683       });
22684
22685       it('should update', function() {
22686         element(by.model('val')).clear();
22687         element(by.model('val')).sendKeys('3374.333');
22688         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
22689         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
22690         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
22691      });
22692     </file>
22693   </example>
22694 */
22695numberFilter.$inject = ['$locale'];
22696function numberFilter($locale) {
22697  var formats = $locale.NUMBER_FORMATS;
22698  return function(number, fractionSize) {
22699
22700    // if null or undefined pass it through
22701    return (number == null)
22702        ? number
22703        : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
22704                       fractionSize);
22705  };
22706}
22707
22708/**
22709 * Parse a number (as a string) into three components that can be used
22710 * for formatting the number.
22711 *
22712 * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
22713 *
22714 * @param  {string} numStr The number to parse
22715 * @return {object} An object describing this number, containing the following keys:
22716 *  - d : an array of digits containing leading zeros as necessary
22717 *  - i : the number of the digits in `d` that are to the left of the decimal point
22718 *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
22719 *
22720 */
22721function parse(numStr) {
22722  var exponent = 0, digits, numberOfIntegerDigits;
22723  var i, j, zeros;
22724
22725  // Decimal point?
22726  if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
22727    numStr = numStr.replace(DECIMAL_SEP, '');
22728  }
22729
22730  // Exponential form?
22731  if ((i = numStr.search(/e/i)) > 0) {
22732    // Work out the exponent.
22733    if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
22734    numberOfIntegerDigits += +numStr.slice(i + 1);
22735    numStr = numStr.substring(0, i);
22736  } else if (numberOfIntegerDigits < 0) {
22737    // There was no decimal point or exponent so it is an integer.
22738    numberOfIntegerDigits = numStr.length;
22739  }
22740
22741  // Count the number of leading zeros.
22742  for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { /* empty */ }
22743
22744  if (i === (zeros = numStr.length)) {
22745    // The digits are all zero.
22746    digits = [0];
22747    numberOfIntegerDigits = 1;
22748  } else {
22749    // Count the number of trailing zeros
22750    zeros--;
22751    while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;
22752
22753    // Trailing zeros are insignificant so ignore them
22754    numberOfIntegerDigits -= i;
22755    digits = [];
22756    // Convert string to array of digits without leading/trailing zeros.
22757    for (j = 0; i <= zeros; i++, j++) {
22758      digits[j] = +numStr.charAt(i);
22759    }
22760  }
22761
22762  // If the number overflows the maximum allowed digits then use an exponent.
22763  if (numberOfIntegerDigits > MAX_DIGITS) {
22764    digits = digits.splice(0, MAX_DIGITS - 1);
22765    exponent = numberOfIntegerDigits - 1;
22766    numberOfIntegerDigits = 1;
22767  }
22768
22769  return { d: digits, e: exponent, i: numberOfIntegerDigits };
22770}
22771
22772/**
22773 * Round the parsed number to the specified number of decimal places
22774 * This function changed the parsedNumber in-place
22775 */
22776function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
22777    var digits = parsedNumber.d;
22778    var fractionLen = digits.length - parsedNumber.i;
22779
22780    // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
22781    fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
22782
22783    // The index of the digit to where rounding is to occur
22784    var roundAt = fractionSize + parsedNumber.i;
22785    var digit = digits[roundAt];
22786
22787    if (roundAt > 0) {
22788      // Drop fractional digits beyond `roundAt`
22789      digits.splice(Math.max(parsedNumber.i, roundAt));
22790
22791      // Set non-fractional digits beyond `roundAt` to 0
22792      for (var j = roundAt; j < digits.length; j++) {
22793        digits[j] = 0;
22794      }
22795    } else {
22796      // We rounded to zero so reset the parsedNumber
22797      fractionLen = Math.max(0, fractionLen);
22798      parsedNumber.i = 1;
22799      digits.length = Math.max(1, roundAt = fractionSize + 1);
22800      digits[0] = 0;
22801      for (var i = 1; i < roundAt; i++) digits[i] = 0;
22802    }
22803
22804    if (digit >= 5) {
22805      if (roundAt - 1 < 0) {
22806        for (var k = 0; k > roundAt; k--) {
22807          digits.unshift(0);
22808          parsedNumber.i++;
22809        }
22810        digits.unshift(1);
22811        parsedNumber.i++;
22812      } else {
22813        digits[roundAt - 1]++;
22814      }
22815    }
22816
22817    // Pad out with zeros to get the required fraction length
22818    for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
22819
22820
22821    // Do any carrying, e.g. a digit was rounded up to 10
22822    var carry = digits.reduceRight(function(carry, d, i, digits) {
22823      d = d + carry;
22824      digits[i] = d % 10;
22825      return Math.floor(d / 10);
22826    }, 0);
22827    if (carry) {
22828      digits.unshift(carry);
22829      parsedNumber.i++;
22830    }
22831}
22832
22833/**
22834 * Format a number into a string
22835 * @param  {number} number       The number to format
22836 * @param  {{
22837 *           minFrac, // the minimum number of digits required in the fraction part of the number
22838 *           maxFrac, // the maximum number of digits required in the fraction part of the number
22839 *           gSize,   // number of digits in each group of separated digits
22840 *           lgSize,  // number of digits in the last group of digits before the decimal separator
22841 *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
22842 *           posPre,  // the string to go in front of a positive number
22843 *           negSuf,  // the string to go after a negative number (e.g. `)`)
22844 *           posSuf   // the string to go after a positive number
22845 *         }} pattern
22846 * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
22847 * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
22848 * @param  {[type]} fractionSize The size of the fractional part of the number
22849 * @return {string}              The number formatted as a string
22850 */
22851function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
22852
22853  if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
22854
22855  var isInfinity = !isFinite(number);
22856  var isZero = false;
22857  var numStr = Math.abs(number) + '',
22858      formattedText = '',
22859      parsedNumber;
22860
22861  if (isInfinity) {
22862    formattedText = '\u221e';
22863  } else {
22864    parsedNumber = parse(numStr);
22865
22866    roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
22867
22868    var digits = parsedNumber.d;
22869    var integerLen = parsedNumber.i;
22870    var exponent = parsedNumber.e;
22871    var decimals = [];
22872    isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
22873
22874    // pad zeros for small numbers
22875    while (integerLen < 0) {
22876      digits.unshift(0);
22877      integerLen++;
22878    }
22879
22880    // extract decimals digits
22881    if (integerLen > 0) {
22882      decimals = digits.splice(integerLen, digits.length);
22883    } else {
22884      decimals = digits;
22885      digits = [0];
22886    }
22887
22888    // format the integer digits with grouping separators
22889    var groups = [];
22890    if (digits.length >= pattern.lgSize) {
22891      groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
22892    }
22893    while (digits.length > pattern.gSize) {
22894      groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
22895    }
22896    if (digits.length) {
22897      groups.unshift(digits.join(''));
22898    }
22899    formattedText = groups.join(groupSep);
22900
22901    // append the decimal digits
22902    if (decimals.length) {
22903      formattedText += decimalSep + decimals.join('');
22904    }
22905
22906    if (exponent) {
22907      formattedText += 'e+' + exponent;
22908    }
22909  }
22910  if (number < 0 && !isZero) {
22911    return pattern.negPre + formattedText + pattern.negSuf;
22912  } else {
22913    return pattern.posPre + formattedText + pattern.posSuf;
22914  }
22915}
22916
22917function padNumber(num, digits, trim, negWrap) {
22918  var neg = '';
22919  if (num < 0 || (negWrap && num <= 0)) {
22920    if (negWrap) {
22921      num = -num + 1;
22922    } else {
22923      num = -num;
22924      neg = '-';
22925    }
22926  }
22927  num = '' + num;
22928  while (num.length < digits) num = ZERO_CHAR + num;
22929  if (trim) {
22930    num = num.substr(num.length - digits);
22931  }
22932  return neg + num;
22933}
22934
22935
22936function dateGetter(name, size, offset, trim, negWrap) {
22937  offset = offset || 0;
22938  return function(date) {
22939    var value = date['get' + name]();
22940    if (offset > 0 || value > -offset) {
22941      value += offset;
22942    }
22943    if (value === 0 && offset === -12) value = 12;
22944    return padNumber(value, size, trim, negWrap);
22945  };
22946}
22947
22948function dateStrGetter(name, shortForm, standAlone) {
22949  return function(date, formats) {
22950    var value = date['get' + name]();
22951    var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
22952    var get = uppercase(propPrefix + name);
22953
22954    return formats[get][value];
22955  };
22956}
22957
22958function timeZoneGetter(date, formats, offset) {
22959  var zone = -1 * offset;
22960  var paddedZone = (zone >= 0) ? '+' : '';
22961
22962  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
22963                padNumber(Math.abs(zone % 60), 2);
22964
22965  return paddedZone;
22966}
22967
22968function getFirstThursdayOfYear(year) {
22969    // 0 = index of January
22970    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
22971    // 4 = index of Thursday (+1 to account for 1st = 5)
22972    // 11 = index of *next* Thursday (+1 account for 1st = 12)
22973    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
22974}
22975
22976function getThursdayThisWeek(datetime) {
22977    return new Date(datetime.getFullYear(), datetime.getMonth(),
22978      // 4 = index of Thursday
22979      datetime.getDate() + (4 - datetime.getDay()));
22980}
22981
22982function weekGetter(size) {
22983   return function(date) {
22984      var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
22985         thisThurs = getThursdayThisWeek(date);
22986
22987      var diff = +thisThurs - +firstThurs,
22988         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
22989
22990      return padNumber(result, size);
22991   };
22992}
22993
22994function ampmGetter(date, formats) {
22995  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
22996}
22997
22998function eraGetter(date, formats) {
22999  return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
23000}
23001
23002function longEraGetter(date, formats) {
23003  return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
23004}
23005
23006var DATE_FORMATS = {
23007  yyyy: dateGetter('FullYear', 4, 0, false, true),
23008    yy: dateGetter('FullYear', 2, 0, true, true),
23009     y: dateGetter('FullYear', 1, 0, false, true),
23010  MMMM: dateStrGetter('Month'),
23011   MMM: dateStrGetter('Month', true),
23012    MM: dateGetter('Month', 2, 1),
23013     M: dateGetter('Month', 1, 1),
23014  LLLL: dateStrGetter('Month', false, true),
23015    dd: dateGetter('Date', 2),
23016     d: dateGetter('Date', 1),
23017    HH: dateGetter('Hours', 2),
23018     H: dateGetter('Hours', 1),
23019    hh: dateGetter('Hours', 2, -12),
23020     h: dateGetter('Hours', 1, -12),
23021    mm: dateGetter('Minutes', 2),
23022     m: dateGetter('Minutes', 1),
23023    ss: dateGetter('Seconds', 2),
23024     s: dateGetter('Seconds', 1),
23025     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
23026     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
23027   sss: dateGetter('Milliseconds', 3),
23028  EEEE: dateStrGetter('Day'),
23029   EEE: dateStrGetter('Day', true),
23030     a: ampmGetter,
23031     Z: timeZoneGetter,
23032    ww: weekGetter(2),
23033     w: weekGetter(1),
23034     G: eraGetter,
23035     GG: eraGetter,
23036     GGG: eraGetter,
23037     GGGG: longEraGetter
23038};
23039
23040var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/,
23041    NUMBER_STRING = /^-?\d+$/;
23042
23043/**
23044 * @ngdoc filter
23045 * @name date
23046 * @kind function
23047 *
23048 * @description
23049 *   Formats `date` to a string based on the requested `format`.
23050 *
23051 *   `format` string can be composed of the following elements:
23052 *
23053 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
23054 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
23055 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
23056 *   * `'MMMM'`: Month in year (January-December)
23057 *   * `'MMM'`: Month in year (Jan-Dec)
23058 *   * `'MM'`: Month in year, padded (01-12)
23059 *   * `'M'`: Month in year (1-12)
23060 *   * `'LLLL'`: Stand-alone month in year (January-December)
23061 *   * `'dd'`: Day in month, padded (01-31)
23062 *   * `'d'`: Day in month (1-31)
23063 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
23064 *   * `'EEE'`: Day in Week, (Sun-Sat)
23065 *   * `'HH'`: Hour in day, padded (00-23)
23066 *   * `'H'`: Hour in day (0-23)
23067 *   * `'hh'`: Hour in AM/PM, padded (01-12)
23068 *   * `'h'`: Hour in AM/PM, (1-12)
23069 *   * `'mm'`: Minute in hour, padded (00-59)
23070 *   * `'m'`: Minute in hour (0-59)
23071 *   * `'ss'`: Second in minute, padded (00-59)
23072 *   * `'s'`: Second in minute (0-59)
23073 *   * `'sss'`: Millisecond in second, padded (000-999)
23074 *   * `'a'`: AM/PM marker
23075 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
23076 *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
23077 *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
23078 *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
23079 *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
23080 *
23081 *   `format` string can also be one of the following predefined
23082 *   {@link guide/i18n localizable formats}:
23083 *
23084 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
23085 *     (e.g. Sep 3, 2010 12:05:08 PM)
23086 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
23087 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
23088 *     (e.g. Friday, September 3, 2010)
23089 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
23090 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
23091 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
23092 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
23093 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
23094 *
23095 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
23096 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
23097 *   (e.g. `"h 'o''clock'"`).
23098 *
23099 *   Any other characters in the `format` string will be output as-is.
23100 *
23101 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
23102 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
23103 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
23104 *    specified in the string input, the time is considered to be in the local timezone.
23105 * @param {string=} format Formatting rules (see Description). If not specified,
23106 *    `mediumDate` is used.
23107 * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
23108 *    continental US time zone abbreviations, but for general use, use a time zone offset, for
23109 *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
23110 *    If not specified, the timezone of the browser will be used.
23111 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
23112 *
23113 * @example
23114   <example name="filter-date">
23115     <file name="index.html">
23116       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
23117           <span>{{1288323623006 | date:'medium'}}</span><br>
23118       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
23119          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
23120       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
23121          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
23122       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
23123          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
23124     </file>
23125     <file name="protractor.js" type="protractor">
23126       it('should format date', function() {
23127         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
23128            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
23129         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
23130            toMatch(/2010-10-2\d \d{2}:\d{2}:\d{2} (-|\+)?\d{4}/);
23131         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
23132            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
23133         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
23134            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
23135       });
23136     </file>
23137   </example>
23138 */
23139dateFilter.$inject = ['$locale'];
23140function dateFilter($locale) {
23141
23142
23143  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
23144                     // 1        2       3         4          5          6          7          8  9     10      11
23145  function jsonStringToDate(string) {
23146    var match;
23147    if ((match = string.match(R_ISO8601_STR))) {
23148      var date = new Date(0),
23149          tzHour = 0,
23150          tzMin  = 0,
23151          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
23152          timeSetter = match[8] ? date.setUTCHours : date.setHours;
23153
23154      if (match[9]) {
23155        tzHour = toInt(match[9] + match[10]);
23156        tzMin = toInt(match[9] + match[11]);
23157      }
23158      dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
23159      var h = toInt(match[4] || 0) - tzHour;
23160      var m = toInt(match[5] || 0) - tzMin;
23161      var s = toInt(match[6] || 0);
23162      var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
23163      timeSetter.call(date, h, m, s, ms);
23164      return date;
23165    }
23166    return string;
23167  }
23168
23169
23170  return function(date, format, timezone) {
23171    var text = '',
23172        parts = [],
23173        fn, match;
23174
23175    format = format || 'mediumDate';
23176    format = $locale.DATETIME_FORMATS[format] || format;
23177    if (isString(date)) {
23178      date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
23179    }
23180
23181    if (isNumber(date)) {
23182      date = new Date(date);
23183    }
23184
23185    if (!isDate(date) || !isFinite(date.getTime())) {
23186      return date;
23187    }
23188
23189    while (format) {
23190      match = DATE_FORMATS_SPLIT.exec(format);
23191      if (match) {
23192        parts = concat(parts, match, 1);
23193        format = parts.pop();
23194      } else {
23195        parts.push(format);
23196        format = null;
23197      }
23198    }
23199
23200    var dateTimezoneOffset = date.getTimezoneOffset();
23201    if (timezone) {
23202      dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
23203      date = convertTimezoneToLocal(date, timezone, true);
23204    }
23205    forEach(parts, function(value) {
23206      fn = DATE_FORMATS[value];
23207      text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
23208                 : value === '\'\'' ? '\'' : value.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
23209    });
23210
23211    return text;
23212  };
23213}
23214
23215
23216/**
23217 * @ngdoc filter
23218 * @name json
23219 * @kind function
23220 *
23221 * @description
23222 *   Allows you to convert a JavaScript object into JSON string.
23223 *
23224 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
23225 *   the binding is automatically converted to JSON.
23226 *
23227 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
23228 * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
23229 * @returns {string} JSON string.
23230 *
23231 *
23232 * @example
23233   <example name="filter-json">
23234     <file name="index.html">
23235       <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
23236       <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
23237     </file>
23238     <file name="protractor.js" type="protractor">
23239       it('should jsonify filtered objects', function() {
23240         expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n {2}"name": ?"value"\n}/);
23241         expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n {4}"name": ?"value"\n}/);
23242       });
23243     </file>
23244   </example>
23245 *
23246 */
23247function jsonFilter() {
23248  return function(object, spacing) {
23249    if (isUndefined(spacing)) {
23250        spacing = 2;
23251    }
23252    return toJson(object, spacing);
23253  };
23254}
23255
23256
23257/**
23258 * @ngdoc filter
23259 * @name lowercase
23260 * @kind function
23261 * @description
23262 * Converts string to lowercase.
23263 *
23264 * See the {@link ng.uppercase uppercase filter documentation} for a functionally identical example.
23265 *
23266 * @see angular.lowercase
23267 */
23268var lowercaseFilter = valueFn(lowercase);
23269
23270
23271/**
23272 * @ngdoc filter
23273 * @name uppercase
23274 * @kind function
23275 * @description
23276 * Converts string to uppercase.
23277 * @example
23278   <example module="uppercaseFilterExample" name="filter-uppercase">
23279     <file name="index.html">
23280       <script>
23281         angular.module('uppercaseFilterExample', [])
23282           .controller('ExampleController', ['$scope', function($scope) {
23283             $scope.title = 'This is a title';
23284           }]);
23285       </script>
23286       <div ng-controller="ExampleController">
23287         <!-- This title should be formatted normally -->
23288         <h1>{{title}}</h1>
23289         <!-- This title should be capitalized -->
23290         <h1>{{title | uppercase}}</h1>
23291       </div>
23292     </file>
23293   </example>
23294 */
23295var uppercaseFilter = valueFn(uppercase);
23296
23297/**
23298 * @ngdoc filter
23299 * @name limitTo
23300 * @kind function
23301 *
23302 * @description
23303 * Creates a new array or string containing only a specified number of elements. The elements are
23304 * taken from either the beginning or the end of the source array, string or number, as specified by
23305 * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
23306 * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
23307 * it is converted to a string.
23308 *
23309 * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
23310 * @param {string|number} limit - The length of the returned array or string. If the `limit` number
23311 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
23312 *     If the number is negative, `limit` number  of items from the end of the source array/string
23313 *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
23314 *     the input will be returned unchanged.
23315 * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
23316 *     `begin` indicates an offset from the end of `input`. Defaults to `0`.
23317 * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
23318 *     less than `limit` elements.
23319 *
23320 * @example
23321   <example module="limitToExample" name="limit-to-filter">
23322     <file name="index.html">
23323       <script>
23324         angular.module('limitToExample', [])
23325           .controller('ExampleController', ['$scope', function($scope) {
23326             $scope.numbers = [1,2,3,4,5,6,7,8,9];
23327             $scope.letters = "abcdefghi";
23328             $scope.longNumber = 2345432342;
23329             $scope.numLimit = 3;
23330             $scope.letterLimit = 3;
23331             $scope.longNumberLimit = 3;
23332           }]);
23333       </script>
23334       <div ng-controller="ExampleController">
23335         <label>
23336            Limit {{numbers}} to:
23337            <input type="number" step="1" ng-model="numLimit">
23338         </label>
23339         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
23340         <label>
23341            Limit {{letters}} to:
23342            <input type="number" step="1" ng-model="letterLimit">
23343         </label>
23344         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
23345         <label>
23346            Limit {{longNumber}} to:
23347            <input type="number" step="1" ng-model="longNumberLimit">
23348         </label>
23349         <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
23350       </div>
23351     </file>
23352     <file name="protractor.js" type="protractor">
23353       var numLimitInput = element(by.model('numLimit'));
23354       var letterLimitInput = element(by.model('letterLimit'));
23355       var longNumberLimitInput = element(by.model('longNumberLimit'));
23356       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
23357       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
23358       var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
23359
23360       it('should limit the number array to first three items', function() {
23361         expect(numLimitInput.getAttribute('value')).toBe('3');
23362         expect(letterLimitInput.getAttribute('value')).toBe('3');
23363         expect(longNumberLimitInput.getAttribute('value')).toBe('3');
23364         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
23365         expect(limitedLetters.getText()).toEqual('Output letters: abc');
23366         expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
23367       });
23368
23369       // There is a bug in safari and protractor that doesn't like the minus key
23370       // it('should update the output when -3 is entered', function() {
23371       //   numLimitInput.clear();
23372       //   numLimitInput.sendKeys('-3');
23373       //   letterLimitInput.clear();
23374       //   letterLimitInput.sendKeys('-3');
23375       //   longNumberLimitInput.clear();
23376       //   longNumberLimitInput.sendKeys('-3');
23377       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
23378       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
23379       //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
23380       // });
23381
23382       it('should not exceed the maximum size of input array', function() {
23383         numLimitInput.clear();
23384         numLimitInput.sendKeys('100');
23385         letterLimitInput.clear();
23386         letterLimitInput.sendKeys('100');
23387         longNumberLimitInput.clear();
23388         longNumberLimitInput.sendKeys('100');
23389         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
23390         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
23391         expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
23392       });
23393     </file>
23394   </example>
23395*/
23396function limitToFilter() {
23397  return function(input, limit, begin) {
23398    if (Math.abs(Number(limit)) === Infinity) {
23399      limit = Number(limit);
23400    } else {
23401      limit = toInt(limit);
23402    }
23403    if (isNumberNaN(limit)) return input;
23404
23405    if (isNumber(input)) input = input.toString();
23406    if (!isArrayLike(input)) return input;
23407
23408    begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
23409    begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
23410
23411    if (limit >= 0) {
23412      return sliceFn(input, begin, begin + limit);
23413    } else {
23414      if (begin === 0) {
23415        return sliceFn(input, limit, input.length);
23416      } else {
23417        return sliceFn(input, Math.max(0, begin + limit), begin);
23418      }
23419    }
23420  };
23421}
23422
23423function sliceFn(input, begin, end) {
23424  if (isString(input)) return input.slice(begin, end);
23425
23426  return slice.call(input, begin, end);
23427}
23428
23429/**
23430 * @ngdoc filter
23431 * @name orderBy
23432 * @kind function
23433 *
23434 * @description
23435 * Returns an array containing the items from the specified `collection`, ordered by a `comparator`
23436 * function based on the values computed using the `expression` predicate.
23437 *
23438 * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in
23439 * `[{id: 'bar'}, {id: 'foo'}]`.
23440 *
23441 * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,
23442 * String, etc).
23443 *
23444 * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker
23445 * for the preceding one. The `expression` is evaluated against each item and the output is used
23446 * for comparing with other items.
23447 *
23448 * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in
23449 * ascending order.
23450 *
23451 * The comparison is done using the `comparator` function. If none is specified, a default, built-in
23452 * comparator is used (see below for details - in a nutshell, it compares numbers numerically and
23453 * strings alphabetically).
23454 *
23455 * ### Under the hood
23456 *
23457 * Ordering the specified `collection` happens in two phases:
23458 *
23459 * 1. All items are passed through the predicate (or predicates), and the returned values are saved
23460 *    along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed
23461 *    through a predicate that extracts the value of the `label` property, would be transformed to:
23462 *    ```
23463 *    {
23464 *      value: 'foo',
23465 *      type: 'string',
23466 *      index: ...
23467 *    }
23468 *    ```
23469 *    **Note:** `null` values use `'null'` as their type.
23470 * 2. The comparator function is used to sort the items, based on the derived values, types and
23471 *    indices.
23472 *
23473 * If you use a custom comparator, it will be called with pairs of objects of the form
23474 * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal
23475 * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the
23476 * second, or `1` otherwise.
23477 *
23478 * In order to ensure that the sorting will be deterministic across platforms, if none of the
23479 * specified predicates can distinguish between two items, `orderBy` will automatically introduce a
23480 * dummy predicate that returns the item's index as `value`.
23481 * (If you are using a custom comparator, make sure it can handle this predicate as well.)
23482 *
23483 * If a custom comparator still can't distinguish between two items, then they will be sorted based
23484 * on their index using the built-in comparator.
23485 *
23486 * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
23487 * value for an item, `orderBy` will try to convert that object to a primitive value, before passing
23488 * it to the comparator. The following rules govern the conversion:
23489 *
23490 * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be
23491 *    used instead.<br />
23492 *    (If the object has a `valueOf()` method that returns another object, then the returned object
23493 *    will be used in subsequent steps.)
23494 * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that
23495 *    returns a primitive, its return value will be used instead.<br />
23496 *    (If the object has a `toString()` method that returns another object, then the returned object
23497 *    will be used in subsequent steps.)
23498 * 3. No conversion; the object itself is used.
23499 *
23500 * ### The default comparator
23501 *
23502 * The default, built-in comparator should be sufficient for most usecases. In short, it compares
23503 * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
23504 * using their index in the original collection, sorts values of different types by type and puts
23505 * `undefined` and `null` values at the end of the sorted list.
23506 *
23507 * More specifically, it follows these steps to determine the relative order of items:
23508 *
23509 * 1. If the compared values are of different types:
23510 *    - If one of the values is undefined, consider it "greater than" the other.
23511 *    - Else if one of the values is null, consider it "greater than" the other.
23512 *    - Else compare the types themselves alphabetically.
23513 * 2. If both values are of type `string`, compare them alphabetically in a case- and
23514 *    locale-insensitive way.
23515 * 3. If both values are objects, compare their indices instead.
23516 * 4. Otherwise, return:
23517 *    -  `0`, if the values are equal (by strict equality comparison, i.e. using `===`).
23518 *    - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator).
23519 *    -  `1`, otherwise.
23520 *
23521 * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being
23522 *           saved as numbers and not strings.
23523 * **Note:** For the purpose of sorting, `null` and `undefined` are considered "greater than"
23524 *           any other value (with undefined "greater than" null). This effectively means that `null`
23525 *           and `undefined` values end up at the end of a list sorted in ascending order.
23526 * **Note:** `null` values use `'null'` as their type to be able to distinguish them from objects.
23527 *
23528 * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.
23529 * @param {(Function|string|Array.<Function|string>)=} expression - A predicate (or list of
23530 *    predicates) to be used by the comparator to determine the order of elements.
23531 *
23532 *    Can be one of:
23533 *
23534 *    - `Function`: A getter function. This function will be called with each item as argument and
23535 *      the return value will be used for sorting.
23536 *    - `string`: An AngularJS expression. This expression will be evaluated against each item and the
23537 *      result will be used for sorting. For example, use `'label'` to sort by a property called
23538 *      `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`
23539 *      property.<br />
23540 *      (The result of a constant expression is interpreted as a property name to be used for
23541 *      comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a
23542 *      property called `special name`.)<br />
23543 *      An expression can be optionally prefixed with `+` or `-` to control the sorting direction,
23544 *      ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,
23545 *      (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.
23546 *    - `Array`: An array of function and/or string predicates. If a predicate cannot determine the
23547 *      relative order of two items, the next predicate is used as a tie-breaker.
23548 *
23549 * **Note:** If the predicate is missing or empty then it defaults to `'+'`.
23550 *
23551 * @param {boolean=} reverse - If `true`, reverse the sorting order.
23552 * @param {(Function)=} comparator - The comparator function used to determine the relative order of
23553 *    value pairs. If omitted, the built-in comparator will be used.
23554 *
23555 * @returns {Array} - The sorted array.
23556 *
23557 *
23558 * @example
23559 * ### Ordering a table with `ngRepeat`
23560 *
23561 * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by
23562 * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means
23563 * it defaults to the built-in comparator.
23564 *
23565   <example name="orderBy-static" module="orderByExample1">
23566     <file name="index.html">
23567       <div ng-controller="ExampleController">
23568         <table class="friends">
23569           <tr>
23570             <th>Name</th>
23571             <th>Phone Number</th>
23572             <th>Age</th>
23573           </tr>
23574           <tr ng-repeat="friend in friends | orderBy:'-age'">
23575             <td>{{friend.name}}</td>
23576             <td>{{friend.phone}}</td>
23577             <td>{{friend.age}}</td>
23578           </tr>
23579         </table>
23580       </div>
23581     </file>
23582     <file name="script.js">
23583       angular.module('orderByExample1', [])
23584         .controller('ExampleController', ['$scope', function($scope) {
23585           $scope.friends = [
23586             {name: 'John',   phone: '555-1212',  age: 10},
23587             {name: 'Mary',   phone: '555-9876',  age: 19},
23588             {name: 'Mike',   phone: '555-4321',  age: 21},
23589             {name: 'Adam',   phone: '555-5678',  age: 35},
23590             {name: 'Julie',  phone: '555-8765',  age: 29}
23591           ];
23592         }]);
23593     </file>
23594     <file name="style.css">
23595       .friends {
23596         border-collapse: collapse;
23597       }
23598
23599       .friends th {
23600         border-bottom: 1px solid;
23601       }
23602       .friends td, .friends th {
23603         border-left: 1px solid;
23604         padding: 5px 10px;
23605       }
23606       .friends td:first-child, .friends th:first-child {
23607         border-left: none;
23608       }
23609     </file>
23610     <file name="protractor.js" type="protractor">
23611       // Element locators
23612       var names = element.all(by.repeater('friends').column('friend.name'));
23613
23614       it('should sort friends by age in reverse order', function() {
23615         expect(names.get(0).getText()).toBe('Adam');
23616         expect(names.get(1).getText()).toBe('Julie');
23617         expect(names.get(2).getText()).toBe('Mike');
23618         expect(names.get(3).getText()).toBe('Mary');
23619         expect(names.get(4).getText()).toBe('John');
23620       });
23621     </file>
23622   </example>
23623 * <hr />
23624 *
23625 * @example
23626 * ### Changing parameters dynamically
23627 *
23628 * All parameters can be changed dynamically. The next example shows how you can make the columns of
23629 * a table sortable, by binding the `expression` and `reverse` parameters to scope properties.
23630 *
23631   <example name="orderBy-dynamic" module="orderByExample2">
23632     <file name="index.html">
23633       <div ng-controller="ExampleController">
23634         <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
23635         <hr/>
23636         <button ng-click="propertyName = null; reverse = false">Set to unsorted</button>
23637         <hr/>
23638         <table class="friends">
23639           <tr>
23640             <th>
23641               <button ng-click="sortBy('name')">Name</button>
23642               <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
23643             </th>
23644             <th>
23645               <button ng-click="sortBy('phone')">Phone Number</button>
23646               <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
23647             </th>
23648             <th>
23649               <button ng-click="sortBy('age')">Age</button>
23650               <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
23651             </th>
23652           </tr>
23653           <tr ng-repeat="friend in friends | orderBy:propertyName:reverse">
23654             <td>{{friend.name}}</td>
23655             <td>{{friend.phone}}</td>
23656             <td>{{friend.age}}</td>
23657           </tr>
23658         </table>
23659       </div>
23660     </file>
23661     <file name="script.js">
23662       angular.module('orderByExample2', [])
23663         .controller('ExampleController', ['$scope', function($scope) {
23664           var friends = [
23665             {name: 'John',   phone: '555-1212',  age: 10},
23666             {name: 'Mary',   phone: '555-9876',  age: 19},
23667             {name: 'Mike',   phone: '555-4321',  age: 21},
23668             {name: 'Adam',   phone: '555-5678',  age: 35},
23669             {name: 'Julie',  phone: '555-8765',  age: 29}
23670           ];
23671
23672           $scope.propertyName = 'age';
23673           $scope.reverse = true;
23674           $scope.friends = friends;
23675
23676           $scope.sortBy = function(propertyName) {
23677             $scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;
23678             $scope.propertyName = propertyName;
23679           };
23680         }]);
23681     </file>
23682     <file name="style.css">
23683       .friends {
23684         border-collapse: collapse;
23685       }
23686
23687       .friends th {
23688         border-bottom: 1px solid;
23689       }
23690       .friends td, .friends th {
23691         border-left: 1px solid;
23692         padding: 5px 10px;
23693       }
23694       .friends td:first-child, .friends th:first-child {
23695         border-left: none;
23696       }
23697
23698       .sortorder:after {
23699         content: '\25b2';   // BLACK UP-POINTING TRIANGLE
23700       }
23701       .sortorder.reverse:after {
23702         content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
23703       }
23704     </file>
23705     <file name="protractor.js" type="protractor">
23706       // Element locators
23707       var unsortButton = element(by.partialButtonText('unsorted'));
23708       var nameHeader = element(by.partialButtonText('Name'));
23709       var phoneHeader = element(by.partialButtonText('Phone'));
23710       var ageHeader = element(by.partialButtonText('Age'));
23711       var firstName = element(by.repeater('friends').column('friend.name').row(0));
23712       var lastName = element(by.repeater('friends').column('friend.name').row(4));
23713
23714       it('should sort friends by some property, when clicking on the column header', function() {
23715         expect(firstName.getText()).toBe('Adam');
23716         expect(lastName.getText()).toBe('John');
23717
23718         phoneHeader.click();
23719         expect(firstName.getText()).toBe('John');
23720         expect(lastName.getText()).toBe('Mary');
23721
23722         nameHeader.click();
23723         expect(firstName.getText()).toBe('Adam');
23724         expect(lastName.getText()).toBe('Mike');
23725
23726         ageHeader.click();
23727         expect(firstName.getText()).toBe('John');
23728         expect(lastName.getText()).toBe('Adam');
23729       });
23730
23731       it('should sort friends in reverse order, when clicking on the same column', function() {
23732         expect(firstName.getText()).toBe('Adam');
23733         expect(lastName.getText()).toBe('John');
23734
23735         ageHeader.click();
23736         expect(firstName.getText()).toBe('John');
23737         expect(lastName.getText()).toBe('Adam');
23738
23739         ageHeader.click();
23740         expect(firstName.getText()).toBe('Adam');
23741         expect(lastName.getText()).toBe('John');
23742       });
23743
23744       it('should restore the original order, when clicking "Set to unsorted"', function() {
23745         expect(firstName.getText()).toBe('Adam');
23746         expect(lastName.getText()).toBe('John');
23747
23748         unsortButton.click();
23749         expect(firstName.getText()).toBe('John');
23750         expect(lastName.getText()).toBe('Julie');
23751       });
23752     </file>
23753   </example>
23754 * <hr />
23755 *
23756 * @example
23757 * ### Using `orderBy` inside a controller
23758 *
23759 * It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and
23760 * calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory
23761 * and retrieve the `orderBy` filter with `$filter('orderBy')`.)
23762 *
23763   <example name="orderBy-call-manually" module="orderByExample3">
23764     <file name="index.html">
23765       <div ng-controller="ExampleController">
23766         <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
23767         <hr/>
23768         <button ng-click="sortBy(null)">Set to unsorted</button>
23769         <hr/>
23770         <table class="friends">
23771           <tr>
23772             <th>
23773               <button ng-click="sortBy('name')">Name</button>
23774               <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
23775             </th>
23776             <th>
23777               <button ng-click="sortBy('phone')">Phone Number</button>
23778               <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
23779             </th>
23780             <th>
23781               <button ng-click="sortBy('age')">Age</button>
23782               <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
23783             </th>
23784           </tr>
23785           <tr ng-repeat="friend in friends">
23786             <td>{{friend.name}}</td>
23787             <td>{{friend.phone}}</td>
23788             <td>{{friend.age}}</td>
23789           </tr>
23790         </table>
23791       </div>
23792     </file>
23793     <file name="script.js">
23794       angular.module('orderByExample3', [])
23795         .controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) {
23796           var friends = [
23797             {name: 'John',   phone: '555-1212',  age: 10},
23798             {name: 'Mary',   phone: '555-9876',  age: 19},
23799             {name: 'Mike',   phone: '555-4321',  age: 21},
23800             {name: 'Adam',   phone: '555-5678',  age: 35},
23801             {name: 'Julie',  phone: '555-8765',  age: 29}
23802           ];
23803
23804           $scope.propertyName = 'age';
23805           $scope.reverse = true;
23806           $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
23807
23808           $scope.sortBy = function(propertyName) {
23809             $scope.reverse = (propertyName !== null && $scope.propertyName === propertyName)
23810                 ? !$scope.reverse : false;
23811             $scope.propertyName = propertyName;
23812             $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
23813           };
23814         }]);
23815     </file>
23816     <file name="style.css">
23817       .friends {
23818         border-collapse: collapse;
23819       }
23820
23821       .friends th {
23822         border-bottom: 1px solid;
23823       }
23824       .friends td, .friends th {
23825         border-left: 1px solid;
23826         padding: 5px 10px;
23827       }
23828       .friends td:first-child, .friends th:first-child {
23829         border-left: none;
23830       }
23831
23832       .sortorder:after {
23833         content: '\25b2';   // BLACK UP-POINTING TRIANGLE
23834       }
23835       .sortorder.reverse:after {
23836         content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
23837       }
23838     </file>
23839     <file name="protractor.js" type="protractor">
23840       // Element locators
23841       var unsortButton = element(by.partialButtonText('unsorted'));
23842       var nameHeader = element(by.partialButtonText('Name'));
23843       var phoneHeader = element(by.partialButtonText('Phone'));
23844       var ageHeader = element(by.partialButtonText('Age'));
23845       var firstName = element(by.repeater('friends').column('friend.name').row(0));
23846       var lastName = element(by.repeater('friends').column('friend.name').row(4));
23847
23848       it('should sort friends by some property, when clicking on the column header', function() {
23849         expect(firstName.getText()).toBe('Adam');
23850         expect(lastName.getText()).toBe('John');
23851
23852         phoneHeader.click();
23853         expect(firstName.getText()).toBe('John');
23854         expect(lastName.getText()).toBe('Mary');
23855
23856         nameHeader.click();
23857         expect(firstName.getText()).toBe('Adam');
23858         expect(lastName.getText()).toBe('Mike');
23859
23860         ageHeader.click();
23861         expect(firstName.getText()).toBe('John');
23862         expect(lastName.getText()).toBe('Adam');
23863       });
23864
23865       it('should sort friends in reverse order, when clicking on the same column', function() {
23866         expect(firstName.getText()).toBe('Adam');
23867         expect(lastName.getText()).toBe('John');
23868
23869         ageHeader.click();
23870         expect(firstName.getText()).toBe('John');
23871         expect(lastName.getText()).toBe('Adam');
23872
23873         ageHeader.click();
23874         expect(firstName.getText()).toBe('Adam');
23875         expect(lastName.getText()).toBe('John');
23876       });
23877
23878       it('should restore the original order, when clicking "Set to unsorted"', function() {
23879         expect(firstName.getText()).toBe('Adam');
23880         expect(lastName.getText()).toBe('John');
23881
23882         unsortButton.click();
23883         expect(firstName.getText()).toBe('John');
23884         expect(lastName.getText()).toBe('Julie');
23885       });
23886     </file>
23887   </example>
23888 * <hr />
23889 *
23890 * @example
23891 * ### Using a custom comparator
23892 *
23893 * If you have very specific requirements about the way items are sorted, you can pass your own
23894 * comparator function. For example, you might need to compare some strings in a locale-sensitive
23895 * way. (When specifying a custom comparator, you also need to pass a value for the `reverse`
23896 * argument - passing `false` retains the default sorting order, i.e. ascending.)
23897 *
23898   <example name="orderBy-custom-comparator" module="orderByExample4">
23899     <file name="index.html">
23900       <div ng-controller="ExampleController">
23901         <div class="friends-container custom-comparator">
23902           <h3>Locale-sensitive Comparator</h3>
23903           <table class="friends">
23904             <tr>
23905               <th>Name</th>
23906               <th>Favorite Letter</th>
23907             </tr>
23908             <tr ng-repeat="friend in friends | orderBy:'favoriteLetter':false:localeSensitiveComparator">
23909               <td>{{friend.name}}</td>
23910               <td>{{friend.favoriteLetter}}</td>
23911             </tr>
23912           </table>
23913         </div>
23914         <div class="friends-container default-comparator">
23915           <h3>Default Comparator</h3>
23916           <table class="friends">
23917             <tr>
23918               <th>Name</th>
23919               <th>Favorite Letter</th>
23920             </tr>
23921             <tr ng-repeat="friend in friends | orderBy:'favoriteLetter'">
23922               <td>{{friend.name}}</td>
23923               <td>{{friend.favoriteLetter}}</td>
23924             </tr>
23925           </table>
23926         </div>
23927       </div>
23928     </file>
23929     <file name="script.js">
23930       angular.module('orderByExample4', [])
23931         .controller('ExampleController', ['$scope', function($scope) {
23932           $scope.friends = [
23933             {name: 'John',   favoriteLetter: 'Ä'},
23934             {name: 'Mary',   favoriteLetter: 'Ü'},
23935             {name: 'Mike',   favoriteLetter: 'Ö'},
23936             {name: 'Adam',   favoriteLetter: 'H'},
23937             {name: 'Julie',  favoriteLetter: 'Z'}
23938           ];
23939
23940           $scope.localeSensitiveComparator = function(v1, v2) {
23941             // If we don't get strings, just compare by index
23942             if (v1.type !== 'string' || v2.type !== 'string') {
23943               return (v1.index < v2.index) ? -1 : 1;
23944             }
23945
23946             // Compare strings alphabetically, taking locale into account
23947             return v1.value.localeCompare(v2.value);
23948           };
23949         }]);
23950     </file>
23951     <file name="style.css">
23952       .friends-container {
23953         display: inline-block;
23954         margin: 0 30px;
23955       }
23956
23957       .friends {
23958         border-collapse: collapse;
23959       }
23960
23961       .friends th {
23962         border-bottom: 1px solid;
23963       }
23964       .friends td, .friends th {
23965         border-left: 1px solid;
23966         padding: 5px 10px;
23967       }
23968       .friends td:first-child, .friends th:first-child {
23969         border-left: none;
23970       }
23971     </file>
23972     <file name="protractor.js" type="protractor">
23973       // Element locators
23974       var container = element(by.css('.custom-comparator'));
23975       var names = container.all(by.repeater('friends').column('friend.name'));
23976
23977       it('should sort friends by favorite letter (in correct alphabetical order)', function() {
23978         expect(names.get(0).getText()).toBe('John');
23979         expect(names.get(1).getText()).toBe('Adam');
23980         expect(names.get(2).getText()).toBe('Mike');
23981         expect(names.get(3).getText()).toBe('Mary');
23982         expect(names.get(4).getText()).toBe('Julie');
23983       });
23984     </file>
23985   </example>
23986 *
23987 */
23988orderByFilter.$inject = ['$parse'];
23989function orderByFilter($parse) {
23990  return function(array, sortPredicate, reverseOrder, compareFn) {
23991
23992    if (array == null) return array;
23993    if (!isArrayLike(array)) {
23994      throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
23995    }
23996
23997    if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
23998    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
23999
24000    var predicates = processPredicates(sortPredicate);
24001
24002    var descending = reverseOrder ? -1 : 1;
24003
24004    // Define the `compare()` function. Use a default comparator if none is specified.
24005    var compare = isFunction(compareFn) ? compareFn : defaultCompare;
24006
24007    // The next three lines are a version of a Swartzian Transform idiom from Perl
24008    // (sometimes called the Decorate-Sort-Undecorate idiom)
24009    // See https://en.wikipedia.org/wiki/Schwartzian_transform
24010    var compareValues = Array.prototype.map.call(array, getComparisonObject);
24011    compareValues.sort(doComparison);
24012    array = compareValues.map(function(item) { return item.value; });
24013
24014    return array;
24015
24016    function getComparisonObject(value, index) {
24017      // NOTE: We are adding an extra `tieBreaker` value based on the element's index.
24018      // This will be used to keep the sort stable when none of the input predicates can
24019      // distinguish between two elements.
24020      return {
24021        value: value,
24022        tieBreaker: {value: index, type: 'number', index: index},
24023        predicateValues: predicates.map(function(predicate) {
24024          return getPredicateValue(predicate.get(value), index);
24025        })
24026      };
24027    }
24028
24029    function doComparison(v1, v2) {
24030      for (var i = 0, ii = predicates.length; i < ii; i++) {
24031        var result = compare(v1.predicateValues[i], v2.predicateValues[i]);
24032        if (result) {
24033          return result * predicates[i].descending * descending;
24034        }
24035      }
24036
24037      return (compare(v1.tieBreaker, v2.tieBreaker) || defaultCompare(v1.tieBreaker, v2.tieBreaker)) * descending;
24038    }
24039  };
24040
24041  function processPredicates(sortPredicates) {
24042    return sortPredicates.map(function(predicate) {
24043      var descending = 1, get = identity;
24044
24045      if (isFunction(predicate)) {
24046        get = predicate;
24047      } else if (isString(predicate)) {
24048        if ((predicate.charAt(0) === '+' || predicate.charAt(0) === '-')) {
24049          descending = predicate.charAt(0) === '-' ? -1 : 1;
24050          predicate = predicate.substring(1);
24051        }
24052        if (predicate !== '') {
24053          get = $parse(predicate);
24054          if (get.constant) {
24055            var key = get();
24056            get = function(value) { return value[key]; };
24057          }
24058        }
24059      }
24060      return {get: get, descending: descending};
24061    });
24062  }
24063
24064  function isPrimitive(value) {
24065    switch (typeof value) {
24066      case 'number': /* falls through */
24067      case 'boolean': /* falls through */
24068      case 'string':
24069        return true;
24070      default:
24071        return false;
24072    }
24073  }
24074
24075  function objectValue(value) {
24076    // If `valueOf` is a valid function use that
24077    if (isFunction(value.valueOf)) {
24078      value = value.valueOf();
24079      if (isPrimitive(value)) return value;
24080    }
24081    // If `toString` is a valid function and not the one from `Object.prototype` use that
24082    if (hasCustomToString(value)) {
24083      value = value.toString();
24084      if (isPrimitive(value)) return value;
24085    }
24086
24087    return value;
24088  }
24089
24090  function getPredicateValue(value, index) {
24091    var type = typeof value;
24092    if (value === null) {
24093      type = 'null';
24094    } else if (type === 'object') {
24095      value = objectValue(value);
24096    }
24097    return {value: value, type: type, index: index};
24098  }
24099
24100  function defaultCompare(v1, v2) {
24101    var result = 0;
24102    var type1 = v1.type;
24103    var type2 = v2.type;
24104
24105    if (type1 === type2) {
24106      var value1 = v1.value;
24107      var value2 = v2.value;
24108
24109      if (type1 === 'string') {
24110        // Compare strings case-insensitively
24111        value1 = value1.toLowerCase();
24112        value2 = value2.toLowerCase();
24113      } else if (type1 === 'object') {
24114        // For basic objects, use the position of the object
24115        // in the collection instead of the value
24116        if (isObject(value1)) value1 = v1.index;
24117        if (isObject(value2)) value2 = v2.index;
24118      }
24119
24120      if (value1 !== value2) {
24121        result = value1 < value2 ? -1 : 1;
24122      }
24123    } else {
24124      result = (type1 === 'undefined') ? 1 :
24125        (type2 === 'undefined') ? -1 :
24126        (type1 === 'null') ? 1 :
24127        (type2 === 'null') ? -1 :
24128        (type1 < type2) ? -1 : 1;
24129    }
24130
24131    return result;
24132  }
24133}
24134
24135function ngDirective(directive) {
24136  if (isFunction(directive)) {
24137    directive = {
24138      link: directive
24139    };
24140  }
24141  directive.restrict = directive.restrict || 'AC';
24142  return valueFn(directive);
24143}
24144
24145/**
24146 * @ngdoc directive
24147 * @name a
24148 * @restrict E
24149 *
24150 * @description
24151 * Modifies the default behavior of the html a tag so that the default action is prevented when
24152 * the href attribute is empty.
24153 *
24154 * For dynamically creating `href` attributes for a tags, see the {@link ng.ngHref `ngHref`} directive.
24155 */
24156var htmlAnchorDirective = valueFn({
24157  restrict: 'E',
24158  compile: function(element, attr) {
24159    if (!attr.href && !attr.xlinkHref) {
24160      return function(scope, element) {
24161        // If the linked element is not an anchor tag anymore, do nothing
24162        if (element[0].nodeName.toLowerCase() !== 'a') return;
24163
24164        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
24165        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
24166                   'xlink:href' : 'href';
24167        element.on('click', function(event) {
24168          // if we have no href url, then don't navigate anywhere.
24169          if (!element.attr(href)) {
24170            event.preventDefault();
24171          }
24172        });
24173      };
24174    }
24175  }
24176});
24177
24178/**
24179 * @ngdoc directive
24180 * @name ngHref
24181 * @restrict A
24182 * @priority 99
24183 *
24184 * @description
24185 * Using AngularJS markup like `{{hash}}` in an href attribute will
24186 * make the link go to the wrong URL if the user clicks it before
24187 * AngularJS has a chance to replace the `{{hash}}` markup with its
24188 * value. Until AngularJS replaces the markup the link will be broken
24189 * and will most likely return a 404 error. The `ngHref` directive
24190 * solves this problem.
24191 *
24192 * The wrong way to write it:
24193 * ```html
24194 * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
24195 * ```
24196 *
24197 * The correct way to write it:
24198 * ```html
24199 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
24200 * ```
24201 *
24202 * @element A
24203 * @param {template} ngHref any string which can contain `{{}}` markup.
24204 *
24205 * @example
24206 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
24207 * in links and their different behaviors:
24208    <example name="ng-href">
24209      <file name="index.html">
24210        <input ng-model="value" /><br />
24211        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
24212        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
24213        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
24214        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
24215        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
24216        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
24217      </file>
24218      <file name="protractor.js" type="protractor">
24219        it('should execute ng-click but not reload when href without value', function() {
24220          element(by.id('link-1')).click();
24221          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
24222          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
24223        });
24224
24225        it('should execute ng-click but not reload when href empty string', function() {
24226          element(by.id('link-2')).click();
24227          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
24228          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
24229        });
24230
24231        it('should execute ng-click and change url when ng-href specified', function() {
24232          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
24233
24234          element(by.id('link-3')).click();
24235
24236          // At this point, we navigate away from an AngularJS page, so we need
24237          // to use browser.driver to get the base webdriver.
24238
24239          browser.wait(function() {
24240            return browser.driver.getCurrentUrl().then(function(url) {
24241              return url.match(/\/123$/);
24242            });
24243          }, 5000, 'page should navigate to /123');
24244        });
24245
24246        it('should execute ng-click but not reload when href empty string and name specified', function() {
24247          element(by.id('link-4')).click();
24248          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
24249          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
24250        });
24251
24252        it('should execute ng-click but not reload when no href but name specified', function() {
24253          element(by.id('link-5')).click();
24254          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
24255          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
24256        });
24257
24258        it('should only change url when only ng-href', function() {
24259          element(by.model('value')).clear();
24260          element(by.model('value')).sendKeys('6');
24261          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
24262
24263          element(by.id('link-6')).click();
24264
24265          // At this point, we navigate away from an AngularJS page, so we need
24266          // to use browser.driver to get the base webdriver.
24267          browser.wait(function() {
24268            return browser.driver.getCurrentUrl().then(function(url) {
24269              return url.match(/\/6$/);
24270            });
24271          }, 5000, 'page should navigate to /6');
24272        });
24273      </file>
24274    </example>
24275 */
24276
24277/**
24278 * @ngdoc directive
24279 * @name ngSrc
24280 * @restrict A
24281 * @priority 99
24282 *
24283 * @description
24284 * Using AngularJS markup like `{{hash}}` in a `src` attribute doesn't
24285 * work right: The browser will fetch from the URL with the literal
24286 * text `{{hash}}` until AngularJS replaces the expression inside
24287 * `{{hash}}`. The `ngSrc` directive solves this problem.
24288 *
24289 * The buggy way to write it:
24290 * ```html
24291 * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
24292 * ```
24293 *
24294 * The correct way to write it:
24295 * ```html
24296 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
24297 * ```
24298 *
24299 * @element IMG
24300 * @param {template} ngSrc any string which can contain `{{}}` markup.
24301 */
24302
24303/**
24304 * @ngdoc directive
24305 * @name ngSrcset
24306 * @restrict A
24307 * @priority 99
24308 *
24309 * @description
24310 * Using AngularJS markup like `{{hash}}` in a `srcset` attribute doesn't
24311 * work right: The browser will fetch from the URL with the literal
24312 * text `{{hash}}` until AngularJS replaces the expression inside
24313 * `{{hash}}`. The `ngSrcset` directive solves this problem.
24314 *
24315 * The buggy way to write it:
24316 * ```html
24317 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
24318 * ```
24319 *
24320 * The correct way to write it:
24321 * ```html
24322 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
24323 * ```
24324 *
24325 * @element IMG
24326 * @param {template} ngSrcset any string which can contain `{{}}` markup.
24327 */
24328
24329/**
24330 * @ngdoc directive
24331 * @name ngDisabled
24332 * @restrict A
24333 * @priority 100
24334 *
24335 * @description
24336 *
24337 * This directive sets the `disabled` attribute on the element (typically a form control,
24338 * e.g. `input`, `button`, `select` etc.) if the
24339 * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
24340 *
24341 * A special directive is necessary because we cannot use interpolation inside the `disabled`
24342 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
24343 *
24344 * @example
24345    <example name="ng-disabled">
24346      <file name="index.html">
24347        <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
24348        <button ng-model="button" ng-disabled="checked">Button</button>
24349      </file>
24350      <file name="protractor.js" type="protractor">
24351        it('should toggle button', function() {
24352          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
24353          element(by.model('checked')).click();
24354          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
24355        });
24356      </file>
24357    </example>
24358 *
24359 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
24360 *     then the `disabled` attribute will be set on the element
24361 */
24362
24363
24364/**
24365 * @ngdoc directive
24366 * @name ngChecked
24367 * @restrict A
24368 * @priority 100
24369 *
24370 * @description
24371 * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
24372 *
24373 * Note that this directive should not be used together with {@link ngModel `ngModel`},
24374 * as this can lead to unexpected behavior.
24375 *
24376 * A special directive is necessary because we cannot use interpolation inside the `checked`
24377 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
24378 *
24379 * @example
24380    <example name="ng-checked">
24381      <file name="index.html">
24382        <label>Check me to check both: <input type="checkbox" ng-model="leader"></label><br/>
24383        <input id="checkFollower" type="checkbox" ng-checked="leader" aria-label="Follower input">
24384      </file>
24385      <file name="protractor.js" type="protractor">
24386        it('should check both checkBoxes', function() {
24387          expect(element(by.id('checkFollower')).getAttribute('checked')).toBeFalsy();
24388          element(by.model('leader')).click();
24389          expect(element(by.id('checkFollower')).getAttribute('checked')).toBeTruthy();
24390        });
24391      </file>
24392    </example>
24393 *
24394 * @element INPUT
24395 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
24396 *     then the `checked` attribute will be set on the element
24397 */
24398
24399
24400/**
24401 * @ngdoc directive
24402 * @name ngReadonly
24403 * @restrict A
24404 * @priority 100
24405 *
24406 * @description
24407 *
24408 * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.
24409 * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on
24410 * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.
24411 *
24412 * A special directive is necessary because we cannot use interpolation inside the `readonly`
24413 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
24414 *
24415 * @example
24416    <example name="ng-readonly">
24417      <file name="index.html">
24418        <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
24419        <input type="text" ng-readonly="checked" value="I'm AngularJS" aria-label="Readonly field" />
24420      </file>
24421      <file name="protractor.js" type="protractor">
24422        it('should toggle readonly attr', function() {
24423          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
24424          element(by.model('checked')).click();
24425          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
24426        });
24427      </file>
24428    </example>
24429 *
24430 * @element INPUT
24431 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
24432 *     then special attribute "readonly" will be set on the element
24433 */
24434
24435
24436/**
24437 * @ngdoc directive
24438 * @name ngSelected
24439 * @restrict A
24440 * @priority 100
24441 *
24442 * @description
24443 *
24444 * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
24445 *
24446 * A special directive is necessary because we cannot use interpolation inside the `selected`
24447 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
24448 *
24449 * <div class="alert alert-warning">
24450 *   **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only
24451 *   sets the `selected` attribute on the element. If you are using `ngModel` on the select, you
24452 *   should not use `ngSelected` on the options, as `ngModel` will set the select value and
24453 *   selected options.
24454 * </div>
24455 *
24456 * @example
24457    <example name="ng-selected">
24458      <file name="index.html">
24459        <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
24460        <select aria-label="ngSelected demo">
24461          <option>Hello!</option>
24462          <option id="greet" ng-selected="selected">Greetings!</option>
24463        </select>
24464      </file>
24465      <file name="protractor.js" type="protractor">
24466        it('should select Greetings!', function() {
24467          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
24468          element(by.model('selected')).click();
24469          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
24470        });
24471      </file>
24472    </example>
24473 *
24474 * @element OPTION
24475 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
24476 *     then special attribute "selected" will be set on the element
24477 */
24478
24479/**
24480 * @ngdoc directive
24481 * @name ngOpen
24482 * @restrict A
24483 * @priority 100
24484 *
24485 * @description
24486 *
24487 * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
24488 *
24489 * A special directive is necessary because we cannot use interpolation inside the `open`
24490 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
24491 *
24492 * ## A note about browser compatibility
24493 *
24494 * Internet Explorer and Edge do not support the `details` element, it is
24495 * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.
24496 *
24497 * @example
24498     <example name="ng-open">
24499       <file name="index.html">
24500         <label>Toggle details: <input type="checkbox" ng-model="open"></label><br/>
24501         <details id="details" ng-open="open">
24502            <summary>List</summary>
24503            <ul>
24504              <li>Apple</li>
24505              <li>Orange</li>
24506              <li>Durian</li>
24507            </ul>
24508         </details>
24509       </file>
24510       <file name="protractor.js" type="protractor">
24511         it('should toggle open', function() {
24512           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
24513           element(by.model('open')).click();
24514           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
24515         });
24516       </file>
24517     </example>
24518 *
24519 * @element DETAILS
24520 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
24521 *     then special attribute "open" will be set on the element
24522 */
24523
24524var ngAttributeAliasDirectives = {};
24525
24526// boolean attrs are evaluated
24527forEach(BOOLEAN_ATTR, function(propName, attrName) {
24528  // binding to multiple is not supported
24529  if (propName === 'multiple') return;
24530
24531  function defaultLinkFn(scope, element, attr) {
24532    scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
24533      attr.$set(attrName, !!value);
24534    });
24535  }
24536
24537  var normalized = directiveNormalize('ng-' + attrName);
24538  var linkFn = defaultLinkFn;
24539
24540  if (propName === 'checked') {
24541    linkFn = function(scope, element, attr) {
24542      // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
24543      if (attr.ngModel !== attr[normalized]) {
24544        defaultLinkFn(scope, element, attr);
24545      }
24546    };
24547  }
24548
24549  ngAttributeAliasDirectives[normalized] = function() {
24550    return {
24551      restrict: 'A',
24552      priority: 100,
24553      link: linkFn
24554    };
24555  };
24556});
24557
24558// aliased input attrs are evaluated
24559forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
24560  ngAttributeAliasDirectives[ngAttr] = function() {
24561    return {
24562      priority: 100,
24563      link: function(scope, element, attr) {
24564        //special case ngPattern when a literal regular expression value
24565        //is used as the expression (this way we don't have to watch anything).
24566        if (ngAttr === 'ngPattern' && attr.ngPattern.charAt(0) === '/') {
24567          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
24568          if (match) {
24569            attr.$set('ngPattern', new RegExp(match[1], match[2]));
24570            return;
24571          }
24572        }
24573
24574        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
24575          attr.$set(ngAttr, value);
24576        });
24577      }
24578    };
24579  };
24580});
24581
24582// ng-src, ng-srcset, ng-href are interpolated
24583forEach(['src', 'srcset', 'href'], function(attrName) {
24584  var normalized = directiveNormalize('ng-' + attrName);
24585  ngAttributeAliasDirectives[normalized] = ['$sce', function($sce) {
24586    return {
24587      priority: 99, // it needs to run after the attributes are interpolated
24588      link: function(scope, element, attr) {
24589        var propName = attrName,
24590            name = attrName;
24591
24592        if (attrName === 'href' &&
24593            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
24594          name = 'xlinkHref';
24595          attr.$attr[name] = 'xlink:href';
24596          propName = null;
24597        }
24598
24599        // We need to sanitize the url at least once, in case it is a constant
24600        // non-interpolated attribute.
24601        attr.$set(normalized, $sce.getTrustedMediaUrl(attr[normalized]));
24602
24603        attr.$observe(normalized, function(value) {
24604          if (!value) {
24605            if (attrName === 'href') {
24606              attr.$set(name, null);
24607            }
24608            return;
24609          }
24610
24611          attr.$set(name, value);
24612
24613          // Support: IE 9-11 only
24614          // On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
24615          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
24616          // to set the property as well to achieve the desired effect.
24617          // We use attr[attrName] value since $set might have sanitized the url.
24618          if (msie && propName) element.prop(propName, attr[name]);
24619        });
24620      }
24621    };
24622  }];
24623});
24624
24625/* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS
24626 */
24627var nullFormCtrl = {
24628  $addControl: noop,
24629  $getControls: valueFn([]),
24630  $$renameControl: nullFormRenameControl,
24631  $removeControl: noop,
24632  $setValidity: noop,
24633  $setDirty: noop,
24634  $setPristine: noop,
24635  $setSubmitted: noop,
24636  $$setSubmitted: noop
24637},
24638PENDING_CLASS = 'ng-pending',
24639SUBMITTED_CLASS = 'ng-submitted';
24640
24641function nullFormRenameControl(control, name) {
24642  control.$name = name;
24643}
24644
24645/**
24646 * @ngdoc type
24647 * @name form.FormController
24648 *
24649 * @property {boolean} $pristine True if user has not interacted with the form yet.
24650 * @property {boolean} $dirty True if user has already interacted with the form.
24651 * @property {boolean} $valid True if all of the containing forms and controls are valid.
24652 * @property {boolean} $invalid True if at least one containing control or form is invalid.
24653 * @property {boolean} $submitted True if user has submitted the form even if its invalid.
24654 *
24655 * @property {Object} $pending An object hash, containing references to controls or forms with
24656 *  pending validators, where:
24657 *
24658 *  - keys are validations tokens (error names).
24659 *  - values are arrays of controls or forms that have a pending validator for the given error name.
24660 *
24661 * See {@link form.FormController#$error $error} for a list of built-in validation tokens.
24662 *
24663 * @property {Object} $error An object hash, containing references to controls or forms with failing
24664 *  validators, where:
24665 *
24666 *  - keys are validation tokens (error names),
24667 *  - values are arrays of controls or forms that have a failing validator for the given error name.
24668 *
24669 *  Built-in validation tokens:
24670 *  - `email`
24671 *  - `max`
24672 *  - `maxlength`
24673 *  - `min`
24674 *  - `minlength`
24675 *  - `number`
24676 *  - `pattern`
24677 *  - `required`
24678 *  - `url`
24679 *  - `date`
24680 *  - `datetimelocal`
24681 *  - `time`
24682 *  - `week`
24683 *  - `month`
24684 *
24685 * @description
24686 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
24687 * such as being valid/invalid or dirty/pristine.
24688 *
24689 * Each {@link ng.directive:form form} directive creates an instance
24690 * of `FormController`.
24691 *
24692 */
24693//asks for $scope to fool the BC controller module
24694FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
24695function FormController($element, $attrs, $scope, $animate, $interpolate) {
24696  this.$$controls = [];
24697
24698  // init state
24699  this.$error = {};
24700  this.$$success = {};
24701  this.$pending = undefined;
24702  this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope);
24703  this.$dirty = false;
24704  this.$pristine = true;
24705  this.$valid = true;
24706  this.$invalid = false;
24707  this.$submitted = false;
24708  this.$$parentForm = nullFormCtrl;
24709
24710  this.$$element = $element;
24711  this.$$animate = $animate;
24712
24713  setupValidity(this);
24714}
24715
24716FormController.prototype = {
24717  /**
24718   * @ngdoc method
24719   * @name form.FormController#$rollbackViewValue
24720   *
24721   * @description
24722   * Rollback all form controls pending updates to the `$modelValue`.
24723   *
24724   * Updates may be pending by a debounced event or because the input is waiting for a some future
24725   * event defined in `ng-model-options`. This method is typically needed by the reset button of
24726   * a form that uses `ng-model-options` to pend updates.
24727   */
24728  $rollbackViewValue: function() {
24729    forEach(this.$$controls, function(control) {
24730      control.$rollbackViewValue();
24731    });
24732  },
24733
24734  /**
24735   * @ngdoc method
24736   * @name form.FormController#$commitViewValue
24737   *
24738   * @description
24739   * Commit all form controls pending updates to the `$modelValue`.
24740   *
24741   * Updates may be pending by a debounced event or because the input is waiting for a some future
24742   * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
24743   * usually handles calling this in response to input events.
24744   */
24745  $commitViewValue: function() {
24746    forEach(this.$$controls, function(control) {
24747      control.$commitViewValue();
24748    });
24749  },
24750
24751  /**
24752   * @ngdoc method
24753   * @name form.FormController#$addControl
24754   * @param {object} control control object, either a {@link form.FormController} or an
24755   * {@link ngModel.NgModelController}
24756   *
24757   * @description
24758   * Register a control with the form. Input elements using ngModelController do this automatically
24759   * when they are linked.
24760   *
24761   * Note that the current state of the control will not be reflected on the new parent form. This
24762   * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
24763   * state.
24764   *
24765   * However, if the method is used programmatically, for example by adding dynamically created controls,
24766   * or controls that have been previously removed without destroying their corresponding DOM element,
24767   * it's the developers responsibility to make sure the current state propagates to the parent form.
24768   *
24769   * For example, if an input control is added that is already `$dirty` and has `$error` properties,
24770   * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
24771   */
24772  $addControl: function(control) {
24773    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
24774    // and not added to the scope.  Now we throw an error.
24775    assertNotHasOwnProperty(control.$name, 'input');
24776    this.$$controls.push(control);
24777
24778    if (control.$name) {
24779      this[control.$name] = control;
24780    }
24781
24782    control.$$parentForm = this;
24783  },
24784
24785  /**
24786   * @ngdoc method
24787   * @name form.FormController#$getControls
24788   * @returns {Array} the controls that are currently part of this form
24789   *
24790   * @description
24791   * This method returns a **shallow copy** of the controls that are currently part of this form.
24792   * The controls can be instances of {@link form.FormController `FormController`}
24793   * ({@link ngForm "child-forms"}) and of {@link ngModel.NgModelController `NgModelController`}.
24794   * If you need access to the controls of child-forms, you have to call `$getControls()`
24795   * recursively on them.
24796   * This can be used for example to iterate over all controls to validate them.
24797   *
24798   * The controls can be accessed normally, but adding to, or removing controls from the array has
24799   * no effect on the form. Instead, use {@link form.FormController#$addControl `$addControl()`} and
24800   * {@link form.FormController#$removeControl `$removeControl()`} for this use-case.
24801   * Likewise, adding a control to, or removing a control from the form is not reflected
24802   * in the shallow copy. That means you should get a fresh copy from `$getControls()` every time
24803   * you need access to the controls.
24804   */
24805  $getControls: function() {
24806    return shallowCopy(this.$$controls);
24807  },
24808
24809  // Private API: rename a form control
24810  $$renameControl: function(control, newName) {
24811    var oldName = control.$name;
24812
24813    if (this[oldName] === control) {
24814      delete this[oldName];
24815    }
24816    this[newName] = control;
24817    control.$name = newName;
24818  },
24819
24820  /**
24821   * @ngdoc method
24822   * @name form.FormController#$removeControl
24823   * @param {object} control control object, either a {@link form.FormController} or an
24824   * {@link ngModel.NgModelController}
24825   *
24826   * @description
24827   * Deregister a control from the form.
24828   *
24829   * Input elements using ngModelController do this automatically when they are destroyed.
24830   *
24831   * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
24832   * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
24833   * different from case to case. For example, removing the only `$dirty` control from a form may or
24834   * may not mean that the form is still `$dirty`.
24835   */
24836  $removeControl: function(control) {
24837    if (control.$name && this[control.$name] === control) {
24838      delete this[control.$name];
24839    }
24840    forEach(this.$pending, function(value, name) {
24841      // eslint-disable-next-line no-invalid-this
24842      this.$setValidity(name, null, control);
24843    }, this);
24844    forEach(this.$error, function(value, name) {
24845      // eslint-disable-next-line no-invalid-this
24846      this.$setValidity(name, null, control);
24847    }, this);
24848    forEach(this.$$success, function(value, name) {
24849      // eslint-disable-next-line no-invalid-this
24850      this.$setValidity(name, null, control);
24851    }, this);
24852
24853    arrayRemove(this.$$controls, control);
24854    control.$$parentForm = nullFormCtrl;
24855  },
24856
24857  /**
24858   * @ngdoc method
24859   * @name form.FormController#$setDirty
24860   *
24861   * @description
24862   * Sets the form to a dirty state.
24863   *
24864   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
24865   * state (ng-dirty class). This method will also propagate to parent forms.
24866   */
24867  $setDirty: function() {
24868    this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
24869    this.$$animate.addClass(this.$$element, DIRTY_CLASS);
24870    this.$dirty = true;
24871    this.$pristine = false;
24872    this.$$parentForm.$setDirty();
24873  },
24874
24875  /**
24876   * @ngdoc method
24877   * @name form.FormController#$setPristine
24878   *
24879   * @description
24880   * Sets the form to its pristine state.
24881   *
24882   * This method sets the form's `$pristine` state to true, the `$dirty` state to false, removes
24883   * the `ng-dirty` class and adds the `ng-pristine` class. Additionally, it sets the `$submitted`
24884   * state to false.
24885   *
24886   * This method will also propagate to all the controls contained in this form.
24887   *
24888   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
24889   * saving or resetting it.
24890   */
24891  $setPristine: function() {
24892    this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
24893    this.$dirty = false;
24894    this.$pristine = true;
24895    this.$submitted = false;
24896    forEach(this.$$controls, function(control) {
24897      control.$setPristine();
24898    });
24899  },
24900
24901  /**
24902   * @ngdoc method
24903   * @name form.FormController#$setUntouched
24904   *
24905   * @description
24906   * Sets the form to its untouched state.
24907   *
24908   * This method can be called to remove the 'ng-touched' class and set the form controls to their
24909   * untouched state (ng-untouched class).
24910   *
24911   * Setting a form controls back to their untouched state is often useful when setting the form
24912   * back to its pristine state.
24913   */
24914  $setUntouched: function() {
24915    forEach(this.$$controls, function(control) {
24916      control.$setUntouched();
24917    });
24918  },
24919
24920  /**
24921   * @ngdoc method
24922   * @name form.FormController#$setSubmitted
24923   *
24924   * @description
24925   * Sets the form to its `$submitted` state. This will also set `$submitted` on all child and
24926   * parent forms of the form.
24927   */
24928  $setSubmitted: function() {
24929    var rootForm = this;
24930    while (rootForm.$$parentForm && (rootForm.$$parentForm !== nullFormCtrl)) {
24931      rootForm = rootForm.$$parentForm;
24932    }
24933    rootForm.$$setSubmitted();
24934  },
24935
24936  $$setSubmitted: function() {
24937    this.$$animate.addClass(this.$$element, SUBMITTED_CLASS);
24938    this.$submitted = true;
24939    forEach(this.$$controls, function(control) {
24940      if (control.$$setSubmitted) {
24941        control.$$setSubmitted();
24942      }
24943    });
24944  }
24945};
24946
24947/**
24948 * @ngdoc method
24949 * @name form.FormController#$setValidity
24950 *
24951 * @description
24952 * Change the validity state of the form, and notify the parent form (if any).
24953 *
24954 * Application developers will rarely need to call this method directly. It is used internally, by
24955 * {@link ngModel.NgModelController#$setValidity NgModelController.$setValidity()}, to propagate a
24956 * control's validity state to the parent `FormController`.
24957 *
24958 * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be
24959 *        assigned to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` (for
24960 *        unfulfilled `$asyncValidators`), so that it is available for data-binding. The
24961 *        `validationErrorKey` should be in camelCase and will get converted into dash-case for
24962 *        class name. Example: `myError` will result in `ng-valid-my-error` and
24963 *        `ng-invalid-my-error` classes and can be bound to as `{{ someForm.$error.myError }}`.
24964 * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending
24965 *        (undefined),  or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
24966 *        Skipped is used by AngularJS when validators do not run because of parse errors and when
24967 *        `$asyncValidators` do not run because any of the `$validators` failed.
24968 * @param {NgModelController | FormController} controller - The controller whose validity state is
24969 *        triggering the change.
24970 */
24971addSetValidityMethod({
24972  clazz: FormController,
24973  set: function(object, property, controller) {
24974    var list = object[property];
24975    if (!list) {
24976      object[property] = [controller];
24977    } else {
24978      var index = list.indexOf(controller);
24979      if (index === -1) {
24980        list.push(controller);
24981      }
24982    }
24983  },
24984  unset: function(object, property, controller) {
24985    var list = object[property];
24986    if (!list) {
24987      return;
24988    }
24989    arrayRemove(list, controller);
24990    if (list.length === 0) {
24991      delete object[property];
24992    }
24993  }
24994});
24995
24996/**
24997 * @ngdoc directive
24998 * @name ngForm
24999 * @restrict EAC
25000 *
25001 * @description
25002 * Helper directive that makes it possible to create control groups inside a
25003 * {@link ng.directive:form `form`} directive.
25004 * These "child forms" can be used, for example, to determine the validity of a sub-group of
25005 * controls.
25006 *
25007 * <div class="alert alert-danger">
25008 * **Note**: `ngForm` cannot be used as a replacement for `<form>`, because it lacks its
25009 * [built-in HTML functionality](https://html.spec.whatwg.org/#the-form-element).
25010 * Specifically, you cannot submit `ngForm` like a `<form>` tag. That means,
25011 * you cannot send data to the server with `ngForm`, or integrate it with
25012 * {@link ng.directive:ngSubmit `ngSubmit`}.
25013 * </div>
25014 *
25015 * @param {string=} ngForm|name Name of the form. If specified, the form controller will
25016 *                              be published into the related scope, under this name.
25017 *
25018 */
25019
25020 /**
25021 * @ngdoc directive
25022 * @name form
25023 * @restrict E
25024 *
25025 * @description
25026 * Directive that instantiates
25027 * {@link form.FormController FormController}.
25028 *
25029 * If the `name` attribute is specified, the form controller is published onto the current scope under
25030 * this name.
25031 *
25032 * ## Alias: {@link ng.directive:ngForm `ngForm`}
25033 *
25034 * In AngularJS, forms can be nested. This means that the outer form is valid when all of the child
25035 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
25036 * AngularJS provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
25037 * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
25038 * of controls needs to be determined.
25039 *
25040 * ## CSS classes
25041 *  - `ng-valid` is set if the form is valid.
25042 *  - `ng-invalid` is set if the form is invalid.
25043 *  - `ng-pending` is set if the form is pending.
25044 *  - `ng-pristine` is set if the form is pristine.
25045 *  - `ng-dirty` is set if the form is dirty.
25046 *  - `ng-submitted` is set if the form was submitted.
25047 *
25048 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25049 *
25050 *
25051 * ## Submitting a form and preventing the default action
25052 *
25053 * Since the role of forms in client-side AngularJS applications is different than in classical
25054 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
25055 * page reload that sends the data to the server. Instead some javascript logic should be triggered
25056 * to handle the form submission in an application-specific way.
25057 *
25058 * For this reason, AngularJS prevents the default action (form submission to the server) unless the
25059 * `<form>` element has an `action` attribute specified.
25060 *
25061 * You can use one of the following two ways to specify what javascript method should be called when
25062 * a form is submitted:
25063 *
25064 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
25065 * - {@link ng.directive:ngClick ngClick} directive on the first
25066  *  button or input field of type submit (input[type=submit])
25067 *
25068 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
25069 * or {@link ng.directive:ngClick ngClick} directives.
25070 * This is because of the following form submission rules in the HTML specification:
25071 *
25072 * - If a form has only one input field then hitting enter in this field triggers form submit
25073 * (`ngSubmit`)
25074 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
25075 * doesn't trigger submit
25076 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
25077 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
25078 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
25079 *
25080 * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
25081 * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25082 * to have access to the updated model.
25083 *
25084 * @animations
25085 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
25086 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
25087 * other validations that are performed within the form. Animations in ngForm are similar to how
25088 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
25089 * as JS animations.
25090 *
25091 * The following example shows a simple way to utilize CSS transitions to style a form element
25092 * that has been rendered as invalid after it has been validated:
25093 *
25094 * <pre>
25095 * //be sure to include ngAnimate as a module to hook into more
25096 * //advanced animations
25097 * .my-form {
25098 *   transition:0.5s linear all;
25099 *   background: white;
25100 * }
25101 * .my-form.ng-invalid {
25102 *   background: red;
25103 *   color:white;
25104 * }
25105 * </pre>
25106 *
25107 * @example
25108    <example name="ng-form" deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
25109      <file name="index.html">
25110       <script>
25111         angular.module('formExample', [])
25112           .controller('FormController', ['$scope', function($scope) {
25113             $scope.userType = 'guest';
25114           }]);
25115       </script>
25116       <style>
25117        .my-form {
25118          transition:all linear 0.5s;
25119          background: transparent;
25120        }
25121        .my-form.ng-invalid {
25122          background: red;
25123        }
25124       </style>
25125       <form name="myForm" ng-controller="FormController" class="my-form">
25126         userType: <input name="input" ng-model="userType" required>
25127         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
25128         <code>userType = {{userType}}</code><br>
25129         <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
25130         <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
25131         <code>myForm.$valid = {{myForm.$valid}}</code><br>
25132         <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
25133        </form>
25134      </file>
25135      <file name="protractor.js" type="protractor">
25136        it('should initialize to model', function() {
25137          var userType = element(by.binding('userType'));
25138          var valid = element(by.binding('myForm.input.$valid'));
25139
25140          expect(userType.getText()).toContain('guest');
25141          expect(valid.getText()).toContain('true');
25142        });
25143
25144        it('should be invalid if empty', function() {
25145          var userType = element(by.binding('userType'));
25146          var valid = element(by.binding('myForm.input.$valid'));
25147          var userInput = element(by.model('userType'));
25148
25149          userInput.clear();
25150          userInput.sendKeys('');
25151
25152          expect(userType.getText()).toEqual('userType =');
25153          expect(valid.getText()).toContain('false');
25154        });
25155      </file>
25156    </example>
25157 *
25158 * @param {string=} name Name of the form. If specified, the form controller will be published into
25159 *                       related scope, under this name.
25160 */
25161var formDirectiveFactory = function(isNgForm) {
25162  return ['$timeout', '$parse', function($timeout, $parse) {
25163    var formDirective = {
25164      name: 'form',
25165      restrict: isNgForm ? 'EAC' : 'E',
25166      require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
25167      controller: FormController,
25168      compile: function ngFormCompile(formElement, attr) {
25169        // Setup initial state of the control
25170        formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
25171
25172        var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
25173
25174        return {
25175          pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
25176            var controller = ctrls[0];
25177
25178            // if `action` attr is not present on the form, prevent the default action (submission)
25179            if (!('action' in attr)) {
25180              // we can't use jq events because if a form is destroyed during submission the default
25181              // action is not prevented. see #1238
25182              //
25183              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
25184              // page reload if the form was destroyed by submission of the form via a click handler
25185              // on a button in the form. Looks like an IE9 specific bug.
25186              var handleFormSubmission = function(event) {
25187                scope.$apply(function() {
25188                  controller.$commitViewValue();
25189                  controller.$setSubmitted();
25190                });
25191
25192                event.preventDefault();
25193              };
25194
25195              formElement[0].addEventListener('submit', handleFormSubmission);
25196
25197              // unregister the preventDefault listener so that we don't not leak memory but in a
25198              // way that will achieve the prevention of the default action.
25199              formElement.on('$destroy', function() {
25200                $timeout(function() {
25201                  formElement[0].removeEventListener('submit', handleFormSubmission);
25202                }, 0, false);
25203              });
25204            }
25205
25206            var parentFormCtrl = ctrls[1] || controller.$$parentForm;
25207            parentFormCtrl.$addControl(controller);
25208
25209            var setter = nameAttr ? getSetter(controller.$name) : noop;
25210
25211            if (nameAttr) {
25212              setter(scope, controller);
25213              attr.$observe(nameAttr, function(newValue) {
25214                if (controller.$name === newValue) return;
25215                setter(scope, undefined);
25216                controller.$$parentForm.$$renameControl(controller, newValue);
25217                setter = getSetter(controller.$name);
25218                setter(scope, controller);
25219              });
25220            }
25221            formElement.on('$destroy', function() {
25222              controller.$$parentForm.$removeControl(controller);
25223              setter(scope, undefined);
25224              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
25225            });
25226          }
25227        };
25228      }
25229    };
25230
25231    return formDirective;
25232
25233    function getSetter(expression) {
25234      if (expression === '') {
25235        //create an assignable expression, so forms with an empty name can be renamed later
25236        return $parse('this[""]').assign;
25237      }
25238      return $parse(expression).assign || noop;
25239    }
25240  }];
25241};
25242
25243var formDirective = formDirectiveFactory();
25244var ngFormDirective = formDirectiveFactory(true);
25245
25246
25247
25248// helper methods
25249function setupValidity(instance) {
25250  instance.$$classCache = {};
25251  instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS));
25252}
25253function addSetValidityMethod(context) {
25254  var clazz = context.clazz,
25255      set = context.set,
25256      unset = context.unset;
25257
25258  clazz.prototype.$setValidity = function(validationErrorKey, state, controller) {
25259    if (isUndefined(state)) {
25260      createAndSet(this, '$pending', validationErrorKey, controller);
25261    } else {
25262      unsetAndCleanup(this, '$pending', validationErrorKey, controller);
25263    }
25264    if (!isBoolean(state)) {
25265      unset(this.$error, validationErrorKey, controller);
25266      unset(this.$$success, validationErrorKey, controller);
25267    } else {
25268      if (state) {
25269        unset(this.$error, validationErrorKey, controller);
25270        set(this.$$success, validationErrorKey, controller);
25271      } else {
25272        set(this.$error, validationErrorKey, controller);
25273        unset(this.$$success, validationErrorKey, controller);
25274      }
25275    }
25276    if (this.$pending) {
25277      cachedToggleClass(this, PENDING_CLASS, true);
25278      this.$valid = this.$invalid = undefined;
25279      toggleValidationCss(this, '', null);
25280    } else {
25281      cachedToggleClass(this, PENDING_CLASS, false);
25282      this.$valid = isObjectEmpty(this.$error);
25283      this.$invalid = !this.$valid;
25284      toggleValidationCss(this, '', this.$valid);
25285    }
25286
25287    // re-read the state as the set/unset methods could have
25288    // combined state in this.$error[validationError] (used for forms),
25289    // where setting/unsetting only increments/decrements the value,
25290    // and does not replace it.
25291    var combinedState;
25292    if (this.$pending && this.$pending[validationErrorKey]) {
25293      combinedState = undefined;
25294    } else if (this.$error[validationErrorKey]) {
25295      combinedState = false;
25296    } else if (this.$$success[validationErrorKey]) {
25297      combinedState = true;
25298    } else {
25299      combinedState = null;
25300    }
25301
25302    toggleValidationCss(this, validationErrorKey, combinedState);
25303    this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
25304  };
25305
25306  function createAndSet(ctrl, name, value, controller) {
25307    if (!ctrl[name]) {
25308      ctrl[name] = {};
25309    }
25310    set(ctrl[name], value, controller);
25311  }
25312
25313  function unsetAndCleanup(ctrl, name, value, controller) {
25314    if (ctrl[name]) {
25315      unset(ctrl[name], value, controller);
25316    }
25317    if (isObjectEmpty(ctrl[name])) {
25318      ctrl[name] = undefined;
25319    }
25320  }
25321
25322  function cachedToggleClass(ctrl, className, switchValue) {
25323    if (switchValue && !ctrl.$$classCache[className]) {
25324      ctrl.$$animate.addClass(ctrl.$$element, className);
25325      ctrl.$$classCache[className] = true;
25326    } else if (!switchValue && ctrl.$$classCache[className]) {
25327      ctrl.$$animate.removeClass(ctrl.$$element, className);
25328      ctrl.$$classCache[className] = false;
25329    }
25330  }
25331
25332  function toggleValidationCss(ctrl, validationErrorKey, isValid) {
25333    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
25334
25335    cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true);
25336    cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false);
25337  }
25338}
25339
25340function isObjectEmpty(obj) {
25341  if (obj) {
25342    for (var prop in obj) {
25343      if (obj.hasOwnProperty(prop)) {
25344        return false;
25345      }
25346    }
25347  }
25348  return true;
25349}
25350
25351/* global
25352  VALID_CLASS: false,
25353  INVALID_CLASS: false,
25354  PRISTINE_CLASS: false,
25355  DIRTY_CLASS: false,
25356  ngModelMinErr: false
25357*/
25358
25359// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
25360var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/;
25361// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
25362// Note: We are being more lenient, because browsers are too.
25363//   1. Scheme
25364//   2. Slashes
25365//   3. Username
25366//   4. Password
25367//   5. Hostname
25368//   6. Port
25369//   7. Path
25370//   8. Query
25371//   9. Fragment
25372//                 1111111111111111 222   333333    44444        55555555555555555555555     666     77777777     8888888     999
25373var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
25374// eslint-disable-next-line max-len
25375var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
25376var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
25377var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
25378var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
25379var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
25380var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
25381var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
25382
25383var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
25384var PARTIAL_VALIDATION_TYPES = createMap();
25385forEach('date,datetime-local,month,time,week'.split(','), function(type) {
25386  PARTIAL_VALIDATION_TYPES[type] = true;
25387});
25388
25389var inputType = {
25390
25391  /**
25392   * @ngdoc input
25393   * @name input[text]
25394   *
25395   * @description
25396   * Standard HTML text input with AngularJS data binding, inherited by most of the `input` elements.
25397   *
25398   *
25399   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25400   * @param {string=} name Property name of the form under which the control is published.
25401   * @param {string=} required Adds `required` validation error key if the value is not entered.
25402   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25403   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25404   *    `required` when you want to data-bind to the `required` attribute.
25405   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
25406   *    minlength.
25407   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
25408   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
25409   *    any length.
25410   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
25411   *    that contains the regular expression body that will be converted to a regular expression
25412   *    as in the ngPattern directive.
25413   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
25414   *    does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
25415   *    If the expression evaluates to a RegExp object, then this is used directly.
25416   *    If the expression evaluates to a string, then it will be converted to a RegExp
25417   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
25418   *    `new RegExp('^abc$')`.<br />
25419   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
25420   *    start at the index of the last search's match, thus not taking the whole input value into
25421   *    account.
25422   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25423   *    interaction with the input element.
25424   * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
25425   *    This parameter is ignored for input[type=password] controls, which will never trim the
25426   *    input.
25427   *
25428   * @example
25429      <example name="text-input-directive" module="textInputExample">
25430        <file name="index.html">
25431         <script>
25432           angular.module('textInputExample', [])
25433             .controller('ExampleController', ['$scope', function($scope) {
25434               $scope.example = {
25435                 text: 'guest',
25436                 word: /^\s*\w*\s*$/
25437               };
25438             }]);
25439         </script>
25440         <form name="myForm" ng-controller="ExampleController">
25441           <label>Single word:
25442             <input type="text" name="input" ng-model="example.text"
25443                    ng-pattern="example.word" required ng-trim="false">
25444           </label>
25445           <div role="alert">
25446             <span class="error" ng-show="myForm.input.$error.required">
25447               Required!</span>
25448             <span class="error" ng-show="myForm.input.$error.pattern">
25449               Single word only!</span>
25450           </div>
25451           <code>text = {{example.text}}</code><br/>
25452           <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br/>
25453           <code>myForm.input.$error = {{myForm.input.$error}}</code><br/>
25454           <code>myForm.$valid = {{myForm.$valid}}</code><br/>
25455           <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br/>
25456          </form>
25457        </file>
25458        <file name="protractor.js" type="protractor">
25459          var text = element(by.binding('example.text'));
25460          var valid = element(by.binding('myForm.input.$valid'));
25461          var input = element(by.model('example.text'));
25462
25463          it('should initialize to model', function() {
25464            expect(text.getText()).toContain('guest');
25465            expect(valid.getText()).toContain('true');
25466          });
25467
25468          it('should be invalid if empty', function() {
25469            input.clear();
25470            input.sendKeys('');
25471
25472            expect(text.getText()).toEqual('text =');
25473            expect(valid.getText()).toContain('false');
25474          });
25475
25476          it('should be invalid if multi word', function() {
25477            input.clear();
25478            input.sendKeys('hello world');
25479
25480            expect(valid.getText()).toContain('false');
25481          });
25482        </file>
25483      </example>
25484   */
25485  'text': textInputType,
25486
25487    /**
25488     * @ngdoc input
25489     * @name input[date]
25490     *
25491     * @description
25492     * Input with date validation and transformation. In browsers that do not yet support
25493     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
25494     * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
25495     * modern browsers do not yet support this input type, it is important to provide cues to users on the
25496     * expected input format via a placeholder or label.
25497     *
25498     * The model must always be a Date object, otherwise AngularJS will throw an error.
25499     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
25500     *
25501     * The timezone to be used to read/write the `Date` instance in the model can be defined using
25502     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
25503     *
25504     * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25505     * @param {string=} name Property name of the form under which the control is published.
25506     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
25507     *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
25508     *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
25509     *   constraint validation.
25510     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
25511     *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
25512     *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
25513     *   constraint validation.
25514     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
25515     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
25516     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
25517     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
25518     * @param {string=} required Sets `required` validation error key if the value is not entered.
25519     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25520     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25521     *    `required` when you want to data-bind to the `required` attribute.
25522     * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25523     *    interaction with the input element.
25524     *
25525     * @example
25526     <example name="date-input-directive" module="dateInputExample">
25527     <file name="index.html">
25528       <script>
25529          angular.module('dateInputExample', [])
25530            .controller('DateController', ['$scope', function($scope) {
25531              $scope.example = {
25532                value: new Date(2013, 9, 22)
25533              };
25534            }]);
25535       </script>
25536       <form name="myForm" ng-controller="DateController as dateCtrl">
25537          <label for="exampleInput">Pick a date in 2013:</label>
25538          <input type="date" id="exampleInput" name="input" ng-model="example.value"
25539              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
25540          <div role="alert">
25541            <span class="error" ng-show="myForm.input.$error.required">
25542                Required!</span>
25543            <span class="error" ng-show="myForm.input.$error.date">
25544                Not a valid date!</span>
25545           </div>
25546           <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
25547           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
25548           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
25549           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25550           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25551       </form>
25552     </file>
25553     <file name="protractor.js" type="protractor">
25554        var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
25555        var valid = element(by.binding('myForm.input.$valid'));
25556
25557        // currently protractor/webdriver does not support
25558        // sending keys to all known HTML5 input controls
25559        // for various browsers (see https://github.com/angular/protractor/issues/562).
25560        function setInput(val) {
25561          // set the value of the element and force validation.
25562          var scr = "var ipt = document.getElementById('exampleInput'); " +
25563          "ipt.value = '" + val + "';" +
25564          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
25565          browser.executeScript(scr);
25566        }
25567
25568        it('should initialize to model', function() {
25569          expect(value.getText()).toContain('2013-10-22');
25570          expect(valid.getText()).toContain('myForm.input.$valid = true');
25571        });
25572
25573        it('should be invalid if empty', function() {
25574          setInput('');
25575          expect(value.getText()).toEqual('value =');
25576          expect(valid.getText()).toContain('myForm.input.$valid = false');
25577        });
25578
25579        it('should be invalid if over max', function() {
25580          setInput('2015-01-01');
25581          expect(value.getText()).toContain('');
25582          expect(valid.getText()).toContain('myForm.input.$valid = false');
25583        });
25584     </file>
25585     </example>
25586     */
25587  'date': createDateInputType('date', DATE_REGEXP,
25588         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
25589         'yyyy-MM-dd'),
25590
25591   /**
25592    * @ngdoc input
25593    * @name input[datetime-local]
25594    *
25595    * @description
25596    * Input with datetime validation and transformation. In browsers that do not yet support
25597    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
25598    * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
25599    *
25600    * The model must always be a Date object, otherwise AngularJS will throw an error.
25601    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
25602    *
25603    * The timezone to be used to read/write the `Date` instance in the model can be defined using
25604    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
25605    *
25606    * The format of the displayed time can be adjusted with the
25607    * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
25608    * and `timeStripZeroSeconds`.
25609    *
25610    * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25611    * @param {string=} name Property name of the form under which the control is published.
25612    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
25613    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
25614    *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
25615    *   Note that `min` will also add native HTML5 constraint validation.
25616    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
25617    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
25618    *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
25619    *   Note that `max` will also add native HTML5 constraint validation.
25620    * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
25621    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
25622    * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
25623    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
25624    * @param {string=} required Sets `required` validation error key if the value is not entered.
25625    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25626    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25627    *    `required` when you want to data-bind to the `required` attribute.
25628    * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25629    *    interaction with the input element.
25630    *
25631    * @example
25632    <example name="datetimelocal-input-directive" module="dateExample">
25633    <file name="index.html">
25634      <script>
25635        angular.module('dateExample', [])
25636          .controller('DateController', ['$scope', function($scope) {
25637            $scope.example = {
25638              value: new Date(2010, 11, 28, 14, 57)
25639            };
25640          }]);
25641      </script>
25642      <form name="myForm" ng-controller="DateController as dateCtrl">
25643        <label for="exampleInput">Pick a date between in 2013:</label>
25644        <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
25645            placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
25646        <div role="alert">
25647          <span class="error" ng-show="myForm.input.$error.required">
25648              Required!</span>
25649          <span class="error" ng-show="myForm.input.$error.datetimelocal">
25650              Not a valid date!</span>
25651        </div>
25652        <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
25653        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
25654        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
25655        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25656        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25657      </form>
25658    </file>
25659    <file name="protractor.js" type="protractor">
25660      var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
25661      var valid = element(by.binding('myForm.input.$valid'));
25662
25663      // currently protractor/webdriver does not support
25664      // sending keys to all known HTML5 input controls
25665      // for various browsers (https://github.com/angular/protractor/issues/562).
25666      function setInput(val) {
25667        // set the value of the element and force validation.
25668        var scr = "var ipt = document.getElementById('exampleInput'); " +
25669        "ipt.value = '" + val + "';" +
25670        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
25671        browser.executeScript(scr);
25672      }
25673
25674      it('should initialize to model', function() {
25675        expect(value.getText()).toContain('2010-12-28T14:57:00');
25676        expect(valid.getText()).toContain('myForm.input.$valid = true');
25677      });
25678
25679      it('should be invalid if empty', function() {
25680        setInput('');
25681        expect(value.getText()).toEqual('value =');
25682        expect(valid.getText()).toContain('myForm.input.$valid = false');
25683      });
25684
25685      it('should be invalid if over max', function() {
25686        setInput('2015-01-01T23:59:00');
25687        expect(value.getText()).toContain('');
25688        expect(valid.getText()).toContain('myForm.input.$valid = false');
25689      });
25690    </file>
25691    </example>
25692    */
25693  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
25694      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
25695      'yyyy-MM-ddTHH:mm:ss.sss'),
25696
25697  /**
25698   * @ngdoc input
25699   * @name input[time]
25700   *
25701   * @description
25702   * Input with time validation and transformation. In browsers that do not yet support
25703   * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
25704   * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
25705   * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
25706   *
25707   * The model must always be a Date object, otherwise AngularJS will throw an error.
25708   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
25709   *
25710   * The timezone to be used to read/write the `Date` instance in the model can be defined using
25711   * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions}. By default,
25712   * this is the timezone of the browser.
25713   *
25714   * The format of the displayed time can be adjusted with the
25715   * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
25716   * and `timeStripZeroSeconds`.
25717   *
25718   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25719   * @param {string=} name Property name of the form under which the control is published.
25720   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
25721   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
25722   *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
25723   *   native HTML5 constraint validation.
25724   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
25725   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
25726   *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
25727   *   native HTML5 constraint validation.
25728   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
25729   *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
25730   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
25731   *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
25732   * @param {string=} required Sets `required` validation error key if the value is not entered.
25733   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25734   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25735   *    `required` when you want to data-bind to the `required` attribute.
25736   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25737   *    interaction with the input element.
25738   *
25739   * @example
25740   <example name="time-input-directive" module="timeExample">
25741   <file name="index.html">
25742     <script>
25743      angular.module('timeExample', [])
25744        .controller('DateController', ['$scope', function($scope) {
25745          $scope.example = {
25746            value: new Date(1970, 0, 1, 14, 57, 0)
25747          };
25748        }]);
25749     </script>
25750     <form name="myForm" ng-controller="DateController as dateCtrl">
25751        <label for="exampleInput">Pick a time between 8am and 5pm:</label>
25752        <input type="time" id="exampleInput" name="input" ng-model="example.value"
25753            placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
25754        <div role="alert">
25755          <span class="error" ng-show="myForm.input.$error.required">
25756              Required!</span>
25757          <span class="error" ng-show="myForm.input.$error.time">
25758              Not a valid date!</span>
25759        </div>
25760        <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
25761        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
25762        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
25763        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25764        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25765     </form>
25766   </file>
25767   <file name="protractor.js" type="protractor">
25768      var value = element(by.binding('example.value | date: "HH:mm:ss"'));
25769      var valid = element(by.binding('myForm.input.$valid'));
25770
25771      // currently protractor/webdriver does not support
25772      // sending keys to all known HTML5 input controls
25773      // for various browsers (https://github.com/angular/protractor/issues/562).
25774      function setInput(val) {
25775        // set the value of the element and force validation.
25776        var scr = "var ipt = document.getElementById('exampleInput'); " +
25777        "ipt.value = '" + val + "';" +
25778        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
25779        browser.executeScript(scr);
25780      }
25781
25782      it('should initialize to model', function() {
25783        expect(value.getText()).toContain('14:57:00');
25784        expect(valid.getText()).toContain('myForm.input.$valid = true');
25785      });
25786
25787      it('should be invalid if empty', function() {
25788        setInput('');
25789        expect(value.getText()).toEqual('value =');
25790        expect(valid.getText()).toContain('myForm.input.$valid = false');
25791      });
25792
25793      it('should be invalid if over max', function() {
25794        setInput('23:59:00');
25795        expect(value.getText()).toContain('');
25796        expect(valid.getText()).toContain('myForm.input.$valid = false');
25797      });
25798   </file>
25799   </example>
25800   */
25801  'time': createDateInputType('time', TIME_REGEXP,
25802      createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
25803     'HH:mm:ss.sss'),
25804
25805   /**
25806    * @ngdoc input
25807    * @name input[week]
25808    *
25809    * @description
25810    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
25811    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
25812    * week format (yyyy-W##), for example: `2013-W02`.
25813    *
25814    * The model must always be a Date object, otherwise AngularJS will throw an error.
25815    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
25816    *
25817    * The value of the resulting Date object will be set to Thursday at 00:00:00 of the requested week,
25818    * due to ISO-8601 week numbering standards. Information on ISO's system for numbering the weeks of the
25819    * year can be found at: https://en.wikipedia.org/wiki/ISO_8601#Week_dates
25820    *
25821    * The timezone to be used to read/write the `Date` instance in the model can be defined using
25822    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
25823    *
25824    * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25825    * @param {string=} name Property name of the form under which the control is published.
25826    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
25827    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
25828    *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
25829    *   native HTML5 constraint validation.
25830    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
25831    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
25832    *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
25833    *   native HTML5 constraint validation.
25834    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
25835    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
25836    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
25837    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
25838    * @param {string=} required Sets `required` validation error key if the value is not entered.
25839    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25840    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25841    *    `required` when you want to data-bind to the `required` attribute.
25842    * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25843    *    interaction with the input element.
25844    *
25845    * @example
25846    <example name="week-input-directive" module="weekExample">
25847    <file name="index.html">
25848      <script>
25849      angular.module('weekExample', [])
25850        .controller('DateController', ['$scope', function($scope) {
25851          $scope.example = {
25852            value: new Date(2013, 0, 3)
25853          };
25854        }]);
25855      </script>
25856      <form name="myForm" ng-controller="DateController as dateCtrl">
25857        <label>Pick a date between in 2013:
25858          <input id="exampleInput" type="week" name="input" ng-model="example.value"
25859                 placeholder="YYYY-W##" min="2012-W32"
25860                 max="2013-W52" required />
25861        </label>
25862        <div role="alert">
25863          <span class="error" ng-show="myForm.input.$error.required">
25864              Required!</span>
25865          <span class="error" ng-show="myForm.input.$error.week">
25866              Not a valid date!</span>
25867        </div>
25868        <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
25869        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
25870        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
25871        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25872        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25873      </form>
25874    </file>
25875    <file name="protractor.js" type="protractor">
25876      var value = element(by.binding('example.value | date: "yyyy-Www"'));
25877      var valid = element(by.binding('myForm.input.$valid'));
25878
25879      // currently protractor/webdriver does not support
25880      // sending keys to all known HTML5 input controls
25881      // for various browsers (https://github.com/angular/protractor/issues/562).
25882      function setInput(val) {
25883        // set the value of the element and force validation.
25884        var scr = "var ipt = document.getElementById('exampleInput'); " +
25885        "ipt.value = '" + val + "';" +
25886        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
25887        browser.executeScript(scr);
25888      }
25889
25890      it('should initialize to model', function() {
25891        expect(value.getText()).toContain('2013-W01');
25892        expect(valid.getText()).toContain('myForm.input.$valid = true');
25893      });
25894
25895      it('should be invalid if empty', function() {
25896        setInput('');
25897        expect(value.getText()).toEqual('value =');
25898        expect(valid.getText()).toContain('myForm.input.$valid = false');
25899      });
25900
25901      it('should be invalid if over max', function() {
25902        setInput('2015-W01');
25903        expect(value.getText()).toContain('');
25904        expect(valid.getText()).toContain('myForm.input.$valid = false');
25905      });
25906    </file>
25907    </example>
25908    */
25909  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
25910
25911  /**
25912   * @ngdoc input
25913   * @name input[month]
25914   *
25915   * @description
25916   * Input with month validation and transformation. In browsers that do not yet support
25917   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
25918   * month format (yyyy-MM), for example: `2009-01`.
25919   *
25920   * The model must always be a Date object, otherwise AngularJS will throw an error.
25921   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
25922   * If the model is not set to the first of the month, the next view to model update will set it
25923   * to the first of the month.
25924   *
25925   * The timezone to be used to read/write the `Date` instance in the model can be defined using
25926   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
25927   *
25928   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
25929   * @param {string=} name Property name of the form under which the control is published.
25930   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
25931   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
25932   *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
25933   *   native HTML5 constraint validation.
25934   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
25935   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
25936   *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
25937   *   native HTML5 constraint validation.
25938   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
25939   *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
25940   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
25941   *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
25942
25943   * @param {string=} required Sets `required` validation error key if the value is not entered.
25944   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25945   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25946   *    `required` when you want to data-bind to the `required` attribute.
25947   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
25948   *    interaction with the input element.
25949   *
25950   * @example
25951   <example name="month-input-directive" module="monthExample">
25952   <file name="index.html">
25953     <script>
25954      angular.module('monthExample', [])
25955        .controller('DateController', ['$scope', function($scope) {
25956          $scope.example = {
25957            value: new Date(2013, 9, 1)
25958          };
25959        }]);
25960     </script>
25961     <form name="myForm" ng-controller="DateController as dateCtrl">
25962       <label for="exampleInput">Pick a month in 2013:</label>
25963       <input id="exampleInput" type="month" name="input" ng-model="example.value"
25964          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
25965       <div role="alert">
25966         <span class="error" ng-show="myForm.input.$error.required">
25967            Required!</span>
25968         <span class="error" ng-show="myForm.input.$error.month">
25969            Not a valid month!</span>
25970       </div>
25971       <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
25972       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
25973       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
25974       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25975       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25976     </form>
25977   </file>
25978   <file name="protractor.js" type="protractor">
25979      var value = element(by.binding('example.value | date: "yyyy-MM"'));
25980      var valid = element(by.binding('myForm.input.$valid'));
25981
25982      // currently protractor/webdriver does not support
25983      // sending keys to all known HTML5 input controls
25984      // for various browsers (https://github.com/angular/protractor/issues/562).
25985      function setInput(val) {
25986        // set the value of the element and force validation.
25987        var scr = "var ipt = document.getElementById('exampleInput'); " +
25988        "ipt.value = '" + val + "';" +
25989        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
25990        browser.executeScript(scr);
25991      }
25992
25993      it('should initialize to model', function() {
25994        expect(value.getText()).toContain('2013-10');
25995        expect(valid.getText()).toContain('myForm.input.$valid = true');
25996      });
25997
25998      it('should be invalid if empty', function() {
25999        setInput('');
26000        expect(value.getText()).toEqual('value =');
26001        expect(valid.getText()).toContain('myForm.input.$valid = false');
26002      });
26003
26004      it('should be invalid if over max', function() {
26005        setInput('2015-01');
26006        expect(value.getText()).toContain('');
26007        expect(valid.getText()).toContain('myForm.input.$valid = false');
26008      });
26009   </file>
26010   </example>
26011   */
26012  'month': createDateInputType('month', MONTH_REGEXP,
26013     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
26014     'yyyy-MM'),
26015
26016  /**
26017   * @ngdoc input
26018   * @name input[number]
26019   *
26020   * @description
26021   * Text input with number validation and transformation. Sets the `number` validation
26022   * error if not a valid number.
26023   *
26024   * <div class="alert alert-warning">
26025   * The model must always be of type `number` otherwise AngularJS will throw an error.
26026   * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
26027   * error docs for more information and an example of how to convert your model if necessary.
26028   * </div>
26029   *
26030   *
26031   *
26032   * @knownIssue
26033   *
26034   * ### HTML5 constraint validation and `allowInvalid`
26035   *
26036   * In browsers that follow the
26037   * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
26038   * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
26039   * If a non-number is entered in the input, the browser will report the value as an empty string,
26040   * which means the view / model values in `ngModel` and subsequently the scope value
26041   * will also be an empty string.
26042   *
26043   * @knownIssue
26044   *
26045   * ### Large numbers and `step` validation
26046   *
26047   * The `step` validation will not work correctly for very large numbers (e.g. 9999999999) due to
26048   * Javascript's arithmetic limitations. If you need to handle large numbers, purpose-built
26049   * libraries (e.g. https://github.com/MikeMcl/big.js/), can be included into AngularJS by
26050   * {@link guide/forms#modifying-built-in-validators overwriting the validators}
26051   * for `number` and / or `step`, or by {@link guide/forms#custom-validation applying custom validators}
26052   * to an `input[text]` element. The source for `input[number]` type can be used as a starting
26053   * point for both implementations.
26054   *
26055   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
26056   * @param {string=} name Property name of the form under which the control is published.
26057   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
26058   *    Can be interpolated.
26059   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
26060   *    Can be interpolated.
26061   * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
26062   *    but does not trigger HTML5 native validation. Takes an expression.
26063   * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
26064   *    but does not trigger HTML5 native validation. Takes an expression.
26065   * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
26066   *    Can be interpolated.
26067   * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
26068   *    but does not trigger HTML5 native validation. Takes an expression.
26069   * @param {string=} required Sets `required` validation error key if the value is not entered.
26070   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26071   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26072   *    `required` when you want to data-bind to the `required` attribute.
26073   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
26074   *    minlength.
26075   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
26076   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
26077   *    any length.
26078   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
26079   *    that contains the regular expression body that will be converted to a regular expression
26080   *    as in the ngPattern directive.
26081   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
26082   *    does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
26083   *    If the expression evaluates to a RegExp object, then this is used directly.
26084   *    If the expression evaluates to a string, then it will be converted to a RegExp
26085   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
26086   *    `new RegExp('^abc$')`.<br />
26087   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
26088   *    start at the index of the last search's match, thus not taking the whole input value into
26089   *    account.
26090   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
26091   *    interaction with the input element.
26092   *
26093   * @example
26094      <example name="number-input-directive" module="numberExample">
26095        <file name="index.html">
26096         <script>
26097           angular.module('numberExample', [])
26098             .controller('ExampleController', ['$scope', function($scope) {
26099               $scope.example = {
26100                 value: 12
26101               };
26102             }]);
26103         </script>
26104         <form name="myForm" ng-controller="ExampleController">
26105           <label>Number:
26106             <input type="number" name="input" ng-model="example.value"
26107                    min="0" max="99" required>
26108          </label>
26109           <div role="alert">
26110             <span class="error" ng-show="myForm.input.$error.required">
26111               Required!</span>
26112             <span class="error" ng-show="myForm.input.$error.number">
26113               Not valid number!</span>
26114           </div>
26115           <tt>value = {{example.value}}</tt><br/>
26116           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26117           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
26118           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
26119           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26120          </form>
26121        </file>
26122        <file name="protractor.js" type="protractor">
26123          var value = element(by.binding('example.value'));
26124          var valid = element(by.binding('myForm.input.$valid'));
26125          var input = element(by.model('example.value'));
26126
26127          it('should initialize to model', function() {
26128            expect(value.getText()).toContain('12');
26129            expect(valid.getText()).toContain('true');
26130          });
26131
26132          it('should be invalid if empty', function() {
26133            input.clear();
26134            input.sendKeys('');
26135            expect(value.getText()).toEqual('value =');
26136            expect(valid.getText()).toContain('false');
26137          });
26138
26139          it('should be invalid if over max', function() {
26140            input.clear();
26141            input.sendKeys('123');
26142            expect(value.getText()).toEqual('value =');
26143            expect(valid.getText()).toContain('false');
26144          });
26145        </file>
26146      </example>
26147   */
26148  'number': numberInputType,
26149
26150
26151  /**
26152   * @ngdoc input
26153   * @name input[url]
26154   *
26155   * @description
26156   * Text input with URL validation. Sets the `url` validation error key if the content is not a
26157   * valid URL.
26158   *
26159   * <div class="alert alert-warning">
26160   * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
26161   * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
26162   * the built-in validators (see the {@link guide/forms Forms guide})
26163   * </div>
26164   *
26165   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
26166   * @param {string=} name Property name of the form under which the control is published.
26167   * @param {string=} required Sets `required` validation error key if the value is not entered.
26168   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26169   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26170   *    `required` when you want to data-bind to the `required` attribute.
26171   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
26172   *    minlength.
26173   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
26174   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
26175   *    any length.
26176   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
26177   *    that contains the regular expression body that will be converted to a regular expression
26178   *    as in the ngPattern directive.
26179   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
26180   *    does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
26181   *    If the expression evaluates to a RegExp object, then this is used directly.
26182   *    If the expression evaluates to a string, then it will be converted to a RegExp
26183   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
26184   *    `new RegExp('^abc$')`.<br />
26185   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
26186   *    start at the index of the last search's match, thus not taking the whole input value into
26187   *    account.
26188   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
26189   *    interaction with the input element.
26190   *
26191   * @example
26192      <example name="url-input-directive" module="urlExample">
26193        <file name="index.html">
26194         <script>
26195           angular.module('urlExample', [])
26196             .controller('ExampleController', ['$scope', function($scope) {
26197               $scope.url = {
26198                 text: 'http://google.com'
26199               };
26200             }]);
26201         </script>
26202         <form name="myForm" ng-controller="ExampleController">
26203           <label>URL:
26204             <input type="url" name="input" ng-model="url.text" required>
26205           <label>
26206           <div role="alert">
26207             <span class="error" ng-show="myForm.input.$error.required">
26208               Required!</span>
26209             <span class="error" ng-show="myForm.input.$error.url">
26210               Not valid url!</span>
26211           </div>
26212           <tt>text = {{url.text}}</tt><br/>
26213           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26214           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
26215           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
26216           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26217           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
26218          </form>
26219        </file>
26220        <file name="protractor.js" type="protractor">
26221          var text = element(by.binding('url.text'));
26222          var valid = element(by.binding('myForm.input.$valid'));
26223          var input = element(by.model('url.text'));
26224
26225          it('should initialize to model', function() {
26226            expect(text.getText()).toContain('http://google.com');
26227            expect(valid.getText()).toContain('true');
26228          });
26229
26230          it('should be invalid if empty', function() {
26231            input.clear();
26232            input.sendKeys('');
26233
26234            expect(text.getText()).toEqual('text =');
26235            expect(valid.getText()).toContain('false');
26236          });
26237
26238          it('should be invalid if not url', function() {
26239            input.clear();
26240            input.sendKeys('box');
26241
26242            expect(valid.getText()).toContain('false');
26243          });
26244        </file>
26245      </example>
26246   */
26247  'url': urlInputType,
26248
26249
26250  /**
26251   * @ngdoc input
26252   * @name input[email]
26253   *
26254   * @description
26255   * Text input with email validation. Sets the `email` validation error key if not a valid email
26256   * address.
26257   *
26258   * <div class="alert alert-warning">
26259   * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
26260   * used in Chromium, which may not fulfill your app's requirements.
26261   * If you need stricter (e.g. requiring a top-level domain), or more relaxed validation
26262   * (e.g. allowing IPv6 address literals) you can use `ng-pattern` or
26263   * modify the built-in validators (see the {@link guide/forms Forms guide}).
26264   * </div>
26265   *
26266   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
26267   * @param {string=} name Property name of the form under which the control is published.
26268   * @param {string=} required Sets `required` validation error key if the value is not entered.
26269   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26270   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26271   *    `required` when you want to data-bind to the `required` attribute.
26272   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
26273   *    minlength.
26274   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
26275   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
26276   *    any length.
26277   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
26278   *    that contains the regular expression body that will be converted to a regular expression
26279   *    as in the ngPattern directive.
26280   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
26281   *    does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
26282   *    If the expression evaluates to a RegExp object, then this is used directly.
26283   *    If the expression evaluates to a string, then it will be converted to a RegExp
26284   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
26285   *    `new RegExp('^abc$')`.<br />
26286   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
26287   *    start at the index of the last search's match, thus not taking the whole input value into
26288   *    account.
26289   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
26290   *    interaction with the input element.
26291   *
26292   * @example
26293      <example name="email-input-directive" module="emailExample">
26294        <file name="index.html">
26295         <script>
26296           angular.module('emailExample', [])
26297             .controller('ExampleController', ['$scope', function($scope) {
26298               $scope.email = {
26299                 text: '[email protected]'
26300               };
26301             }]);
26302         </script>
26303           <form name="myForm" ng-controller="ExampleController">
26304             <label>Email:
26305               <input type="email" name="input" ng-model="email.text" required>
26306             </label>
26307             <div role="alert">
26308               <span class="error" ng-show="myForm.input.$error.required">
26309                 Required!</span>
26310               <span class="error" ng-show="myForm.input.$error.email">
26311                 Not valid email!</span>
26312             </div>
26313             <tt>text = {{email.text}}</tt><br/>
26314             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26315             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
26316             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
26317             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26318             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
26319           </form>
26320         </file>
26321        <file name="protractor.js" type="protractor">
26322          var text = element(by.binding('email.text'));
26323          var valid = element(by.binding('myForm.input.$valid'));
26324          var input = element(by.model('email.text'));
26325
26326          it('should initialize to model', function() {
26327            expect(text.getText()).toContain('[email protected]');
26328            expect(valid.getText()).toContain('true');
26329          });
26330
26331          it('should be invalid if empty', function() {
26332            input.clear();
26333            input.sendKeys('');
26334            expect(text.getText()).toEqual('text =');
26335            expect(valid.getText()).toContain('false');
26336          });
26337
26338          it('should be invalid if not email', function() {
26339            input.clear();
26340            input.sendKeys('xxx');
26341
26342            expect(valid.getText()).toContain('false');
26343          });
26344        </file>
26345      </example>
26346   */
26347  'email': emailInputType,
26348
26349
26350  /**
26351   * @ngdoc input
26352   * @name input[radio]
26353   *
26354   * @description
26355   * HTML radio button.
26356   *
26357   * **Note:**<br>
26358   * All inputs controlled by {@link ngModel ngModel} (including those of type `radio`) will use the
26359   * value of their `name` attribute to determine the property under which their
26360   * {@link ngModel.NgModelController NgModelController} will be published on the parent
26361   * {@link form.FormController FormController}. Thus, if you use the same `name` for multiple
26362   * inputs of a form (e.g. a group of radio inputs), only _one_ `NgModelController` will be
26363   * published on the parent `FormController` under that name. The rest of the controllers will
26364   * continue to work as expected, but you won't be able to access them as properties on the parent
26365   * `FormController`.
26366   *
26367   * <div class="alert alert-info">
26368   *   <p>
26369   *     In plain HTML forms, the `name` attribute is used to identify groups of radio inputs, so
26370   *     that the browser can manage their state (checked/unchecked) based on the state of other
26371   *     inputs in the same group.
26372   *   </p>
26373   *   <p>
26374   *     In AngularJS forms, this is not necessary. The input's state will be updated based on the
26375   *     value of the underlying model data.
26376   *   </p>
26377   * </div>
26378   *
26379   * <div class="alert alert-success">
26380   *   If you omit the `name` attribute on a radio input, `ngModel` will automatically assign it a
26381   *   unique name.
26382   * </div>
26383   *
26384   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
26385   * @param {string} value The value to which the `ngModel` expression should be set when selected.
26386   *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
26387   *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
26388   * @param {string=} name Property name of the form under which the control is published.
26389   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
26390   *    interaction with the input element.
26391   * @param {string} ngValue AngularJS expression to which `ngModel` will be be set when the radio
26392   *    is selected. Should be used instead of the `value` attribute if you need
26393   *    a non-string `ngModel` (`boolean`, `array`, ...).
26394   *
26395   * @example
26396      <example name="radio-input-directive" module="radioExample">
26397        <file name="index.html">
26398         <script>
26399           angular.module('radioExample', [])
26400             .controller('ExampleController', ['$scope', function($scope) {
26401               $scope.color = {
26402                 name: 'blue'
26403               };
26404               $scope.specialValue = {
26405                 "id": "12345",
26406                 "value": "green"
26407               };
26408             }]);
26409         </script>
26410         <form name="myForm" ng-controller="ExampleController">
26411           <label>
26412             <input type="radio" ng-model="color.name" value="red">
26413             Red
26414           </label><br/>
26415           <label>
26416             <input type="radio" ng-model="color.name" ng-value="specialValue">
26417             Green
26418           </label><br/>
26419           <label>
26420             <input type="radio" ng-model="color.name" value="blue">
26421             Blue
26422           </label><br/>
26423           <tt>color = {{color.name | json}}</tt><br/>
26424          </form>
26425          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
26426        </file>
26427        <file name="protractor.js" type="protractor">
26428          it('should change state', function() {
26429            var inputs = element.all(by.model('color.name'));
26430            var color = element(by.binding('color.name'));
26431
26432            expect(color.getText()).toContain('blue');
26433
26434            inputs.get(0).click();
26435            expect(color.getText()).toContain('red');
26436
26437            inputs.get(1).click();
26438            expect(color.getText()).toContain('green');
26439          });
26440        </file>
26441      </example>
26442   */
26443  'radio': radioInputType,
26444
26445  /**
26446   * @ngdoc input
26447   * @name input[range]
26448   *
26449   * @description
26450   * Native range input with validation and transformation.
26451   *
26452   * The model for the range input must always be a `Number`.
26453   *
26454   * IE9 and other browsers that do not support the `range` type fall back
26455   * to a text input without any default values for `min`, `max` and `step`. Model binding,
26456   * validation and number parsing are nevertheless supported.
26457   *
26458   * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]`
26459   * in a way that never allows the input to hold an invalid value. That means:
26460   * - any non-numerical value is set to `(max + min) / 2`.
26461   * - any numerical value that is less than the current min val, or greater than the current max val
26462   * is set to the min / max val respectively.
26463   * - additionally, the current `step` is respected, so the nearest value that satisfies a step
26464   * is used.
26465   *
26466   * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range))
26467   * for more info.
26468   *
26469   * This has the following consequences for AngularJS:
26470   *
26471   * Since the element value should always reflect the current model value, a range input
26472   * will set the bound ngModel expression to the value that the browser has set for the
26473   * input element. For example, in the following input `<input type="range" ng-model="model.value">`,
26474   * if the application sets `model.value = null`, the browser will set the input to `'50'`.
26475   * AngularJS will then set the model to `50`, to prevent input and model value being out of sync.
26476   *
26477   * That means the model for range will immediately be set to `50` after `ngModel` has been
26478   * initialized. It also means a range input can never have the required error.
26479   *
26480   * This does not only affect changes to the model value, but also to the values of the `min`,
26481   * `max`, and `step` attributes. When these change in a way that will cause the browser to modify
26482   * the input value, AngularJS will also update the model value.
26483   *
26484   * Automatic value adjustment also means that a range input element can never have the `required`,
26485   * `min`, or `max` errors.
26486   *
26487   * However, `step` is currently only fully implemented by Firefox. Other browsers have problems
26488   * when the step value changes dynamically - they do not adjust the element value correctly, but
26489   * instead may set the `stepMismatch` error. If that's the case, the AngularJS will set the `step`
26490   * error on the input, and set the model to `undefined`.
26491   *
26492   * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
26493   * not set the `min` and `max` attributes, which means that the browser won't automatically adjust
26494   * the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
26495   *
26496   * @param {string}  ngModel Assignable AngularJS expression to data-bind to.
26497   * @param {string=} name Property name of the form under which the control is published.
26498   * @param {string=} min Sets the `min` validation to ensure that the value entered is greater
26499   *                  than `min`. Can be interpolated.
26500   * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`.
26501   *                  Can be interpolated.
26502   * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step`
26503   *                  Can be interpolated.
26504   * @param {expression=} ngChange AngularJS expression to be executed when the ngModel value changes due
26505   *                      to user interaction with the input element.
26506   * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the
26507   *                      element. **Note** : `ngChecked` should not be used alongside `ngModel`.
26508   *                      Checkout {@link ng.directive:ngChecked ngChecked} for usage.
26509   *
26510   * @example
26511      <example name="range-input-directive" module="rangeExample">
26512        <file name="index.html">
26513          <script>
26514            angular.module('rangeExample', [])
26515              .controller('ExampleController', ['$scope', function($scope) {
26516                $scope.value = 75;
26517                $scope.min = 10;
26518                $scope.max = 90;
26519              }]);
26520          </script>
26521          <form name="myForm" ng-controller="ExampleController">
26522
26523            Model as range: <input type="range" name="range" ng-model="value" min="{{min}}"  max="{{max}}">
26524            <hr>
26525            Model as number: <input type="number" ng-model="value"><br>
26526            Min: <input type="number" ng-model="min"><br>
26527            Max: <input type="number" ng-model="max"><br>
26528            value = <code>{{value}}</code><br/>
26529            myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
26530            myForm.range.$error = <code>{{myForm.range.$error}}</code>
26531          </form>
26532        </file>
26533      </example>
26534
26535   * ## Range Input with ngMin & ngMax attributes
26536
26537   * @example
26538      <example name="range-input-directive-ng" module="rangeExample">
26539        <file name="index.html">
26540          <script>
26541            angular.module('rangeExample', [])
26542              .controller('ExampleController', ['$scope', function($scope) {
26543                $scope.value = 75;
26544                $scope.min = 10;
26545                $scope.max = 90;
26546              }]);
26547          </script>
26548          <form name="myForm" ng-controller="ExampleController">
26549            Model as range: <input type="range" name="range" ng-model="value" ng-min="min" ng-max="max">
26550            <hr>
26551            Model as number: <input type="number" ng-model="value"><br>
26552            Min: <input type="number" ng-model="min"><br>
26553            Max: <input type="number" ng-model="max"><br>
26554            value = <code>{{value}}</code><br/>
26555            myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
26556            myForm.range.$error = <code>{{myForm.range.$error}}</code>
26557          </form>
26558        </file>
26559      </example>
26560
26561   */
26562  'range': rangeInputType,
26563
26564  /**
26565   * @ngdoc input
26566   * @name input[checkbox]
26567   *
26568   * @description
26569   * HTML checkbox.
26570   *
26571   * @param {string} ngModel Assignable AngularJS expression to data-bind to.
26572   * @param {string=} name Property name of the form under which the control is published.
26573   * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
26574   * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
26575   * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
26576   *    interaction with the input element.
26577   *
26578   * @example
26579      <example name="checkbox-input-directive" module="checkboxExample">
26580        <file name="index.html">
26581         <script>
26582           angular.module('checkboxExample', [])
26583             .controller('ExampleController', ['$scope', function($scope) {
26584               $scope.checkboxModel = {
26585                value1 : true,
26586                value2 : 'YES'
26587              };
26588             }]);
26589         </script>
26590         <form name="myForm" ng-controller="ExampleController">
26591           <label>Value1:
26592             <input type="checkbox" ng-model="checkboxModel.value1">
26593           </label><br/>
26594           <label>Value2:
26595             <input type="checkbox" ng-model="checkboxModel.value2"
26596                    ng-true-value="'YES'" ng-false-value="'NO'">
26597            </label><br/>
26598           <tt>value1 = {{checkboxModel.value1}}</tt><br/>
26599           <tt>value2 = {{checkboxModel.value2}}</tt><br/>
26600          </form>
26601        </file>
26602        <file name="protractor.js" type="protractor">
26603          it('should change state', function() {
26604            var value1 = element(by.binding('checkboxModel.value1'));
26605            var value2 = element(by.binding('checkboxModel.value2'));
26606
26607            expect(value1.getText()).toContain('true');
26608            expect(value2.getText()).toContain('YES');
26609
26610            element(by.model('checkboxModel.value1')).click();
26611            element(by.model('checkboxModel.value2')).click();
26612
26613            expect(value1.getText()).toContain('false');
26614            expect(value2.getText()).toContain('NO');
26615          });
26616        </file>
26617      </example>
26618   */
26619  'checkbox': checkboxInputType,
26620
26621  'hidden': noop,
26622  'button': noop,
26623  'submit': noop,
26624  'reset': noop,
26625  'file': noop
26626};
26627
26628function stringBasedInputType(ctrl) {
26629  ctrl.$formatters.push(function(value) {
26630    return ctrl.$isEmpty(value) ? value : value.toString();
26631  });
26632}
26633
26634function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26635  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
26636  stringBasedInputType(ctrl);
26637}
26638
26639function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26640  var type = lowercase(element[0].type);
26641
26642  // In composition mode, users are still inputting intermediate text buffer,
26643  // hold the listener until composition is done.
26644  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
26645  if (!$sniffer.android) {
26646    var composing = false;
26647
26648    element.on('compositionstart', function() {
26649      composing = true;
26650    });
26651
26652    // Support: IE9+
26653    element.on('compositionupdate', function(ev) {
26654      // End composition when ev.data is empty string on 'compositionupdate' event.
26655      // When the input de-focusses (e.g. by clicking away), IE triggers 'compositionupdate'
26656      // instead of 'compositionend'.
26657      if (isUndefined(ev.data) || ev.data === '') {
26658        composing = false;
26659      }
26660    });
26661
26662    element.on('compositionend', function() {
26663      composing = false;
26664      listener();
26665    });
26666  }
26667
26668  var timeout;
26669
26670  var listener = function(ev) {
26671    if (timeout) {
26672      $browser.defer.cancel(timeout);
26673      timeout = null;
26674    }
26675    if (composing) return;
26676    var value = element.val(),
26677        event = ev && ev.type;
26678
26679    // By default we will trim the value
26680    // If the attribute ng-trim exists we will avoid trimming
26681    // If input type is 'password', the value is never trimmed
26682    if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
26683      value = trim(value);
26684    }
26685
26686    // If a control is suffering from bad input (due to native validators), browsers discard its
26687    // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
26688    // control's value is the same empty value twice in a row.
26689    if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
26690      ctrl.$setViewValue(value, event);
26691    }
26692  };
26693
26694  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
26695  // input event on backspace, delete or cut
26696  if ($sniffer.hasEvent('input')) {
26697    element.on('input', listener);
26698  } else {
26699    var deferListener = function(ev, input, origValue) {
26700      if (!timeout) {
26701        timeout = $browser.defer(function() {
26702          timeout = null;
26703          if (!input || input.value !== origValue) {
26704            listener(ev);
26705          }
26706        });
26707      }
26708    };
26709
26710    element.on('keydown', /** @this */ function(event) {
26711      var key = event.keyCode;
26712
26713      // ignore
26714      //    command            modifiers                   arrows
26715      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
26716
26717      deferListener(event, this, this.value);
26718    });
26719
26720    // if user modifies input value using context menu in IE, we need "paste", "cut" and "drop" events to catch it
26721    if ($sniffer.hasEvent('paste')) {
26722      element.on('paste cut drop', deferListener);
26723    }
26724  }
26725
26726  // if user paste into input using mouse on older browser
26727  // or form autocomplete on newer browser, we need "change" event to catch it
26728  element.on('change', listener);
26729
26730  // Some native input types (date-family) have the ability to change validity without
26731  // firing any input/change events.
26732  // For these event types, when native validators are present and the browser supports the type,
26733  // check for validity changes on various DOM events.
26734  if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
26735    element.on(PARTIAL_VALIDATION_EVENTS, /** @this */ function(ev) {
26736      if (!timeout) {
26737        var validity = this[VALIDITY_STATE_PROPERTY];
26738        var origBadInput = validity.badInput;
26739        var origTypeMismatch = validity.typeMismatch;
26740        timeout = $browser.defer(function() {
26741          timeout = null;
26742          if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
26743            listener(ev);
26744          }
26745        });
26746      }
26747    });
26748  }
26749
26750  ctrl.$render = function() {
26751    // Workaround for Firefox validation #12102.
26752    var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
26753    if (element.val() !== value) {
26754      element.val(value);
26755    }
26756  };
26757}
26758
26759function weekParser(isoWeek, existingDate) {
26760  if (isDate(isoWeek)) {
26761    return isoWeek;
26762  }
26763
26764  if (isString(isoWeek)) {
26765    WEEK_REGEXP.lastIndex = 0;
26766    var parts = WEEK_REGEXP.exec(isoWeek);
26767    if (parts) {
26768      var year = +parts[1],
26769          week = +parts[2],
26770          hours = 0,
26771          minutes = 0,
26772          seconds = 0,
26773          milliseconds = 0,
26774          firstThurs = getFirstThursdayOfYear(year),
26775          addDays = (week - 1) * 7;
26776
26777      if (existingDate) {
26778        hours = existingDate.getHours();
26779        minutes = existingDate.getMinutes();
26780        seconds = existingDate.getSeconds();
26781        milliseconds = existingDate.getMilliseconds();
26782      }
26783
26784      return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
26785    }
26786  }
26787
26788  return NaN;
26789}
26790
26791function createDateParser(regexp, mapping) {
26792  return function(iso, previousDate) {
26793    var parts, map;
26794
26795    if (isDate(iso)) {
26796      return iso;
26797    }
26798
26799    if (isString(iso)) {
26800      // When a date is JSON'ified to wraps itself inside of an extra
26801      // set of double quotes. This makes the date parsing code unable
26802      // to match the date string and parse it as a date.
26803      if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') {
26804        iso = iso.substring(1, iso.length - 1);
26805      }
26806      if (ISO_DATE_REGEXP.test(iso)) {
26807        return new Date(iso);
26808      }
26809      regexp.lastIndex = 0;
26810      parts = regexp.exec(iso);
26811
26812      if (parts) {
26813        parts.shift();
26814        if (previousDate) {
26815          map = {
26816            yyyy: previousDate.getFullYear(),
26817            MM: previousDate.getMonth() + 1,
26818            dd: previousDate.getDate(),
26819            HH: previousDate.getHours(),
26820            mm: previousDate.getMinutes(),
26821            ss: previousDate.getSeconds(),
26822            sss: previousDate.getMilliseconds() / 1000
26823          };
26824        } else {
26825          map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
26826        }
26827
26828        forEach(parts, function(part, index) {
26829          if (index < mapping.length) {
26830            map[mapping[index]] = +part;
26831          }
26832        });
26833
26834        var date = new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
26835        if (map.yyyy < 100) {
26836          // In the constructor, 2-digit years map to 1900-1999.
26837          // Use `setFullYear()` to set the correct year.
26838          date.setFullYear(map.yyyy);
26839        }
26840
26841        return date;
26842      }
26843    }
26844
26845    return NaN;
26846  };
26847}
26848
26849function createDateInputType(type, regexp, parseDate, format) {
26850  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
26851    badInputChecker(scope, element, attr, ctrl, type);
26852    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
26853
26854    var isTimeType = type === 'time' || type === 'datetimelocal';
26855    var previousDate;
26856    var previousTimezone;
26857
26858    ctrl.$parsers.push(function(value) {
26859      if (ctrl.$isEmpty(value)) return null;
26860
26861      if (regexp.test(value)) {
26862        // Note: We cannot read ctrl.$modelValue, as there might be a different
26863        // parser/formatter in the processing chain so that the model
26864        // contains some different data format!
26865        return parseDateAndConvertTimeZoneToLocal(value, previousDate);
26866      }
26867      ctrl.$$parserName = type;
26868      return undefined;
26869    });
26870
26871    ctrl.$formatters.push(function(value) {
26872      if (value && !isDate(value)) {
26873        throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
26874      }
26875      if (isValidDate(value)) {
26876        previousDate = value;
26877        var timezone = ctrl.$options.getOption('timezone');
26878
26879        if (timezone) {
26880          previousTimezone = timezone;
26881          previousDate = convertTimezoneToLocal(previousDate, timezone, true);
26882        }
26883
26884        return formatter(value, timezone);
26885      } else {
26886        previousDate = null;
26887        previousTimezone = null;
26888        return '';
26889      }
26890    });
26891
26892    if (isDefined(attr.min) || attr.ngMin) {
26893      var minVal = attr.min || $parse(attr.ngMin)(scope);
26894      var parsedMinVal = parseObservedDateValue(minVal);
26895
26896      ctrl.$validators.min = function(value) {
26897        return !isValidDate(value) || isUndefined(parsedMinVal) || parseDate(value) >= parsedMinVal;
26898      };
26899      attr.$observe('min', function(val) {
26900        if (val !== minVal) {
26901          parsedMinVal = parseObservedDateValue(val);
26902          minVal = val;
26903          ctrl.$validate();
26904        }
26905      });
26906    }
26907
26908    if (isDefined(attr.max) || attr.ngMax) {
26909      var maxVal = attr.max || $parse(attr.ngMax)(scope);
26910      var parsedMaxVal = parseObservedDateValue(maxVal);
26911
26912      ctrl.$validators.max = function(value) {
26913        return !isValidDate(value) || isUndefined(parsedMaxVal) || parseDate(value) <= parsedMaxVal;
26914      };
26915      attr.$observe('max', function(val) {
26916        if (val !== maxVal) {
26917          parsedMaxVal = parseObservedDateValue(val);
26918          maxVal = val;
26919          ctrl.$validate();
26920        }
26921      });
26922    }
26923
26924    function isValidDate(value) {
26925      // Invalid Date: getTime() returns NaN
26926      return value && !(value.getTime && value.getTime() !== value.getTime());
26927    }
26928
26929    function parseObservedDateValue(val) {
26930      return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val;
26931    }
26932
26933    function parseDateAndConvertTimeZoneToLocal(value, previousDate) {
26934      var timezone = ctrl.$options.getOption('timezone');
26935
26936      if (previousTimezone && previousTimezone !== timezone) {
26937        // If the timezone has changed, adjust the previousDate to the default timezone
26938        // so that the new date is converted with the correct timezone offset
26939        previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone));
26940      }
26941
26942      var parsedDate = parseDate(value, previousDate);
26943
26944      if (!isNaN(parsedDate) && timezone) {
26945        parsedDate = convertTimezoneToLocal(parsedDate, timezone);
26946      }
26947      return parsedDate;
26948    }
26949
26950    function formatter(value, timezone) {
26951      var targetFormat = format;
26952
26953      if (isTimeType && isString(ctrl.$options.getOption('timeSecondsFormat'))) {
26954        targetFormat = format
26955          .replace('ss.sss', ctrl.$options.getOption('timeSecondsFormat'))
26956          .replace(/:$/, '');
26957      }
26958
26959      var formatted =  $filter('date')(value, targetFormat, timezone);
26960
26961      if (isTimeType && ctrl.$options.getOption('timeStripZeroSeconds')) {
26962        formatted = formatted.replace(/(?::00)?(?:\.000)?$/, '');
26963      }
26964
26965      return formatted;
26966    }
26967  };
26968}
26969
26970function badInputChecker(scope, element, attr, ctrl, parserName) {
26971  var node = element[0];
26972  var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
26973  if (nativeValidation) {
26974    ctrl.$parsers.push(function(value) {
26975      var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
26976      if (validity.badInput || validity.typeMismatch) {
26977        ctrl.$$parserName = parserName;
26978        return undefined;
26979      }
26980
26981      return value;
26982    });
26983  }
26984}
26985
26986function numberFormatterParser(ctrl) {
26987  ctrl.$parsers.push(function(value) {
26988    if (ctrl.$isEmpty(value))      return null;
26989    if (NUMBER_REGEXP.test(value)) return parseFloat(value);
26990
26991    ctrl.$$parserName = 'number';
26992    return undefined;
26993  });
26994
26995  ctrl.$formatters.push(function(value) {
26996    if (!ctrl.$isEmpty(value)) {
26997      if (!isNumber(value)) {
26998        throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
26999      }
27000      value = value.toString();
27001    }
27002    return value;
27003  });
27004}
27005
27006function parseNumberAttrVal(val) {
27007  if (isDefined(val) && !isNumber(val)) {
27008    val = parseFloat(val);
27009  }
27010  return !isNumberNaN(val) ? val : undefined;
27011}
27012
27013function isNumberInteger(num) {
27014  // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066
27015  // (minus the assumption that `num` is a number)
27016
27017  // eslint-disable-next-line no-bitwise
27018  return (num | 0) === num;
27019}
27020
27021function countDecimals(num) {
27022  var numString = num.toString();
27023  var decimalSymbolIndex = numString.indexOf('.');
27024
27025  if (decimalSymbolIndex === -1) {
27026    if (-1 < num && num < 1) {
27027      // It may be in the exponential notation format (`1e-X`)
27028      var match = /e-(\d+)$/.exec(numString);
27029
27030      if (match) {
27031        return Number(match[1]);
27032      }
27033    }
27034
27035    return 0;
27036  }
27037
27038  return numString.length - decimalSymbolIndex - 1;
27039}
27040
27041function isValidForStep(viewValue, stepBase, step) {
27042  // At this point `stepBase` and `step` are expected to be non-NaN values
27043  // and `viewValue` is expected to be a valid stringified number.
27044  var value = Number(viewValue);
27045
27046  var isNonIntegerValue = !isNumberInteger(value);
27047  var isNonIntegerStepBase = !isNumberInteger(stepBase);
27048  var isNonIntegerStep = !isNumberInteger(step);
27049
27050  // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
27051  // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
27052  if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
27053    var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
27054    var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
27055    var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
27056
27057    var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
27058    var multiplier = Math.pow(10, decimalCount);
27059
27060    value = value * multiplier;
27061    stepBase = stepBase * multiplier;
27062    step = step * multiplier;
27063
27064    if (isNonIntegerValue) value = Math.round(value);
27065    if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
27066    if (isNonIntegerStep) step = Math.round(step);
27067  }
27068
27069  return (value - stepBase) % step === 0;
27070}
27071
27072function numberInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
27073  badInputChecker(scope, element, attr, ctrl, 'number');
27074  numberFormatterParser(ctrl);
27075  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
27076
27077  var parsedMinVal;
27078
27079  if (isDefined(attr.min) || attr.ngMin) {
27080    var minVal = attr.min || $parse(attr.ngMin)(scope);
27081    parsedMinVal = parseNumberAttrVal(minVal);
27082
27083    ctrl.$validators.min = function(modelValue, viewValue) {
27084      return ctrl.$isEmpty(viewValue) || isUndefined(parsedMinVal) || viewValue >= parsedMinVal;
27085    };
27086
27087    attr.$observe('min', function(val) {
27088      if (val !== minVal) {
27089        parsedMinVal = parseNumberAttrVal(val);
27090        minVal = val;
27091        // TODO(matsko): implement validateLater to reduce number of validations
27092        ctrl.$validate();
27093      }
27094    });
27095  }
27096
27097  if (isDefined(attr.max) || attr.ngMax) {
27098    var maxVal = attr.max || $parse(attr.ngMax)(scope);
27099    var parsedMaxVal = parseNumberAttrVal(maxVal);
27100
27101    ctrl.$validators.max = function(modelValue, viewValue) {
27102      return ctrl.$isEmpty(viewValue) || isUndefined(parsedMaxVal) || viewValue <= parsedMaxVal;
27103    };
27104
27105    attr.$observe('max', function(val) {
27106      if (val !== maxVal) {
27107        parsedMaxVal = parseNumberAttrVal(val);
27108        maxVal = val;
27109        // TODO(matsko): implement validateLater to reduce number of validations
27110        ctrl.$validate();
27111      }
27112    });
27113  }
27114
27115  if (isDefined(attr.step) || attr.ngStep) {
27116    var stepVal = attr.step || $parse(attr.ngStep)(scope);
27117    var parsedStepVal = parseNumberAttrVal(stepVal);
27118
27119    ctrl.$validators.step = function(modelValue, viewValue) {
27120      return ctrl.$isEmpty(viewValue) || isUndefined(parsedStepVal) ||
27121        isValidForStep(viewValue, parsedMinVal || 0, parsedStepVal);
27122    };
27123
27124    attr.$observe('step', function(val) {
27125      // TODO(matsko): implement validateLater to reduce number of validations
27126      if (val !== stepVal) {
27127        parsedStepVal = parseNumberAttrVal(val);
27128        stepVal = val;
27129        ctrl.$validate();
27130      }
27131
27132    });
27133
27134  }
27135}
27136
27137function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
27138  badInputChecker(scope, element, attr, ctrl, 'range');
27139  numberFormatterParser(ctrl);
27140  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
27141
27142  var supportsRange = ctrl.$$hasNativeValidators && element[0].type === 'range',
27143      minVal = supportsRange ? 0 : undefined,
27144      maxVal = supportsRange ? 100 : undefined,
27145      stepVal = supportsRange ? 1 : undefined,
27146      validity = element[0].validity,
27147      hasMinAttr = isDefined(attr.min),
27148      hasMaxAttr = isDefined(attr.max),
27149      hasStepAttr = isDefined(attr.step);
27150
27151  var originalRender = ctrl.$render;
27152
27153  ctrl.$render = supportsRange && isDefined(validity.rangeUnderflow) && isDefined(validity.rangeOverflow) ?
27154    //Browsers that implement range will set these values automatically, but reading the adjusted values after
27155    //$render would cause the min / max validators to be applied with the wrong value
27156    function rangeRender() {
27157      originalRender();
27158      ctrl.$setViewValue(element.val());
27159    } :
27160    originalRender;
27161
27162  if (hasMinAttr) {
27163    minVal = parseNumberAttrVal(attr.min);
27164
27165    ctrl.$validators.min = supportsRange ?
27166      // Since all browsers set the input to a valid value, we don't need to check validity
27167      function noopMinValidator() { return true; } :
27168      // non-support browsers validate the min val
27169      function minValidator(modelValue, viewValue) {
27170        return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal;
27171      };
27172
27173    setInitialValueAndObserver('min', minChange);
27174  }
27175
27176  if (hasMaxAttr) {
27177    maxVal = parseNumberAttrVal(attr.max);
27178
27179    ctrl.$validators.max = supportsRange ?
27180      // Since all browsers set the input to a valid value, we don't need to check validity
27181      function noopMaxValidator() { return true; } :
27182      // non-support browsers validate the max val
27183      function maxValidator(modelValue, viewValue) {
27184        return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal;
27185      };
27186
27187    setInitialValueAndObserver('max', maxChange);
27188  }
27189
27190  if (hasStepAttr) {
27191    stepVal = parseNumberAttrVal(attr.step);
27192
27193    ctrl.$validators.step = supportsRange ?
27194      function nativeStepValidator() {
27195        // Currently, only FF implements the spec on step change correctly (i.e. adjusting the
27196        // input element value to a valid value). It's possible that other browsers set the stepMismatch
27197        // validity error instead, so we can at least report an error in that case.
27198        return !validity.stepMismatch;
27199      } :
27200      // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would
27201      function stepValidator(modelValue, viewValue) {
27202        return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
27203               isValidForStep(viewValue, minVal || 0, stepVal);
27204      };
27205
27206    setInitialValueAndObserver('step', stepChange);
27207  }
27208
27209  function setInitialValueAndObserver(htmlAttrName, changeFn) {
27210    // interpolated attributes set the attribute value only after a digest, but we need the
27211    // attribute value when the input is first rendered, so that the browser can adjust the
27212    // input value based on the min/max value
27213    element.attr(htmlAttrName, attr[htmlAttrName]);
27214    var oldVal = attr[htmlAttrName];
27215    attr.$observe(htmlAttrName, function wrappedObserver(val) {
27216      if (val !== oldVal) {
27217        oldVal = val;
27218        changeFn(val);
27219      }
27220    });
27221  }
27222
27223  function minChange(val) {
27224    minVal = parseNumberAttrVal(val);
27225    // ignore changes before model is initialized
27226    if (isNumberNaN(ctrl.$modelValue)) {
27227      return;
27228    }
27229
27230    if (supportsRange) {
27231      var elVal = element.val();
27232      // IE11 doesn't set the el val correctly if the minVal is greater than the element value
27233      if (minVal > elVal) {
27234        elVal = minVal;
27235        element.val(elVal);
27236      }
27237      ctrl.$setViewValue(elVal);
27238    } else {
27239      // TODO(matsko): implement validateLater to reduce number of validations
27240      ctrl.$validate();
27241    }
27242  }
27243
27244  function maxChange(val) {
27245    maxVal = parseNumberAttrVal(val);
27246    // ignore changes before model is initialized
27247    if (isNumberNaN(ctrl.$modelValue)) {
27248      return;
27249    }
27250
27251    if (supportsRange) {
27252      var elVal = element.val();
27253      // IE11 doesn't set the el val correctly if the maxVal is less than the element value
27254      if (maxVal < elVal) {
27255        element.val(maxVal);
27256        // IE11 and Chrome don't set the value to the minVal when max < min
27257        elVal = maxVal < minVal ? minVal : maxVal;
27258      }
27259      ctrl.$setViewValue(elVal);
27260    } else {
27261      // TODO(matsko): implement validateLater to reduce number of validations
27262      ctrl.$validate();
27263    }
27264  }
27265
27266  function stepChange(val) {
27267    stepVal = parseNumberAttrVal(val);
27268    // ignore changes before model is initialized
27269    if (isNumberNaN(ctrl.$modelValue)) {
27270      return;
27271    }
27272
27273    // Some browsers don't adjust the input value correctly, but set the stepMismatch error
27274    if (!supportsRange) {
27275      // TODO(matsko): implement validateLater to reduce number of validations
27276      ctrl.$validate();
27277    } else if (ctrl.$viewValue !== element.val()) {
27278      ctrl.$setViewValue(element.val());
27279    }
27280  }
27281}
27282
27283function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
27284  // Note: no badInputChecker here by purpose as `url` is only a validation
27285  // in browsers, i.e. we can always read out input.value even if it is not valid!
27286  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
27287  stringBasedInputType(ctrl);
27288
27289  ctrl.$validators.url = function(modelValue, viewValue) {
27290    var value = modelValue || viewValue;
27291    return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
27292  };
27293}
27294
27295function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
27296  // Note: no badInputChecker here by purpose as `url` is only a validation
27297  // in browsers, i.e. we can always read out input.value even if it is not valid!
27298  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
27299  stringBasedInputType(ctrl);
27300
27301  ctrl.$validators.email = function(modelValue, viewValue) {
27302    var value = modelValue || viewValue;
27303    return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
27304  };
27305}
27306
27307function radioInputType(scope, element, attr, ctrl) {
27308  var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false';
27309  // make the name unique, if not defined
27310  if (isUndefined(attr.name)) {
27311    element.attr('name', nextUid());
27312  }
27313
27314  var listener = function(ev) {
27315    var value;
27316    if (element[0].checked) {
27317      value = attr.value;
27318      if (doTrim) {
27319        value = trim(value);
27320      }
27321      ctrl.$setViewValue(value, ev && ev.type);
27322    }
27323  };
27324
27325  element.on('change', listener);
27326
27327  ctrl.$render = function() {
27328    var value = attr.value;
27329    if (doTrim) {
27330      value = trim(value);
27331    }
27332    element[0].checked = (value === ctrl.$viewValue);
27333  };
27334
27335  attr.$observe('value', ctrl.$render);
27336}
27337
27338function parseConstantExpr($parse, context, name, expression, fallback) {
27339  var parseFn;
27340  if (isDefined(expression)) {
27341    parseFn = $parse(expression);
27342    if (!parseFn.constant) {
27343      throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
27344                                   '`{1}`.', name, expression);
27345    }
27346    return parseFn(context);
27347  }
27348  return fallback;
27349}
27350
27351function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
27352  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
27353  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
27354
27355  var listener = function(ev) {
27356    ctrl.$setViewValue(element[0].checked, ev && ev.type);
27357  };
27358
27359  element.on('change', listener);
27360
27361  ctrl.$render = function() {
27362    element[0].checked = ctrl.$viewValue;
27363  };
27364
27365  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
27366  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
27367  // it to a boolean.
27368  ctrl.$isEmpty = function(value) {
27369    return value === false;
27370  };
27371
27372  ctrl.$formatters.push(function(value) {
27373    return equals(value, trueValue);
27374  });
27375
27376  ctrl.$parsers.push(function(value) {
27377    return value ? trueValue : falseValue;
27378  });
27379}
27380
27381
27382/**
27383 * @ngdoc directive
27384 * @name textarea
27385 * @restrict E
27386 *
27387 * @description
27388 * HTML textarea element control with AngularJS data-binding. The data-binding and validation
27389 * properties of this element are exactly the same as those of the
27390 * {@link ng.directive:input input element}.
27391 *
27392 * @param {string} ngModel Assignable AngularJS expression to data-bind to.
27393 * @param {string=} name Property name of the form under which the control is published.
27394 * @param {string=} required Sets `required` validation error key if the value is not entered.
27395 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27396 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27397 *    `required` when you want to data-bind to the `required` attribute.
27398 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
27399 *    minlength.
27400 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
27401 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
27402 *    length.
27403 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
27404 *    does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
27405 *    If the expression evaluates to a RegExp object, then this is used directly.
27406 *    If the expression evaluates to a string, then it will be converted to a RegExp
27407 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
27408 *    `new RegExp('^abc$')`.<br />
27409 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
27410 *    start at the index of the last search's match, thus not taking the whole input value into
27411 *    account.
27412 * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
27413 *    interaction with the input element.
27414 * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
27415 *
27416 * @knownIssue
27417 *
27418 * When specifying the `placeholder` attribute of `<textarea>`, Internet Explorer will temporarily
27419 * insert the placeholder value as the textarea's content. If the placeholder value contains
27420 * interpolation (`{{ ... }}`), an error will be logged in the console when AngularJS tries to update
27421 * the value of the by-then-removed text node. This doesn't affect the functionality of the
27422 * textarea, but can be undesirable.
27423 *
27424 * You can work around this Internet Explorer issue by using `ng-attr-placeholder` instead of
27425 * `placeholder` on textareas, whenever you need interpolation in the placeholder value. You can
27426 * find more details on `ngAttr` in the
27427 * [Interpolation](guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes) section of the
27428 * Developer Guide.
27429 */
27430
27431
27432/**
27433 * @ngdoc directive
27434 * @name input
27435 * @restrict E
27436 *
27437 * @description
27438 * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
27439 * input state control, and validation.
27440 * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
27441 *
27442 * <div class="alert alert-warning">
27443 * **Note:** Not every feature offered is available for all input types.
27444 * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
27445 * </div>
27446 *
27447 * @param {string} ngModel Assignable AngularJS expression to data-bind to.
27448 * @param {string=} name Property name of the form under which the control is published.
27449 * @param {string=} required Sets `required` validation error key if the value is not entered.
27450 * @param {boolean=} ngRequired Sets `required` attribute if set to true
27451 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
27452 *    minlength.
27453 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
27454 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
27455 *    length.
27456 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
27457 *    value does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
27458 *    If the expression evaluates to a RegExp object, then this is used directly.
27459 *    If the expression evaluates to a string, then it will be converted to a RegExp
27460 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
27461 *    `new RegExp('^abc$')`.<br />
27462 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
27463 *    start at the index of the last search's match, thus not taking the whole input value into
27464 *    account.
27465 * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
27466 *    interaction with the input element.
27467 * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
27468 *    This parameter is ignored for input[type=password] controls, which will never trim the
27469 *    input.
27470 *
27471 * @example
27472    <example name="input-directive" module="inputExample">
27473      <file name="index.html">
27474       <script>
27475          angular.module('inputExample', [])
27476            .controller('ExampleController', ['$scope', function($scope) {
27477              $scope.user = {name: 'guest', last: 'visitor'};
27478            }]);
27479       </script>
27480       <div ng-controller="ExampleController">
27481         <form name="myForm">
27482           <label>
27483              User name:
27484              <input type="text" name="userName" ng-model="user.name" required>
27485           </label>
27486           <div role="alert">
27487             <span class="error" ng-show="myForm.userName.$error.required">
27488              Required!</span>
27489           </div>
27490           <label>
27491              Last name:
27492              <input type="text" name="lastName" ng-model="user.last"
27493              ng-minlength="3" ng-maxlength="10">
27494           </label>
27495           <div role="alert">
27496             <span class="error" ng-show="myForm.lastName.$error.minlength">
27497               Too short!</span>
27498             <span class="error" ng-show="myForm.lastName.$error.maxlength">
27499               Too long!</span>
27500           </div>
27501         </form>
27502         <hr>
27503         <tt>user = {{user}}</tt><br/>
27504         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
27505         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
27506         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
27507         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
27508         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27509         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27510         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
27511         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
27512       </div>
27513      </file>
27514      <file name="protractor.js" type="protractor">
27515        var user = element(by.exactBinding('user'));
27516        var userNameValid = element(by.binding('myForm.userName.$valid'));
27517        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
27518        var lastNameError = element(by.binding('myForm.lastName.$error'));
27519        var formValid = element(by.binding('myForm.$valid'));
27520        var userNameInput = element(by.model('user.name'));
27521        var userLastInput = element(by.model('user.last'));
27522
27523        it('should initialize to model', function() {
27524          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
27525          expect(userNameValid.getText()).toContain('true');
27526          expect(formValid.getText()).toContain('true');
27527        });
27528
27529        it('should be invalid if empty when required', function() {
27530          userNameInput.clear();
27531          userNameInput.sendKeys('');
27532
27533          expect(user.getText()).toContain('{"last":"visitor"}');
27534          expect(userNameValid.getText()).toContain('false');
27535          expect(formValid.getText()).toContain('false');
27536        });
27537
27538        it('should be valid if empty when min length is set', function() {
27539          userLastInput.clear();
27540          userLastInput.sendKeys('');
27541
27542          expect(user.getText()).toContain('{"name":"guest","last":""}');
27543          expect(lastNameValid.getText()).toContain('true');
27544          expect(formValid.getText()).toContain('true');
27545        });
27546
27547        it('should be invalid if less than required min length', function() {
27548          userLastInput.clear();
27549          userLastInput.sendKeys('xx');
27550
27551          expect(user.getText()).toContain('{"name":"guest"}');
27552          expect(lastNameValid.getText()).toContain('false');
27553          expect(lastNameError.getText()).toContain('minlength');
27554          expect(formValid.getText()).toContain('false');
27555        });
27556
27557        it('should be invalid if longer than max length', function() {
27558          userLastInput.clear();
27559          userLastInput.sendKeys('some ridiculously long name');
27560
27561          expect(user.getText()).toContain('{"name":"guest"}');
27562          expect(lastNameValid.getText()).toContain('false');
27563          expect(lastNameError.getText()).toContain('maxlength');
27564          expect(formValid.getText()).toContain('false');
27565        });
27566      </file>
27567    </example>
27568 */
27569var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
27570    function($browser, $sniffer, $filter, $parse) {
27571  return {
27572    restrict: 'E',
27573    require: ['?ngModel'],
27574    link: {
27575      pre: function(scope, element, attr, ctrls) {
27576        if (ctrls[0]) {
27577          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
27578                                                              $browser, $filter, $parse);
27579        }
27580      }
27581    }
27582  };
27583}];
27584
27585
27586var hiddenInputBrowserCacheDirective = function() {
27587  var valueProperty = {
27588    configurable: true,
27589    enumerable: false,
27590    get: function() {
27591      return this.getAttribute('value') || '';
27592    },
27593    set: function(val) {
27594      this.setAttribute('value', val);
27595    }
27596  };
27597
27598  return {
27599    restrict: 'E',
27600    priority: 200,
27601    compile: function(_, attr) {
27602      if (lowercase(attr.type) !== 'hidden') {
27603        return;
27604      }
27605
27606      return {
27607        pre: function(scope, element, attr, ctrls) {
27608          var node = element[0];
27609
27610          // Support: Edge
27611          // Moving the DOM around prevents autofillling
27612          if (node.parentNode) {
27613            node.parentNode.insertBefore(node, node.nextSibling);
27614          }
27615
27616          // Support: FF, IE
27617          // Avoiding direct assignment to .value prevents autofillling
27618          if (Object.defineProperty) {
27619            Object.defineProperty(node, 'value', valueProperty);
27620          }
27621        }
27622      };
27623    }
27624  };
27625};
27626
27627
27628
27629var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
27630/**
27631 * @ngdoc directive
27632 * @name ngValue
27633 * @restrict A
27634 * @priority 100
27635 *
27636 * @description
27637 * Binds the given expression to the value of the element.
27638 *
27639 * It is mainly used on {@link input[radio] `input[radio]`} and option elements,
27640 * so that when the element is selected, the {@link ngModel `ngModel`} of that element (or its
27641 * {@link select `select`} parent element) is set to the bound value. It is especially useful
27642 * for dynamically generated lists using {@link ngRepeat `ngRepeat`}, as shown below.
27643 *
27644 * It can also be used to achieve one-way binding of a given expression to an input element
27645 * such as an `input[text]` or a `textarea`, when that element does not use ngModel.
27646 *
27647 * @element ANY
27648 * @param {string=} ngValue AngularJS expression, whose value will be bound to the `value` attribute
27649 * and `value` property of the element.
27650 *
27651 * @example
27652    <example name="ngValue-directive" module="valueExample">
27653      <file name="index.html">
27654       <script>
27655          angular.module('valueExample', [])
27656            .controller('ExampleController', ['$scope', function($scope) {
27657              $scope.names = ['pizza', 'unicorns', 'robots'];
27658              $scope.my = { favorite: 'unicorns' };
27659            }]);
27660       </script>
27661        <form ng-controller="ExampleController">
27662          <h2>Which is your favorite?</h2>
27663            <label ng-repeat="name in names" for="{{name}}">
27664              {{name}}
27665              <input type="radio"
27666                     ng-model="my.favorite"
27667                     ng-value="name"
27668                     id="{{name}}"
27669                     name="favorite">
27670            </label>
27671          <div>You chose {{my.favorite}}</div>
27672        </form>
27673      </file>
27674      <file name="protractor.js" type="protractor">
27675        var favorite = element(by.binding('my.favorite'));
27676
27677        it('should initialize to model', function() {
27678          expect(favorite.getText()).toContain('unicorns');
27679        });
27680        it('should bind the values to the inputs', function() {
27681          element.all(by.model('my.favorite')).get(0).click();
27682          expect(favorite.getText()).toContain('pizza');
27683        });
27684      </file>
27685    </example>
27686 */
27687var ngValueDirective = function() {
27688  /**
27689   *  inputs use the value attribute as their default value if the value property is not set.
27690   *  Once the value property has been set (by adding input), it will not react to changes to
27691   *  the value attribute anymore. Setting both attribute and property fixes this behavior, and
27692   *  makes it possible to use ngValue as a sort of one-way bind.
27693   */
27694  function updateElementValue(element, attr, value) {
27695    // Support: IE9 only
27696    // In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
27697    var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
27698    element.prop('value', propValue);
27699    attr.$set('value', value);
27700  }
27701
27702  return {
27703    restrict: 'A',
27704    priority: 100,
27705    compile: function(tpl, tplAttr) {
27706      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
27707        return function ngValueConstantLink(scope, elm, attr) {
27708          var value = scope.$eval(attr.ngValue);
27709          updateElementValue(elm, attr, value);
27710        };
27711      } else {
27712        return function ngValueLink(scope, elm, attr) {
27713          scope.$watch(attr.ngValue, function valueWatchAction(value) {
27714            updateElementValue(elm, attr, value);
27715          });
27716        };
27717      }
27718    }
27719  };
27720};
27721
27722/**
27723 * @ngdoc directive
27724 * @name ngBind
27725 * @restrict AC
27726 *
27727 * @description
27728 * The `ngBind` attribute tells AngularJS to replace the text content of the specified HTML element
27729 * with the value of a given expression, and to update the text content when the value of that
27730 * expression changes.
27731 *
27732 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
27733 * `{{ expression }}` which is similar but less verbose.
27734 *
27735 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
27736 * displayed by the browser in its raw state before AngularJS compiles it. Since `ngBind` is an
27737 * element attribute, it makes the bindings invisible to the user while the page is loading.
27738 *
27739 * An alternative solution to this problem would be using the
27740 * {@link ng.directive:ngCloak ngCloak} directive.
27741 *
27742 *
27743 * @element ANY
27744 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
27745 *
27746 * @example
27747 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
27748   <example module="bindExample" name="ng-bind">
27749     <file name="index.html">
27750       <script>
27751         angular.module('bindExample', [])
27752           .controller('ExampleController', ['$scope', function($scope) {
27753             $scope.name = 'Whirled';
27754           }]);
27755       </script>
27756       <div ng-controller="ExampleController">
27757         <label>Enter name: <input type="text" ng-model="name"></label><br>
27758         Hello <span ng-bind="name"></span>!
27759       </div>
27760     </file>
27761     <file name="protractor.js" type="protractor">
27762       it('should check ng-bind', function() {
27763         var nameInput = element(by.model('name'));
27764
27765         expect(element(by.binding('name')).getText()).toBe('Whirled');
27766         nameInput.clear();
27767         nameInput.sendKeys('world');
27768         expect(element(by.binding('name')).getText()).toBe('world');
27769       });
27770     </file>
27771   </example>
27772 */
27773var ngBindDirective = ['$compile', function($compile) {
27774  return {
27775    restrict: 'AC',
27776    compile: function ngBindCompile(templateElement) {
27777      $compile.$$addBindingClass(templateElement);
27778      return function ngBindLink(scope, element, attr) {
27779        $compile.$$addBindingInfo(element, attr.ngBind);
27780        element = element[0];
27781        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
27782          element.textContent = stringify(value);
27783        });
27784      };
27785    }
27786  };
27787}];
27788
27789
27790/**
27791 * @ngdoc directive
27792 * @name ngBindTemplate
27793 *
27794 * @description
27795 * The `ngBindTemplate` directive specifies that the element
27796 * text content should be replaced with the interpolation of the template
27797 * in the `ngBindTemplate` attribute.
27798 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
27799 * expressions. This directive is needed since some HTML elements
27800 * (such as TITLE and OPTION) cannot contain SPAN elements.
27801 *
27802 * @element ANY
27803 * @param {string} ngBindTemplate template of form
27804 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
27805 *
27806 * @example
27807 * Try it here: enter text in text box and watch the greeting change.
27808   <example module="bindExample" name="ng-bind-template">
27809     <file name="index.html">
27810       <script>
27811         angular.module('bindExample', [])
27812           .controller('ExampleController', ['$scope', function($scope) {
27813             $scope.salutation = 'Hello';
27814             $scope.name = 'World';
27815           }]);
27816       </script>
27817       <div ng-controller="ExampleController">
27818        <label>Salutation: <input type="text" ng-model="salutation"></label><br>
27819        <label>Name: <input type="text" ng-model="name"></label><br>
27820        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
27821       </div>
27822     </file>
27823     <file name="protractor.js" type="protractor">
27824       it('should check ng-bind', function() {
27825         var salutationElem = element(by.binding('salutation'));
27826         var salutationInput = element(by.model('salutation'));
27827         var nameInput = element(by.model('name'));
27828
27829         expect(salutationElem.getText()).toBe('Hello World!');
27830
27831         salutationInput.clear();
27832         salutationInput.sendKeys('Greetings');
27833         nameInput.clear();
27834         nameInput.sendKeys('user');
27835
27836         expect(salutationElem.getText()).toBe('Greetings user!');
27837       });
27838     </file>
27839   </example>
27840 */
27841var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
27842  return {
27843    compile: function ngBindTemplateCompile(templateElement) {
27844      $compile.$$addBindingClass(templateElement);
27845      return function ngBindTemplateLink(scope, element, attr) {
27846        var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
27847        $compile.$$addBindingInfo(element, interpolateFn.expressions);
27848        element = element[0];
27849        attr.$observe('ngBindTemplate', function(value) {
27850          element.textContent = isUndefined(value) ? '' : value;
27851        });
27852      };
27853    }
27854  };
27855}];
27856
27857
27858/**
27859 * @ngdoc directive
27860 * @name ngBindHtml
27861 *
27862 * @description
27863 * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
27864 * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
27865 * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
27866 * ngSanitize} in your module's dependencies (not in core AngularJS). In order to use {@link ngSanitize}
27867 * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
27868 *
27869 * You may also bypass sanitization for values you know are safe. To do so, bind to
27870 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
27871 * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
27872 *
27873 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
27874 * will have an exception (instead of an exploit.)
27875 *
27876 * @element ANY
27877 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
27878 *
27879 * @example
27880
27881   <example module="bindHtmlExample" deps="angular-sanitize.js" name="ng-bind-html">
27882     <file name="index.html">
27883       <div ng-controller="ExampleController">
27884        <p ng-bind-html="myHTML"></p>
27885       </div>
27886     </file>
27887
27888     <file name="script.js">
27889       angular.module('bindHtmlExample', ['ngSanitize'])
27890         .controller('ExampleController', ['$scope', function($scope) {
27891           $scope.myHTML =
27892              'I am an <code>HTML</code>string with ' +
27893              '<a href="#">links!</a> and other <em>stuff</em>';
27894         }]);
27895     </file>
27896
27897     <file name="protractor.js" type="protractor">
27898       it('should check ng-bind-html', function() {
27899         expect(element(by.binding('myHTML')).getText()).toBe(
27900             'I am an HTMLstring with links! and other stuff');
27901       });
27902     </file>
27903   </example>
27904 */
27905var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
27906  return {
27907    restrict: 'A',
27908    compile: function ngBindHtmlCompile(tElement, tAttrs) {
27909      var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
27910      var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function sceValueOf(val) {
27911        // Unwrap the value to compare the actual inner safe value, not the wrapper object.
27912        return $sce.valueOf(val);
27913      });
27914      $compile.$$addBindingClass(tElement);
27915
27916      return function ngBindHtmlLink(scope, element, attr) {
27917        $compile.$$addBindingInfo(element, attr.ngBindHtml);
27918
27919        scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
27920          // The watched value is the unwrapped value. To avoid re-escaping, use the direct getter.
27921          var value = ngBindHtmlGetter(scope);
27922          element.html($sce.getTrustedHtml(value) || '');
27923        });
27924      };
27925    }
27926  };
27927}];
27928
27929/**
27930 * @ngdoc directive
27931 * @name ngChange
27932 * @restrict A
27933 *
27934 * @description
27935 * Evaluate the given expression when the user changes the input.
27936 * The expression is evaluated immediately, unlike the JavaScript onchange event
27937 * which only triggers at the end of a change (usually, when the user leaves the
27938 * form element or presses the return key).
27939 *
27940 * The `ngChange` expression is only evaluated when a change in the input value causes
27941 * a new value to be committed to the model.
27942 *
27943 * It will not be evaluated:
27944 * * if the value returned from the `$parsers` transformation pipeline has not changed
27945 * * if the input has continued to be invalid since the model will stay `null`
27946 * * if the model is changed programmatically and not by a change to the input value
27947 *
27948 *
27949 * Note, this directive requires `ngModel` to be present.
27950 *
27951 * @element ANY
27952 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
27953 * in input value.
27954 *
27955 * @example
27956 * <example name="ngChange-directive" module="changeExample">
27957 *   <file name="index.html">
27958 *     <script>
27959 *       angular.module('changeExample', [])
27960 *         .controller('ExampleController', ['$scope', function($scope) {
27961 *           $scope.counter = 0;
27962 *           $scope.change = function() {
27963 *             $scope.counter++;
27964 *           };
27965 *         }]);
27966 *     </script>
27967 *     <div ng-controller="ExampleController">
27968 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
27969 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
27970 *       <label for="ng-change-example2">Confirmed</label><br />
27971 *       <tt>debug = {{confirmed}}</tt><br/>
27972 *       <tt>counter = {{counter}}</tt><br/>
27973 *     </div>
27974 *   </file>
27975 *   <file name="protractor.js" type="protractor">
27976 *     var counter = element(by.binding('counter'));
27977 *     var debug = element(by.binding('confirmed'));
27978 *
27979 *     it('should evaluate the expression if changing from view', function() {
27980 *       expect(counter.getText()).toContain('0');
27981 *
27982 *       element(by.id('ng-change-example1')).click();
27983 *
27984 *       expect(counter.getText()).toContain('1');
27985 *       expect(debug.getText()).toContain('true');
27986 *     });
27987 *
27988 *     it('should not evaluate the expression if changing from model', function() {
27989 *       element(by.id('ng-change-example2')).click();
27990
27991 *       expect(counter.getText()).toContain('0');
27992 *       expect(debug.getText()).toContain('true');
27993 *     });
27994 *   </file>
27995 * </example>
27996 */
27997var ngChangeDirective = valueFn({
27998  restrict: 'A',
27999  require: 'ngModel',
28000  link: function(scope, element, attr, ctrl) {
28001    ctrl.$viewChangeListeners.push(function() {
28002      scope.$eval(attr.ngChange);
28003    });
28004  }
28005});
28006
28007/* exported
28008  ngClassDirective,
28009  ngClassEvenDirective,
28010  ngClassOddDirective
28011*/
28012
28013function classDirective(name, selector) {
28014  name = 'ngClass' + name;
28015  var indexWatchExpression;
28016
28017  return ['$parse', function($parse) {
28018    return {
28019      restrict: 'AC',
28020      link: function(scope, element, attr) {
28021        var classCounts = element.data('$classCounts');
28022        var oldModulo = true;
28023        var oldClassString;
28024
28025        if (!classCounts) {
28026          // Use createMap() to prevent class assumptions involving property
28027          // names in Object.prototype
28028          classCounts = createMap();
28029          element.data('$classCounts', classCounts);
28030        }
28031
28032        if (name !== 'ngClass') {
28033          if (!indexWatchExpression) {
28034            indexWatchExpression = $parse('$index', function moduloTwo($index) {
28035              // eslint-disable-next-line no-bitwise
28036              return $index & 1;
28037            });
28038          }
28039
28040          scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
28041        }
28042
28043        scope.$watch($parse(attr[name], toClassString), ngClassWatchAction);
28044
28045        function addClasses(classString) {
28046          classString = digestClassCounts(split(classString), 1);
28047          attr.$addClass(classString);
28048        }
28049
28050        function removeClasses(classString) {
28051          classString = digestClassCounts(split(classString), -1);
28052          attr.$removeClass(classString);
28053        }
28054
28055        function updateClasses(oldClassString, newClassString) {
28056          var oldClassArray = split(oldClassString);
28057          var newClassArray = split(newClassString);
28058
28059          var toRemoveArray = arrayDifference(oldClassArray, newClassArray);
28060          var toAddArray = arrayDifference(newClassArray, oldClassArray);
28061
28062          var toRemoveString = digestClassCounts(toRemoveArray, -1);
28063          var toAddString = digestClassCounts(toAddArray, 1);
28064
28065          attr.$addClass(toAddString);
28066          attr.$removeClass(toRemoveString);
28067        }
28068
28069        function digestClassCounts(classArray, count) {
28070          var classesToUpdate = [];
28071
28072          forEach(classArray, function(className) {
28073            if (count > 0 || classCounts[className]) {
28074              classCounts[className] = (classCounts[className] || 0) + count;
28075              if (classCounts[className] === +(count > 0)) {
28076                classesToUpdate.push(className);
28077              }
28078            }
28079          });
28080
28081          return classesToUpdate.join(' ');
28082        }
28083
28084        function ngClassIndexWatchAction(newModulo) {
28085          // This watch-action should run before the `ngClassWatchAction()`, thus it
28086          // adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
28087          // `ngClassWatchAction()` will update the classes.
28088          if (newModulo === selector) {
28089            addClasses(oldClassString);
28090          } else {
28091            removeClasses(oldClassString);
28092          }
28093
28094          oldModulo = newModulo;
28095        }
28096
28097        function ngClassWatchAction(newClassString) {
28098          if (oldModulo === selector) {
28099            updateClasses(oldClassString, newClassString);
28100          }
28101
28102          oldClassString = newClassString;
28103        }
28104      }
28105    };
28106  }];
28107
28108  // Helpers
28109  function arrayDifference(tokens1, tokens2) {
28110    if (!tokens1 || !tokens1.length) return [];
28111    if (!tokens2 || !tokens2.length) return tokens1;
28112
28113    var values = [];
28114
28115    outer:
28116    for (var i = 0; i < tokens1.length; i++) {
28117      var token = tokens1[i];
28118      for (var j = 0; j < tokens2.length; j++) {
28119        if (token === tokens2[j]) continue outer;
28120      }
28121      values.push(token);
28122    }
28123
28124    return values;
28125  }
28126
28127  function split(classString) {
28128    return classString && classString.split(' ');
28129  }
28130
28131  function toClassString(classValue) {
28132    if (!classValue) return classValue;
28133
28134    var classString = classValue;
28135
28136    if (isArray(classValue)) {
28137      classString = classValue.map(toClassString).join(' ');
28138    } else if (isObject(classValue)) {
28139      classString = Object.keys(classValue).
28140        filter(function(key) { return classValue[key]; }).
28141        join(' ');
28142    } else if (!isString(classValue)) {
28143      classString = classValue + '';
28144    }
28145
28146    return classString;
28147  }
28148}
28149
28150/**
28151 * @ngdoc directive
28152 * @name ngClass
28153 * @restrict AC
28154 * @element ANY
28155 *
28156 * @description
28157 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
28158 * an expression that represents all classes to be added.
28159 *
28160 * The directive operates in three different ways, depending on which of three types the expression
28161 * evaluates to:
28162 *
28163 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
28164 * names.
28165 *
28166 * 2. If the expression evaluates to an object, then for each key-value pair of the
28167 * object with a truthy value the corresponding key is used as a class name.
28168 *
28169 * 3. If the expression evaluates to an array, each element of the array should either be a string as in
28170 * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
28171 * to give you more control over what CSS classes appear. See the code below for an example of this.
28172 *
28173 *
28174 * The directive won't add duplicate classes if a particular class was already set.
28175 *
28176 * When the expression changes, the previously added classes are removed and only then are the
28177 * new classes added.
28178 *
28179 * @knownIssue
28180 * You should not use {@link guide/interpolation interpolation} in the value of the `class`
28181 * attribute, when using the `ngClass` directive on the same element.
28182 * See {@link guide/interpolation#known-issues here} for more info.
28183 *
28184 * @animations
28185 * | Animation                        | Occurs                              |
28186 * |----------------------------------|-------------------------------------|
28187 * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
28188 * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
28189 * | {@link ng.$animate#setClass setClass} | just before classes are added and classes are removed from the element at the same time |
28190 *
28191 * ### ngClass and pre-existing CSS3 Transitions/Animations
28192   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
28193   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
28194   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
28195   to view the step by step details of {@link $animate#addClass $animate.addClass} and
28196   {@link $animate#removeClass $animate.removeClass}.
28197 *
28198 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
28199 *   of the evaluation can be a string representing space delimited class
28200 *   names, an array, or a map of class names to boolean values. In the case of a map, the
28201 *   names of the properties whose values are truthy will be added as css classes to the
28202 *   element.
28203 *
28204 * @example
28205 * ### Basic
28206   <example name="ng-class">
28207     <file name="index.html">
28208       <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
28209       <label>
28210          <input type="checkbox" ng-model="deleted">
28211          deleted (apply "strike" class)
28212       </label><br>
28213       <label>
28214          <input type="checkbox" ng-model="important">
28215          important (apply "bold" class)
28216       </label><br>
28217       <label>
28218          <input type="checkbox" ng-model="error">
28219          error (apply "has-error" class)
28220       </label>
28221       <hr>
28222       <p ng-class="style">Using String Syntax</p>
28223       <input type="text" ng-model="style"
28224              placeholder="Type: bold strike red" aria-label="Type: bold strike red">
28225       <hr>
28226       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
28227       <input ng-model="style1"
28228              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
28229       <input ng-model="style2"
28230              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
28231       <input ng-model="style3"
28232              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
28233       <hr>
28234       <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
28235       <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
28236       <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
28237     </file>
28238     <file name="style.css">
28239       .strike {
28240           text-decoration: line-through;
28241       }
28242       .bold {
28243           font-weight: bold;
28244       }
28245       .red {
28246           color: red;
28247       }
28248       .has-error {
28249           color: red;
28250           background-color: yellow;
28251       }
28252       .orange {
28253           color: orange;
28254       }
28255     </file>
28256     <file name="protractor.js" type="protractor">
28257       var ps = element.all(by.css('p'));
28258
28259       it('should let you toggle the class', function() {
28260
28261         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
28262         expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
28263
28264         element(by.model('important')).click();
28265         expect(ps.first().getAttribute('class')).toMatch(/bold/);
28266
28267         element(by.model('error')).click();
28268         expect(ps.first().getAttribute('class')).toMatch(/has-error/);
28269       });
28270
28271       it('should let you toggle string example', function() {
28272         expect(ps.get(1).getAttribute('class')).toBe('');
28273         element(by.model('style')).clear();
28274         element(by.model('style')).sendKeys('red');
28275         expect(ps.get(1).getAttribute('class')).toBe('red');
28276       });
28277
28278       it('array example should have 3 classes', function() {
28279         expect(ps.get(2).getAttribute('class')).toBe('');
28280         element(by.model('style1')).sendKeys('bold');
28281         element(by.model('style2')).sendKeys('strike');
28282         element(by.model('style3')).sendKeys('red');
28283         expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
28284       });
28285
28286       it('array with map example should have 2 classes', function() {
28287         expect(ps.last().getAttribute('class')).toBe('');
28288         element(by.model('style4')).sendKeys('bold');
28289         element(by.model('warning')).click();
28290         expect(ps.last().getAttribute('class')).toBe('bold orange');
28291       });
28292     </file>
28293   </example>
28294
28295   @example
28296   ### Animations
28297
28298   The example below demonstrates how to perform animations using ngClass.
28299
28300   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-class">
28301     <file name="index.html">
28302      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
28303      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
28304      <br>
28305      <span class="base-class" ng-class="myVar">Sample Text</span>
28306     </file>
28307     <file name="style.css">
28308       .base-class {
28309         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
28310       }
28311
28312       .base-class.my-class {
28313         color: red;
28314         font-size:3em;
28315       }
28316     </file>
28317     <file name="protractor.js" type="protractor">
28318       it('should check ng-class', function() {
28319         expect(element(by.css('.base-class')).getAttribute('class')).not.
28320           toMatch(/my-class/);
28321
28322         element(by.id('setbtn')).click();
28323
28324         expect(element(by.css('.base-class')).getAttribute('class')).
28325           toMatch(/my-class/);
28326
28327         element(by.id('clearbtn')).click();
28328
28329         expect(element(by.css('.base-class')).getAttribute('class')).not.
28330           toMatch(/my-class/);
28331       });
28332     </file>
28333   </example>
28334 */
28335var ngClassDirective = classDirective('', true);
28336
28337/**
28338 * @ngdoc directive
28339 * @name ngClassOdd
28340 * @restrict AC
28341 *
28342 * @description
28343 * The `ngClassOdd` and `ngClassEven` directives work exactly as
28344 * {@link ng.directive:ngClass ngClass}, except they work in
28345 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
28346 *
28347 * This directive can be applied only within the scope of an
28348 * {@link ng.directive:ngRepeat ngRepeat}.
28349 *
28350 * @animations
28351 * | Animation                        | Occurs                              |
28352 * |----------------------------------|-------------------------------------|
28353 * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
28354 * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
28355 *
28356 * @element ANY
28357 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
28358 *   of the evaluation can be a string representing space delimited class names or an array.
28359 *
28360 * @example
28361   <example name="ng-class-odd">
28362     <file name="index.html">
28363        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
28364          <li ng-repeat="name in names">
28365           <span ng-class-odd="'odd'" ng-class-even="'even'">
28366             {{name}}
28367           </span>
28368          </li>
28369        </ol>
28370     </file>
28371     <file name="style.css">
28372       .odd {
28373         color: red;
28374       }
28375       .even {
28376         color: blue;
28377       }
28378     </file>
28379     <file name="protractor.js" type="protractor">
28380       it('should check ng-class-odd and ng-class-even', function() {
28381         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
28382           toMatch(/odd/);
28383         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
28384           toMatch(/even/);
28385       });
28386     </file>
28387   </example>
28388 *
28389 * <hr />
28390 * @example
28391 * An example on how to implement animations using `ngClassOdd`:
28392 *
28393   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-class-odd-animate">
28394     <file name="index.html">
28395       <div ng-init="items=['Item 3', 'Item 2', 'Item 1', 'Item 0']">
28396         <button ng-click="items.unshift('Item ' + items.length)">Add item</button>
28397         <hr />
28398         <table>
28399           <tr ng-repeat="item in items" ng-class-odd="'odd'">
28400             <td>{{ item }}</td>
28401           </tr>
28402         </table>
28403       </div>
28404     </file>
28405     <file name="style.css">
28406       .odd {
28407         background: rgba(255, 255, 0, 0.25);
28408       }
28409
28410       .odd-add, .odd-remove {
28411         transition: 1.5s;
28412       }
28413     </file>
28414     <file name="protractor.js" type="protractor">
28415       it('should add new entries to the beginning of the list', function() {
28416         var button = element(by.buttonText('Add item'));
28417         var rows = element.all(by.repeater('item in items'));
28418
28419         expect(rows.count()).toBe(4);
28420         expect(rows.get(0).getText()).toBe('Item 3');
28421         expect(rows.get(1).getText()).toBe('Item 2');
28422
28423         button.click();
28424
28425         expect(rows.count()).toBe(5);
28426         expect(rows.get(0).getText()).toBe('Item 4');
28427         expect(rows.get(1).getText()).toBe('Item 3');
28428       });
28429
28430       it('should add odd class to odd entries', function() {
28431         var button = element(by.buttonText('Add item'));
28432         var rows = element.all(by.repeater('item in items'));
28433
28434         expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
28435         expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
28436
28437         button.click();
28438
28439         expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
28440         expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
28441       });
28442     </file>
28443   </example>
28444 */
28445var ngClassOddDirective = classDirective('Odd', 0);
28446
28447/**
28448 * @ngdoc directive
28449 * @name ngClassEven
28450 * @restrict AC
28451 *
28452 * @description
28453 * The `ngClassOdd` and `ngClassEven` directives work exactly as
28454 * {@link ng.directive:ngClass ngClass}, except they work in
28455 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
28456 *
28457 * This directive can be applied only within the scope of an
28458 * {@link ng.directive:ngRepeat ngRepeat}.
28459 *
28460 * @animations
28461 * | Animation                        | Occurs                              |
28462 * |----------------------------------|-------------------------------------|
28463 * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
28464 * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
28465 *
28466 * @element ANY
28467 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
28468 *   result of the evaluation can be a string representing space delimited class names or an array.
28469 *
28470 * @example
28471   <example name="ng-class-even">
28472     <file name="index.html">
28473        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
28474          <li ng-repeat="name in names">
28475           <span ng-class-odd="'odd'" ng-class-even="'even'">
28476             {{name}} &nbsp; &nbsp; &nbsp;
28477           </span>
28478          </li>
28479        </ol>
28480     </file>
28481     <file name="style.css">
28482       .odd {
28483         color: red;
28484       }
28485       .even {
28486         color: blue;
28487       }
28488     </file>
28489     <file name="protractor.js" type="protractor">
28490       it('should check ng-class-odd and ng-class-even', function() {
28491         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
28492           toMatch(/odd/);
28493         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
28494           toMatch(/even/);
28495       });
28496     </file>
28497   </example>
28498 *
28499 * <hr />
28500 * @example
28501 * An example on how to implement animations using `ngClassEven`:
28502 *
28503   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-class-even-animate">
28504     <file name="index.html">
28505       <div ng-init="items=['Item 3', 'Item 2', 'Item 1', 'Item 0']">
28506         <button ng-click="items.unshift('Item ' + items.length)">Add item</button>
28507         <hr />
28508         <table>
28509           <tr ng-repeat="item in items" ng-class-even="'even'">
28510             <td>{{ item }}</td>
28511           </tr>
28512         </table>
28513       </div>
28514     </file>
28515     <file name="style.css">
28516       .even {
28517         background: rgba(255, 255, 0, 0.25);
28518       }
28519
28520       .even-add, .even-remove {
28521         transition: 1.5s;
28522       }
28523     </file>
28524     <file name="protractor.js" type="protractor">
28525       it('should add new entries to the beginning of the list', function() {
28526         var button = element(by.buttonText('Add item'));
28527         var rows = element.all(by.repeater('item in items'));
28528
28529         expect(rows.count()).toBe(4);
28530         expect(rows.get(0).getText()).toBe('Item 3');
28531         expect(rows.get(1).getText()).toBe('Item 2');
28532
28533         button.click();
28534
28535         expect(rows.count()).toBe(5);
28536         expect(rows.get(0).getText()).toBe('Item 4');
28537         expect(rows.get(1).getText()).toBe('Item 3');
28538       });
28539
28540       it('should add even class to even entries', function() {
28541         var button = element(by.buttonText('Add item'));
28542         var rows = element.all(by.repeater('item in items'));
28543
28544         expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
28545         expect(rows.get(1).getAttribute('class')).toMatch(/even/);
28546
28547         button.click();
28548
28549         expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
28550         expect(rows.get(1).getAttribute('class')).toMatch(/even/);
28551       });
28552     </file>
28553   </example>
28554 */
28555var ngClassEvenDirective = classDirective('Even', 1);
28556
28557/**
28558 * @ngdoc directive
28559 * @name ngCloak
28560 * @restrict AC
28561 *
28562 * @description
28563 * The `ngCloak` directive is used to prevent the AngularJS html template from being briefly
28564 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
28565 * directive to avoid the undesirable flicker effect caused by the html template display.
28566 *
28567 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
28568 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
28569 * of the browser view.
28570 *
28571 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
28572 * `angular.min.js`.
28573 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
28574 *
28575 * ```css
28576 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
28577 *   display: none !important;
28578 * }
28579 * ```
28580 *
28581 * When this css rule is loaded by the browser, all html elements (including their children) that
28582 * are tagged with the `ngCloak` directive are hidden. When AngularJS encounters this directive
28583 * during the compilation of the template it deletes the `ngCloak` element attribute, making
28584 * the compiled element visible.
28585 *
28586 * For the best result, the `angular.js` script must be loaded in the head section of the html
28587 * document; alternatively, the css rule above must be included in the external stylesheet of the
28588 * application.
28589 *
28590 * @element ANY
28591 *
28592 * @example
28593   <example name="ng-cloak">
28594     <file name="index.html">
28595        <div id="template1" ng-cloak>{{ 'hello' }}</div>
28596        <div id="template2" class="ng-cloak">{{ 'world' }}</div>
28597     </file>
28598     <file name="protractor.js" type="protractor">
28599       it('should remove the template directive and css class', function() {
28600         expect($('#template1').getAttribute('ng-cloak')).
28601           toBeNull();
28602         expect($('#template2').getAttribute('ng-cloak')).
28603           toBeNull();
28604       });
28605     </file>
28606   </example>
28607 *
28608 */
28609var ngCloakDirective = ngDirective({
28610  compile: function(element, attr) {
28611    attr.$set('ngCloak', undefined);
28612    element.removeClass('ng-cloak');
28613  }
28614});
28615
28616/**
28617 * @ngdoc directive
28618 * @name ngController
28619 *
28620 * @description
28621 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
28622 * supports the principles behind the Model-View-Controller design pattern.
28623 *
28624 * MVC components in angular:
28625 *
28626 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
28627 *   are accessed through bindings.
28628 * * View — The template (HTML with data bindings) that is rendered into the View.
28629 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
28630 *   logic behind the application to decorate the scope with functions and values
28631 *
28632 * Note that you can also attach controllers to the DOM by declaring it in a route definition
28633 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
28634 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
28635 * and executed twice.
28636 *
28637 * @element ANY
28638 * @scope
28639 * @priority 500
28640 * @param {expression} ngController Name of a constructor function registered with the current
28641 * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
28642 * that on the current scope evaluates to a constructor function.
28643 *
28644 * The controller instance can be published into a scope property by specifying
28645 * `ng-controller="as propertyName"`.
28646 *
28647 * @example
28648 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
28649 * greeting are methods declared on the controller (see source tab). These methods can
28650 * easily be called from the AngularJS markup. Any changes to the data are automatically reflected
28651 * in the View without the need for a manual update.
28652 *
28653 * Two different declaration styles are included below:
28654 *
28655 * * one binds methods and properties directly onto the controller using `this`:
28656 * `ng-controller="SettingsController1 as settings"`
28657 * * one injects `$scope` into the controller:
28658 * `ng-controller="SettingsController2"`
28659 *
28660 * The second option is more common in the AngularJS community, and is generally used in boilerplates
28661 * and in this guide. However, there are advantages to binding properties directly to the controller
28662 * and avoiding scope.
28663 *
28664 * * Using `controller as` makes it obvious which controller you are accessing in the template when
28665 * multiple controllers apply to an element.
28666 * * If you are writing your controllers as classes you have easier access to the properties and
28667 * methods, which will appear on the scope, from inside the controller code.
28668 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
28669 * inheritance masking primitives.
28670 *
28671 * This example demonstrates the `controller as` syntax.
28672 *
28673 * <example name="ngControllerAs" module="controllerAsExample">
28674 *   <file name="index.html">
28675 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
28676 *      <label>Name: <input type="text" ng-model="settings.name"/></label>
28677 *      <button ng-click="settings.greet()">greet</button><br/>
28678 *      Contact:
28679 *      <ul>
28680 *        <li ng-repeat="contact in settings.contacts">
28681 *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
28682 *             <option>phone</option>
28683 *             <option>email</option>
28684 *          </select>
28685 *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
28686 *          <button ng-click="settings.clearContact(contact)">clear</button>
28687 *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
28688 *        </li>
28689 *        <li><button ng-click="settings.addContact()">add</button></li>
28690 *     </ul>
28691 *    </div>
28692 *   </file>
28693 *   <file name="app.js">
28694 *    angular.module('controllerAsExample', [])
28695 *      .controller('SettingsController1', SettingsController1);
28696 *
28697 *    function SettingsController1() {
28698 *      this.name = 'John Smith';
28699 *      this.contacts = [
28700 *        {type: 'phone', value: '408 555 1212'},
28701 *        {type: 'email', value: '[email protected]'}
28702 *      ];
28703 *    }
28704 *
28705 *    SettingsController1.prototype.greet = function() {
28706 *      alert(this.name);
28707 *    };
28708 *
28709 *    SettingsController1.prototype.addContact = function() {
28710 *      this.contacts.push({type: 'email', value: '[email protected]'});
28711 *    };
28712 *
28713 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
28714 *     var index = this.contacts.indexOf(contactToRemove);
28715 *      this.contacts.splice(index, 1);
28716 *    };
28717 *
28718 *    SettingsController1.prototype.clearContact = function(contact) {
28719 *      contact.type = 'phone';
28720 *      contact.value = '';
28721 *    };
28722 *   </file>
28723 *   <file name="protractor.js" type="protractor">
28724 *     it('should check controller as', function() {
28725 *       var container = element(by.id('ctrl-as-exmpl'));
28726 *         expect(container.element(by.model('settings.name'))
28727 *           .getAttribute('value')).toBe('John Smith');
28728 *
28729 *       var firstRepeat =
28730 *           container.element(by.repeater('contact in settings.contacts').row(0));
28731 *       var secondRepeat =
28732 *           container.element(by.repeater('contact in settings.contacts').row(1));
28733 *
28734 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28735 *           .toBe('408 555 1212');
28736 *
28737 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
28738 *           .toBe('[email protected]');
28739 *
28740 *       firstRepeat.element(by.buttonText('clear')).click();
28741 *
28742 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28743 *           .toBe('');
28744 *
28745 *       container.element(by.buttonText('add')).click();
28746 *
28747 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
28748 *           .element(by.model('contact.value'))
28749 *           .getAttribute('value'))
28750 *           .toBe('[email protected]');
28751 *     });
28752 *   </file>
28753 * </example>
28754 *
28755 * This example demonstrates the "attach to `$scope`" style of controller.
28756 *
28757 * <example name="ngController" module="controllerExample">
28758 *  <file name="index.html">
28759 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
28760 *     <label>Name: <input type="text" ng-model="name"/></label>
28761 *     <button ng-click="greet()">greet</button><br/>
28762 *     Contact:
28763 *     <ul>
28764 *       <li ng-repeat="contact in contacts">
28765 *         <select ng-model="contact.type" id="select_{{$index}}">
28766 *            <option>phone</option>
28767 *            <option>email</option>
28768 *         </select>
28769 *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
28770 *         <button ng-click="clearContact(contact)">clear</button>
28771 *         <button ng-click="removeContact(contact)">X</button>
28772 *       </li>
28773 *       <li>[ <button ng-click="addContact()">add</button> ]</li>
28774 *    </ul>
28775 *   </div>
28776 *  </file>
28777 *  <file name="app.js">
28778 *   angular.module('controllerExample', [])
28779 *     .controller('SettingsController2', ['$scope', SettingsController2]);
28780 *
28781 *   function SettingsController2($scope) {
28782 *     $scope.name = 'John Smith';
28783 *     $scope.contacts = [
28784 *       {type:'phone', value:'408 555 1212'},
28785 *       {type:'email', value:'[email protected]'}
28786 *     ];
28787 *
28788 *     $scope.greet = function() {
28789 *       alert($scope.name);
28790 *     };
28791 *
28792 *     $scope.addContact = function() {
28793 *       $scope.contacts.push({type:'email', value:'[email protected]'});
28794 *     };
28795 *
28796 *     $scope.removeContact = function(contactToRemove) {
28797 *       var index = $scope.contacts.indexOf(contactToRemove);
28798 *       $scope.contacts.splice(index, 1);
28799 *     };
28800 *
28801 *     $scope.clearContact = function(contact) {
28802 *       contact.type = 'phone';
28803 *       contact.value = '';
28804 *     };
28805 *   }
28806 *  </file>
28807 *  <file name="protractor.js" type="protractor">
28808 *    it('should check controller', function() {
28809 *      var container = element(by.id('ctrl-exmpl'));
28810 *
28811 *      expect(container.element(by.model('name'))
28812 *          .getAttribute('value')).toBe('John Smith');
28813 *
28814 *      var firstRepeat =
28815 *          container.element(by.repeater('contact in contacts').row(0));
28816 *      var secondRepeat =
28817 *          container.element(by.repeater('contact in contacts').row(1));
28818 *
28819 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28820 *          .toBe('408 555 1212');
28821 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
28822 *          .toBe('[email protected]');
28823 *
28824 *      firstRepeat.element(by.buttonText('clear')).click();
28825 *
28826 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28827 *          .toBe('');
28828 *
28829 *      container.element(by.buttonText('add')).click();
28830 *
28831 *      expect(container.element(by.repeater('contact in contacts').row(2))
28832 *          .element(by.model('contact.value'))
28833 *          .getAttribute('value'))
28834 *          .toBe('[email protected]');
28835 *    });
28836 *  </file>
28837 *</example>
28838
28839 */
28840var ngControllerDirective = [function() {
28841  return {
28842    restrict: 'A',
28843    scope: true,
28844    controller: '@',
28845    priority: 500
28846  };
28847}];
28848
28849/**
28850 * @ngdoc directive
28851 * @name ngCsp
28852 *
28853 * @restrict A
28854 * @element ANY
28855 * @description
28856 *
28857 * AngularJS has some features that can conflict with certain restrictions that are applied when using
28858 * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
28859 *
28860 * If you intend to implement CSP with these rules then you must tell AngularJS not to use these
28861 * features.
28862 *
28863 * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
28864 *
28865 *
28866 * The following default rules in CSP affect AngularJS:
28867 *
28868 * * The use of `eval()`, `Function(string)` and similar functions to dynamically create and execute
28869 * code from strings is forbidden. AngularJS makes use of this in the {@link $parse} service to
28870 * provide a 30% increase in the speed of evaluating AngularJS expressions. (This CSP rule can be
28871 * disabled with the CSP keyword `unsafe-eval`, but it is generally not recommended as it would
28872 * weaken the protections offered by CSP.)
28873 *
28874 * * The use of inline resources, such as inline `<script>` and `<style>` elements, are forbidden.
28875 * This prevents apps from injecting custom styles directly into the document. AngularJS makes use of
28876 * this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}). To make these
28877 * directives work when a CSP rule is blocking inline styles, you must link to the `angular-csp.css`
28878 * in your HTML manually. (This CSP rule can be disabled with the CSP keyword `unsafe-inline`, but
28879 * it is generally not recommended as it would weaken the protections offered by CSP.)
28880 *
28881 * If you do not provide `ngCsp` then AngularJS tries to autodetect if CSP is blocking dynamic code
28882 * creation from strings (e.g., `unsafe-eval` not specified in CSP header) and automatically
28883 * deactivates this feature in the {@link $parse} service. This autodetection, however, triggers a
28884 * CSP error to be logged in the console:
28885 *
28886 * ```
28887 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
28888 * script in the following Content Security Policy directive: "default-src 'self'". Note that
28889 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
28890 * ```
28891 *
28892 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
28893 * directive on an element of the HTML document that appears before the `<script>` tag that loads
28894 * the `angular.js` file.
28895 *
28896 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
28897 *
28898 * You can specify which of the CSP related AngularJS features should be deactivated by providing
28899 * a value for the `ng-csp` attribute. The options are as follows:
28900 *
28901 * * no-inline-style: this stops AngularJS from injecting CSS styles into the DOM
28902 *
28903 * * no-unsafe-eval: this stops AngularJS from optimizing $parse with unsafe eval of strings
28904 *
28905 * You can use these values in the following combinations:
28906 *
28907 *
28908 * * No declaration means that AngularJS will assume that you can do inline styles, but it will do
28909 * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous
28910 * versions of AngularJS.
28911 *
28912 * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell AngularJS to deactivate both inline
28913 * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous
28914 * versions of AngularJS.
28915 *
28916 * * Specifying only `no-unsafe-eval` tells AngularJS that we must not use eval, but that we can
28917 * inject inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
28918 *
28919 * * Specifying only `no-inline-style` tells AngularJS that we must not inject styles, but that we can
28920 * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
28921 *
28922 * * Specifying both `no-unsafe-eval` and `no-inline-style` tells AngularJS that we must not inject
28923 * styles nor use eval, which is the same as an empty: ng-csp.
28924 * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
28925 *
28926 * @example
28927 *
28928 * This example shows how to apply the `ngCsp` directive to the `html` tag.
28929   ```html
28930     <!doctype html>
28931     <html ng-app ng-csp>
28932     ...
28933     ...
28934     </html>
28935   ```
28936
28937  <!-- Note: the `.csp` suffix in the example name triggers CSP mode in our http server! -->
28938  <example name="example.csp" module="cspExample" ng-csp="true">
28939    <file name="index.html">
28940      <div ng-controller="MainController as ctrl">
28941        <div>
28942          <button ng-click="ctrl.inc()" id="inc">Increment</button>
28943          <span id="counter">
28944            {{ctrl.counter}}
28945          </span>
28946        </div>
28947
28948        <div>
28949          <button ng-click="ctrl.evil()" id="evil">Evil</button>
28950          <span id="evilError">
28951            {{ctrl.evilError}}
28952          </span>
28953        </div>
28954      </div>
28955    </file>
28956    <file name="script.js">
28957       angular.module('cspExample', [])
28958         .controller('MainController', function MainController() {
28959            this.counter = 0;
28960            this.inc = function() {
28961              this.counter++;
28962            };
28963            this.evil = function() {
28964              try {
28965                eval('1+2'); // eslint-disable-line no-eval
28966              } catch (e) {
28967                this.evilError = e.message;
28968              }
28969            };
28970          });
28971    </file>
28972    <file name="protractor.js" type="protractor">
28973      var util, webdriver;
28974
28975      var incBtn = element(by.id('inc'));
28976      var counter = element(by.id('counter'));
28977      var evilBtn = element(by.id('evil'));
28978      var evilError = element(by.id('evilError'));
28979
28980      function getAndClearSevereErrors() {
28981        return browser.manage().logs().get('browser').then(function(browserLog) {
28982          return browserLog.filter(function(logEntry) {
28983            return logEntry.level.value > webdriver.logging.Level.WARNING.value;
28984          });
28985        });
28986      }
28987
28988      function clearErrors() {
28989        getAndClearSevereErrors();
28990      }
28991
28992      function expectNoErrors() {
28993        getAndClearSevereErrors().then(function(filteredLog) {
28994          expect(filteredLog.length).toEqual(0);
28995          if (filteredLog.length) {
28996            console.log('browser console errors: ' + util.inspect(filteredLog));
28997          }
28998        });
28999      }
29000
29001      function expectError(regex) {
29002        getAndClearSevereErrors().then(function(filteredLog) {
29003          var found = false;
29004          filteredLog.forEach(function(log) {
29005            if (log.message.match(regex)) {
29006              found = true;
29007            }
29008          });
29009          if (!found) {
29010            throw new Error('expected an error that matches ' + regex);
29011          }
29012        });
29013      }
29014
29015      beforeEach(function() {
29016        util = require('util');
29017        webdriver = require('selenium-webdriver');
29018      });
29019
29020      // For now, we only test on Chrome,
29021      // as Safari does not load the page with Protractor's injected scripts,
29022      // and Firefox webdriver always disables content security policy (#6358)
29023      if (browser.params.browser !== 'chrome') {
29024        return;
29025      }
29026
29027      it('should not report errors when the page is loaded', function() {
29028        // clear errors so we are not dependent on previous tests
29029        clearErrors();
29030        // Need to reload the page as the page is already loaded when
29031        // we come here
29032        browser.driver.getCurrentUrl().then(function(url) {
29033          browser.get(url);
29034        });
29035        expectNoErrors();
29036      });
29037
29038      it('should evaluate expressions', function() {
29039        expect(counter.getText()).toEqual('0');
29040        incBtn.click();
29041        expect(counter.getText()).toEqual('1');
29042        expectNoErrors();
29043      });
29044
29045      it('should throw and report an error when using "eval"', function() {
29046        evilBtn.click();
29047        expect(evilError.getText()).toMatch(/Content Security Policy/);
29048        expectError(/Content Security Policy/);
29049      });
29050    </file>
29051  </example>
29052  */
29053
29054// `ngCsp` is not implemented as a proper directive any more, because we need it be processed while
29055// we bootstrap the app (before `$parse` is instantiated). For this reason, we just have the `csp()`
29056// fn that looks for the `ng-csp` attribute anywhere in the current doc.
29057
29058/**
29059 * @ngdoc directive
29060 * @name ngClick
29061 * @restrict A
29062 * @element ANY
29063 * @priority 0
29064 *
29065 * @description
29066 * The ngClick directive allows you to specify custom behavior when
29067 * an element is clicked.
29068 *
29069 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
29070 * click. ({@link guide/expression#-event- Event object is available as `$event`})
29071 *
29072 * @example
29073   <example name="ng-click">
29074     <file name="index.html">
29075      <button ng-click="count = count + 1" ng-init="count=0">
29076        Increment
29077      </button>
29078      <span>
29079        count: {{count}}
29080      </span>
29081     </file>
29082     <file name="protractor.js" type="protractor">
29083       it('should check ng-click', function() {
29084         expect(element(by.binding('count')).getText()).toMatch('0');
29085         element(by.css('button')).click();
29086         expect(element(by.binding('count')).getText()).toMatch('1');
29087       });
29088     </file>
29089   </example>
29090 */
29091/*
29092 * A collection of directives that allows creation of custom event handlers that are defined as
29093 * AngularJS expressions and are compiled and executed within the current scope.
29094 */
29095var ngEventDirectives = {};
29096
29097// For events that might fire synchronously during DOM manipulation
29098// we need to execute their event handlers asynchronously using $evalAsync,
29099// so that they are not executed in an inconsistent state.
29100var forceAsyncEvents = {
29101  'blur': true,
29102  'focus': true
29103};
29104forEach(
29105  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
29106  function(eventName) {
29107    var directiveName = directiveNormalize('ng-' + eventName);
29108    ngEventDirectives[directiveName] = ['$parse', '$rootScope', '$exceptionHandler', function($parse, $rootScope, $exceptionHandler) {
29109      return createEventDirective($parse, $rootScope, $exceptionHandler, directiveName, eventName, forceAsyncEvents[eventName]);
29110    }];
29111  }
29112);
29113
29114function createEventDirective($parse, $rootScope, $exceptionHandler, directiveName, eventName, forceAsync) {
29115  return {
29116    restrict: 'A',
29117    compile: function($element, attr) {
29118      // NOTE:
29119      // We expose the powerful `$event` object on the scope that provides access to the Window,
29120      // etc. This is OK, because expressions are not sandboxed any more (and the expression
29121      // sandbox was never meant to be a security feature anyway).
29122      var fn = $parse(attr[directiveName]);
29123      return function ngEventHandler(scope, element) {
29124        element.on(eventName, function(event) {
29125          var callback = function() {
29126            fn(scope, {$event: event});
29127          };
29128
29129          if (!$rootScope.$$phase) {
29130            scope.$apply(callback);
29131          } else if (forceAsync) {
29132            scope.$evalAsync(callback);
29133          } else {
29134            try {
29135              callback();
29136            } catch (error) {
29137              $exceptionHandler(error);
29138            }
29139          }
29140        });
29141      };
29142    }
29143  };
29144}
29145
29146/**
29147 * @ngdoc directive
29148 * @name ngDblclick
29149 * @restrict A
29150 * @element ANY
29151 * @priority 0
29152 *
29153 * @description
29154 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
29155 *
29156 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
29157 * a dblclick. (The Event object is available as `$event`)
29158 *
29159 * @example
29160   <example name="ng-dblclick">
29161     <file name="index.html">
29162      <button ng-dblclick="count = count + 1" ng-init="count=0">
29163        Increment (on double click)
29164      </button>
29165      count: {{count}}
29166     </file>
29167   </example>
29168 */
29169
29170
29171/**
29172 * @ngdoc directive
29173 * @name ngMousedown
29174 * @restrict A
29175 * @element ANY
29176 * @priority 0
29177 *
29178 * @description
29179 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
29180 *
29181 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
29182 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
29183 *
29184 * @example
29185   <example name="ng-mousedown">
29186     <file name="index.html">
29187      <button ng-mousedown="count = count + 1" ng-init="count=0">
29188        Increment (on mouse down)
29189      </button>
29190      count: {{count}}
29191     </file>
29192   </example>
29193 */
29194
29195
29196/**
29197 * @ngdoc directive
29198 * @name ngMouseup
29199 * @restrict A
29200 * @element ANY
29201 * @priority 0
29202 *
29203 * @description
29204 * Specify custom behavior on mouseup event.
29205 *
29206 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
29207 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
29208 *
29209 * @example
29210   <example name="ng-mouseup">
29211     <file name="index.html">
29212      <button ng-mouseup="count = count + 1" ng-init="count=0">
29213        Increment (on mouse up)
29214      </button>
29215      count: {{count}}
29216     </file>
29217   </example>
29218 */
29219
29220/**
29221 * @ngdoc directive
29222 * @name ngMouseover
29223 * @restrict A
29224 * @element ANY
29225 * @priority 0
29226 *
29227 * @description
29228 * Specify custom behavior on mouseover event.
29229 *
29230 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
29231 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
29232 *
29233 * @example
29234   <example name="ng-mouseover">
29235     <file name="index.html">
29236      <button ng-mouseover="count = count + 1" ng-init="count=0">
29237        Increment (when mouse is over)
29238      </button>
29239      count: {{count}}
29240     </file>
29241   </example>
29242 */
29243
29244
29245/**
29246 * @ngdoc directive
29247 * @name ngMouseenter
29248 * @restrict A
29249 * @element ANY
29250 * @priority 0
29251 *
29252 * @description
29253 * Specify custom behavior on mouseenter event.
29254 *
29255 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
29256 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
29257 *
29258 * @example
29259   <example name="ng-mouseenter">
29260     <file name="index.html">
29261      <button ng-mouseenter="count = count + 1" ng-init="count=0">
29262        Increment (when mouse enters)
29263      </button>
29264      count: {{count}}
29265     </file>
29266   </example>
29267 */
29268
29269
29270/**
29271 * @ngdoc directive
29272 * @name ngMouseleave
29273 * @restrict A
29274 * @element ANY
29275 * @priority 0
29276 *
29277 * @description
29278 * Specify custom behavior on mouseleave event.
29279 *
29280 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
29281 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
29282 *
29283 * @example
29284   <example name="ng-mouseleave">
29285     <file name="index.html">
29286      <button ng-mouseleave="count = count + 1" ng-init="count=0">
29287        Increment (when mouse leaves)
29288      </button>
29289      count: {{count}}
29290     </file>
29291   </example>
29292 */
29293
29294
29295/**
29296 * @ngdoc directive
29297 * @name ngMousemove
29298 * @restrict A
29299 * @element ANY
29300 * @priority 0
29301 *
29302 * @description
29303 * Specify custom behavior on mousemove event.
29304 *
29305 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
29306 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
29307 *
29308 * @example
29309   <example name="ng-mousemove">
29310     <file name="index.html">
29311      <button ng-mousemove="count = count + 1" ng-init="count=0">
29312        Increment (when mouse moves)
29313      </button>
29314      count: {{count}}
29315     </file>
29316   </example>
29317 */
29318
29319
29320/**
29321 * @ngdoc directive
29322 * @name ngKeydown
29323 * @restrict A
29324 * @element ANY
29325 * @priority 0
29326 *
29327 * @description
29328 * Specify custom behavior on keydown event.
29329 *
29330 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
29331 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
29332 *
29333 * @example
29334   <example name="ng-keydown">
29335     <file name="index.html">
29336      <input ng-keydown="count = count + 1" ng-init="count=0">
29337      key down count: {{count}}
29338     </file>
29339   </example>
29340 */
29341
29342
29343/**
29344 * @ngdoc directive
29345 * @name ngKeyup
29346 * @restrict A
29347 * @element ANY
29348 * @priority 0
29349 *
29350 * @description
29351 * Specify custom behavior on keyup event.
29352 *
29353 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
29354 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
29355 *
29356 * @example
29357   <example name="ng-keyup">
29358     <file name="index.html">
29359       <p>Typing in the input box below updates the key count</p>
29360       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
29361
29362       <p>Typing in the input box below updates the keycode</p>
29363       <input ng-keyup="event=$event">
29364       <p>event keyCode: {{ event.keyCode }}</p>
29365       <p>event altKey: {{ event.altKey }}</p>
29366     </file>
29367   </example>
29368 */
29369
29370
29371/**
29372 * @ngdoc directive
29373 * @name ngKeypress
29374 * @restrict A
29375 * @element ANY
29376 *
29377 * @description
29378 * Specify custom behavior on keypress event.
29379 *
29380 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
29381 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
29382 * and can be interrogated for keyCode, altKey, etc.)
29383 *
29384 * @example
29385   <example name="ng-keypress">
29386     <file name="index.html">
29387      <input ng-keypress="count = count + 1" ng-init="count=0">
29388      key press count: {{count}}
29389     </file>
29390   </example>
29391 */
29392
29393
29394/**
29395 * @ngdoc directive
29396 * @name ngSubmit
29397 * @restrict A
29398 * @element form
29399 * @priority 0
29400 *
29401 * @description
29402 * Enables binding AngularJS expressions to onsubmit events.
29403 *
29404 * Additionally it prevents the default action (which for form means sending the request to the
29405 * server and reloading the current page), but only if the form does not contain `action`,
29406 * `data-action`, or `x-action` attributes.
29407 *
29408 * <div class="alert alert-warning">
29409 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
29410 * `ngSubmit` handlers together. See the
29411 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
29412 * for a detailed discussion of when `ngSubmit` may be triggered.
29413 * </div>
29414 *
29415 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
29416 * ({@link guide/expression#-event- Event object is available as `$event`})
29417 *
29418 * @example
29419   <example module="submitExample" name="ng-submit">
29420     <file name="index.html">
29421      <script>
29422        angular.module('submitExample', [])
29423          .controller('ExampleController', ['$scope', function($scope) {
29424            $scope.list = [];
29425            $scope.text = 'hello';
29426            $scope.submit = function() {
29427              if ($scope.text) {
29428                $scope.list.push(this.text);
29429                $scope.text = '';
29430              }
29431            };
29432          }]);
29433      </script>
29434      <form ng-submit="submit()" ng-controller="ExampleController">
29435        Enter text and hit enter:
29436        <input type="text" ng-model="text" name="text" />
29437        <input type="submit" id="submit" value="Submit" />
29438        <pre>list={{list}}</pre>
29439      </form>
29440     </file>
29441     <file name="protractor.js" type="protractor">
29442       it('should check ng-submit', function() {
29443         expect(element(by.binding('list')).getText()).toBe('list=[]');
29444         element(by.css('#submit')).click();
29445         expect(element(by.binding('list')).getText()).toContain('hello');
29446         expect(element(by.model('text')).getAttribute('value')).toBe('');
29447       });
29448       it('should ignore empty strings', function() {
29449         expect(element(by.binding('list')).getText()).toBe('list=[]');
29450         element(by.css('#submit')).click();
29451         element(by.css('#submit')).click();
29452         expect(element(by.binding('list')).getText()).toContain('hello');
29453        });
29454     </file>
29455   </example>
29456 */
29457
29458/**
29459 * @ngdoc directive
29460 * @name ngFocus
29461 * @restrict A
29462 * @element window, input, select, textarea, a
29463 * @priority 0
29464 *
29465 * @description
29466 * Specify custom behavior on focus event.
29467 *
29468 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
29469 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
29470 * during an `$apply` to ensure a consistent state.
29471 *
29472 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
29473 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
29474 *
29475 * @example
29476 * See {@link ng.directive:ngClick ngClick}
29477 */
29478
29479/**
29480 * @ngdoc directive
29481 * @name ngBlur
29482 * @restrict A
29483 * @element window, input, select, textarea, a
29484 * @priority 0
29485 *
29486 * @description
29487 * Specify custom behavior on blur event.
29488 *
29489 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
29490 * an element has lost focus.
29491 *
29492 * Note: As the `blur` event is executed synchronously also during DOM manipulations
29493 * (e.g. removing a focussed input),
29494 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
29495 * during an `$apply` to ensure a consistent state.
29496 *
29497 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
29498 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
29499 *
29500 * @example
29501 * See {@link ng.directive:ngClick ngClick}
29502 */
29503
29504/**
29505 * @ngdoc directive
29506 * @name ngCopy
29507 * @restrict A
29508 * @element window, input, select, textarea, a
29509 * @priority 0
29510 *
29511 * @description
29512 * Specify custom behavior on copy event.
29513 *
29514 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
29515 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
29516 *
29517 * @example
29518   <example name="ng-copy">
29519     <file name="index.html">
29520      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
29521      copied: {{copied}}
29522     </file>
29523   </example>
29524 */
29525
29526/**
29527 * @ngdoc directive
29528 * @name ngCut
29529 * @restrict A
29530 * @element window, input, select, textarea, a
29531 * @priority 0
29532 *
29533 * @description
29534 * Specify custom behavior on cut event.
29535 *
29536 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
29537 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
29538 *
29539 * @example
29540   <example name="ng-cut">
29541     <file name="index.html">
29542      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
29543      cut: {{cut}}
29544     </file>
29545   </example>
29546 */
29547
29548/**
29549 * @ngdoc directive
29550 * @name ngPaste
29551 * @restrict A
29552 * @element window, input, select, textarea, a
29553 * @priority 0
29554 *
29555 * @description
29556 * Specify custom behavior on paste event.
29557 *
29558 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
29559 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
29560 *
29561 * @example
29562   <example name="ng-paste">
29563     <file name="index.html">
29564      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
29565      pasted: {{paste}}
29566     </file>
29567   </example>
29568 */
29569
29570/**
29571 * @ngdoc directive
29572 * @name ngIf
29573 * @restrict A
29574 * @multiElement
29575 *
29576 * @description
29577 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
29578 * {expression}. If the expression assigned to `ngIf` evaluates to a false
29579 * value then the element is removed from the DOM, otherwise a clone of the
29580 * element is reinserted into the DOM.
29581 *
29582 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
29583 * element in the DOM rather than changing its visibility via the `display` css property.  A common
29584 * case when this difference is significant is when using css selectors that rely on an element's
29585 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
29586 *
29587 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
29588 * is created when the element is restored.  The scope created within `ngIf` inherits from
29589 * its parent scope using
29590 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
29591 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
29592 * a javascript primitive defined in the parent scope. In this case any modifications made to the
29593 * variable within the child scope will override (hide) the value in the parent scope.
29594 *
29595 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
29596 * is if an element's class attribute is directly modified after it's compiled, using something like
29597 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
29598 * the added class will be lost because the original compiled state is used to regenerate the element.
29599 *
29600 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
29601 * and `leave` effects.
29602 *
29603 * @animations
29604 * | Animation                        | Occurs                               |
29605 * |----------------------------------|-------------------------------------|
29606 * | {@link ng.$animate#enter enter}  | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
29607 * | {@link ng.$animate#leave leave}  | just before the `ngIf` contents are removed from the DOM |
29608 *
29609 * @element ANY
29610 * @scope
29611 * @priority 600
29612 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
29613 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
29614 *     element is added to the DOM tree.
29615 *
29616 * @example
29617  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-if">
29618    <file name="index.html">
29619      <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
29620      Show when checked:
29621      <span ng-if="checked" class="animate-if">
29622        This is removed when the checkbox is unchecked.
29623      </span>
29624    </file>
29625    <file name="animations.css">
29626      .animate-if {
29627        background:white;
29628        border:1px solid black;
29629        padding:10px;
29630      }
29631
29632      .animate-if.ng-enter, .animate-if.ng-leave {
29633        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
29634      }
29635
29636      .animate-if.ng-enter,
29637      .animate-if.ng-leave.ng-leave-active {
29638        opacity:0;
29639      }
29640
29641      .animate-if.ng-leave,
29642      .animate-if.ng-enter.ng-enter-active {
29643        opacity:1;
29644      }
29645    </file>
29646  </example>
29647 */
29648var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
29649  return {
29650    multiElement: true,
29651    transclude: 'element',
29652    priority: 600,
29653    terminal: true,
29654    restrict: 'A',
29655    $$tlb: true,
29656    link: function($scope, $element, $attr, ctrl, $transclude) {
29657        var block, childScope, previousElements;
29658        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
29659
29660          if (value) {
29661            if (!childScope) {
29662              $transclude(function(clone, newScope) {
29663                childScope = newScope;
29664                clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
29665                // Note: We only need the first/last node of the cloned nodes.
29666                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
29667                // by a directive with templateUrl when its template arrives.
29668                block = {
29669                  clone: clone
29670                };
29671                $animate.enter(clone, $element.parent(), $element);
29672              });
29673            }
29674          } else {
29675            if (previousElements) {
29676              previousElements.remove();
29677              previousElements = null;
29678            }
29679            if (childScope) {
29680              childScope.$destroy();
29681              childScope = null;
29682            }
29683            if (block) {
29684              previousElements = getBlockNodes(block.clone);
29685              $animate.leave(previousElements).done(function(response) {
29686                if (response !== false) previousElements = null;
29687              });
29688              block = null;
29689            }
29690          }
29691        });
29692    }
29693  };
29694}];
29695
29696/**
29697 * @ngdoc directive
29698 * @name ngInclude
29699 * @restrict ECA
29700 * @scope
29701 * @priority -400
29702 *
29703 * @description
29704 * Fetches, compiles and includes an external HTML fragment.
29705 *
29706 * By default, the template URL is restricted to the same domain and protocol as the
29707 * application document. This is done by calling {@link $sce#getTrustedResourceUrl
29708 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
29709 * you may either add them to your {@link ng.$sceDelegateProvider#trustedResourceUrlList trusted
29710 * resource URL list} or {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to
29711 * AngularJS's {@link ng.$sce Strict Contextual Escaping}.
29712 *
29713 * In addition, the browser's
29714 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
29715 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
29716 * policy may further restrict whether the template is successfully loaded.
29717 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
29718 * access on some browsers.
29719 *
29720 * @animations
29721 * | Animation                        | Occurs                              |
29722 * |----------------------------------|-------------------------------------|
29723 * | {@link ng.$animate#enter enter}  | when the expression changes, on the new include |
29724 * | {@link ng.$animate#leave leave}  | when the expression changes, on the old include |
29725 *
29726 * The enter and leave animation occur concurrently.
29727 *
29728 * @param {string} ngInclude|src AngularJS expression evaluating to URL. If the source is a string constant,
29729 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
29730 * @param {string=} onload Expression to evaluate when a new partial is loaded.
29731 *                  <div class="alert alert-warning">
29732 *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
29733 *                  a function with the name on the window element, which will usually throw a
29734 *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
29735 *                  different form that {@link guide/directive#normalization matches} `onload`.
29736 *                  </div>
29737   *
29738 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
29739 *                  $anchorScroll} to scroll the viewport after the content is loaded.
29740 *
29741 *                  - If the attribute is not set, disable scrolling.
29742 *                  - If the attribute is set without value, enable scrolling.
29743 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
29744 *
29745 * @example
29746  <example module="includeExample" deps="angular-animate.js" animations="true" name="ng-include">
29747    <file name="index.html">
29748     <div ng-controller="ExampleController">
29749       <select ng-model="template" ng-options="t.name for t in templates">
29750        <option value="">(blank)</option>
29751       </select>
29752       url of the template: <code>{{template.url}}</code>
29753       <hr/>
29754       <div class="slide-animate-container">
29755         <div class="slide-animate" ng-include="template.url"></div>
29756       </div>
29757     </div>
29758    </file>
29759    <file name="script.js">
29760      angular.module('includeExample', ['ngAnimate'])
29761        .controller('ExampleController', ['$scope', function($scope) {
29762          $scope.templates =
29763            [{ name: 'template1.html', url: 'template1.html'},
29764             { name: 'template2.html', url: 'template2.html'}];
29765          $scope.template = $scope.templates[0];
29766        }]);
29767     </file>
29768    <file name="template1.html">
29769      Content of template1.html
29770    </file>
29771    <file name="template2.html">
29772      Content of template2.html
29773    </file>
29774    <file name="animations.css">
29775      .slide-animate-container {
29776        position:relative;
29777        background:white;
29778        border:1px solid black;
29779        height:40px;
29780        overflow:hidden;
29781      }
29782
29783      .slide-animate {
29784        padding:10px;
29785      }
29786
29787      .slide-animate.ng-enter, .slide-animate.ng-leave {
29788        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
29789
29790        position:absolute;
29791        top:0;
29792        left:0;
29793        right:0;
29794        bottom:0;
29795        display:block;
29796        padding:10px;
29797      }
29798
29799      .slide-animate.ng-enter {
29800        top:-50px;
29801      }
29802      .slide-animate.ng-enter.ng-enter-active {
29803        top:0;
29804      }
29805
29806      .slide-animate.ng-leave {
29807        top:0;
29808      }
29809      .slide-animate.ng-leave.ng-leave-active {
29810        top:50px;
29811      }
29812    </file>
29813    <file name="protractor.js" type="protractor">
29814      var templateSelect = element(by.model('template'));
29815      var includeElem = element(by.css('[ng-include]'));
29816
29817      it('should load template1.html', function() {
29818        expect(includeElem.getText()).toMatch(/Content of template1.html/);
29819      });
29820
29821      it('should load template2.html', function() {
29822        if (browser.params.browser === 'firefox') {
29823          // Firefox can't handle using selects
29824          // See https://github.com/angular/protractor/issues/480
29825          return;
29826        }
29827        templateSelect.click();
29828        templateSelect.all(by.css('option')).get(2).click();
29829        expect(includeElem.getText()).toMatch(/Content of template2.html/);
29830      });
29831
29832      it('should change to blank', function() {
29833        if (browser.params.browser === 'firefox') {
29834          // Firefox can't handle using selects
29835          return;
29836        }
29837        templateSelect.click();
29838        templateSelect.all(by.css('option')).get(0).click();
29839        expect(includeElem.isPresent()).toBe(false);
29840      });
29841    </file>
29842  </example>
29843 */
29844
29845
29846/**
29847 * @ngdoc event
29848 * @name ngInclude#$includeContentRequested
29849 * @eventType emit on the scope ngInclude was declared in
29850 * @description
29851 * Emitted every time the ngInclude content is requested.
29852 *
29853 * @param {Object} angularEvent Synthetic event object.
29854 * @param {String} src URL of content to load.
29855 */
29856
29857
29858/**
29859 * @ngdoc event
29860 * @name ngInclude#$includeContentLoaded
29861 * @eventType emit on the current ngInclude scope
29862 * @description
29863 * Emitted every time the ngInclude content is reloaded.
29864 *
29865 * @param {Object} angularEvent Synthetic event object.
29866 * @param {String} src URL of content to load.
29867 */
29868
29869
29870/**
29871 * @ngdoc event
29872 * @name ngInclude#$includeContentError
29873 * @eventType emit on the scope ngInclude was declared in
29874 * @description
29875 * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
29876 *
29877 * @param {Object} angularEvent Synthetic event object.
29878 * @param {String} src URL of content to load.
29879 */
29880var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
29881                  function($templateRequest,   $anchorScroll,   $animate) {
29882  return {
29883    restrict: 'ECA',
29884    priority: 400,
29885    terminal: true,
29886    transclude: 'element',
29887    controller: angular.noop,
29888    compile: function(element, attr) {
29889      var srcExp = attr.ngInclude || attr.src,
29890          onloadExp = attr.onload || '',
29891          autoScrollExp = attr.autoscroll;
29892
29893      return function(scope, $element, $attr, ctrl, $transclude) {
29894        var changeCounter = 0,
29895            currentScope,
29896            previousElement,
29897            currentElement;
29898
29899        var cleanupLastIncludeContent = function() {
29900          if (previousElement) {
29901            previousElement.remove();
29902            previousElement = null;
29903          }
29904          if (currentScope) {
29905            currentScope.$destroy();
29906            currentScope = null;
29907          }
29908          if (currentElement) {
29909            $animate.leave(currentElement).done(function(response) {
29910              if (response !== false) previousElement = null;
29911            });
29912            previousElement = currentElement;
29913            currentElement = null;
29914          }
29915        };
29916
29917        scope.$watch(srcExp, function ngIncludeWatchAction(src) {
29918          var afterAnimation = function(response) {
29919            if (response !== false && isDefined(autoScrollExp) &&
29920              (!autoScrollExp || scope.$eval(autoScrollExp))) {
29921                $anchorScroll();
29922            }
29923          };
29924          var thisChangeId = ++changeCounter;
29925
29926          if (src) {
29927            //set the 2nd param to true to ignore the template request error so that the inner
29928            //contents and scope can be cleaned up.
29929            $templateRequest(src, true).then(function(response) {
29930              if (scope.$$destroyed) return;
29931
29932              if (thisChangeId !== changeCounter) return;
29933              var newScope = scope.$new();
29934              ctrl.template = response;
29935
29936              // Note: This will also link all children of ng-include that were contained in the original
29937              // html. If that content contains controllers, ... they could pollute/change the scope.
29938              // However, using ng-include on an element with additional content does not make sense...
29939              // Note: We can't remove them in the cloneAttchFn of $transclude as that
29940              // function is called before linking the content, which would apply child
29941              // directives to non existing elements.
29942              var clone = $transclude(newScope, function(clone) {
29943                cleanupLastIncludeContent();
29944                $animate.enter(clone, null, $element).done(afterAnimation);
29945              });
29946
29947              currentScope = newScope;
29948              currentElement = clone;
29949
29950              currentScope.$emit('$includeContentLoaded', src);
29951              scope.$eval(onloadExp);
29952            }, function() {
29953              if (scope.$$destroyed) return;
29954
29955              if (thisChangeId === changeCounter) {
29956                cleanupLastIncludeContent();
29957                scope.$emit('$includeContentError', src);
29958              }
29959            });
29960            scope.$emit('$includeContentRequested', src);
29961          } else {
29962            cleanupLastIncludeContent();
29963            ctrl.template = null;
29964          }
29965        });
29966      };
29967    }
29968  };
29969}];
29970
29971// This directive is called during the $transclude call of the first `ngInclude` directive.
29972// It will replace and compile the content of the element with the loaded template.
29973// We need this directive so that the element content is already filled when
29974// the link function of another directive on the same element as ngInclude
29975// is called.
29976var ngIncludeFillContentDirective = ['$compile',
29977  function($compile) {
29978    return {
29979      restrict: 'ECA',
29980      priority: -400,
29981      require: 'ngInclude',
29982      link: function(scope, $element, $attr, ctrl) {
29983        if (toString.call($element[0]).match(/SVG/)) {
29984          // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
29985          // support innerHTML, so detect this here and try to generate the contents
29986          // specially.
29987          $element.empty();
29988          $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
29989              function namespaceAdaptedClone(clone) {
29990            $element.append(clone);
29991          }, {futureParentElement: $element});
29992          return;
29993        }
29994
29995        $element.html(ctrl.template);
29996        $compile($element.contents())(scope);
29997      }
29998    };
29999  }];
30000
30001/**
30002 * @ngdoc directive
30003 * @name ngInit
30004 * @restrict AC
30005 * @priority 450
30006 * @element ANY
30007 *
30008 * @param {expression} ngInit {@link guide/expression Expression} to eval.
30009 *
30010 * @description
30011 * The `ngInit` directive allows you to evaluate an expression in the
30012 * current scope.
30013 *
30014 * <div class="alert alert-danger">
30015 * This directive can be abused to add unnecessary amounts of logic into your templates.
30016 * There are only a few appropriate uses of `ngInit`:
30017 * <ul>
30018 *   <li>aliasing special properties of {@link ng.directive:ngRepeat `ngRepeat`},
30019 *     as seen in the demo below.</li>
30020 *   <li>initializing data during development, or for examples, as seen throughout these docs.</li>
30021 *   <li>injecting data via server side scripting.</li>
30022 * </ul>
30023 *
30024 * Besides these few cases, you should use {@link guide/component Components} or
30025 * {@link guide/controller Controllers} rather than `ngInit` to initialize values on a scope.
30026 * </div>
30027 *
30028 * <div class="alert alert-warning">
30029 * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
30030 * sure you have parentheses to ensure correct operator precedence:
30031 * <pre class="prettyprint">
30032 * `<div ng-init="test1 = ($index | toString)"></div>`
30033 * </pre>
30034 * </div>
30035 *
30036 * @example
30037   <example module="initExample" name="ng-init">
30038     <file name="index.html">
30039   <script>
30040     angular.module('initExample', [])
30041       .controller('ExampleController', ['$scope', function($scope) {
30042         $scope.list = [['a', 'b'], ['c', 'd']];
30043       }]);
30044   </script>
30045   <div ng-controller="ExampleController">
30046     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
30047       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
30048          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
30049       </div>
30050     </div>
30051   </div>
30052     </file>
30053     <file name="protractor.js" type="protractor">
30054       it('should alias index positions', function() {
30055         var elements = element.all(by.css('.example-init'));
30056         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
30057         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
30058         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
30059         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
30060       });
30061     </file>
30062   </example>
30063 */
30064var ngInitDirective = ngDirective({
30065  priority: 450,
30066  compile: function() {
30067    return {
30068      pre: function(scope, element, attrs) {
30069        scope.$eval(attrs.ngInit);
30070      }
30071    };
30072  }
30073});
30074
30075/**
30076 * @ngdoc directive
30077 * @name ngList
30078 * @restrict A
30079 * @priority 100
30080 *
30081 * @param {string=} ngList optional delimiter that should be used to split the value.
30082 *
30083 * @description
30084 * Text input that converts between a delimited string and an array of strings. The default
30085 * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
30086 * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
30087 *
30088 * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
30089 * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
30090 *   list item is respected. This implies that the user of the directive is responsible for
30091 *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
30092 *   tab or newline character.
30093 * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
30094 *   when joining the list items back together) and whitespace around each list item is stripped
30095 *   before it is added to the model.
30096 *
30097 * @example
30098 * ### Validation
30099 *
30100 * <example name="ngList-directive" module="listExample">
30101 *   <file name="app.js">
30102 *      angular.module('listExample', [])
30103 *        .controller('ExampleController', ['$scope', function($scope) {
30104 *          $scope.names = ['morpheus', 'neo', 'trinity'];
30105 *        }]);
30106 *   </file>
30107 *   <file name="index.html">
30108 *    <form name="myForm" ng-controller="ExampleController">
30109 *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
30110 *      <span role="alert">
30111 *        <span class="error" ng-show="myForm.namesInput.$error.required">
30112 *        Required!</span>
30113 *      </span>
30114 *      <br>
30115 *      <tt>names = {{names}}</tt><br/>
30116 *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
30117 *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
30118 *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30119 *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30120 *     </form>
30121 *   </file>
30122 *   <file name="protractor.js" type="protractor">
30123 *     var listInput = element(by.model('names'));
30124 *     var names = element(by.exactBinding('names'));
30125 *     var valid = element(by.binding('myForm.namesInput.$valid'));
30126 *     var error = element(by.css('span.error'));
30127 *
30128 *     it('should initialize to model', function() {
30129 *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
30130 *       expect(valid.getText()).toContain('true');
30131 *       expect(error.getCssValue('display')).toBe('none');
30132 *     });
30133 *
30134 *     it('should be invalid if empty', function() {
30135 *       listInput.clear();
30136 *       listInput.sendKeys('');
30137 *
30138 *       expect(names.getText()).toContain('');
30139 *       expect(valid.getText()).toContain('false');
30140 *       expect(error.getCssValue('display')).not.toBe('none');
30141 *     });
30142 *   </file>
30143 * </example>
30144 *
30145 * @example
30146 * ### Splitting on newline
30147 *
30148 * <example name="ngList-directive-newlines">
30149 *   <file name="index.html">
30150 *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
30151 *    <pre>{{ list | json }}</pre>
30152 *   </file>
30153 *   <file name="protractor.js" type="protractor">
30154 *     it("should split the text by newlines", function() {
30155 *       var listInput = element(by.model('list'));
30156 *       var output = element(by.binding('list | json'));
30157 *       listInput.sendKeys('abc\ndef\nghi');
30158 *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
30159 *     });
30160 *   </file>
30161 * </example>
30162 *
30163 */
30164var ngListDirective = function() {
30165  return {
30166    restrict: 'A',
30167    priority: 100,
30168    require: 'ngModel',
30169    link: function(scope, element, attr, ctrl) {
30170      var ngList = attr.ngList || ', ';
30171      var trimValues = attr.ngTrim !== 'false';
30172      var separator = trimValues ? trim(ngList) : ngList;
30173
30174      var parse = function(viewValue) {
30175        // If the viewValue is invalid (say required but empty) it will be `undefined`
30176        if (isUndefined(viewValue)) return;
30177
30178        var list = [];
30179
30180        if (viewValue) {
30181          forEach(viewValue.split(separator), function(value) {
30182            if (value) list.push(trimValues ? trim(value) : value);
30183          });
30184        }
30185
30186        return list;
30187      };
30188
30189      ctrl.$parsers.push(parse);
30190      ctrl.$formatters.push(function(value) {
30191        if (isArray(value)) {
30192          return value.join(ngList);
30193        }
30194
30195        return undefined;
30196      });
30197
30198      // Override the standard $isEmpty because an empty array means the input is empty.
30199      ctrl.$isEmpty = function(value) {
30200        return !value || !value.length;
30201      };
30202    }
30203  };
30204};
30205
30206/* global VALID_CLASS: true,
30207  INVALID_CLASS: true,
30208  PRISTINE_CLASS: true,
30209  DIRTY_CLASS: true,
30210  UNTOUCHED_CLASS: true,
30211  TOUCHED_CLASS: true,
30212  PENDING_CLASS: true,
30213  addSetValidityMethod: true,
30214  setupValidity: true,
30215  defaultModelOptions: false
30216*/
30217
30218
30219var VALID_CLASS = 'ng-valid',
30220    INVALID_CLASS = 'ng-invalid',
30221    PRISTINE_CLASS = 'ng-pristine',
30222    DIRTY_CLASS = 'ng-dirty',
30223    UNTOUCHED_CLASS = 'ng-untouched',
30224    TOUCHED_CLASS = 'ng-touched',
30225    EMPTY_CLASS = 'ng-empty',
30226    NOT_EMPTY_CLASS = 'ng-not-empty';
30227
30228var ngModelMinErr = minErr('ngModel');
30229
30230/**
30231 * @ngdoc type
30232 * @name ngModel.NgModelController
30233 * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
30234 * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
30235 * is set.
30236 *
30237 * @property {*} $modelValue The value in the model that the control is bound to.
30238 *
30239 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
30240 *  the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue
30241    `$viewValue`} from the DOM, usually via user input.
30242    See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation.
30243    Note that the `$parsers` are not called when the bound ngModel expression changes programmatically.
30244
30245  The functions are called in array order, each passing
30246    its return value through to the next. The last return value is forwarded to the
30247    {@link ngModel.NgModelController#$validators `$validators`} collection.
30248
30249  Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
30250    `$viewValue`}.
30251
30252  Returning `undefined` from a parser means a parse error occurred. In that case,
30253    no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
30254    will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
30255    is set to `true`. The parse error is stored in `ngModel.$error.parse`.
30256
30257  This simple example shows a parser that would convert text input value to lowercase:
30258 * ```js
30259 * function parse(value) {
30260 *   if (value) {
30261 *     return value.toLowerCase();
30262 *   }
30263 * }
30264 * ngModelController.$parsers.push(parse);
30265 * ```
30266
30267 *
30268 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
30269    the bound ngModel expression changes programmatically. The `$formatters` are not called when the
30270    value of the control is changed by user interaction.
30271
30272  Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue
30273    `$modelValue`} for display in the control.
30274
30275  The functions are called in reverse array order, each passing the value through to the
30276    next. The last return value is used as the actual DOM value.
30277
30278  This simple example shows a formatter that would convert the model value to uppercase:
30279
30280 * ```js
30281 * function format(value) {
30282 *   if (value) {
30283 *     return value.toUpperCase();
30284 *   }
30285 * }
30286 * ngModel.$formatters.push(format);
30287 * ```
30288 *
30289 * @property {Object.<string, function>} $validators A collection of validators that are applied
30290 *      whenever the model value changes. The key value within the object refers to the name of the
30291 *      validator while the function refers to the validation operation. The validation operation is
30292 *      provided with the model value as an argument and must return a true or false value depending
30293 *      on the response of that validation.
30294 *
30295 * ```js
30296 * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
30297 *   var value = modelValue || viewValue;
30298 *   return /[0-9]+/.test(value) &&
30299 *          /[a-z]+/.test(value) &&
30300 *          /[A-Z]+/.test(value) &&
30301 *          /\W+/.test(value);
30302 * };
30303 * ```
30304 *
30305 * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
30306 *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
30307 *      is expected to return a promise when it is run during the model validation process. Once the promise
30308 *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
30309 *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
30310 *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
30311 *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
30312 *      will only run once all synchronous validators have passed.
30313 *
30314 * Please note that if $http is used then it is important that the server returns a success HTTP response code
30315 * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
30316 *
30317 * ```js
30318 * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
30319 *   var value = modelValue || viewValue;
30320 *
30321 *   // Lookup user by username
30322 *   return $http.get('/api/users/' + value).
30323 *      then(function resolved() {
30324 *        //username exists, this means validation fails
30325 *        return $q.reject('exists');
30326 *      }, function rejected() {
30327 *        //username does not exist, therefore this validation passes
30328 *        return true;
30329 *      });
30330 * };
30331 * ```
30332 *
30333 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever
30334 *     a change to {@link ngModel.NgModelController#$viewValue `$viewValue`} has caused a change
30335 *     to {@link ngModel.NgModelController#$modelValue `$modelValue`}.
30336 *     It is called with no arguments, and its return value is ignored.
30337 *     This can be used in place of additional $watches against the model value.
30338 *
30339 * @property {Object} $error An object hash with all failing validator ids as keys.
30340 * @property {Object} $pending An object hash with all pending validator ids as keys.
30341 *
30342 * @property {boolean} $untouched True if control has not lost focus yet.
30343 * @property {boolean} $touched True if control has lost focus.
30344 * @property {boolean} $pristine True if user has not interacted with the control yet.
30345 * @property {boolean} $dirty True if user has already interacted with the control.
30346 * @property {boolean} $valid True if there is no error.
30347 * @property {boolean} $invalid True if at least one error on the control.
30348 * @property {string} $name The name attribute of the control.
30349 *
30350 * @description
30351 *
30352 * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
30353 * The controller contains services for data-binding, validation, CSS updates, and value formatting
30354 * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
30355 * listening to DOM events.
30356 * Such DOM related logic should be provided by other directives which make use of
30357 * `NgModelController` for data-binding to control elements.
30358 * AngularJS provides this DOM logic for most {@link input `input`} elements.
30359 * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
30360 * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
30361 *
30362 * @example
30363 * ### Custom Control Example
30364 * This example shows how to use `NgModelController` with a custom control to achieve
30365 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
30366 * collaborate together to achieve the desired result.
30367 *
30368 * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
30369 * contents be edited in place by the user.
30370 *
30371 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
30372 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
30373 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
30374 * that content using the `$sce` service.
30375 *
30376 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
30377    <file name="style.css">
30378      [contenteditable] {
30379        border: 1px solid black;
30380        background-color: white;
30381        min-height: 20px;
30382      }
30383
30384      .ng-invalid {
30385        border: 1px solid red;
30386      }
30387
30388    </file>
30389    <file name="script.js">
30390      angular.module('customControl', ['ngSanitize']).
30391        directive('contenteditable', ['$sce', function($sce) {
30392          return {
30393            restrict: 'A', // only activate on element attribute
30394            require: '?ngModel', // get a hold of NgModelController
30395            link: function(scope, element, attrs, ngModel) {
30396              if (!ngModel) return; // do nothing if no ng-model
30397
30398              // Specify how UI should be updated
30399              ngModel.$render = function() {
30400                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
30401              };
30402
30403              // Listen for change events to enable binding
30404              element.on('blur keyup change', function() {
30405                scope.$evalAsync(read);
30406              });
30407              read(); // initialize
30408
30409              // Write data to the model
30410              function read() {
30411                var html = element.html();
30412                // When we clear the content editable the browser leaves a <br> behind
30413                // If strip-br attribute is provided then we strip this out
30414                if (attrs.stripBr && html === '<br>') {
30415                  html = '';
30416                }
30417                ngModel.$setViewValue(html);
30418              }
30419            }
30420          };
30421        }]);
30422    </file>
30423    <file name="index.html">
30424      <form name="myForm">
30425       <div contenteditable
30426            name="myWidget" ng-model="userContent"
30427            strip-br="true"
30428            required>Change me!</div>
30429        <span ng-show="myForm.myWidget.$error.required">Required!</span>
30430       <hr>
30431       <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
30432      </form>
30433    </file>
30434    <file name="protractor.js" type="protractor">
30435    it('should data-bind and become invalid', function() {
30436      if (browser.params.browser === 'safari' || browser.params.browser === 'firefox') {
30437        // SafariDriver can't handle contenteditable
30438        // and Firefox driver can't clear contenteditables very well
30439        return;
30440      }
30441      var contentEditable = element(by.css('[contenteditable]'));
30442      var content = 'Change me!';
30443
30444      expect(contentEditable.getText()).toEqual(content);
30445
30446      contentEditable.clear();
30447      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
30448      expect(contentEditable.getText()).toEqual('');
30449      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
30450    });
30451    </file>
30452 * </example>
30453 *
30454 *
30455 */
30456NgModelController.$inject = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$q', '$interpolate'];
30457function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $q, $interpolate) {
30458  this.$viewValue = Number.NaN;
30459  this.$modelValue = Number.NaN;
30460  this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
30461  this.$validators = {};
30462  this.$asyncValidators = {};
30463  this.$parsers = [];
30464  this.$formatters = [];
30465  this.$viewChangeListeners = [];
30466  this.$untouched = true;
30467  this.$touched = false;
30468  this.$pristine = true;
30469  this.$dirty = false;
30470  this.$valid = true;
30471  this.$invalid = false;
30472  this.$error = {}; // keep invalid keys here
30473  this.$$success = {}; // keep valid keys here
30474  this.$pending = undefined; // keep pending keys here
30475  this.$name = $interpolate($attr.name || '', false)($scope);
30476  this.$$parentForm = nullFormCtrl;
30477  this.$options = defaultModelOptions;
30478  this.$$updateEvents = '';
30479  // Attach the correct context to the event handler function for updateOn
30480  this.$$updateEventHandler = this.$$updateEventHandler.bind(this);
30481
30482  this.$$parsedNgModel = $parse($attr.ngModel);
30483  this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
30484  this.$$ngModelGet = this.$$parsedNgModel;
30485  this.$$ngModelSet = this.$$parsedNgModelAssign;
30486  this.$$pendingDebounce = null;
30487  this.$$parserValid = undefined;
30488  this.$$parserName = 'parse';
30489
30490  this.$$currentValidationRunId = 0;
30491
30492  this.$$scope = $scope;
30493  this.$$rootScope = $scope.$root;
30494  this.$$attr = $attr;
30495  this.$$element = $element;
30496  this.$$animate = $animate;
30497  this.$$timeout = $timeout;
30498  this.$$parse = $parse;
30499  this.$$q = $q;
30500  this.$$exceptionHandler = $exceptionHandler;
30501
30502  setupValidity(this);
30503  setupModelWatcher(this);
30504}
30505
30506NgModelController.prototype = {
30507  $$initGetterSetters: function() {
30508    if (this.$options.getOption('getterSetter')) {
30509      var invokeModelGetter = this.$$parse(this.$$attr.ngModel + '()'),
30510          invokeModelSetter = this.$$parse(this.$$attr.ngModel + '($$$p)');
30511
30512      this.$$ngModelGet = function($scope) {
30513        var modelValue = this.$$parsedNgModel($scope);
30514        if (isFunction(modelValue)) {
30515          modelValue = invokeModelGetter($scope);
30516        }
30517        return modelValue;
30518      };
30519      this.$$ngModelSet = function($scope, newValue) {
30520        if (isFunction(this.$$parsedNgModel($scope))) {
30521          invokeModelSetter($scope, {$$$p: newValue});
30522        } else {
30523          this.$$parsedNgModelAssign($scope, newValue);
30524        }
30525      };
30526    } else if (!this.$$parsedNgModel.assign) {
30527      throw ngModelMinErr('nonassign', 'Expression \'{0}\' is non-assignable. Element: {1}',
30528          this.$$attr.ngModel, startingTag(this.$$element));
30529    }
30530  },
30531
30532
30533  /**
30534   * @ngdoc method
30535   * @name ngModel.NgModelController#$render
30536   *
30537   * @description
30538   * Called when the view needs to be updated. It is expected that the user of the ng-model
30539   * directive will implement this method.
30540   *
30541   * The `$render()` method is invoked in the following situations:
30542   *
30543   * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
30544   *   committed value then `$render()` is called to update the input control.
30545   * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
30546   *   the `$viewValue` are different from last time.
30547   *
30548   * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
30549   * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
30550   * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
30551   * invoked if you only change a property on the objects.
30552   */
30553  $render: noop,
30554
30555  /**
30556   * @ngdoc method
30557   * @name ngModel.NgModelController#$isEmpty
30558   *
30559   * @description
30560   * This is called when we need to determine if the value of an input is empty.
30561   *
30562   * For instance, the required directive does this to work out if the input has data or not.
30563   *
30564   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
30565   *
30566   * You can override this for input directives whose concept of being empty is different from the
30567   * default. The `checkboxInputType` directive does this because in its case a value of `false`
30568   * implies empty.
30569   *
30570   * @param {*} value The value of the input to check for emptiness.
30571   * @returns {boolean} True if `value` is "empty".
30572   */
30573  $isEmpty: function(value) {
30574    // eslint-disable-next-line no-self-compare
30575    return isUndefined(value) || value === '' || value === null || value !== value;
30576  },
30577
30578  $$updateEmptyClasses: function(value) {
30579    if (this.$isEmpty(value)) {
30580      this.$$animate.removeClass(this.$$element, NOT_EMPTY_CLASS);
30581      this.$$animate.addClass(this.$$element, EMPTY_CLASS);
30582    } else {
30583      this.$$animate.removeClass(this.$$element, EMPTY_CLASS);
30584      this.$$animate.addClass(this.$$element, NOT_EMPTY_CLASS);
30585    }
30586  },
30587
30588  /**
30589   * @ngdoc method
30590   * @name ngModel.NgModelController#$setPristine
30591   *
30592   * @description
30593   * Sets the control to its pristine state.
30594   *
30595   * This method can be called to remove the `ng-dirty` class and set the control to its pristine
30596   * state (`ng-pristine` class). A model is considered to be pristine when the control
30597   * has not been changed from when first compiled.
30598   */
30599  $setPristine: function() {
30600    this.$dirty = false;
30601    this.$pristine = true;
30602    this.$$animate.removeClass(this.$$element, DIRTY_CLASS);
30603    this.$$animate.addClass(this.$$element, PRISTINE_CLASS);
30604  },
30605
30606  /**
30607   * @ngdoc method
30608   * @name ngModel.NgModelController#$setDirty
30609   *
30610   * @description
30611   * Sets the control to its dirty state.
30612   *
30613   * This method can be called to remove the `ng-pristine` class and set the control to its dirty
30614   * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
30615   * from when first compiled.
30616   */
30617  $setDirty: function() {
30618    this.$dirty = true;
30619    this.$pristine = false;
30620    this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
30621    this.$$animate.addClass(this.$$element, DIRTY_CLASS);
30622    this.$$parentForm.$setDirty();
30623  },
30624
30625  /**
30626   * @ngdoc method
30627   * @name ngModel.NgModelController#$setUntouched
30628   *
30629   * @description
30630   * Sets the control to its untouched state.
30631   *
30632   * This method can be called to remove the `ng-touched` class and set the control to its
30633   * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
30634   * by default, however this function can be used to restore that state if the model has
30635   * already been touched by the user.
30636   */
30637  $setUntouched: function() {
30638    this.$touched = false;
30639    this.$untouched = true;
30640    this.$$animate.setClass(this.$$element, UNTOUCHED_CLASS, TOUCHED_CLASS);
30641  },
30642
30643  /**
30644   * @ngdoc method
30645   * @name ngModel.NgModelController#$setTouched
30646   *
30647   * @description
30648   * Sets the control to its touched state.
30649   *
30650   * This method can be called to remove the `ng-untouched` class and set the control to its
30651   * touched state (`ng-touched` class). A model is considered to be touched when the user has
30652   * first focused the control element and then shifted focus away from the control (blur event).
30653   */
30654  $setTouched: function() {
30655    this.$touched = true;
30656    this.$untouched = false;
30657    this.$$animate.setClass(this.$$element, TOUCHED_CLASS, UNTOUCHED_CLASS);
30658  },
30659
30660  /**
30661   * @ngdoc method
30662   * @name ngModel.NgModelController#$rollbackViewValue
30663   *
30664   * @description
30665   * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
30666   * which may be caused by a pending debounced event or because the input is waiting for some
30667   * future event.
30668   *
30669   * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
30670   * depend on special events such as `blur`, there can be a period when the `$viewValue` is out of
30671   * sync with the ngModel's `$modelValue`.
30672   *
30673   * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
30674   * and reset the input to the last committed view value.
30675   *
30676   * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
30677   * programmatically before these debounced/future events have resolved/occurred, because AngularJS's
30678   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
30679   *
30680   * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
30681   * input which may have such events pending. This is important in order to make sure that the
30682   * input field will be updated with the new model value and any pending operations are cancelled.
30683   *
30684   * @example
30685   * <example name="ng-model-cancel-update" module="cancel-update-example">
30686   *   <file name="app.js">
30687   *     angular.module('cancel-update-example', [])
30688   *
30689   *     .controller('CancelUpdateController', ['$scope', function($scope) {
30690   *       $scope.model = {value1: '', value2: ''};
30691   *
30692   *       $scope.setEmpty = function(e, value, rollback) {
30693   *         if (e.keyCode === 27) {
30694   *           e.preventDefault();
30695   *           if (rollback) {
30696   *             $scope.myForm[value].$rollbackViewValue();
30697   *           }
30698   *           $scope.model[value] = '';
30699   *         }
30700   *       };
30701   *     }]);
30702   *   </file>
30703   *   <file name="index.html">
30704   *     <div ng-controller="CancelUpdateController">
30705   *       <p>Both of these inputs are only updated if they are blurred. Hitting escape should
30706   *       empty them. Follow these steps and observe the difference:</p>
30707   *       <ol>
30708   *         <li>Type something in the input. You will see that the model is not yet updated</li>
30709   *         <li>Press the Escape key.
30710   *           <ol>
30711   *             <li> In the first example, nothing happens, because the model is already '', and no
30712   *             update is detected. If you blur the input, the model will be set to the current view.
30713   *             </li>
30714   *             <li> In the second example, the pending update is cancelled, and the input is set back
30715   *             to the last committed view value (''). Blurring the input does nothing.
30716   *             </li>
30717   *           </ol>
30718   *         </li>
30719   *       </ol>
30720   *
30721   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
30722   *         <div>
30723   *           <p id="inputDescription1">Without $rollbackViewValue():</p>
30724   *           <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
30725   *                  ng-keydown="setEmpty($event, 'value1')">
30726   *           value1: "{{ model.value1 }}"
30727   *         </div>
30728   *
30729   *         <div>
30730   *           <p id="inputDescription2">With $rollbackViewValue():</p>
30731   *           <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
30732   *                  ng-keydown="setEmpty($event, 'value2', true)">
30733   *           value2: "{{ model.value2 }}"
30734   *         </div>
30735   *       </form>
30736   *     </div>
30737   *   </file>
30738       <file name="style.css">
30739          div {
30740            display: table-cell;
30741          }
30742          div:nth-child(1) {
30743            padding-right: 30px;
30744          }
30745
30746        </file>
30747   * </example>
30748   */
30749  $rollbackViewValue: function() {
30750    this.$$timeout.cancel(this.$$pendingDebounce);
30751    this.$viewValue = this.$$lastCommittedViewValue;
30752    this.$render();
30753  },
30754
30755  /**
30756   * @ngdoc method
30757   * @name ngModel.NgModelController#$validate
30758   *
30759   * @description
30760   * Runs each of the registered validators (first synchronous validators and then
30761   * asynchronous validators).
30762   * If the validity changes to invalid, the model will be set to `undefined`,
30763   * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
30764   * If the validity changes to valid, it will set the model to the last available valid
30765   * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
30766   */
30767  $validate: function() {
30768
30769    // ignore $validate before model is initialized
30770    if (isNumberNaN(this.$modelValue)) {
30771      return;
30772    }
30773
30774    var viewValue = this.$$lastCommittedViewValue;
30775    // Note: we use the $$rawModelValue as $modelValue might have been
30776    // set to undefined during a view -> model update that found validation
30777    // errors. We can't parse the view here, since that could change
30778    // the model although neither viewValue nor the model on the scope changed
30779    var modelValue = this.$$rawModelValue;
30780
30781    var prevValid = this.$valid;
30782    var prevModelValue = this.$modelValue;
30783
30784    var allowInvalid = this.$options.getOption('allowInvalid');
30785
30786    var that = this;
30787    this.$$runValidators(modelValue, viewValue, function(allValid) {
30788      // If there was no change in validity, don't update the model
30789      // This prevents changing an invalid modelValue to undefined
30790      if (!allowInvalid && prevValid !== allValid) {
30791        // Note: Don't check this.$valid here, as we could have
30792        // external validators (e.g. calculated on the server),
30793        // that just call $setValidity and need the model value
30794        // to calculate their validity.
30795        that.$modelValue = allValid ? modelValue : undefined;
30796
30797        if (that.$modelValue !== prevModelValue) {
30798          that.$$writeModelToScope();
30799        }
30800      }
30801    });
30802  },
30803
30804  $$runValidators: function(modelValue, viewValue, doneCallback) {
30805    this.$$currentValidationRunId++;
30806    var localValidationRunId = this.$$currentValidationRunId;
30807    var that = this;
30808
30809    // check parser error
30810    if (!processParseErrors()) {
30811      validationDone(false);
30812      return;
30813    }
30814    if (!processSyncValidators()) {
30815      validationDone(false);
30816      return;
30817    }
30818    processAsyncValidators();
30819
30820    function processParseErrors() {
30821      var errorKey = that.$$parserName;
30822
30823      if (isUndefined(that.$$parserValid)) {
30824        setValidity(errorKey, null);
30825      } else {
30826        if (!that.$$parserValid) {
30827          forEach(that.$validators, function(v, name) {
30828            setValidity(name, null);
30829          });
30830          forEach(that.$asyncValidators, function(v, name) {
30831            setValidity(name, null);
30832          });
30833        }
30834
30835        // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
30836        setValidity(errorKey, that.$$parserValid);
30837        return that.$$parserValid;
30838      }
30839      return true;
30840    }
30841
30842    function processSyncValidators() {
30843      var syncValidatorsValid = true;
30844      forEach(that.$validators, function(validator, name) {
30845        var result = Boolean(validator(modelValue, viewValue));
30846        syncValidatorsValid = syncValidatorsValid && result;
30847        setValidity(name, result);
30848      });
30849      if (!syncValidatorsValid) {
30850        forEach(that.$asyncValidators, function(v, name) {
30851          setValidity(name, null);
30852        });
30853        return false;
30854      }
30855      return true;
30856    }
30857
30858    function processAsyncValidators() {
30859      var validatorPromises = [];
30860      var allValid = true;
30861      forEach(that.$asyncValidators, function(validator, name) {
30862        var promise = validator(modelValue, viewValue);
30863        if (!isPromiseLike(promise)) {
30864          throw ngModelMinErr('nopromise',
30865            'Expected asynchronous validator to return a promise but got \'{0}\' instead.', promise);
30866        }
30867        setValidity(name, undefined);
30868        validatorPromises.push(promise.then(function() {
30869          setValidity(name, true);
30870        }, function() {
30871          allValid = false;
30872          setValidity(name, false);
30873        }));
30874      });
30875      if (!validatorPromises.length) {
30876        validationDone(true);
30877      } else {
30878        that.$$q.all(validatorPromises).then(function() {
30879          validationDone(allValid);
30880        }, noop);
30881      }
30882    }
30883
30884    function setValidity(name, isValid) {
30885      if (localValidationRunId === that.$$currentValidationRunId) {
30886        that.$setValidity(name, isValid);
30887      }
30888    }
30889
30890    function validationDone(allValid) {
30891      if (localValidationRunId === that.$$currentValidationRunId) {
30892
30893        doneCallback(allValid);
30894      }
30895    }
30896  },
30897
30898  /**
30899   * @ngdoc method
30900   * @name ngModel.NgModelController#$commitViewValue
30901   *
30902   * @description
30903   * Commit a pending update to the `$modelValue`.
30904   *
30905   * Updates may be pending by a debounced event or because the input is waiting for a some future
30906   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
30907   * usually handles calling this in response to input events.
30908   */
30909  $commitViewValue: function() {
30910    var viewValue = this.$viewValue;
30911
30912    this.$$timeout.cancel(this.$$pendingDebounce);
30913
30914    // If the view value has not changed then we should just exit, except in the case where there is
30915    // a native validator on the element. In this case the validation state may have changed even though
30916    // the viewValue has stayed empty.
30917    if (this.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !this.$$hasNativeValidators)) {
30918      return;
30919    }
30920    this.$$updateEmptyClasses(viewValue);
30921    this.$$lastCommittedViewValue = viewValue;
30922
30923    // change to dirty
30924    if (this.$pristine) {
30925      this.$setDirty();
30926    }
30927    this.$$parseAndValidate();
30928  },
30929
30930  $$parseAndValidate: function() {
30931    var viewValue = this.$$lastCommittedViewValue;
30932    var modelValue = viewValue;
30933    var that = this;
30934
30935    this.$$parserValid = isUndefined(modelValue) ? undefined : true;
30936
30937    // Reset any previous parse error
30938    this.$setValidity(this.$$parserName, null);
30939    this.$$parserName = 'parse';
30940
30941    if (this.$$parserValid) {
30942      for (var i = 0; i < this.$parsers.length; i++) {
30943        modelValue = this.$parsers[i](modelValue);
30944        if (isUndefined(modelValue)) {
30945          this.$$parserValid = false;
30946          break;
30947        }
30948      }
30949    }
30950    if (isNumberNaN(this.$modelValue)) {
30951      // this.$modelValue has not been touched yet...
30952      this.$modelValue = this.$$ngModelGet(this.$$scope);
30953    }
30954    var prevModelValue = this.$modelValue;
30955    var allowInvalid = this.$options.getOption('allowInvalid');
30956    this.$$rawModelValue = modelValue;
30957
30958    if (allowInvalid) {
30959      this.$modelValue = modelValue;
30960      writeToModelIfNeeded();
30961    }
30962
30963    // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
30964    // This can happen if e.g. $setViewValue is called from inside a parser
30965    this.$$runValidators(modelValue, this.$$lastCommittedViewValue, function(allValid) {
30966      if (!allowInvalid) {
30967        // Note: Don't check this.$valid here, as we could have
30968        // external validators (e.g. calculated on the server),
30969        // that just call $setValidity and need the model value
30970        // to calculate their validity.
30971        that.$modelValue = allValid ? modelValue : undefined;
30972        writeToModelIfNeeded();
30973      }
30974    });
30975
30976    function writeToModelIfNeeded() {
30977      if (that.$modelValue !== prevModelValue) {
30978        that.$$writeModelToScope();
30979      }
30980    }
30981  },
30982
30983  $$writeModelToScope: function() {
30984    this.$$ngModelSet(this.$$scope, this.$modelValue);
30985    forEach(this.$viewChangeListeners, function(listener) {
30986      try {
30987        listener();
30988      } catch (e) {
30989        // eslint-disable-next-line no-invalid-this
30990        this.$$exceptionHandler(e);
30991      }
30992    }, this);
30993  },
30994
30995  /**
30996   * @ngdoc method
30997   * @name ngModel.NgModelController#$setViewValue
30998   *
30999   * @description
31000   * Update the view value.
31001   *
31002   * This method should be called when a control wants to change the view value; typically,
31003   * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
31004   * directive calls it when the value of the input changes and {@link ng.directive:select select}
31005   * calls it when an option is selected.
31006   *
31007   * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
31008   * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
31009   * value is sent directly for processing through the `$parsers` pipeline. After this, the `$validators` and
31010   * `$asyncValidators` are called and the value is applied to `$modelValue`.
31011   * Finally, the value is set to the **expression** specified in the `ng-model` attribute and
31012   * all the registered change listeners, in the `$viewChangeListeners` list are called.
31013   *
31014   * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
31015   * and the `default` trigger is not listed, all those actions will remain pending until one of the
31016   * `updateOn` events is triggered on the DOM element.
31017   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
31018   * directive is used with a custom debounce for this particular event.
31019   * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
31020   * is specified, once the timer runs out.
31021   *
31022   * When used with standard inputs, the view value will always be a string (which is in some cases
31023   * parsed into another type, such as a `Date` object for `input[date]`.)
31024   * However, custom controls might also pass objects to this method. In this case, we should make
31025   * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
31026   * perform a deep watch of objects, it only looks for a change of identity. If you only change
31027   * the property of the object then ngModel will not realize that the object has changed and
31028   * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
31029   * not change properties of the copy once it has been passed to `$setViewValue`.
31030   * Otherwise you may cause the model value on the scope to change incorrectly.
31031   *
31032   * <div class="alert alert-info">
31033   * In any case, the value passed to the method should always reflect the current value
31034   * of the control. For example, if you are calling `$setViewValue` for an input element,
31035   * you should pass the input DOM value. Otherwise, the control and the scope model become
31036   * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
31037   * the control's DOM value in any way. If we want to change the control's DOM value
31038   * programmatically, we should update the `ngModel` scope expression. Its new value will be
31039   * picked up by the model controller, which will run it through the `$formatters`, `$render` it
31040   * to update the DOM, and finally call `$validate` on it.
31041   * </div>
31042   *
31043   * @param {*} value value from the view.
31044   * @param {string} trigger Event that triggered the update.
31045   */
31046  $setViewValue: function(value, trigger) {
31047    this.$viewValue = value;
31048    if (this.$options.getOption('updateOnDefault')) {
31049      this.$$debounceViewValueCommit(trigger);
31050    }
31051  },
31052
31053  $$debounceViewValueCommit: function(trigger) {
31054    var debounceDelay = this.$options.getOption('debounce');
31055
31056    if (isNumber(debounceDelay[trigger])) {
31057      debounceDelay = debounceDelay[trigger];
31058    } else if (isNumber(debounceDelay['default']) &&
31059      this.$options.getOption('updateOn').indexOf(trigger) === -1
31060    ) {
31061      debounceDelay = debounceDelay['default'];
31062    } else if (isNumber(debounceDelay['*'])) {
31063      debounceDelay = debounceDelay['*'];
31064    }
31065
31066    this.$$timeout.cancel(this.$$pendingDebounce);
31067    var that = this;
31068    if (debounceDelay > 0) { // this fails if debounceDelay is an object
31069      this.$$pendingDebounce = this.$$timeout(function() {
31070        that.$commitViewValue();
31071      }, debounceDelay);
31072    } else if (this.$$rootScope.$$phase) {
31073      this.$commitViewValue();
31074    } else {
31075      this.$$scope.$apply(function() {
31076        that.$commitViewValue();
31077      });
31078    }
31079  },
31080
31081  /**
31082   * @ngdoc method
31083   *
31084   * @name ngModel.NgModelController#$overrideModelOptions
31085   *
31086   * @description
31087   *
31088   * Override the current model options settings programmatically.
31089   *
31090   * The previous `ModelOptions` value will not be modified. Instead, a
31091   * new `ModelOptions` object will inherit from the previous one overriding
31092   * or inheriting settings that are defined in the given parameter.
31093   *
31094   * See {@link ngModelOptions} for information about what options can be specified
31095   * and how model option inheritance works.
31096   *
31097   * <div class="alert alert-warning">
31098   * **Note:** this function only affects the options set on the `ngModelController`,
31099   * and not the options on the {@link ngModelOptions} directive from which they might have been
31100   * obtained initially.
31101   * </div>
31102   *
31103   * <div class="alert alert-danger">
31104   * **Note:** it is not possible to override the `getterSetter` option.
31105   * </div>
31106   *
31107   * @param {Object} options a hash of settings to override the previous options
31108   *
31109   */
31110  $overrideModelOptions: function(options) {
31111    this.$options = this.$options.createChild(options);
31112    this.$$setUpdateOnEvents();
31113  },
31114
31115  /**
31116   * @ngdoc method
31117   *
31118   * @name  ngModel.NgModelController#$processModelValue
31119
31120   * @description
31121   *
31122   * Runs the model -> view pipeline on the current
31123   * {@link ngModel.NgModelController#$modelValue $modelValue}.
31124   *
31125   * The following actions are performed by this method:
31126   *
31127   * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters}
31128   * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue}
31129   * - the `ng-empty` or `ng-not-empty` class is set on the element
31130   * - if the `$viewValue` has changed:
31131   *   - {@link ngModel.NgModelController#$render $render} is called on the control
31132   *   - the {@link ngModel.NgModelController#$validators $validators} are run and
31133   *   the validation status is set.
31134   *
31135   * This method is called by ngModel internally when the bound scope value changes.
31136   * Application developers usually do not have to call this function themselves.
31137   *
31138   * This function can be used when the `$viewValue` or the rendered DOM value are not correctly
31139   * formatted and the `$modelValue` must be run through the `$formatters` again.
31140   *
31141   * @example
31142   * Consider a text input with an autocomplete list (for fruit), where the items are
31143   * objects with a name and an id.
31144   * A user enters `ap` and then selects `Apricot` from the list.
31145   * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`,
31146   * but the rendered value will still be `ap`.
31147   * The widget can then call `ctrl.$processModelValue()` to run the model -> view
31148   * pipeline again, which formats the object to the string `Apricot`,
31149   * then updates the `$viewValue`, and finally renders it in the DOM.
31150   *
31151   * <example module="inputExample" name="ng-model-process">
31152     <file name="index.html">
31153      <div ng-controller="inputController" style="display: flex;">
31154        <div style="margin-right: 30px;">
31155          Search Fruit:
31156          <basic-autocomplete items="items" on-select="selectedFruit = item"></basic-autocomplete>
31157        </div>
31158        <div>
31159          Model:<br>
31160          <pre>{{selectedFruit | json}}</pre>
31161        </div>
31162      </div>
31163     </file>
31164     <file name="app.js">
31165      angular.module('inputExample', [])
31166        .controller('inputController', function($scope) {
31167          $scope.items = [
31168            {name: 'Apricot', id: 443},
31169            {name: 'Clementine', id: 972},
31170            {name: 'Durian', id: 169},
31171            {name: 'Jackfruit', id: 982},
31172            {name: 'Strawberry', id: 863}
31173          ];
31174        })
31175        .component('basicAutocomplete', {
31176          bindings: {
31177            items: '<',
31178            onSelect: '&'
31179          },
31180          templateUrl: 'autocomplete.html',
31181          controller: function($element, $scope) {
31182            var that = this;
31183            var ngModel;
31184
31185            that.$postLink = function() {
31186              ngModel = $element.find('input').controller('ngModel');
31187
31188              ngModel.$formatters.push(function(value) {
31189                return (value && value.name) || value;
31190              });
31191
31192              ngModel.$parsers.push(function(value) {
31193                var match = value;
31194                for (var i = 0; i < that.items.length; i++) {
31195                  if (that.items[i].name === value) {
31196                    match = that.items[i];
31197                    break;
31198                  }
31199                }
31200
31201                return match;
31202              });
31203            };
31204
31205            that.selectItem = function(item) {
31206              ngModel.$setViewValue(item);
31207              ngModel.$processModelValue();
31208              that.onSelect({item: item});
31209            };
31210          }
31211        });
31212     </file>
31213     <file name="autocomplete.html">
31214       <div>
31215         <input type="search" ng-model="$ctrl.searchTerm" />
31216         <ul>
31217           <li ng-repeat="item in $ctrl.items | filter:$ctrl.searchTerm">
31218             <button ng-click="$ctrl.selectItem(item)">{{ item.name }}</button>
31219           </li>
31220         </ul>
31221       </div>
31222     </file>
31223   * </example>
31224   *
31225   */
31226  $processModelValue: function() {
31227    var viewValue = this.$$format();
31228
31229    if (this.$viewValue !== viewValue) {
31230      this.$$updateEmptyClasses(viewValue);
31231      this.$viewValue = this.$$lastCommittedViewValue = viewValue;
31232      this.$render();
31233      // It is possible that model and view value have been updated during render
31234      this.$$runValidators(this.$modelValue, this.$viewValue, noop);
31235    }
31236  },
31237
31238  /**
31239   * This method is called internally to run the $formatters on the $modelValue
31240   */
31241  $$format: function() {
31242    var formatters = this.$formatters,
31243        idx = formatters.length;
31244
31245    var viewValue = this.$modelValue;
31246    while (idx--) {
31247      viewValue = formatters[idx](viewValue);
31248    }
31249
31250    return viewValue;
31251  },
31252
31253  /**
31254   * This method is called internally when the bound scope value changes.
31255   */
31256  $$setModelValue: function(modelValue) {
31257    this.$modelValue = this.$$rawModelValue = modelValue;
31258    this.$$parserValid = undefined;
31259    this.$processModelValue();
31260  },
31261
31262  $$setUpdateOnEvents: function() {
31263    if (this.$$updateEvents) {
31264      this.$$element.off(this.$$updateEvents, this.$$updateEventHandler);
31265    }
31266
31267    this.$$updateEvents = this.$options.getOption('updateOn');
31268    if (this.$$updateEvents) {
31269      this.$$element.on(this.$$updateEvents, this.$$updateEventHandler);
31270    }
31271  },
31272
31273  $$updateEventHandler: function(ev) {
31274    this.$$debounceViewValueCommit(ev && ev.type);
31275  }
31276};
31277
31278function setupModelWatcher(ctrl) {
31279  // model -> value
31280  // Note: we cannot use a normal scope.$watch as we want to detect the following:
31281  // 1. scope value is 'a'
31282  // 2. user enters 'b'
31283  // 3. ng-change kicks in and reverts scope value to 'a'
31284  //    -> scope value did not change since the last digest as
31285  //       ng-change executes in apply phase
31286  // 4. view should be changed back to 'a'
31287  ctrl.$$scope.$watch(function ngModelWatch(scope) {
31288    var modelValue = ctrl.$$ngModelGet(scope);
31289
31290    // if scope model value and ngModel value are out of sync
31291    // This cannot be moved to the action function, because it would not catch the
31292    // case where the model is changed in the ngChange function or the model setter
31293    if (modelValue !== ctrl.$modelValue &&
31294      // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
31295      // eslint-disable-next-line no-self-compare
31296      (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
31297    ) {
31298      ctrl.$$setModelValue(modelValue);
31299    }
31300
31301    return modelValue;
31302  });
31303}
31304
31305/**
31306 * @ngdoc method
31307 * @name ngModel.NgModelController#$setValidity
31308 *
31309 * @description
31310 * Change the validity state, and notify the form.
31311 *
31312 * This method can be called within $parsers/$formatters or a custom validation implementation.
31313 * However, in most cases it should be sufficient to use the `ngModel.$validators` and
31314 * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
31315 *
31316 * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
31317 *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
31318 *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
31319 *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
31320 *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
31321 *        classes and can be bound to as `{{ someForm.someControl.$error.myError }}`.
31322 * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
31323 *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
31324 *                          Skipped is used by AngularJS when validators do not run because of parse errors and
31325 *                          when `$asyncValidators` do not run because any of the `$validators` failed.
31326 */
31327addSetValidityMethod({
31328  clazz: NgModelController,
31329  set: function(object, property) {
31330    object[property] = true;
31331  },
31332  unset: function(object, property) {
31333    delete object[property];
31334  }
31335});
31336
31337
31338/**
31339 * @ngdoc directive
31340 * @name ngModel
31341 * @restrict A
31342 * @priority 1
31343 * @param {expression} ngModel assignable {@link guide/expression Expression} to bind to.
31344 *
31345 * @description
31346 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
31347 * property on the scope using {@link ngModel.NgModelController NgModelController},
31348 * which is created and exposed by this directive.
31349 *
31350 * `ngModel` is responsible for:
31351 *
31352 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
31353 *   require.
31354 * - Providing validation behavior (i.e. required, number, email, url).
31355 * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
31356 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
31357 *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
31358 * - Registering the control with its parent {@link ng.directive:form form}.
31359 *
31360 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
31361 * current scope. If the property doesn't already exist on this scope, it will be created
31362 * implicitly and added to the scope.
31363 *
31364 * For best practices on using `ngModel`, see:
31365 *
31366 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
31367 *
31368 * For basic examples, how to use `ngModel`, see:
31369 *
31370 *  - {@link ng.directive:input input}
31371 *    - {@link input[text] text}
31372 *    - {@link input[checkbox] checkbox}
31373 *    - {@link input[radio] radio}
31374 *    - {@link input[number] number}
31375 *    - {@link input[email] email}
31376 *    - {@link input[url] url}
31377 *    - {@link input[date] date}
31378 *    - {@link input[datetime-local] datetime-local}
31379 *    - {@link input[time] time}
31380 *    - {@link input[month] month}
31381 *    - {@link input[week] week}
31382 *  - {@link ng.directive:select select}
31383 *  - {@link ng.directive:textarea textarea}
31384 *
31385 * ## Complex Models (objects or collections)
31386 *
31387 * By default, `ngModel` watches the model by reference, not value. This is important to know when
31388 * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
31389 * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
31390 *
31391 * The model must be assigned an entirely new object or collection before a re-rendering will occur.
31392 *
31393 * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
31394 * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
31395 * if the select is given the `multiple` attribute.
31396 *
31397 * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
31398 * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
31399 * not trigger a re-rendering of the model.
31400 *
31401 * ## CSS classes
31402 * The following CSS classes are added and removed on the associated input/select/textarea element
31403 * depending on the validity of the model.
31404 *
31405 *  - `ng-valid`: the model is valid
31406 *  - `ng-invalid`: the model is invalid
31407 *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
31408 *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
31409 *  - `ng-pristine`: the control hasn't been interacted with yet
31410 *  - `ng-dirty`: the control has been interacted with
31411 *  - `ng-touched`: the control has been blurred
31412 *  - `ng-untouched`: the control hasn't been blurred
31413 *  - `ng-pending`: any `$asyncValidators` are unfulfilled
31414 *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
31415 *     by the {@link ngModel.NgModelController#$isEmpty} method
31416 *  - `ng-not-empty`: the view contains a non-empty value
31417 *
31418 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
31419 *
31420 * @animations
31421 * Animations within models are triggered when any of the associated CSS classes are added and removed
31422 * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
31423 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
31424 * The animations that are triggered within ngModel are similar to how they work in ngClass and
31425 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
31426 *
31427 * The following example shows a simple way to utilize CSS transitions to style an input element
31428 * that has been rendered as invalid after it has been validated:
31429 *
31430 * <pre>
31431 * //be sure to include ngAnimate as a module to hook into more
31432 * //advanced animations
31433 * .my-input {
31434 *   transition:0.5s linear all;
31435 *   background: white;
31436 * }
31437 * .my-input.ng-invalid {
31438 *   background: red;
31439 *   color:white;
31440 * }
31441 * </pre>
31442 *
31443 * @example
31444 * ### Basic Usage
31445 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample" name="ng-model">
31446     <file name="index.html">
31447       <script>
31448        angular.module('inputExample', [])
31449          .controller('ExampleController', ['$scope', function($scope) {
31450            $scope.val = '1';
31451          }]);
31452       </script>
31453       <style>
31454         .my-input {
31455           transition:all linear 0.5s;
31456           background: transparent;
31457         }
31458         .my-input.ng-invalid {
31459           color:white;
31460           background: red;
31461         }
31462       </style>
31463       <p id="inputDescription">
31464        Update input to see transitions when valid/invalid.
31465        Integer is a valid value.
31466       </p>
31467       <form name="testForm" ng-controller="ExampleController">
31468         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
31469                aria-describedby="inputDescription" />
31470       </form>
31471     </file>
31472 * </example>
31473 *
31474 * @example
31475 * ### Binding to a getter/setter
31476 *
31477 * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
31478 * function that returns a representation of the model when called with zero arguments, and sets
31479 * the internal state of a model when called with an argument. It's sometimes useful to use this
31480 * for models that have an internal representation that's different from what the model exposes
31481 * to the view.
31482 *
31483 * <div class="alert alert-success">
31484 * **Best Practice:** It's best to keep getters fast because AngularJS is likely to call them more
31485 * frequently than other parts of your code.
31486 * </div>
31487 *
31488 * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
31489 * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
31490 * a `<form>`, which will enable this behavior for all `<input>`s within it. See
31491 * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
31492 *
31493 * The following example shows how to use `ngModel` with a getter/setter:
31494 *
31495 * @example
31496 * <example name="ngModel-getter-setter" module="getterSetterExample">
31497     <file name="index.html">
31498       <div ng-controller="ExampleController">
31499         <form name="userForm">
31500           <label>Name:
31501             <input type="text" name="userName"
31502                    ng-model="user.name"
31503                    ng-model-options="{ getterSetter: true }" />
31504           </label>
31505         </form>
31506         <pre>user.name = <span ng-bind="user.name()"></span></pre>
31507       </div>
31508     </file>
31509     <file name="app.js">
31510       angular.module('getterSetterExample', [])
31511         .controller('ExampleController', ['$scope', function($scope) {
31512           var _name = 'Brian';
31513           $scope.user = {
31514             name: function(newName) {
31515              // Note that newName can be undefined for two reasons:
31516              // 1. Because it is called as a getter and thus called with no arguments
31517              // 2. Because the property should actually be set to undefined. This happens e.g. if the
31518              //    input is invalid
31519              return arguments.length ? (_name = newName) : _name;
31520             }
31521           };
31522         }]);
31523     </file>
31524 * </example>
31525 */
31526var ngModelDirective = ['$rootScope', function($rootScope) {
31527  return {
31528    restrict: 'A',
31529    require: ['ngModel', '^?form', '^?ngModelOptions'],
31530    controller: NgModelController,
31531    // Prelink needs to run before any input directive
31532    // so that we can set the NgModelOptions in NgModelController
31533    // before anyone else uses it.
31534    priority: 1,
31535    compile: function ngModelCompile(element) {
31536      // Setup initial state of the control
31537      element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
31538
31539      return {
31540        pre: function ngModelPreLink(scope, element, attr, ctrls) {
31541          var modelCtrl = ctrls[0],
31542              formCtrl = ctrls[1] || modelCtrl.$$parentForm,
31543              optionsCtrl = ctrls[2];
31544
31545          if (optionsCtrl) {
31546            modelCtrl.$options = optionsCtrl.$options;
31547          }
31548
31549          modelCtrl.$$initGetterSetters();
31550
31551          // notify others, especially parent forms
31552          formCtrl.$addControl(modelCtrl);
31553
31554          attr.$observe('name', function(newValue) {
31555            if (modelCtrl.$name !== newValue) {
31556              modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
31557            }
31558          });
31559
31560          scope.$on('$destroy', function() {
31561            modelCtrl.$$parentForm.$removeControl(modelCtrl);
31562          });
31563        },
31564        post: function ngModelPostLink(scope, element, attr, ctrls) {
31565          var modelCtrl = ctrls[0];
31566          modelCtrl.$$setUpdateOnEvents();
31567
31568          function setTouched() {
31569            modelCtrl.$setTouched();
31570          }
31571
31572          element.on('blur', function() {
31573            if (modelCtrl.$touched) return;
31574
31575            if ($rootScope.$$phase) {
31576              scope.$evalAsync(setTouched);
31577            } else {
31578              scope.$apply(setTouched);
31579            }
31580          });
31581        }
31582      };
31583    }
31584  };
31585}];
31586
31587/* exported defaultModelOptions */
31588var defaultModelOptions;
31589var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
31590
31591/**
31592 * @ngdoc type
31593 * @name ModelOptions
31594 * @description
31595 * A container for the options set by the {@link ngModelOptions} directive
31596 */
31597function ModelOptions(options) {
31598  this.$$options = options;
31599}
31600
31601ModelOptions.prototype = {
31602
31603  /**
31604   * @ngdoc method
31605   * @name ModelOptions#getOption
31606   * @param {string} name the name of the option to retrieve
31607   * @returns {*} the value of the option
31608   * @description
31609   * Returns the value of the given option
31610   */
31611  getOption: function(name) {
31612    return this.$$options[name];
31613  },
31614
31615  /**
31616   * @ngdoc method
31617   * @name ModelOptions#createChild
31618   * @param {Object} options a hash of options for the new child that will override the parent's options
31619   * @return {ModelOptions} a new `ModelOptions` object initialized with the given options.
31620   */
31621  createChild: function(options) {
31622    var inheritAll = false;
31623
31624    // make a shallow copy
31625    options = extend({}, options);
31626
31627    // Inherit options from the parent if specified by the value `"$inherit"`
31628    forEach(options, /** @this */ function(option, key) {
31629      if (option === '$inherit') {
31630        if (key === '*') {
31631          inheritAll = true;
31632        } else {
31633          options[key] = this.$$options[key];
31634          // `updateOn` is special so we must also inherit the `updateOnDefault` option
31635          if (key === 'updateOn') {
31636            options.updateOnDefault = this.$$options.updateOnDefault;
31637          }
31638        }
31639      } else {
31640        if (key === 'updateOn') {
31641          // If the `updateOn` property contains the `default` event then we have to remove
31642          // it from the event list and set the `updateOnDefault` flag.
31643          options.updateOnDefault = false;
31644          options[key] = trim(option.replace(DEFAULT_REGEXP, function() {
31645            options.updateOnDefault = true;
31646            return ' ';
31647          }));
31648        }
31649      }
31650    }, this);
31651
31652    if (inheritAll) {
31653      // We have a property of the form: `"*": "$inherit"`
31654      delete options['*'];
31655      defaults(options, this.$$options);
31656    }
31657
31658    // Finally add in any missing defaults
31659    defaults(options, defaultModelOptions.$$options);
31660
31661    return new ModelOptions(options);
31662  }
31663};
31664
31665
31666defaultModelOptions = new ModelOptions({
31667  updateOn: '',
31668  updateOnDefault: true,
31669  debounce: 0,
31670  getterSetter: false,
31671  allowInvalid: false,
31672  timezone: null
31673});
31674
31675
31676/**
31677 * @ngdoc directive
31678 * @name ngModelOptions
31679 * @restrict A
31680 * @priority 10
31681 *
31682 * @description
31683 * This directive allows you to modify the behaviour of {@link ngModel} directives within your
31684 * application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel}
31685 * directives will use the options of their nearest `ngModelOptions` ancestor.
31686 *
31687 * The `ngModelOptions` settings are found by evaluating the value of the attribute directive as
31688 * an AngularJS expression. This expression should evaluate to an object, whose properties contain
31689 * the settings. For example: `<div ng-model-options="{ debounce: 100 }"`.
31690 *
31691 * ## Inheriting Options
31692 *
31693 * You can specify that an `ngModelOptions` setting should be inherited from a parent `ngModelOptions`
31694 * directive by giving it the value of `"$inherit"`.
31695 * Then it will inherit that setting from the first `ngModelOptions` directive found by traversing up the
31696 * DOM tree. If there is no ancestor element containing an `ngModelOptions` directive then default settings
31697 * will be used.
31698 *
31699 * For example given the following fragment of HTML
31700 *
31701 *
31702 * ```html
31703 * <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
31704 *   <form ng-model-options="{ updateOn: 'blur', allowInvalid: '$inherit' }">
31705 *     <input ng-model-options="{ updateOn: 'default', allowInvalid: '$inherit' }" />
31706 *   </form>
31707 * </div>
31708 * ```
31709 *
31710 * the `input` element will have the following settings
31711 *
31712 * ```js
31713 * { allowInvalid: true, updateOn: 'default', debounce: 0 }
31714 * ```
31715 *
31716 * Notice that the `debounce` setting was not inherited and used the default value instead.
31717 *
31718 * You can specify that all undefined settings are automatically inherited from an ancestor by
31719 * including a property with key of `"*"` and value of `"$inherit"`.
31720 *
31721 * For example given the following fragment of HTML
31722 *
31723 *
31724 * ```html
31725 * <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
31726 *   <form ng-model-options="{ updateOn: 'blur', "*": '$inherit' }">
31727 *     <input ng-model-options="{ updateOn: 'default', "*": '$inherit' }" />
31728 *   </form>
31729 * </div>
31730 * ```
31731 *
31732 * the `input` element will have the following settings
31733 *
31734 * ```js
31735 * { allowInvalid: true, updateOn: 'default', debounce: 200 }
31736 * ```
31737 *
31738 * Notice that the `debounce` setting now inherits the value from the outer `<div>` element.
31739 *
31740 * If you are creating a reusable component then you should be careful when using `"*": "$inherit"`
31741 * since you may inadvertently inherit a setting in the future that changes the behavior of your component.
31742 *
31743 *
31744 * ## Triggering and debouncing model updates
31745 *
31746 * The `updateOn` and `debounce` properties allow you to specify a custom list of events that will
31747 * trigger a model update and/or a debouncing delay so that the actual update only takes place when
31748 * a timer expires; this timer will be reset after another change takes place.
31749 *
31750 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
31751 * be different from the value in the actual model. This means that if you update the model you
31752 * should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in
31753 * order to make sure it is synchronized with the model and that any debounced action is canceled.
31754 *
31755 * The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue}
31756 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
31757 * important because `form` controllers are published to the related scope under the name in their
31758 * `name` attribute.
31759 *
31760 * Any pending changes will take place immediately when an enclosing form is submitted via the
31761 * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
31762 * to have access to the updated model.
31763 *
31764 * ### Overriding immediate updates
31765 *
31766 * The following example shows how to override immediate updates. Changes on the inputs within the
31767 * form will update the model only when the control loses focus (blur event). If `escape` key is
31768 * pressed while the input field is focused, the value is reset to the value in the current model.
31769 *
31770 * <example name="ngModelOptions-directive-blur" module="optionsExample">
31771 *   <file name="index.html">
31772 *     <div ng-controller="ExampleController">
31773 *       <form name="userForm">
31774 *         <label>
31775 *           Name:
31776 *           <input type="text" name="userName"
31777 *                  ng-model="user.name"
31778 *                  ng-model-options="{ updateOn: 'blur' }"
31779 *                  ng-keyup="cancel($event)" />
31780 *         </label><br />
31781 *         <label>
31782 *           Other data:
31783 *           <input type="text" ng-model="user.data" />
31784 *         </label><br />
31785 *       </form>
31786 *       <pre>user.name = <span ng-bind="user.name"></span></pre>
31787 *     </div>
31788 *   </file>
31789 *   <file name="app.js">
31790 *     angular.module('optionsExample', [])
31791 *       .controller('ExampleController', ['$scope', function($scope) {
31792 *         $scope.user = { name: 'say', data: '' };
31793 *
31794 *         $scope.cancel = function(e) {
31795 *           if (e.keyCode === 27) {
31796 *             $scope.userForm.userName.$rollbackViewValue();
31797 *           }
31798 *         };
31799 *       }]);
31800 *   </file>
31801 *   <file name="protractor.js" type="protractor">
31802 *     var model = element(by.binding('user.name'));
31803 *     var input = element(by.model('user.name'));
31804 *     var other = element(by.model('user.data'));
31805 *
31806 *     it('should allow custom events', function() {
31807 *       input.sendKeys(' hello');
31808 *       input.click();
31809 *       expect(model.getText()).toEqual('say');
31810 *       other.click();
31811 *       expect(model.getText()).toEqual('say hello');
31812 *     });
31813 *
31814 *     it('should $rollbackViewValue when model changes', function() {
31815 *       input.sendKeys(' hello');
31816 *       expect(input.getAttribute('value')).toEqual('say hello');
31817 *       input.sendKeys(protractor.Key.ESCAPE);
31818 *       expect(input.getAttribute('value')).toEqual('say');
31819 *       other.click();
31820 *       expect(model.getText()).toEqual('say');
31821 *     });
31822 *   </file>
31823 * </example>
31824 *
31825 * ### Debouncing updates
31826 *
31827 * The next example shows how to debounce model changes. Model will be updated only 1 sec after last change.
31828 * If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
31829 *
31830 * <example name="ngModelOptions-directive-debounce" module="optionsExample">
31831 *   <file name="index.html">
31832 *     <div ng-controller="ExampleController">
31833 *       <form name="userForm">
31834 *         Name:
31835 *         <input type="text" name="userName"
31836 *                ng-model="user.name"
31837 *                ng-model-options="{ debounce: 1000 }" />
31838 *         <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
31839 *       </form>
31840 *       <pre>user.name = <span ng-bind="user.name"></span></pre>
31841 *     </div>
31842 *   </file>
31843 *   <file name="app.js">
31844 *     angular.module('optionsExample', [])
31845 *       .controller('ExampleController', ['$scope', function($scope) {
31846 *         $scope.user = { name: 'say' };
31847 *       }]);
31848 *   </file>
31849 * </example>
31850 *
31851 * ### Default events, extra triggers, and catch-all debounce values
31852 *
31853 * This example shows the relationship between "default" update events and
31854 * additional `updateOn` triggers.
31855 *
31856 * `default` events are those that are bound to the control, and when fired, update the `$viewValue`
31857 * via {@link ngModel.NgModelController#$setViewValue $setViewValue}. Every event that is not listed
31858 * in `updateOn` is considered a "default" event, since different control types have different
31859 * default events.
31860 *
31861 * The control in this example updates by "default", "click", and "blur", with different `debounce`
31862 * values. You can see that "click" doesn't have an individual `debounce` value -
31863 * therefore it uses the `*` debounce value.
31864 *
31865 * There is also a button that calls {@link ngModel.NgModelController#$setViewValue $setViewValue}
31866 * directly with a "custom" event. Since "custom" is not defined in the `updateOn` list,
31867 * it is considered a "default" event and will update the
31868 * control if "default" is defined in `updateOn`, and will receive the "default" debounce value.
31869 * Note that this is just to illustrate how custom controls would possibly call `$setViewValue`.
31870 *
31871 * You can change the `updateOn` and `debounce` configuration to test different scenarios. This
31872 * is done with {@link ngModel.NgModelController#$overrideModelOptions $overrideModelOptions}.
31873 *
31874  <example name="ngModelOptions-advanced" module="optionsExample">
31875    <file name="index.html">
31876       <model-update-demo></model-update-demo>
31877    </file>
31878    <file name="app.js">
31879      angular.module('optionsExample', [])
31880        .component('modelUpdateDemo', {
31881          templateUrl: 'template.html',
31882          controller: function() {
31883            this.name = 'Chinua';
31884
31885            this.options = {
31886              updateOn: 'default blur click',
31887              debounce: {
31888                default: 2000,
31889                blur: 0,
31890                '*': 1000
31891              }
31892            };
31893
31894            this.updateEvents = function() {
31895              var eventList = this.options.updateOn.split(' ');
31896              eventList.push('*');
31897              var events = {};
31898
31899              for (var i = 0; i < eventList.length; i++) {
31900                events[eventList[i]] = this.options.debounce[eventList[i]];
31901              }
31902
31903              this.events = events;
31904            };
31905
31906            this.updateOptions = function() {
31907              var options = angular.extend(this.options, {
31908                updateOn: Object.keys(this.events).join(' ').replace('*', ''),
31909                debounce: this.events
31910              });
31911
31912              this.form.input.$overrideModelOptions(options);
31913            };
31914
31915            // Initialize the event form
31916            this.updateEvents();
31917          }
31918        });
31919    </file>
31920    <file name="template.html">
31921      <form name="$ctrl.form">
31922        Input: <input type="text" name="input" ng-model="$ctrl.name" ng-model-options="$ctrl.options" />
31923      </form>
31924      Model: <tt>{{$ctrl.name}}</tt>
31925      <hr>
31926      <button ng-click="$ctrl.form.input.$setViewValue('some value', 'custom')">Trigger setViewValue with 'some value' and 'custom' event</button>
31927
31928      <hr>
31929      <form ng-submit="$ctrl.updateOptions()">
31930        <b>updateOn</b><br>
31931        <input type="text" ng-model="$ctrl.options.updateOn" ng-change="$ctrl.updateEvents()" ng-model-options="{debounce: 500}">
31932
31933        <table>
31934          <tr>
31935            <th>Option</th>
31936            <th>Debounce value</th>
31937          </tr>
31938          <tr ng-repeat="(key, value) in $ctrl.events">
31939            <td>{{key}}</td>
31940            <td><input type="number" ng-model="$ctrl.events[key]" /></td>
31941          </tr>
31942        </table>
31943
31944        <br>
31945        <input type="submit" value="Update options">
31946      </form>
31947    </file>
31948  </example>
31949 *
31950 *
31951 * ## Model updates and validation
31952 *
31953 * The default behaviour in `ngModel` is that the model value is set to `undefined` when the
31954 * validation determines that the value is invalid. By setting the `allowInvalid` property to true,
31955 * the model will still be updated even if the value is invalid.
31956 *
31957 *
31958 * ## Connecting to the scope
31959 *
31960 * By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression
31961 * on the scope refers to a "getter/setter" function rather than the value itself.
31962 *
31963 * The following example shows how to bind to getter/setters:
31964 *
31965 * <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
31966 *   <file name="index.html">
31967 *     <div ng-controller="ExampleController">
31968 *       <form name="userForm">
31969 *         <label>
31970 *           Name:
31971 *           <input type="text" name="userName"
31972 *                  ng-model="user.name"
31973 *                  ng-model-options="{ getterSetter: true }" />
31974 *         </label>
31975 *       </form>
31976 *       <pre>user.name = <span ng-bind="user.name()"></span></pre>
31977 *     </div>
31978 *   </file>
31979 *   <file name="app.js">
31980 *     angular.module('getterSetterExample', [])
31981 *       .controller('ExampleController', ['$scope', function($scope) {
31982 *         var _name = 'Brian';
31983 *         $scope.user = {
31984 *           name: function(newName) {
31985 *             return angular.isDefined(newName) ? (_name = newName) : _name;
31986 *           }
31987 *         };
31988 *       }]);
31989 *   </file>
31990 * </example>
31991 *
31992 *
31993 * ## Programmatically changing options
31994 *
31995 * The `ngModelOptions` expression is only evaluated once when the directive is linked; it is not
31996 * watched for changes. However, it is possible to override the options on a single
31997 * {@link ngModel.NgModelController} instance with
31998 * {@link ngModel.NgModelController#$overrideModelOptions `NgModelController#$overrideModelOptions()`}.
31999 * See also the example for
32000 * {@link ngModelOptions#default-events-extra-triggers-and-catch-all-debounce-values
32001 * Default events, extra triggers, and catch-all debounce values}.
32002 *
32003 *
32004 * ## Specifying timezones
32005 *
32006 * You can specify the timezone that date/time input directives expect by providing its name in the
32007 * `timezone` property.
32008 *
32009 *
32010 * ## Formatting the value of `time` and `datetime-local`
32011 *
32012 * With the options `timeSecondsFormat` and `timeStripZeroSeconds` it is possible to adjust the value
32013 * that is displayed in the control. Note that browsers may apply their own formatting
32014 * in the user interface.
32015 *
32016   <example name="ngModelOptions-time-format" module="timeExample">
32017     <file name="index.html">
32018       <time-example></time-example>
32019     </file>
32020     <file name="script.js">
32021        angular.module('timeExample', [])
32022          .component('timeExample', {
32023            templateUrl: 'timeExample.html',
32024            controller: function() {
32025              this.time = new Date(1970, 0, 1, 14, 57, 0);
32026
32027              this.options = {
32028                timeSecondsFormat: 'ss',
32029                timeStripZeroSeconds: true
32030              };
32031
32032              this.optionChange = function() {
32033                this.timeForm.timeFormatted.$overrideModelOptions(this.options);
32034                this.time = new Date(this.time);
32035              };
32036            }
32037          });
32038     </file>
32039     <file name="timeExample.html">
32040       <form name="$ctrl.timeForm">
32041         <strong>Default</strong>:
32042         <input type="time" ng-model="$ctrl.time" step="any" /><br>
32043         <strong>With options</strong>:
32044         <input type="time" name="timeFormatted" ng-model="$ctrl.time" step="any" ng-model-options="$ctrl.options" />
32045         <br>
32046
32047         Options:<br>
32048         <code>timeSecondsFormat</code>:
32049         <input
32050           type="text"
32051           ng-model="$ctrl.options.timeSecondsFormat"
32052           ng-change="$ctrl.optionChange()">
32053         <br>
32054         <code>timeStripZeroSeconds</code>:
32055         <input
32056           type="checkbox"
32057           ng-model="$ctrl.options.timeStripZeroSeconds"
32058           ng-change="$ctrl.optionChange()">
32059        </form>
32060      </file>
32061 *  </example>
32062 *
32063 * @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and
32064 *   and its descendents.
32065 *
32066 * **General options**:
32067 *
32068 *   - `updateOn`: string specifying which event should the input be bound to. You can set several
32069 *     events using an space delimited list. There is a special event called `default` that
32070 *     matches the default events belonging to the control. These are the events that are bound to
32071 *     the control, and when fired, update the `$viewValue` via `$setViewValue`.
32072 *
32073 *     `ngModelOptions` considers every event that is not listed in `updateOn` a "default" event,
32074 *     since different control types use different default events.
32075 *
32076 *     See also the section {@link ngModelOptions#triggering-and-debouncing-model-updates
32077 *     Triggering and debouncing model updates}.
32078 *
32079 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
32080 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
32081 *     custom value for each event. For example:
32082 *     ```
32083 *     ng-model-options="{
32084 *       updateOn: 'default blur',
32085 *       debounce: { 'default': 500, 'blur': 0 }
32086 *     }"
32087 *     ```
32088 *     You can use the `*` key to specify a debounce value that applies to all events that are not
32089 *     specifically listed. In the following example, `mouseup` would have a debounce delay of 1000:
32090 *     ```
32091 *     ng-model-options="{
32092 *       updateOn: 'default blur mouseup',
32093 *       debounce: { 'default': 500, 'blur': 0, '*': 1000 }
32094 *     }"
32095 *     ```
32096 *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
32097 *     not validate correctly instead of the default behavior of setting the model to undefined.
32098 *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
32099 *     `ngModel` as getters/setters.
32100 *
32101 *
32102 *  **Input-type specific options**:
32103 *
32104 *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
32105 *     `<input type="date" />`, `<input type="time" />`, ... . It understands UTC/GMT and the
32106 *     continental US time zone abbreviations, but for general use, use a time zone offset, for
32107 *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
32108 *     If not specified, the timezone of the browser will be used.
32109 *     Note that changing the timezone will have no effect on the current date, and is only applied after
32110 *     the next input / model change.
32111 *
32112 *   - `timeSecondsFormat`: Defines if the `time` and `datetime-local` types should show seconds and
32113 *     milliseconds. The option follows the format string of {@link date date filter}.
32114 *     By default, the options is `undefined` which is equal to `'ss.sss'` (seconds and milliseconds).
32115 *     The other options are `'ss'` (strips milliseconds), and `''` (empty string), which strips both
32116 *     seconds and milliseconds.
32117 *     Note that browsers that support `time` and `datetime-local` require the hour and minutes
32118 *     part of the time string, and may show the value differently in the user interface.
32119 *     {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}.
32120 *
32121 *   - `timeStripZeroSeconds`: Defines if the `time` and `datetime-local` types should strip the
32122 *     seconds and milliseconds from the formatted value if they are zero. This option is applied
32123 *     after `timeSecondsFormat`.
32124 *     This option can be used to make the formatting consistent over different browsers, as some
32125 *     browsers with support for `time` will natively hide the milliseconds and
32126 *     seconds if they are zero, but others won't, and browsers that don't implement these input
32127 *     types will always show the full string.
32128 *     {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}.
32129 *
32130 */
32131var ngModelOptionsDirective = function() {
32132  NgModelOptionsController.$inject = ['$attrs', '$scope'];
32133  function NgModelOptionsController($attrs, $scope) {
32134    this.$$attrs = $attrs;
32135    this.$$scope = $scope;
32136  }
32137  NgModelOptionsController.prototype = {
32138    $onInit: function() {
32139      var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions;
32140      var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions);
32141
32142      this.$options = parentOptions.createChild(modelOptionsDefinition);
32143    }
32144  };
32145
32146  return {
32147    restrict: 'A',
32148    // ngModelOptions needs to run before ngModel and input directives
32149    priority: 10,
32150    require: {parentCtrl: '?^^ngModelOptions'},
32151    bindToController: true,
32152    controller: NgModelOptionsController
32153  };
32154};
32155
32156
32157// shallow copy over values from `src` that are not already specified on `dst`
32158function defaults(dst, src) {
32159  forEach(src, function(value, key) {
32160    if (!isDefined(dst[key])) {
32161      dst[key] = value;
32162    }
32163  });
32164}
32165
32166/**
32167 * @ngdoc directive
32168 * @name ngNonBindable
32169 * @restrict AC
32170 * @priority 1000
32171 * @element ANY
32172 *
32173 * @description
32174 * The `ngNonBindable` directive tells AngularJS not to compile or bind the contents of the current
32175 * DOM element, including directives on the element itself that have a lower priority than
32176 * `ngNonBindable`. This is useful if the element contains what appears to be AngularJS directives
32177 * and bindings but which should be ignored by AngularJS. This could be the case if you have a site
32178 * that displays snippets of code, for instance.
32179 *
32180 * @example
32181 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
32182 * but the one wrapped in `ngNonBindable` is left alone.
32183 *
32184  <example name="ng-non-bindable">
32185    <file name="index.html">
32186      <div>Normal: {{1 + 2}}</div>
32187      <div ng-non-bindable>Ignored: {{1 + 2}}</div>
32188    </file>
32189    <file name="protractor.js" type="protractor">
32190     it('should check ng-non-bindable', function() {
32191       expect(element(by.binding('1 + 2')).getText()).toContain('3');
32192       expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
32193     });
32194    </file>
32195  </example>
32196 */
32197var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
32198
32199/* exported ngOptionsDirective */
32200
32201/* global jqLiteRemove */
32202
32203var ngOptionsMinErr = minErr('ngOptions');
32204
32205/**
32206 * @ngdoc directive
32207 * @name ngOptions
32208 * @restrict A
32209 *
32210 * @description
32211 *
32212 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
32213 * elements for the `<select>` element using the array or object obtained by evaluating the
32214 * `ngOptions` comprehension expression.
32215 *
32216 * In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements instead of
32217 * `ngOptions` to achieve a similar result. However, `ngOptions` provides some benefits:
32218 * - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
32219 * comprehension expression
32220 * - reduced memory consumption by not creating a new scope for each repeated instance
32221 * - increased render speed by creating the options in a documentFragment instead of individually
32222 *
32223 * When an item in the `<select>` menu is selected, the array element or object property
32224 * represented by the selected option will be bound to the model identified by the `ngModel`
32225 * directive.
32226 *
32227 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
32228 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
32229 * option. See example below for demonstration.
32230 *
32231 * ## Complex Models (objects or collections)
32232 *
32233 * By default, `ngModel` watches the model by reference, not value. This is important to know when
32234 * binding the select to a model that is an object or a collection.
32235 *
32236 * One issue occurs if you want to preselect an option. For example, if you set
32237 * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
32238 * because the objects are not identical. So by default, you should always reference the item in your collection
32239 * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
32240 *
32241 * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
32242 * of the item not by reference, but by the result of the `track by` expression. For example, if your
32243 * collection items have an id property, you would `track by item.id`.
32244 *
32245 * A different issue with objects or collections is that ngModel won't detect if an object property or
32246 * a collection item changes. For that reason, `ngOptions` additionally watches the model using
32247 * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
32248 * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
32249 * has not changed identity, but only a property on the object or an item in the collection changes.
32250 *
32251 * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
32252 * if the model is an array). This means that changing a property deeper than the first level inside the
32253 * object/collection will not trigger a re-rendering.
32254 *
32255 * ## `select` **`as`**
32256 *
32257 * Using `select` **`as`** will bind the result of the `select` expression to the model, but
32258 * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
32259 * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
32260 * is used, the result of that expression will be set as the value of the `option` and `select` elements.
32261 *
32262 *
32263 * ### `select` **`as`** and **`track by`**
32264 *
32265 * <div class="alert alert-warning">
32266 * Be careful when using `select` **`as`** and **`track by`** in the same expression.
32267 * </div>
32268 *
32269 * Given this array of items on the $scope:
32270 *
32271 * ```js
32272 * $scope.items = [{
32273 *   id: 1,
32274 *   label: 'aLabel',
32275 *   subItem: { name: 'aSubItem' }
32276 * }, {
32277 *   id: 2,
32278 *   label: 'bLabel',
32279 *   subItem: { name: 'bSubItem' }
32280 * }];
32281 * ```
32282 *
32283 * This will work:
32284 *
32285 * ```html
32286 * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
32287 * ```
32288 * ```js
32289 * $scope.selected = $scope.items[0];
32290 * ```
32291 *
32292 * but this will not work:
32293 *
32294 * ```html
32295 * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
32296 * ```
32297 * ```js
32298 * $scope.selected = $scope.items[0].subItem;
32299 * ```
32300 *
32301 * In both examples, the **`track by`** expression is applied successfully to each `item` in the
32302 * `items` array. Because the selected option has been set programmatically in the controller, the
32303 * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
32304 * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
32305 * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
32306 * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
32307 * is not matched against any `<option>` and the `<select>` appears as having no selected value.
32308 *
32309 *
32310 * @param {string} ngModel Assignable AngularJS expression to data-bind to.
32311 * @param {comprehension_expression} ngOptions in one of the following forms:
32312 *
32313 *   * for array data sources:
32314 *     * `label` **`for`** `value` **`in`** `array`
32315 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
32316 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
32317 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
32318 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
32319 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
32320 *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
32321 *        (for including a filter with `track by`)
32322 *   * for object data sources:
32323 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
32324 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
32325 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
32326 *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
32327 *     * `select` **`as`** `label` **`group by`** `group`
32328 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
32329 *     * `select` **`as`** `label` **`disable when`** `disable`
32330 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
32331 *
32332 * Where:
32333 *
32334 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
32335 *   * `value`: local variable which will refer to each item in the `array` or each property value
32336 *      of `object` during iteration.
32337 *   * `key`: local variable which will refer to a property name in `object` during iteration.
32338 *   * `label`: The result of this expression will be the label for `<option>` element. The
32339 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
32340 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
32341 *      element. If not specified, `select` expression will default to `value`.
32342 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
32343 *      DOM element.
32344 *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
32345 *      element. Return `true` to disable.
32346 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
32347 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
32348 *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
32349 *      even when the options are recreated (e.g. reloaded from the server).
32350 * @param {string=} name Property name of the form under which the control is published.
32351 * @param {string=} required The control is considered valid only if value is entered.
32352 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
32353 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
32354 *    `required` when you want to data-bind to the `required` attribute.
32355 * @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
32356 * {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
32357 *
32358 * @example
32359    <example module="selectExample" name="select">
32360      <file name="index.html">
32361        <script>
32362        angular.module('selectExample', [])
32363          .controller('ExampleController', ['$scope', function($scope) {
32364            $scope.colors = [
32365              {name:'black', shade:'dark'},
32366              {name:'white', shade:'light', notAnOption: true},
32367              {name:'red', shade:'dark'},
32368              {name:'blue', shade:'dark', notAnOption: true},
32369              {name:'yellow', shade:'light', notAnOption: false}
32370            ];
32371            $scope.myColor = $scope.colors[2]; // red
32372          }]);
32373        </script>
32374        <div ng-controller="ExampleController">
32375          <ul>
32376            <li ng-repeat="color in colors">
32377              <label>Name: <input ng-model="color.name"></label>
32378              <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
32379              <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
32380            </li>
32381            <li>
32382              <button ng-click="colors.push({})">add</button>
32383            </li>
32384          </ul>
32385          <hr/>
32386          <label>Color (null not allowed):
32387            <select ng-model="myColor" ng-options="color.name for color in colors"></select>
32388          </label><br/>
32389          <label>Color (null allowed):
32390          <span  class="nullable">
32391            <select ng-model="myColor" ng-options="color.name for color in colors">
32392              <option value="">-- choose color --</option>
32393            </select>
32394          </span></label><br/>
32395
32396          <label>Color grouped by shade:
32397            <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
32398            </select>
32399          </label><br/>
32400
32401          <label>Color grouped by shade, with some disabled:
32402            <select ng-model="myColor"
32403                  ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
32404            </select>
32405          </label><br/>
32406
32407
32408
32409          Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
32410          <br/>
32411          <hr/>
32412          Currently selected: {{ {selected_color:myColor} }}
32413          <div style="border:solid 1px black; height:20px"
32414               ng-style="{'background-color':myColor.name}">
32415          </div>
32416        </div>
32417      </file>
32418      <file name="protractor.js" type="protractor">
32419         it('should check ng-options', function() {
32420           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
32421           element.all(by.model('myColor')).first().click();
32422           element.all(by.css('select[ng-model="myColor"] option')).first().click();
32423           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
32424           element(by.css('.nullable select[ng-model="myColor"]')).click();
32425           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
32426           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
32427         });
32428      </file>
32429    </example>
32430 */
32431
32432/* eslint-disable max-len */
32433//                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555000000000666666666666600000007777777777777000000000000000888888888800000000000000000009999999999
32434var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([$\w][$\w]*)|(?:\(\s*([$\w][$\w]*)\s*,\s*([$\w][$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
32435                        // 1: value expression (valueFn)
32436                        // 2: label expression (displayFn)
32437                        // 3: group by expression (groupByFn)
32438                        // 4: disable when expression (disableWhenFn)
32439                        // 5: array item variable name
32440                        // 6: object item key variable name
32441                        // 7: object item value variable name
32442                        // 8: collection expression
32443                        // 9: track by expression
32444/* eslint-enable */
32445
32446
32447var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
32448
32449  function parseOptionsExpression(optionsExp, selectElement, scope) {
32450
32451    var match = optionsExp.match(NG_OPTIONS_REGEXP);
32452    if (!(match)) {
32453      throw ngOptionsMinErr('iexp',
32454        'Expected expression in form of ' +
32455        '\'_select_ (as _label_)? for (_key_,)?_value_ in _collection_\'' +
32456        ' but got \'{0}\'. Element: {1}',
32457        optionsExp, startingTag(selectElement));
32458    }
32459
32460    // Extract the parts from the ngOptions expression
32461
32462    // The variable name for the value of the item in the collection
32463    var valueName = match[5] || match[7];
32464    // The variable name for the key of the item in the collection
32465    var keyName = match[6];
32466
32467    // An expression that generates the viewValue for an option if there is a label expression
32468    var selectAs = / as /.test(match[0]) && match[1];
32469    // An expression that is used to track the id of each object in the options collection
32470    var trackBy = match[9];
32471    // An expression that generates the viewValue for an option if there is no label expression
32472    var valueFn = $parse(match[2] ? match[1] : valueName);
32473    var selectAsFn = selectAs && $parse(selectAs);
32474    var viewValueFn = selectAsFn || valueFn;
32475    var trackByFn = trackBy && $parse(trackBy);
32476
32477    // Get the value by which we are going to track the option
32478    // if we have a trackFn then use that (passing scope and locals)
32479    // otherwise just hash the given viewValue
32480    var getTrackByValueFn = trackBy ?
32481                              function(value, locals) { return trackByFn(scope, locals); } :
32482                              function getHashOfValue(value) { return hashKey(value); };
32483    var getTrackByValue = function(value, key) {
32484      return getTrackByValueFn(value, getLocals(value, key));
32485    };
32486
32487    var displayFn = $parse(match[2] || match[1]);
32488    var groupByFn = $parse(match[3] || '');
32489    var disableWhenFn = $parse(match[4] || '');
32490    var valuesFn = $parse(match[8]);
32491
32492    var locals = {};
32493    var getLocals = keyName ? function(value, key) {
32494      locals[keyName] = key;
32495      locals[valueName] = value;
32496      return locals;
32497    } : function(value) {
32498      locals[valueName] = value;
32499      return locals;
32500    };
32501
32502
32503    function Option(selectValue, viewValue, label, group, disabled) {
32504      this.selectValue = selectValue;
32505      this.viewValue = viewValue;
32506      this.label = label;
32507      this.group = group;
32508      this.disabled = disabled;
32509    }
32510
32511    function getOptionValuesKeys(optionValues) {
32512      var optionValuesKeys;
32513
32514      if (!keyName && isArrayLike(optionValues)) {
32515        optionValuesKeys = optionValues;
32516      } else {
32517        // if object, extract keys, in enumeration order, unsorted
32518        optionValuesKeys = [];
32519        for (var itemKey in optionValues) {
32520          if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
32521            optionValuesKeys.push(itemKey);
32522          }
32523        }
32524      }
32525      return optionValuesKeys;
32526    }
32527
32528    return {
32529      trackBy: trackBy,
32530      getTrackByValue: getTrackByValue,
32531      getWatchables: $parse(valuesFn, function(optionValues) {
32532        // Create a collection of things that we would like to watch (watchedArray)
32533        // so that they can all be watched using a single $watchCollection
32534        // that only runs the handler once if anything changes
32535        var watchedArray = [];
32536        optionValues = optionValues || [];
32537
32538        var optionValuesKeys = getOptionValuesKeys(optionValues);
32539        var optionValuesLength = optionValuesKeys.length;
32540        for (var index = 0; index < optionValuesLength; index++) {
32541          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
32542          var value = optionValues[key];
32543
32544          var locals = getLocals(value, key);
32545          var selectValue = getTrackByValueFn(value, locals);
32546          watchedArray.push(selectValue);
32547
32548          // Only need to watch the displayFn if there is a specific label expression
32549          if (match[2] || match[1]) {
32550            var label = displayFn(scope, locals);
32551            watchedArray.push(label);
32552          }
32553
32554          // Only need to watch the disableWhenFn if there is a specific disable expression
32555          if (match[4]) {
32556            var disableWhen = disableWhenFn(scope, locals);
32557            watchedArray.push(disableWhen);
32558          }
32559        }
32560        return watchedArray;
32561      }),
32562
32563      getOptions: function() {
32564
32565        var optionItems = [];
32566        var selectValueMap = {};
32567
32568        // The option values were already computed in the `getWatchables` fn,
32569        // which must have been called to trigger `getOptions`
32570        var optionValues = valuesFn(scope) || [];
32571        var optionValuesKeys = getOptionValuesKeys(optionValues);
32572        var optionValuesLength = optionValuesKeys.length;
32573
32574        for (var index = 0; index < optionValuesLength; index++) {
32575          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
32576          var value = optionValues[key];
32577          var locals = getLocals(value, key);
32578          var viewValue = viewValueFn(scope, locals);
32579          var selectValue = getTrackByValueFn(viewValue, locals);
32580          var label = displayFn(scope, locals);
32581          var group = groupByFn(scope, locals);
32582          var disabled = disableWhenFn(scope, locals);
32583          var optionItem = new Option(selectValue, viewValue, label, group, disabled);
32584
32585          optionItems.push(optionItem);
32586          selectValueMap[selectValue] = optionItem;
32587        }
32588
32589        return {
32590          items: optionItems,
32591          selectValueMap: selectValueMap,
32592          getOptionFromViewValue: function(value) {
32593            return selectValueMap[getTrackByValue(value)];
32594          },
32595          getViewValueFromOption: function(option) {
32596            // If the viewValue could be an object that may be mutated by the application,
32597            // we need to make a copy and not return the reference to the value on the option.
32598            return trackBy ? copy(option.viewValue) : option.viewValue;
32599          }
32600        };
32601      }
32602    };
32603  }
32604
32605
32606  // Support: IE 9 only
32607  // We can't just jqLite('<option>') since jqLite is not smart enough
32608  // to create it in <select> and IE barfs otherwise.
32609  var optionTemplate = window.document.createElement('option'),
32610      optGroupTemplate = window.document.createElement('optgroup');
32611
32612    function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
32613
32614      var selectCtrl = ctrls[0];
32615      var ngModelCtrl = ctrls[1];
32616      var multiple = attr.multiple;
32617
32618      // The emptyOption allows the application developer to provide their own custom "empty"
32619      // option when the viewValue does not match any of the option values.
32620      for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
32621        if (children[i].value === '') {
32622          selectCtrl.hasEmptyOption = true;
32623          selectCtrl.emptyOption = children.eq(i);
32624          break;
32625        }
32626      }
32627
32628      // The empty option will be compiled and rendered before we first generate the options
32629      selectElement.empty();
32630
32631      var providedEmptyOption = !!selectCtrl.emptyOption;
32632
32633      var unknownOption = jqLite(optionTemplate.cloneNode(false));
32634      unknownOption.val('?');
32635
32636      var options;
32637      var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
32638      // This stores the newly created options before they are appended to the select.
32639      // Since the contents are removed from the fragment when it is appended,
32640      // we only need to create it once.
32641      var listFragment = $document[0].createDocumentFragment();
32642
32643      // Overwrite the implementation. ngOptions doesn't use hashes
32644      selectCtrl.generateUnknownOptionValue = function(val) {
32645        return '?';
32646      };
32647
32648      // Update the controller methods for multiple selectable options
32649      if (!multiple) {
32650
32651        selectCtrl.writeValue = function writeNgOptionsValue(value) {
32652          // The options might not be defined yet when ngModel tries to render
32653          if (!options) return;
32654
32655          var selectedOption = selectElement[0].options[selectElement[0].selectedIndex];
32656          var option = options.getOptionFromViewValue(value);
32657
32658          // Make sure to remove the selected attribute from the previously selected option
32659          // Otherwise, screen readers might get confused
32660          if (selectedOption) selectedOption.removeAttribute('selected');
32661
32662          if (option) {
32663            // Don't update the option when it is already selected.
32664            // For example, the browser will select the first option by default. In that case,
32665            // most properties are set automatically - except the `selected` attribute, which we
32666            // set always
32667
32668            if (selectElement[0].value !== option.selectValue) {
32669              selectCtrl.removeUnknownOption();
32670
32671              selectElement[0].value = option.selectValue;
32672              option.element.selected = true;
32673            }
32674
32675            option.element.setAttribute('selected', 'selected');
32676          } else {
32677            selectCtrl.selectUnknownOrEmptyOption(value);
32678          }
32679        };
32680
32681        selectCtrl.readValue = function readNgOptionsValue() {
32682
32683          var selectedOption = options.selectValueMap[selectElement.val()];
32684
32685          if (selectedOption && !selectedOption.disabled) {
32686            selectCtrl.unselectEmptyOption();
32687            selectCtrl.removeUnknownOption();
32688            return options.getViewValueFromOption(selectedOption);
32689          }
32690          return null;
32691        };
32692
32693        // If we are using `track by` then we must watch the tracked value on the model
32694        // since ngModel only watches for object identity change
32695        // FIXME: When a user selects an option, this watch will fire needlessly
32696        if (ngOptions.trackBy) {
32697          scope.$watch(
32698            function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
32699            function() { ngModelCtrl.$render(); }
32700          );
32701        }
32702
32703      } else {
32704
32705        selectCtrl.writeValue = function writeNgOptionsMultiple(values) {
32706          // The options might not be defined yet when ngModel tries to render
32707          if (!options) return;
32708
32709          // Only set `<option>.selected` if necessary, in order to prevent some browsers from
32710          // scrolling to `<option>` elements that are outside the `<select>` element's viewport.
32711          var selectedOptions = values && values.map(getAndUpdateSelectedOption) || [];
32712
32713          options.items.forEach(function(option) {
32714            if (option.element.selected && !includes(selectedOptions, option)) {
32715              option.element.selected = false;
32716            }
32717          });
32718        };
32719
32720
32721        selectCtrl.readValue = function readNgOptionsMultiple() {
32722          var selectedValues = selectElement.val() || [],
32723              selections = [];
32724
32725          forEach(selectedValues, function(value) {
32726            var option = options.selectValueMap[value];
32727            if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
32728          });
32729
32730          return selections;
32731        };
32732
32733        // If we are using `track by` then we must watch these tracked values on the model
32734        // since ngModel only watches for object identity change
32735        if (ngOptions.trackBy) {
32736
32737          scope.$watchCollection(function() {
32738            if (isArray(ngModelCtrl.$viewValue)) {
32739              return ngModelCtrl.$viewValue.map(function(value) {
32740                return ngOptions.getTrackByValue(value);
32741              });
32742            }
32743          }, function() {
32744            ngModelCtrl.$render();
32745          });
32746
32747        }
32748      }
32749
32750      if (providedEmptyOption) {
32751
32752        // compile the element since there might be bindings in it
32753        $compile(selectCtrl.emptyOption)(scope);
32754
32755        selectElement.prepend(selectCtrl.emptyOption);
32756
32757        if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
32758          // This means the empty option has currently no actual DOM node, probably because
32759          // it has been modified by a transclusion directive.
32760          selectCtrl.hasEmptyOption = false;
32761
32762          // Redefine the registerOption function, which will catch
32763          // options that are added by ngIf etc. (rendering of the node is async because of
32764          // lazy transclusion)
32765          selectCtrl.registerOption = function(optionScope, optionEl) {
32766            if (optionEl.val() === '') {
32767              selectCtrl.hasEmptyOption = true;
32768              selectCtrl.emptyOption = optionEl;
32769              selectCtrl.emptyOption.removeClass('ng-scope');
32770              // This ensures the new empty option is selected if previously no option was selected
32771              ngModelCtrl.$render();
32772
32773              optionEl.on('$destroy', function() {
32774                var needsRerender = selectCtrl.$isEmptyOptionSelected();
32775
32776                selectCtrl.hasEmptyOption = false;
32777                selectCtrl.emptyOption = undefined;
32778
32779                if (needsRerender) ngModelCtrl.$render();
32780              });
32781            }
32782          };
32783
32784        } else {
32785          // remove the class, which is added automatically because we recompile the element and it
32786          // becomes the compilation root
32787          selectCtrl.emptyOption.removeClass('ng-scope');
32788        }
32789
32790      }
32791
32792      // We will re-render the option elements if the option values or labels change
32793      scope.$watchCollection(ngOptions.getWatchables, updateOptions);
32794
32795      // ------------------------------------------------------------------ //
32796
32797      function addOptionElement(option, parent) {
32798        var optionElement = optionTemplate.cloneNode(false);
32799        parent.appendChild(optionElement);
32800        updateOptionElement(option, optionElement);
32801      }
32802
32803      function getAndUpdateSelectedOption(viewValue) {
32804        var option = options.getOptionFromViewValue(viewValue);
32805        var element = option && option.element;
32806
32807        if (element && !element.selected) element.selected = true;
32808
32809        return option;
32810      }
32811
32812      function updateOptionElement(option, element) {
32813        option.element = element;
32814        element.disabled = option.disabled;
32815        // Support: IE 11 only, Edge 12-13 only
32816        // NOTE: The label must be set before the value, otherwise IE 11 & Edge create unresponsive
32817        // selects in certain circumstances when multiple selects are next to each other and display
32818        // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
32819        // See https://github.com/angular/angular.js/issues/11314 for more info.
32820        // This is unfortunately untestable with unit / e2e tests
32821        if (option.label !== element.label) {
32822          element.label = option.label;
32823          element.textContent = option.label;
32824        }
32825        element.value = option.selectValue;
32826      }
32827
32828      function updateOptions() {
32829        var previousValue = options && selectCtrl.readValue();
32830
32831        // We must remove all current options, but cannot simply set innerHTML = null
32832        // since the providedEmptyOption might have an ngIf on it that inserts comments which we
32833        // must preserve.
32834        // Instead, iterate over the current option elements and remove them or their optgroup
32835        // parents
32836        if (options) {
32837
32838          for (var i = options.items.length - 1; i >= 0; i--) {
32839            var option = options.items[i];
32840            if (isDefined(option.group)) {
32841              jqLiteRemove(option.element.parentNode);
32842            } else {
32843              jqLiteRemove(option.element);
32844            }
32845          }
32846        }
32847
32848        options = ngOptions.getOptions();
32849
32850        var groupElementMap = {};
32851
32852        options.items.forEach(function addOption(option) {
32853          var groupElement;
32854
32855          if (isDefined(option.group)) {
32856
32857            // This option is to live in a group
32858            // See if we have already created this group
32859            groupElement = groupElementMap[option.group];
32860
32861            if (!groupElement) {
32862
32863              groupElement = optGroupTemplate.cloneNode(false);
32864              listFragment.appendChild(groupElement);
32865
32866              // Update the label on the group element
32867              // "null" is special cased because of Safari
32868              groupElement.label = option.group === null ? 'null' : option.group;
32869
32870              // Store it for use later
32871              groupElementMap[option.group] = groupElement;
32872            }
32873
32874            addOptionElement(option, groupElement);
32875
32876          } else {
32877
32878            // This option is not in a group
32879            addOptionElement(option, listFragment);
32880          }
32881        });
32882
32883        selectElement[0].appendChild(listFragment);
32884
32885        ngModelCtrl.$render();
32886
32887        // Check to see if the value has changed due to the update to the options
32888        if (!ngModelCtrl.$isEmpty(previousValue)) {
32889          var nextValue = selectCtrl.readValue();
32890          var isNotPrimitive = ngOptions.trackBy || multiple;
32891          if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
32892            ngModelCtrl.$setViewValue(nextValue);
32893            ngModelCtrl.$render();
32894          }
32895        }
32896      }
32897  }
32898
32899  return {
32900    restrict: 'A',
32901    terminal: true,
32902    require: ['select', 'ngModel'],
32903    link: {
32904      pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
32905        // Deactivate the SelectController.register method to prevent
32906        // option directives from accidentally registering themselves
32907        // (and unwanted $destroy handlers etc.)
32908        ctrls[0].registerOption = noop;
32909      },
32910      post: ngOptionsPostLink
32911    }
32912  };
32913}];
32914
32915/**
32916 * @ngdoc directive
32917 * @name ngPluralize
32918 * @restrict EA
32919 *
32920 * @description
32921 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
32922 * These rules are bundled with angular.js, but can be overridden
32923 * (see {@link guide/i18n AngularJS i18n} dev guide). You configure ngPluralize directive
32924 * by specifying the mappings between
32925 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
32926 * and the strings to be displayed.
32927 *
32928 * ## Plural categories and explicit number rules
32929 * There are two
32930 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
32931 * in AngularJS's default en-US locale: "one" and "other".
32932 *
32933 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
32934 * any number that is not 1), an explicit number rule can only match one number. For example, the
32935 * explicit number rule for "3" matches the number 3. There are examples of plural categories
32936 * and explicit number rules throughout the rest of this documentation.
32937 *
32938 * ## Configuring ngPluralize
32939 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
32940 * You can also provide an optional attribute, `offset`.
32941 *
32942 * The value of the `count` attribute can be either a string or an {@link guide/expression
32943 * AngularJS expression}; these are evaluated on the current scope for its bound value.
32944 *
32945 * The `when` attribute specifies the mappings between plural categories and the actual
32946 * string to be displayed. The value of the attribute should be a JSON object.
32947 *
32948 * The following example shows how to configure ngPluralize:
32949 *
32950 * ```html
32951 * <ng-pluralize count="personCount"
32952                 when="{'0': 'Nobody is viewing.',
32953 *                      'one': '1 person is viewing.',
32954 *                      'other': '{} people are viewing.'}">
32955 * </ng-pluralize>
32956 *```
32957 *
32958 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
32959 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
32960 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
32961 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
32962 * show "a dozen people are viewing".
32963 *
32964 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
32965 * into pluralized strings. In the previous example, AngularJS will replace `{}` with
32966 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
32967 * for <span ng-non-bindable>{{numberExpression}}</span>.
32968 *
32969 * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
32970 * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
32971 *
32972 * ## Configuring ngPluralize with offset
32973 * The `offset` attribute allows further customization of pluralized text, which can result in
32974 * a better user experience. For example, instead of the message "4 people are viewing this document",
32975 * you might display "John, Kate and 2 others are viewing this document".
32976 * The offset attribute allows you to offset a number by any desired value.
32977 * Let's take a look at an example:
32978 *
32979 * ```html
32980 * <ng-pluralize count="personCount" offset=2
32981 *               when="{'0': 'Nobody is viewing.',
32982 *                      '1': '{{person1}} is viewing.',
32983 *                      '2': '{{person1}} and {{person2}} are viewing.',
32984 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
32985 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
32986 * </ng-pluralize>
32987 * ```
32988 *
32989 * Notice that we are still using two plural categories(one, other), but we added
32990 * three explicit number rules 0, 1 and 2.
32991 * When one person, perhaps John, views the document, "John is viewing" will be shown.
32992 * When three people view the document, no explicit number rule is found, so
32993 * an offset of 2 is taken off 3, and AngularJS uses 1 to decide the plural category.
32994 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
32995 * is shown.
32996 *
32997 * Note that when you specify offsets, you must provide explicit number rules for
32998 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
32999 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
33000 * plural categories "one" and "other".
33001 *
33002 * @param {string|expression} count The variable to be bound to.
33003 * @param {string} when The mapping between plural category to its corresponding strings.
33004 * @param {number=} offset Offset to deduct from the total number.
33005 *
33006 * @example
33007    <example module="pluralizeExample" name="ng-pluralize">
33008      <file name="index.html">
33009        <script>
33010          angular.module('pluralizeExample', [])
33011            .controller('ExampleController', ['$scope', function($scope) {
33012              $scope.person1 = 'Igor';
33013              $scope.person2 = 'Misko';
33014              $scope.personCount = 1;
33015            }]);
33016        </script>
33017        <div ng-controller="ExampleController">
33018          <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
33019          <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
33020          <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
33021
33022          <!--- Example with simple pluralization rules for en locale --->
33023          Without Offset:
33024          <ng-pluralize count="personCount"
33025                        when="{'0': 'Nobody is viewing.',
33026                               'one': '1 person is viewing.',
33027                               'other': '{} people are viewing.'}">
33028          </ng-pluralize><br>
33029
33030          <!--- Example with offset --->
33031          With Offset(2):
33032          <ng-pluralize count="personCount" offset=2
33033                        when="{'0': 'Nobody is viewing.',
33034                               '1': '{{person1}} is viewing.',
33035                               '2': '{{person1}} and {{person2}} are viewing.',
33036                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
33037                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
33038          </ng-pluralize>
33039        </div>
33040      </file>
33041      <file name="protractor.js" type="protractor">
33042        it('should show correct pluralized string', function() {
33043          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
33044          var withOffset = element.all(by.css('ng-pluralize')).get(1);
33045          var countInput = element(by.model('personCount'));
33046
33047          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
33048          expect(withOffset.getText()).toEqual('Igor is viewing.');
33049
33050          countInput.clear();
33051          countInput.sendKeys('0');
33052
33053          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
33054          expect(withOffset.getText()).toEqual('Nobody is viewing.');
33055
33056          countInput.clear();
33057          countInput.sendKeys('2');
33058
33059          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
33060          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
33061
33062          countInput.clear();
33063          countInput.sendKeys('3');
33064
33065          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
33066          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
33067
33068          countInput.clear();
33069          countInput.sendKeys('4');
33070
33071          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
33072          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
33073        });
33074        it('should show data-bound names', function() {
33075          var withOffset = element.all(by.css('ng-pluralize')).get(1);
33076          var personCount = element(by.model('personCount'));
33077          var person1 = element(by.model('person1'));
33078          var person2 = element(by.model('person2'));
33079          personCount.clear();
33080          personCount.sendKeys('4');
33081          person1.clear();
33082          person1.sendKeys('Di');
33083          person2.clear();
33084          person2.sendKeys('Vojta');
33085          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
33086        });
33087      </file>
33088    </example>
33089 */
33090var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
33091  var BRACE = /{}/g,
33092      IS_WHEN = /^when(Minus)?(.+)$/;
33093
33094  return {
33095    link: function(scope, element, attr) {
33096      var numberExp = attr.count,
33097          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
33098          offset = attr.offset || 0,
33099          whens = scope.$eval(whenExp) || {},
33100          whensExpFns = {},
33101          startSymbol = $interpolate.startSymbol(),
33102          endSymbol = $interpolate.endSymbol(),
33103          braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
33104          watchRemover = angular.noop,
33105          lastCount;
33106
33107      forEach(attr, function(expression, attributeName) {
33108        var tmpMatch = IS_WHEN.exec(attributeName);
33109        if (tmpMatch) {
33110          var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
33111          whens[whenKey] = element.attr(attr.$attr[attributeName]);
33112        }
33113      });
33114      forEach(whens, function(expression, key) {
33115        whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
33116
33117      });
33118
33119      scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
33120        var count = parseFloat(newVal);
33121        var countIsNaN = isNumberNaN(count);
33122
33123        if (!countIsNaN && !(count in whens)) {
33124          // If an explicit number rule such as 1, 2, 3... is defined, just use it.
33125          // Otherwise, check it against pluralization rules in $locale service.
33126          count = $locale.pluralCat(count - offset);
33127        }
33128
33129        // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
33130        // In JS `NaN !== NaN`, so we have to explicitly check.
33131        if ((count !== lastCount) && !(countIsNaN && isNumberNaN(lastCount))) {
33132          watchRemover();
33133          var whenExpFn = whensExpFns[count];
33134          if (isUndefined(whenExpFn)) {
33135            if (newVal != null) {
33136              $log.debug('ngPluralize: no rule defined for \'' + count + '\' in ' + whenExp);
33137            }
33138            watchRemover = noop;
33139            updateElementText();
33140          } else {
33141            watchRemover = scope.$watch(whenExpFn, updateElementText);
33142          }
33143          lastCount = count;
33144        }
33145      });
33146
33147      function updateElementText(newText) {
33148        element.text(newText || '');
33149      }
33150    }
33151  };
33152}];
33153
33154/**
33155 * @ngdoc directive
33156 * @name ngRef
33157 * @restrict A
33158 *
33159 * @description
33160 * The `ngRef` attribute tells AngularJS to assign the controller of a component (or a directive)
33161 * to the given property in the current scope. It is also possible to add the jqlite-wrapped DOM
33162 * element to the scope.
33163 *
33164 * If the element with `ngRef` is destroyed `null` is assigned to the property.
33165 *
33166 * Note that if you want to assign from a child into the parent scope, you must initialize the
33167 * target property on the parent scope, otherwise `ngRef` will assign on the child scope.
33168 * This commonly happens when assigning elements or components wrapped in {@link ngIf} or
33169 * {@link ngRepeat}. See the second example below.
33170 *
33171 *
33172 * @element ANY
33173 * @param {string} ngRef property name - A valid AngularJS expression identifier to which the
33174 *                       controller or jqlite-wrapped DOM element will be bound.
33175 * @param {string=} ngRefRead read value - The name of a directive (or component) on this element,
33176 *                            or the special string `$element`. If a name is provided, `ngRef` will
33177 *                            assign the matching controller. If `$element` is provided, the element
33178 *                            itself is assigned (even if a controller is available).
33179 *
33180 *
33181 * @example
33182 * ### Simple toggle
33183 * This example shows how the controller of the component toggle
33184 * is reused in the template through the scope to use its logic.
33185 * <example name="ng-ref-component" module="myApp">
33186 *   <file name="index.html">
33187 *     <my-toggle ng-ref="myToggle"></my-toggle>
33188 *     <button ng-click="myToggle.toggle()">Toggle</button>
33189 *     <div ng-show="myToggle.isOpen()">
33190 *       You are using a component in the same template to show it.
33191 *     </div>
33192 *   </file>
33193 *   <file name="index.js">
33194 *     angular.module('myApp', [])
33195 *     .component('myToggle', {
33196 *       controller: function ToggleController() {
33197 *         var opened = false;
33198 *         this.isOpen = function() { return opened; };
33199 *         this.toggle = function() { opened = !opened; };
33200 *       }
33201 *     });
33202 *   </file>
33203 *   <file name="protractor.js" type="protractor">
33204 *      it('should publish the toggle into the scope', function() {
33205 *        var toggle = element(by.buttonText('Toggle'));
33206 *        expect(toggle.evaluate('myToggle.isOpen()')).toEqual(false);
33207 *        toggle.click();
33208 *        expect(toggle.evaluate('myToggle.isOpen()')).toEqual(true);
33209 *      });
33210 *   </file>
33211 * </example>
33212 *
33213 * @example
33214 * ### ngRef inside scopes
33215 * This example shows how `ngRef` works with child scopes. The `ngRepeat`-ed `myWrapper` components
33216 * are assigned to the scope of `myRoot`, because the `toggles` property has been initialized.
33217 * The repeated `myToggle` components are published to the child scopes created by `ngRepeat`.
33218 * `ngIf` behaves similarly - the assignment of `myToggle` happens in the `ngIf` child scope,
33219 * because the target property has not been initialized on the `myRoot` component controller.
33220 *
33221 * <example name="ng-ref-scopes" module="myApp">
33222 *   <file name="index.html">
33223 *     <my-root></my-root>
33224 *   </file>
33225 *   <file name="index.js">
33226 *     angular.module('myApp', [])
33227 *     .component('myRoot', {
33228 *       templateUrl: 'root.html',
33229 *       controller: function() {
33230 *         this.wrappers = []; // initialize the array so that the wrappers are assigned into the parent scope
33231 *       }
33232 *     })
33233 *     .component('myToggle', {
33234 *       template: '<strong>myToggle</strong><button ng-click="$ctrl.toggle()" ng-transclude></button>',
33235 *       transclude: true,
33236 *       controller: function ToggleController() {
33237 *         var opened = false;
33238 *         this.isOpen = function() { return opened; };
33239 *         this.toggle = function() { opened = !opened; };
33240 *       }
33241 *     })
33242 *     .component('myWrapper', {
33243 *       transclude: true,
33244 *       template: '<strong>myWrapper</strong>' +
33245 *         '<div>ngRepeatToggle.isOpen(): {{$ctrl.ngRepeatToggle.isOpen() | json}}</div>' +
33246 *         '<my-toggle ng-ref="$ctrl.ngRepeatToggle"><ng-transclude></ng-transclude></my-toggle>'
33247 *     });
33248 *   </file>
33249 *   <file name="root.html">
33250 *     <strong>myRoot</strong>
33251 *     <my-toggle ng-ref="$ctrl.outerToggle">Outer Toggle</my-toggle>
33252 *     <div>outerToggle.isOpen(): {{$ctrl.outerToggle.isOpen() | json}}</div>
33253 *     <div><em>wrappers assigned to root</em><br>
33254 *     <div ng-repeat="wrapper in $ctrl.wrappers">
33255 *       wrapper.ngRepeatToggle.isOpen(): {{wrapper.ngRepeatToggle.isOpen() | json}}
33256 *     </div>
33257 *
33258 *     <ul>
33259 *       <li ng-repeat="(index, value) in [1,2,3]">
33260 *         <strong>ngRepeat</strong>
33261 *         <div>outerToggle.isOpen(): {{$ctrl.outerToggle.isOpen() | json}}</div>
33262 *         <my-wrapper ng-ref="$ctrl.wrappers[index]">ngRepeat Toggle {{$index + 1}}</my-wrapper>
33263 *       </li>
33264 *     </ul>
33265 *
33266 *     <div>ngIfToggle.isOpen(): {{ngIfToggle.isOpen()}} // This is always undefined because it's
33267 *       assigned to the child scope created by ngIf.
33268 *     </div>
33269 *     <div ng-if="true">
33270          <strong>ngIf</strong>
33271 *        <my-toggle ng-ref="ngIfToggle">ngIf Toggle</my-toggle>
33272 *        <div>ngIfToggle.isOpen(): {{ngIfToggle.isOpen() | json}}</div>
33273 *        <div>outerToggle.isOpen(): {{$ctrl.outerToggle.isOpen() | json}}</div>
33274 *     </div>
33275 *   </file>
33276 *   <file name="styles.css">
33277 *     ul {
33278 *       list-style: none;
33279 *       padding-left: 0;
33280 *     }
33281 *
33282 *     li[ng-repeat] {
33283 *       background: lightgreen;
33284 *       padding: 8px;
33285 *       margin: 8px;
33286 *     }
33287 *
33288 *     [ng-if] {
33289 *       background: lightgrey;
33290 *       padding: 8px;
33291 *     }
33292 *
33293 *     my-root {
33294 *       background: lightgoldenrodyellow;
33295 *       padding: 8px;
33296 *       display: block;
33297 *     }
33298 *
33299 *     my-wrapper {
33300 *       background: lightsalmon;
33301 *       padding: 8px;
33302 *       display: block;
33303 *     }
33304 *
33305 *     my-toggle {
33306 *       background: lightblue;
33307 *       padding: 8px;
33308 *       display: block;
33309 *     }
33310 *   </file>
33311 *   <file name="protractor.js" type="protractor">
33312 *      var OuterToggle = function() {
33313 *        this.toggle = function() {
33314 *          element(by.buttonText('Outer Toggle')).click();
33315 *        };
33316 *        this.isOpen = function() {
33317 *          return element.all(by.binding('outerToggle.isOpen()')).first().getText();
33318 *        };
33319 *      };
33320 *      var NgRepeatToggle = function(i) {
33321 *        var parent = element.all(by.repeater('(index, value) in [1,2,3]')).get(i - 1);
33322 *        this.toggle = function() {
33323 *          element(by.buttonText('ngRepeat Toggle ' + i)).click();
33324 *        };
33325 *        this.isOpen = function() {
33326 *          return parent.element(by.binding('ngRepeatToggle.isOpen() | json')).getText();
33327 *        };
33328 *        this.isOuterOpen = function() {
33329 *          return parent.element(by.binding('outerToggle.isOpen() | json')).getText();
33330 *        };
33331 *      };
33332 *      var NgRepeatToggles = function() {
33333 *        var toggles = [1,2,3].map(function(i) { return new NgRepeatToggle(i); });
33334 *        this.forEach = function(fn) {
33335 *          toggles.forEach(fn);
33336 *        };
33337 *        this.isOuterOpen = function(i) {
33338 *          return toggles[i - 1].isOuterOpen();
33339 *        };
33340 *      };
33341 *      var NgIfToggle = function() {
33342 *        var parent = element(by.css('[ng-if]'));
33343 *        this.toggle = function() {
33344 *          element(by.buttonText('ngIf Toggle')).click();
33345 *        };
33346 *        this.isOpen = function() {
33347 *          return by.binding('ngIfToggle.isOpen() | json').getText();
33348 *        };
33349 *        this.isOuterOpen = function() {
33350 *          return parent.element(by.binding('outerToggle.isOpen() | json')).getText();
33351 *        };
33352 *      };
33353 *
33354 *      it('should toggle the outer toggle', function() {
33355 *        var outerToggle = new OuterToggle();
33356 *        expect(outerToggle.isOpen()).toEqual('outerToggle.isOpen(): false');
33357 *        outerToggle.toggle();
33358 *        expect(outerToggle.isOpen()).toEqual('outerToggle.isOpen(): true');
33359 *      });
33360 *
33361 *      it('should toggle all outer toggles', function() {
33362 *        var outerToggle = new OuterToggle();
33363 *        var repeatToggles = new NgRepeatToggles();
33364 *        var ifToggle = new NgIfToggle();
33365 *        expect(outerToggle.isOpen()).toEqual('outerToggle.isOpen(): false');
33366 *        expect(repeatToggles.isOuterOpen(1)).toEqual('outerToggle.isOpen(): false');
33367 *        expect(repeatToggles.isOuterOpen(2)).toEqual('outerToggle.isOpen(): false');
33368 *        expect(repeatToggles.isOuterOpen(3)).toEqual('outerToggle.isOpen(): false');
33369 *        expect(ifToggle.isOuterOpen()).toEqual('outerToggle.isOpen(): false');
33370 *        outerToggle.toggle();
33371 *        expect(outerToggle.isOpen()).toEqual('outerToggle.isOpen(): true');
33372 *        expect(repeatToggles.isOuterOpen(1)).toEqual('outerToggle.isOpen(): true');
33373 *        expect(repeatToggles.isOuterOpen(2)).toEqual('outerToggle.isOpen(): true');
33374 *        expect(repeatToggles.isOuterOpen(3)).toEqual('outerToggle.isOpen(): true');
33375 *        expect(ifToggle.isOuterOpen()).toEqual('outerToggle.isOpen(): true');
33376 *      });
33377 *
33378 *      it('should toggle each repeat iteration separately', function() {
33379 *        var repeatToggles = new NgRepeatToggles();
33380 *
33381 *        repeatToggles.forEach(function(repeatToggle) {
33382 *          expect(repeatToggle.isOpen()).toEqual('ngRepeatToggle.isOpen(): false');
33383 *          expect(repeatToggle.isOuterOpen()).toEqual('outerToggle.isOpen(): false');
33384 *          repeatToggle.toggle();
33385 *          expect(repeatToggle.isOpen()).toEqual('ngRepeatToggle.isOpen(): true');
33386 *          expect(repeatToggle.isOuterOpen()).toEqual('outerToggle.isOpen(): false');
33387 *        });
33388 *      });
33389 *   </file>
33390 * </example>
33391 *
33392 */
33393
33394var ngRefMinErr = minErr('ngRef');
33395
33396var ngRefDirective = ['$parse', function($parse) {
33397  return {
33398    priority: -1, // Needed for compatibility with element transclusion on the same element
33399    restrict: 'A',
33400    compile: function(tElement, tAttrs) {
33401      // Get the expected controller name, converts <data-some-thing> into "someThing"
33402      var controllerName = directiveNormalize(nodeName_(tElement));
33403
33404      // Get the expression for value binding
33405      var getter = $parse(tAttrs.ngRef);
33406      var setter = getter.assign || function() {
33407        throw ngRefMinErr('nonassign', 'Expression in ngRef="{0}" is non-assignable!', tAttrs.ngRef);
33408      };
33409
33410      return function(scope, element, attrs) {
33411        var refValue;
33412
33413        if (attrs.hasOwnProperty('ngRefRead')) {
33414          if (attrs.ngRefRead === '$element') {
33415            refValue = element;
33416          } else {
33417            refValue = element.data('$' + attrs.ngRefRead + 'Controller');
33418
33419            if (!refValue) {
33420              throw ngRefMinErr(
33421                'noctrl',
33422                'The controller for ngRefRead="{0}" could not be found on ngRef="{1}"',
33423                attrs.ngRefRead,
33424                tAttrs.ngRef
33425              );
33426            }
33427          }
33428        } else {
33429          refValue = element.data('$' + controllerName + 'Controller');
33430        }
33431
33432        refValue = refValue || element;
33433
33434        setter(scope, refValue);
33435
33436        // when the element is removed, remove it (nullify it)
33437        element.on('$destroy', function() {
33438          // only remove it if value has not changed,
33439          // because animations (and other procedures) may duplicate elements
33440          if (getter(scope) === refValue) {
33441            setter(scope, null);
33442          }
33443        });
33444      };
33445    }
33446  };
33447}];
33448
33449/* exported ngRepeatDirective */
33450
33451/**
33452 * @ngdoc directive
33453 * @name ngRepeat
33454 * @multiElement
33455 * @restrict A
33456 *
33457 * @description
33458 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
33459 * instance gets its own scope, where the given loop variable is set to the current collection item,
33460 * and `$index` is set to the item index or key.
33461 *
33462 * Special properties are exposed on the local scope of each template instance, including:
33463 *
33464 * | Variable  | Type            | Details                                                                     |
33465 * |-----------|-----------------|-----------------------------------------------------------------------------|
33466 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
33467 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
33468 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
33469 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
33470 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
33471 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
33472 *
33473 * <div class="alert alert-info">
33474 *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
33475 *   This may be useful when, for instance, nesting ngRepeats.
33476 * </div>
33477 *
33478 *
33479 * ## Iterating over object properties
33480 *
33481 * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
33482 * syntax:
33483 *
33484 * ```js
33485 * <div ng-repeat="(key, value) in myObj"> ... </div>
33486 * ```
33487 *
33488 * However, there are a few limitations compared to array iteration:
33489 *
33490 * - The JavaScript specification does not define the order of keys
33491 *   returned for an object, so AngularJS relies on the order returned by the browser
33492 *   when running `for key in myObj`. Browsers generally follow the strategy of providing
33493 *   keys in the order in which they were defined, although there are exceptions when keys are deleted
33494 *   and reinstated. See the
33495 *   [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
33496 *
33497 * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
33498 *   it's a prefix used by AngularJS for public (`$`) and private (`$$`) properties.
33499 *
33500 * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
33501 *   objects, and will throw an error if used with one.
33502 *
33503 * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
33504 * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
33505 * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
33506 * or implement a `$watch` on the object yourself.
33507 *
33508 *
33509 * ## Tracking and Duplicates
33510 *
33511 * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
33512 * the collection. When a change happens, `ngRepeat` then makes the corresponding changes to the DOM:
33513 *
33514 * * When an item is added, a new instance of the template is added to the DOM.
33515 * * When an item is removed, its template instance is removed from the DOM.
33516 * * When items are reordered, their respective templates are reordered in the DOM.
33517 *
33518 * To minimize creation of DOM elements, `ngRepeat` uses a function
33519 * to "keep track" of all items in the collection and their corresponding DOM elements.
33520 * For example, if an item is added to the collection, `ngRepeat` will know that all other items
33521 * already have DOM elements, and will not re-render them.
33522 *
33523 * All different types of tracking functions, their syntax, and their support for duplicate
33524 * items in collections can be found in the
33525 * {@link ngRepeat#ngRepeat-arguments ngRepeat expression description}.
33526 *
33527 * <div class="alert alert-success">
33528 * **Best Practice:** If you are working with objects that have a unique identifier property, you
33529 * should track by this identifier instead of the object instance,
33530 * e.g. `item in items track by item.id`.
33531 * Should you reload your data later, `ngRepeat` will not have to rebuild the DOM elements for items
33532 * it has already rendered, even if the JavaScript objects in the collection have been substituted
33533 * for new ones. For large collections, this significantly improves rendering performance.
33534 * </div>
33535 *
33536 * ### Effects of DOM Element re-use
33537 *
33538 * When DOM elements are re-used, ngRepeat updates the scope for the element, which will
33539 * automatically update any active bindings on the template. However, other
33540 * functionality will not be updated, because the element is not re-created:
33541 *
33542 * - Directives are not re-compiled
33543 * - {@link guide/expression#one-time-binding one-time expressions} on the repeated template are not
33544 * updated if they have stabilized.
33545 *
33546 * The above affects all kinds of element re-use due to tracking, but may be especially visible
33547 * when tracking by `$index` due to the way ngRepeat re-uses elements.
33548 *
33549 * The following example shows the effects of different actions with tracking:
33550
33551  <example module="ngRepeat" name="ngRepeat-tracking" deps="angular-animate.js" animations="true">
33552    <file name="script.js">
33553      angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
33554        var friends = [
33555          {name:'John', age:25},
33556          {name:'Mary', age:40},
33557          {name:'Peter', age:85}
33558        ];
33559
33560        $scope.removeFirst = function() {
33561          $scope.friends.shift();
33562        };
33563
33564        $scope.updateAge = function() {
33565          $scope.friends.forEach(function(el) {
33566            el.age = el.age + 5;
33567          });
33568        };
33569
33570        $scope.copy = function() {
33571          $scope.friends = angular.copy($scope.friends);
33572        };
33573
33574        $scope.reset = function() {
33575          $scope.friends = angular.copy(friends);
33576        };
33577
33578        $scope.reset();
33579      });
33580    </file>
33581    <file name="index.html">
33582      <div ng-controller="repeatController">
33583        <ol>
33584          <li>When you click "Update Age", only the first list updates the age, because all others have
33585          a one-time binding on the age property. If you then click "Copy", the current friend list
33586          is copied, and now the second list updates the age, because the identity of the collection items
33587          has changed and the list must be re-rendered. The 3rd and 4th list stay the same, because all the
33588          items are already known according to their tracking functions.
33589          </li>
33590          <li>When you click "Remove First", the 4th list has the wrong age on both remaining items. This is
33591          due to tracking by $index: when the first collection item is removed, ngRepeat reuses the first
33592          DOM element for the new first collection item, and so on. Since the age property is one-time
33593          bound, the value remains from the collection item which was previously at this index.
33594          </li>
33595        </ol>
33596
33597        <button ng-click="removeFirst()">Remove First</button>
33598        <button ng-click="updateAge()">Update Age</button>
33599        <button ng-click="copy()">Copy</button>
33600        <br><button ng-click="reset()">Reset List</button>
33601        <br>
33602        <code>track by $id(friend)</code> (default):
33603        <ul class="example-animate-container">
33604          <li class="animate-repeat" ng-repeat="friend in friends">
33605            {{friend.name}} is {{friend.age}} years old.
33606          </li>
33607        </ul>
33608        <code>track by $id(friend)</code> (default), with age one-time binding:
33609        <ul class="example-animate-container">
33610          <li class="animate-repeat" ng-repeat="friend in friends">
33611            {{friend.name}} is {{::friend.age}} years old.
33612          </li>
33613        </ul>
33614        <code>track by friend.name</code>, with age one-time binding:
33615        <ul class="example-animate-container">
33616          <li class="animate-repeat" ng-repeat="friend in friends track by friend.name">
33617            {{friend.name}}  is {{::friend.age}} years old.
33618          </li>
33619        </ul>
33620        <code>track by $index</code>, with age one-time binding:
33621        <ul class="example-animate-container">
33622          <li class="animate-repeat" ng-repeat="friend in friends track by $index">
33623            {{friend.name}} is {{::friend.age}} years old.
33624          </li>
33625        </ul>
33626      </div>
33627    </file>
33628    <file name="animations.css">
33629      .example-animate-container {
33630        background:white;
33631        border:1px solid black;
33632        list-style:none;
33633        margin:0;
33634        padding:0 10px;
33635      }
33636
33637      .animate-repeat {
33638        line-height:30px;
33639        list-style:none;
33640        box-sizing:border-box;
33641      }
33642
33643      .animate-repeat.ng-move,
33644      .animate-repeat.ng-enter,
33645      .animate-repeat.ng-leave {
33646        transition:all linear 0.5s;
33647      }
33648
33649      .animate-repeat.ng-leave.ng-leave-active,
33650      .animate-repeat.ng-move,
33651      .animate-repeat.ng-enter {
33652        opacity:0;
33653        max-height:0;
33654      }
33655
33656      .animate-repeat.ng-leave,
33657      .animate-repeat.ng-move.ng-move-active,
33658      .animate-repeat.ng-enter.ng-enter-active {
33659        opacity:1;
33660        max-height:30px;
33661      }
33662    </file>
33663  </example>
33664
33665 *
33666 * ## Special repeat start and end points
33667 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
33668 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
33669 * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
33670 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
33671 *
33672 * The example below makes use of this feature:
33673 * ```html
33674 *   <header ng-repeat-start="item in items">
33675 *     Header {{ item }}
33676 *   </header>
33677 *   <div class="body">
33678 *     Body {{ item }}
33679 *   </div>
33680 *   <footer ng-repeat-end>
33681 *     Footer {{ item }}
33682 *   </footer>
33683 * ```
33684 *
33685 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
33686 * ```html
33687 *   <header>
33688 *     Header A
33689 *   </header>
33690 *   <div class="body">
33691 *     Body A
33692 *   </div>
33693 *   <footer>
33694 *     Footer A
33695 *   </footer>
33696 *   <header>
33697 *     Header B
33698 *   </header>
33699 *   <div class="body">
33700 *     Body B
33701 *   </div>
33702 *   <footer>
33703 *     Footer B
33704 *   </footer>
33705 * ```
33706 *
33707 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
33708 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
33709 *
33710 * @animations
33711 * | Animation                        | Occurs                              |
33712 * |----------------------------------|-------------------------------------|
33713 * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
33714 * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
33715 * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
33716 *
33717 * See the example below for defining CSS animations with ngRepeat.
33718 *
33719 * @element ANY
33720 * @scope
33721 * @priority 1000
33722 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
33723 *   formats are currently supported:
33724 *
33725 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
33726 *     is a scope expression giving the collection to enumerate.
33727 *
33728 *     For example: `album in artist.albums`.
33729 *
33730 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
33731 *     and `expression` is the scope expression giving the collection to enumerate.
33732 *
33733 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
33734 *
33735 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
33736 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
33737 *     is specified, ng-repeat associates elements by identity. It is an error to have
33738 *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
33739 *     mapped to the same DOM element, which is not possible.)
33740 *
33741 *     *Default tracking: $id()*: `item in items` is equivalent to `item in items track by $id(item)`.
33742 *     This implies that the DOM elements will be associated by item identity in the collection.
33743 *
33744 *     The built-in `$id()` function can be used to assign a unique
33745 *     `$$hashKey` property to each item in the collection. This property is then used as a key to associated DOM elements
33746 *     with the corresponding item in the collection by identity. Moving the same object would move
33747 *     the DOM element in the same way in the DOM.
33748 *     Note that the default id function does not support duplicate primitive values (`number`, `string`),
33749 *     but supports duplictae non-primitive values (`object`) that are *equal* in shape.
33750 *
33751 *     *Custom Expression*: It is possible to use any AngularJS expression to compute the tracking
33752 *     id, for example with a function, or using a property on the collection items.
33753 *     `item in items track by item.id` is a typical pattern when the items have a unique identifier,
33754 *     e.g. database id. In this case the object identity does not matter. Two objects are considered
33755 *     equivalent as long as their `id` property is same.
33756 *     Tracking by unique identifier is the most performant way and should be used whenever possible.
33757 *
33758 *     *$index*: This special property tracks the collection items by their index, and
33759 *     re-uses the DOM elements that match that index, e.g. `item in items track by $index`. This can
33760 *     be used for a performance improvement if no unique identfier is available and the identity of
33761 *     the collection items cannot be easily computed. It also allows duplicates.
33762 *
33763 *     <div class="alert alert-warning">
33764 *       <strong>Note:</strong> Re-using DOM elements can have unforeseen effects. Read the
33765 *       {@link ngRepeat#tracking-and-duplicates section on tracking and duplicates} for
33766 *       more info.
33767 *     </div>
33768 *
33769 *     <div class="alert alert-warning">
33770 *       <strong>Note:</strong> the `track by` expression must come last - after any filters, and the alias expression:
33771 *       `item in items | filter:searchText as results  track by item.id`
33772 *     </div>
33773 *
33774 *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
33775 *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
33776 *     when a filter is active on the repeater, but the filtered result set is empty.
33777 *
33778 *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
33779 *     the items have been processed through the filter.
33780 *
33781 *     Please note that `as [variable name]` is not an operator but rather a part of ngRepeat
33782 *     micro-syntax so it can be used only after all filters (and not as operator, inside an expression).
33783 *
33784 *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results track by item.id` .
33785 *
33786 * @example
33787 * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
33788 * results by name or by age. New (entering) and removed (leaving) items are animated.
33789  <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
33790    <file name="index.html">
33791      <div ng-controller="repeatController">
33792        I have {{friends.length}} friends. They are:
33793        <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
33794        <ul class="example-animate-container">
33795          <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results track by friend.name">
33796            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
33797          </li>
33798          <li class="animate-repeat" ng-if="results.length === 0">
33799            <strong>No results found...</strong>
33800          </li>
33801        </ul>
33802      </div>
33803    </file>
33804    <file name="script.js">
33805      angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
33806        $scope.friends = [
33807          {name:'John', age:25, gender:'boy'},
33808          {name:'Jessie', age:30, gender:'girl'},
33809          {name:'Johanna', age:28, gender:'girl'},
33810          {name:'Joy', age:15, gender:'girl'},
33811          {name:'Mary', age:28, gender:'girl'},
33812          {name:'Peter', age:95, gender:'boy'},
33813          {name:'Sebastian', age:50, gender:'boy'},
33814          {name:'Erika', age:27, gender:'girl'},
33815          {name:'Patrick', age:40, gender:'boy'},
33816          {name:'Samantha', age:60, gender:'girl'}
33817        ];
33818      });
33819    </file>
33820    <file name="animations.css">
33821      .example-animate-container {
33822        background:white;
33823        border:1px solid black;
33824        list-style:none;
33825        margin:0;
33826        padding:0 10px;
33827      }
33828
33829      .animate-repeat {
33830        line-height:30px;
33831        list-style:none;
33832        box-sizing:border-box;
33833      }
33834
33835      .animate-repeat.ng-move,
33836      .animate-repeat.ng-enter,
33837      .animate-repeat.ng-leave {
33838        transition:all linear 0.5s;
33839      }
33840
33841      .animate-repeat.ng-leave.ng-leave-active,
33842      .animate-repeat.ng-move,
33843      .animate-repeat.ng-enter {
33844        opacity:0;
33845        max-height:0;
33846      }
33847
33848      .animate-repeat.ng-leave,
33849      .animate-repeat.ng-move.ng-move-active,
33850      .animate-repeat.ng-enter.ng-enter-active {
33851        opacity:1;
33852        max-height:30px;
33853      }
33854    </file>
33855    <file name="protractor.js" type="protractor">
33856      var friends = element.all(by.repeater('friend in friends'));
33857
33858      it('should render initial data set', function() {
33859        expect(friends.count()).toBe(10);
33860        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
33861        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
33862        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
33863        expect(element(by.binding('friends.length')).getText())
33864            .toMatch("I have 10 friends. They are:");
33865      });
33866
33867       it('should update repeater when filter predicate changes', function() {
33868         expect(friends.count()).toBe(10);
33869
33870         element(by.model('q')).sendKeys('ma');
33871
33872         expect(friends.count()).toBe(2);
33873         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
33874         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
33875       });
33876      </file>
33877    </example>
33878 */
33879var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
33880  var NG_REMOVED = '$$NG_REMOVED';
33881  var ngRepeatMinErr = minErr('ngRepeat');
33882
33883  var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
33884    // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
33885    scope[valueIdentifier] = value;
33886    if (keyIdentifier) scope[keyIdentifier] = key;
33887    scope.$index = index;
33888    scope.$first = (index === 0);
33889    scope.$last = (index === (arrayLength - 1));
33890    scope.$middle = !(scope.$first || scope.$last);
33891    // eslint-disable-next-line no-bitwise
33892    scope.$odd = !(scope.$even = (index & 1) === 0);
33893  };
33894
33895  var getBlockStart = function(block) {
33896    return block.clone[0];
33897  };
33898
33899  var getBlockEnd = function(block) {
33900    return block.clone[block.clone.length - 1];
33901  };
33902
33903  var trackByIdArrayFn = function($scope, key, value) {
33904    return hashKey(value);
33905  };
33906
33907  var trackByIdObjFn = function($scope, key) {
33908    return key;
33909  };
33910
33911  return {
33912    restrict: 'A',
33913    multiElement: true,
33914    transclude: 'element',
33915    priority: 1000,
33916    terminal: true,
33917    $$tlb: true,
33918    compile: function ngRepeatCompile($element, $attr) {
33919      var expression = $attr.ngRepeat;
33920      var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
33921
33922      var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
33923
33924      if (!match) {
33925        throw ngRepeatMinErr('iexp', 'Expected expression in form of \'_item_ in _collection_[ track by _id_]\' but got \'{0}\'.',
33926            expression);
33927      }
33928
33929      var lhs = match[1];
33930      var rhs = match[2];
33931      var aliasAs = match[3];
33932      var trackByExp = match[4];
33933
33934      match = lhs.match(/^(?:(\s*[$\w]+)|\(\s*([$\w]+)\s*,\s*([$\w]+)\s*\))$/);
33935
33936      if (!match) {
33937        throw ngRepeatMinErr('iidexp', '\'_item_\' in \'_item_ in _collection_\' should be an identifier or \'(_key_, _value_)\' expression, but got \'{0}\'.',
33938            lhs);
33939      }
33940      var valueIdentifier = match[3] || match[1];
33941      var keyIdentifier = match[2];
33942
33943      if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
33944          /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
33945        throw ngRepeatMinErr('badident', 'alias \'{0}\' is invalid --- must be a valid JS identifier which is not a reserved name.',
33946          aliasAs);
33947      }
33948
33949      var trackByIdExpFn;
33950
33951      if (trackByExp) {
33952        var hashFnLocals = {$id: hashKey};
33953        var trackByExpGetter = $parse(trackByExp);
33954
33955        trackByIdExpFn = function($scope, key, value, index) {
33956          // assign key, value, and $index to the locals so that they can be used in hash functions
33957          if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
33958          hashFnLocals[valueIdentifier] = value;
33959          hashFnLocals.$index = index;
33960          return trackByExpGetter($scope, hashFnLocals);
33961        };
33962      }
33963
33964      return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
33965
33966        // Store a list of elements from previous run. This is a hash where key is the item from the
33967        // iterator, and the value is objects with following properties.
33968        //   - scope: bound scope
33969        //   - clone: previous element.
33970        //   - index: position
33971        //
33972        // We are using no-proto object so that we don't need to guard against inherited props via
33973        // hasOwnProperty.
33974        var lastBlockMap = createMap();
33975
33976        //watch props
33977        $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
33978          var index, length,
33979              previousNode = $element[0],     // node that cloned nodes should be inserted after
33980                                              // initialized to the comment node anchor
33981              nextNode,
33982              // Same as lastBlockMap but it has the current state. It will become the
33983              // lastBlockMap on the next iteration.
33984              nextBlockMap = createMap(),
33985              collectionLength,
33986              key, value, // key/value of iteration
33987              trackById,
33988              trackByIdFn,
33989              collectionKeys,
33990              block,       // last object information {scope, element, id}
33991              nextBlockOrder,
33992              elementsToRemove;
33993
33994          if (aliasAs) {
33995            $scope[aliasAs] = collection;
33996          }
33997
33998          if (isArrayLike(collection)) {
33999            collectionKeys = collection;
34000            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
34001          } else {
34002            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
34003            // if object, extract keys, in enumeration order, unsorted
34004            collectionKeys = [];
34005            for (var itemKey in collection) {
34006              if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
34007                collectionKeys.push(itemKey);
34008              }
34009            }
34010          }
34011
34012          collectionLength = collectionKeys.length;
34013          nextBlockOrder = new Array(collectionLength);
34014
34015          // locate existing items
34016          for (index = 0; index < collectionLength; index++) {
34017            key = (collection === collectionKeys) ? index : collectionKeys[index];
34018            value = collection[key];
34019            trackById = trackByIdFn($scope, key, value, index);
34020            if (lastBlockMap[trackById]) {
34021              // found previously seen block
34022              block = lastBlockMap[trackById];
34023              delete lastBlockMap[trackById];
34024              nextBlockMap[trackById] = block;
34025              nextBlockOrder[index] = block;
34026            } else if (nextBlockMap[trackById]) {
34027              // if collision detected. restore lastBlockMap and throw an error
34028              forEach(nextBlockOrder, function(block) {
34029                if (block && block.scope) lastBlockMap[block.id] = block;
34030              });
34031              throw ngRepeatMinErr('dupes',
34032                  'Duplicates in a repeater are not allowed. Use \'track by\' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}',
34033                  expression, trackById, value);
34034            } else {
34035              // new never before seen block
34036              nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
34037              nextBlockMap[trackById] = true;
34038            }
34039          }
34040
34041          // Clear the value property from the hashFnLocals object to prevent a reference to the last value
34042          // being leaked into the ngRepeatCompile function scope
34043          if (hashFnLocals) {
34044            hashFnLocals[valueIdentifier] = undefined;
34045          }
34046
34047          // remove leftover items
34048          for (var blockKey in lastBlockMap) {
34049            block = lastBlockMap[blockKey];
34050            elementsToRemove = getBlockNodes(block.clone);
34051            $animate.leave(elementsToRemove);
34052            if (elementsToRemove[0].parentNode) {
34053              // if the element was not removed yet because of pending animation, mark it as deleted
34054              // so that we can ignore it later
34055              for (index = 0, length = elementsToRemove.length; index < length; index++) {
34056                elementsToRemove[index][NG_REMOVED] = true;
34057              }
34058            }
34059            block.scope.$destroy();
34060          }
34061
34062          // we are not using forEach for perf reasons (trying to avoid #call)
34063          for (index = 0; index < collectionLength; index++) {
34064            key = (collection === collectionKeys) ? index : collectionKeys[index];
34065            value = collection[key];
34066            block = nextBlockOrder[index];
34067
34068            if (block.scope) {
34069              // if we have already seen this object, then we need to reuse the
34070              // associated scope/element
34071
34072              nextNode = previousNode;
34073
34074              // skip nodes that are already pending removal via leave animation
34075              do {
34076                nextNode = nextNode.nextSibling;
34077              } while (nextNode && nextNode[NG_REMOVED]);
34078
34079              if (getBlockStart(block) !== nextNode) {
34080                // existing item which got moved
34081                $animate.move(getBlockNodes(block.clone), null, previousNode);
34082              }
34083              previousNode = getBlockEnd(block);
34084              updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
34085            } else {
34086              // new item which we don't know about
34087              $transclude(function ngRepeatTransclude(clone, scope) {
34088                block.scope = scope;
34089                // http://jsperf.com/clone-vs-createcomment
34090                var endNode = ngRepeatEndComment.cloneNode(false);
34091                clone[clone.length++] = endNode;
34092
34093                $animate.enter(clone, null, previousNode);
34094                previousNode = endNode;
34095                // Note: We only need the first/last node of the cloned nodes.
34096                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
34097                // by a directive with templateUrl when its template arrives.
34098                block.clone = clone;
34099                nextBlockMap[block.id] = block;
34100                updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
34101              });
34102            }
34103          }
34104          lastBlockMap = nextBlockMap;
34105        });
34106      };
34107    }
34108  };
34109}];
34110
34111var NG_HIDE_CLASS = 'ng-hide';
34112var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
34113/**
34114 * @ngdoc directive
34115 * @name ngShow
34116 * @multiElement
34117 *
34118 * @description
34119 * The `ngShow` directive shows or hides the given HTML element based on the expression provided to
34120 * the `ngShow` attribute.
34121 *
34122 * The element is shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
34123 * The `.ng-hide` CSS class is predefined in AngularJS and sets the display style to none (using an
34124 * `!important` flag). For CSP mode please add `angular-csp.css` to your HTML file (see
34125 * {@link ng.directive:ngCsp ngCsp}).
34126 *
34127 * ```html
34128 * <!-- when $scope.myValue is truthy (element is visible) -->
34129 * <div ng-show="myValue"></div>
34130 *
34131 * <!-- when $scope.myValue is falsy (element is hidden) -->
34132 * <div ng-show="myValue" class="ng-hide"></div>
34133 * ```
34134 *
34135 * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added
34136 * to the class attribute on the element causing it to become hidden. When truthy, the `.ng-hide`
34137 * CSS class is removed from the element causing the element not to appear hidden.
34138 *
34139 * ## Why is `!important` used?
34140 *
34141 * You may be wondering why `!important` is used for the `.ng-hide` CSS class. This is because the
34142 * `.ng-hide` selector can be easily overridden by heavier selectors. For example, something as
34143 * simple as changing the display style on a HTML list item would make hidden elements appear
34144 * visible. This also becomes a bigger issue when dealing with CSS frameworks.
34145 *
34146 * By using `!important`, the show and hide behavior will work as expected despite any clash between
34147 * CSS selector specificity (when `!important` isn't used with any conflicting styles). If a
34148 * developer chooses to override the styling to change how to hide an element then it is just a
34149 * matter of using `!important` in their own CSS code.
34150 *
34151 * ### Overriding `.ng-hide`
34152 *
34153 * By default, the `.ng-hide` class will style the element with `display: none !important`. If you
34154 * wish to change the hide behavior with `ngShow`/`ngHide`, you can simply overwrite the styles for
34155 * the `.ng-hide` CSS class. Note that the selector that needs to be used is actually
34156 * `.ng-hide:not(.ng-hide-animate)` to cope with extra animation classes that can be added.
34157 *
34158 * ```css
34159 * .ng-hide:not(.ng-hide-animate) {
34160 *   /&#42; These are just alternative ways of hiding an element &#42;/
34161 *   display: block!important;
34162 *   position: absolute;
34163 *   top: -9999px;
34164 *   left: -9999px;
34165 * }
34166 * ```
34167 *
34168 * By default you don't need to override anything in CSS and the animations will work around the
34169 * display style.
34170 *
34171 * @animations
34172 * | Animation                                           | Occurs                                                                                                        |
34173 * |-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
34174 * | {@link $animate#addClass addClass} `.ng-hide`       | After the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden. |
34175 * | {@link $animate#removeClass removeClass} `.ng-hide` | After the `ngShow` expression evaluates to a truthy value and just before contents are set to visible.        |
34176 *
34177 * Animations in `ngShow`/`ngHide` work with the show and hide events that are triggered when the
34178 * directive expression is true and false. This system works like the animation system present with
34179 * `ngClass` except that you must also include the `!important` flag to override the display
34180 * property so that the elements are not actually hidden during the animation.
34181 *
34182 * ```css
34183 * /&#42; A working example can be found at the bottom of this page. &#42;/
34184 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
34185 *   transition: all 0.5s linear;
34186 * }
34187 *
34188 * .my-element.ng-hide-add { ... }
34189 * .my-element.ng-hide-add.ng-hide-add-active { ... }
34190 * .my-element.ng-hide-remove { ... }
34191 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
34192 * ```
34193 *
34194 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display property
34195 * to block during animation states - ngAnimate will automatically handle the style toggling for you.
34196 *
34197 * @element ANY
34198 * @param {expression} ngShow If the {@link guide/expression expression} is truthy/falsy then the
34199 *                            element is shown/hidden respectively.
34200 *
34201 * @example
34202 * A simple example, animating the element's opacity:
34203 *
34204  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-show-simple">
34205    <file name="index.html">
34206      Show: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br />
34207      <div class="check-element animate-show-hide" ng-show="checked">
34208        I show up when your checkbox is checked.
34209      </div>
34210    </file>
34211    <file name="animations.css">
34212      .animate-show-hide.ng-hide {
34213        opacity: 0;
34214      }
34215
34216      .animate-show-hide.ng-hide-add,
34217      .animate-show-hide.ng-hide-remove {
34218        transition: all linear 0.5s;
34219      }
34220
34221      .check-element {
34222        border: 1px solid black;
34223        opacity: 1;
34224        padding: 10px;
34225      }
34226    </file>
34227    <file name="protractor.js" type="protractor">
34228      it('should check ngShow', function() {
34229        var checkbox = element(by.model('checked'));
34230        var checkElem = element(by.css('.check-element'));
34231
34232        expect(checkElem.isDisplayed()).toBe(false);
34233        checkbox.click();
34234        expect(checkElem.isDisplayed()).toBe(true);
34235      });
34236    </file>
34237  </example>
34238 *
34239 * <hr />
34240 * @example
34241 * A more complex example, featuring different show/hide animations:
34242 *
34243  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-show-complex">
34244    <file name="index.html">
34245      Show: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br />
34246      <div class="check-element funky-show-hide" ng-show="checked">
34247        I show up when your checkbox is checked.
34248      </div>
34249    </file>
34250    <file name="animations.css">
34251      body {
34252        overflow: hidden;
34253        perspective: 1000px;
34254      }
34255
34256      .funky-show-hide.ng-hide-add {
34257        transform: rotateZ(0);
34258        transform-origin: right;
34259        transition: all 0.5s ease-in-out;
34260      }
34261
34262      .funky-show-hide.ng-hide-add.ng-hide-add-active {
34263        transform: rotateZ(-135deg);
34264      }
34265
34266      .funky-show-hide.ng-hide-remove {
34267        transform: rotateY(90deg);
34268        transform-origin: left;
34269        transition: all 0.5s ease;
34270      }
34271
34272      .funky-show-hide.ng-hide-remove.ng-hide-remove-active {
34273        transform: rotateY(0);
34274      }
34275
34276      .check-element {
34277        border: 1px solid black;
34278        opacity: 1;
34279        padding: 10px;
34280      }
34281    </file>
34282    <file name="protractor.js" type="protractor">
34283      it('should check ngShow', function() {
34284        var checkbox = element(by.model('checked'));
34285        var checkElem = element(by.css('.check-element'));
34286
34287        expect(checkElem.isDisplayed()).toBe(false);
34288        checkbox.click();
34289        expect(checkElem.isDisplayed()).toBe(true);
34290      });
34291    </file>
34292  </example>
34293 *
34294 * @knownIssue
34295 *
34296 * ### Flickering when using ngShow to toggle between elements
34297 *
34298 * When using {@link ngShow} and / or {@link ngHide} to toggle between elements, it can
34299 * happen that both the element to show and the element to hide are visible for a very short time.
34300 *
34301 * This usually happens when the {@link ngAnimate ngAnimate module} is included, but no actual animations
34302 * are defined for {@link ngShow} / {@link ngHide}. Internet Explorer is affected more often than
34303 * other browsers.
34304 *
34305 * There are several way to mitigate this problem:
34306 *
34307 * - {@link guide/animations#how-to-selectively-enable-disable-and-skip-animations Disable animations on the affected elements}.
34308 * - Use {@link ngIf} or {@link ngSwitch} instead of {@link ngShow} / {@link ngHide}.
34309 * - Use the special CSS selector `ng-hide.ng-hide-animate` to set `{display: none}` or similar on the affected elements.
34310 * - Use `ng-class="{'ng-hide': expression}` instead of instead of {@link ngShow} / {@link ngHide}.
34311 * - Define an animation on the affected elements.
34312 */
34313var ngShowDirective = ['$animate', function($animate) {
34314  return {
34315    restrict: 'A',
34316    multiElement: true,
34317    link: function(scope, element, attr) {
34318      scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
34319        // we're adding a temporary, animation-specific class for ng-hide since this way
34320        // we can control when the element is actually displayed on screen without having
34321        // to have a global/greedy CSS selector that breaks when other animations are run.
34322        // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
34323        $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
34324          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
34325        });
34326      });
34327    }
34328  };
34329}];
34330
34331
34332/**
34333 * @ngdoc directive
34334 * @name ngHide
34335 * @multiElement
34336 *
34337 * @description
34338 * The `ngHide` directive shows or hides the given HTML element based on the expression provided to
34339 * the `ngHide` attribute.
34340 *
34341 * The element is shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
34342 * The `.ng-hide` CSS class is predefined in AngularJS and sets the display style to none (using an
34343 * `!important` flag). For CSP mode please add `angular-csp.css` to your HTML file (see
34344 * {@link ng.directive:ngCsp ngCsp}).
34345 *
34346 * ```html
34347 * <!-- when $scope.myValue is truthy (element is hidden) -->
34348 * <div ng-hide="myValue" class="ng-hide"></div>
34349 *
34350 * <!-- when $scope.myValue is falsy (element is visible) -->
34351 * <div ng-hide="myValue"></div>
34352 * ```
34353 *
34354 * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added
34355 * to the class attribute on the element causing it to become hidden. When falsy, the `.ng-hide`
34356 * CSS class is removed from the element causing the element not to appear hidden.
34357 *
34358 * ## Why is `!important` used?
34359 *
34360 * You may be wondering why `!important` is used for the `.ng-hide` CSS class. This is because the
34361 * `.ng-hide` selector can be easily overridden by heavier selectors. For example, something as
34362 * simple as changing the display style on a HTML list item would make hidden elements appear
34363 * visible. This also becomes a bigger issue when dealing with CSS frameworks.
34364 *
34365 * By using `!important`, the show and hide behavior will work as expected despite any clash between
34366 * CSS selector specificity (when `!important` isn't used with any conflicting styles). If a
34367 * developer chooses to override the styling to change how to hide an element then it is just a
34368 * matter of using `!important` in their own CSS code.
34369 *
34370 * ### Overriding `.ng-hide`
34371 *
34372 * By default, the `.ng-hide` class will style the element with `display: none !important`. If you
34373 * wish to change the hide behavior with `ngShow`/`ngHide`, you can simply overwrite the styles for
34374 * the `.ng-hide` CSS class. Note that the selector that needs to be used is actually
34375 * `.ng-hide:not(.ng-hide-animate)` to cope with extra animation classes that can be added.
34376 *
34377 * ```css
34378 * .ng-hide:not(.ng-hide-animate) {
34379 *   /&#42; These are just alternative ways of hiding an element &#42;/
34380 *   display: block!important;
34381 *   position: absolute;
34382 *   top: -9999px;
34383 *   left: -9999px;
34384 * }
34385 * ```
34386 *
34387 * By default you don't need to override in CSS anything and the animations will work around the
34388 * display style.
34389 *
34390 * @animations
34391 * | Animation                                           | Occurs                                                                                                     |
34392 * |-----------------------------------------------------|------------------------------------------------------------------------------------------------------------|
34393 * | {@link $animate#addClass addClass} `.ng-hide`       | After the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden.  |
34394 * | {@link $animate#removeClass removeClass} `.ng-hide` | After the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible. |
34395 *
34396 * Animations in `ngShow`/`ngHide` work with the show and hide events that are triggered when the
34397 * directive expression is true and false. This system works like the animation system present with
34398 * `ngClass` except that you must also include the `!important` flag to override the display
34399 * property so that the elements are not actually hidden during the animation.
34400 *
34401 * ```css
34402 * /&#42; A working example can be found at the bottom of this page. &#42;/
34403 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
34404 *   transition: all 0.5s linear;
34405 * }
34406 *
34407 * .my-element.ng-hide-add { ... }
34408 * .my-element.ng-hide-add.ng-hide-add-active { ... }
34409 * .my-element.ng-hide-remove { ... }
34410 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
34411 * ```
34412 *
34413 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display property
34414 * to block during animation states - ngAnimate will automatically handle the style toggling for you.
34415 *
34416 * @element ANY
34417 * @param {expression} ngHide If the {@link guide/expression expression} is truthy/falsy then the
34418 *                            element is hidden/shown respectively.
34419 *
34420 * @example
34421 * A simple example, animating the element's opacity:
34422 *
34423  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-hide-simple">
34424    <file name="index.html">
34425      Hide: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br />
34426      <div class="check-element animate-show-hide" ng-hide="checked">
34427        I hide when your checkbox is checked.
34428      </div>
34429    </file>
34430    <file name="animations.css">
34431      .animate-show-hide.ng-hide {
34432        opacity: 0;
34433      }
34434
34435      .animate-show-hide.ng-hide-add,
34436      .animate-show-hide.ng-hide-remove {
34437        transition: all linear 0.5s;
34438      }
34439
34440      .check-element {
34441        border: 1px solid black;
34442        opacity: 1;
34443        padding: 10px;
34444      }
34445    </file>
34446    <file name="protractor.js" type="protractor">
34447      it('should check ngHide', function() {
34448        var checkbox = element(by.model('checked'));
34449        var checkElem = element(by.css('.check-element'));
34450
34451        expect(checkElem.isDisplayed()).toBe(true);
34452        checkbox.click();
34453        expect(checkElem.isDisplayed()).toBe(false);
34454      });
34455    </file>
34456  </example>
34457 *
34458 * <hr />
34459 * @example
34460 * A more complex example, featuring different show/hide animations:
34461 *
34462  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-hide-complex">
34463    <file name="index.html">
34464      Hide: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br />
34465      <div class="check-element funky-show-hide" ng-hide="checked">
34466        I hide when your checkbox is checked.
34467      </div>
34468    </file>
34469    <file name="animations.css">
34470      body {
34471        overflow: hidden;
34472        perspective: 1000px;
34473      }
34474
34475      .funky-show-hide.ng-hide-add {
34476        transform: rotateZ(0);
34477        transform-origin: right;
34478        transition: all 0.5s ease-in-out;
34479      }
34480
34481      .funky-show-hide.ng-hide-add.ng-hide-add-active {
34482        transform: rotateZ(-135deg);
34483      }
34484
34485      .funky-show-hide.ng-hide-remove {
34486        transform: rotateY(90deg);
34487        transform-origin: left;
34488        transition: all 0.5s ease;
34489      }
34490
34491      .funky-show-hide.ng-hide-remove.ng-hide-remove-active {
34492        transform: rotateY(0);
34493      }
34494
34495      .check-element {
34496        border: 1px solid black;
34497        opacity: 1;
34498        padding: 10px;
34499      }
34500    </file>
34501    <file name="protractor.js" type="protractor">
34502      it('should check ngHide', function() {
34503        var checkbox = element(by.model('checked'));
34504        var checkElem = element(by.css('.check-element'));
34505
34506        expect(checkElem.isDisplayed()).toBe(true);
34507        checkbox.click();
34508        expect(checkElem.isDisplayed()).toBe(false);
34509      });
34510    </file>
34511  </example>
34512 *
34513 * @knownIssue
34514 *
34515 * ### Flickering when using ngHide to toggle between elements
34516 *
34517 * When using {@link ngShow} and / or {@link ngHide} to toggle between elements, it can
34518 * happen that both the element to show and the element to hide are visible for a very short time.
34519 *
34520 * This usually happens when the {@link ngAnimate ngAnimate module} is included, but no actual animations
34521 * are defined for {@link ngShow} / {@link ngHide}. Internet Explorer is affected more often than
34522 * other browsers.
34523 *
34524 * There are several way to mitigate this problem:
34525 *
34526 * - {@link guide/animations#how-to-selectively-enable-disable-and-skip-animations Disable animations on the affected elements}.
34527 * - Use {@link ngIf} or {@link ngSwitch} instead of {@link ngShow} / {@link ngHide}.
34528 * - Use the special CSS selector `ng-hide.ng-hide-animate` to set `{display: none}` or similar on the affected elements.
34529 * - Use `ng-class="{'ng-hide': expression}` instead of instead of {@link ngShow} / {@link ngHide}.
34530 * - Define an animation on the affected elements.
34531 */
34532var ngHideDirective = ['$animate', function($animate) {
34533  return {
34534    restrict: 'A',
34535    multiElement: true,
34536    link: function(scope, element, attr) {
34537      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
34538        // The comment inside of the ngShowDirective explains why we add and
34539        // remove a temporary class for the show/hide animation
34540        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
34541          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
34542        });
34543      });
34544    }
34545  };
34546}];
34547
34548/**
34549 * @ngdoc directive
34550 * @name ngStyle
34551 * @restrict AC
34552 *
34553 * @description
34554 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
34555 *
34556 * @knownIssue
34557 * You should not use {@link guide/interpolation interpolation} in the value of the `style`
34558 * attribute, when using the `ngStyle` directive on the same element.
34559 * See {@link guide/interpolation#known-issues here} for more info.
34560 *
34561 * @element ANY
34562 * @param {expression} ngStyle
34563 *
34564 * {@link guide/expression Expression} which evals to an
34565 * object whose keys are CSS style names and values are corresponding values for those CSS
34566 * keys.
34567 *
34568 * Since some CSS style names are not valid keys for an object, they must be quoted.
34569 * See the 'background-color' style in the example below.
34570 *
34571 * @example
34572   <example name="ng-style">
34573     <file name="index.html">
34574        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
34575        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
34576        <input type="button" value="clear" ng-click="myStyle={}">
34577        <br/>
34578        <span ng-style="myStyle">Sample Text</span>
34579        <pre>myStyle={{myStyle}}</pre>
34580     </file>
34581     <file name="style.css">
34582       span {
34583         color: black;
34584       }
34585     </file>
34586     <file name="protractor.js" type="protractor">
34587       var colorSpan = element(by.css('span'));
34588
34589       it('should check ng-style', function() {
34590         expect(colorSpan.getCssValue('color')).toMatch(/rgba\(0, 0, 0, 1\)|rgb\(0, 0, 0\)/);
34591         element(by.css('input[value=\'set color\']')).click();
34592         expect(colorSpan.getCssValue('color')).toMatch(/rgba\(255, 0, 0, 1\)|rgb\(255, 0, 0\)/);
34593         element(by.css('input[value=clear]')).click();
34594         expect(colorSpan.getCssValue('color')).toMatch(/rgba\(0, 0, 0, 1\)|rgb\(0, 0, 0\)/);
34595       });
34596     </file>
34597   </example>
34598 */
34599var ngStyleDirective = ngDirective(function(scope, element, attr) {
34600  scope.$watchCollection(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
34601    if (oldStyles && (newStyles !== oldStyles)) {
34602      forEach(oldStyles, function(val, style) { element.css(style, ''); });
34603    }
34604    if (newStyles) element.css(newStyles);
34605  });
34606});
34607
34608/**
34609 * @ngdoc directive
34610 * @name ngSwitch
34611 * @restrict EA
34612 *
34613 * @description
34614 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
34615 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
34616 * as specified in the template.
34617 *
34618 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
34619 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
34620 * matches the value obtained from the evaluated expression. In other words, you define a container element
34621 * (where you place the directive), place an expression on the **`on="..."` attribute**
34622 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
34623 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
34624 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
34625 * attribute is displayed.
34626 *
34627 * <div class="alert alert-info">
34628 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
34629 * as literal string values to match against.
34630 * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
34631 * value of the expression `$scope.someVal`.
34632 * </div>
34633
34634 * @animations
34635 * | Animation                        | Occurs                              |
34636 * |----------------------------------|-------------------------------------|
34637 * | {@link ng.$animate#enter enter}  | after the ngSwitch contents change and the matched child element is placed inside the container |
34638 * | {@link ng.$animate#leave leave}  | after the ngSwitch contents change and just before the former contents are removed from the DOM |
34639 *
34640 * @usage
34641 *
34642 * ```
34643 * <ANY ng-switch="expression">
34644 *   <ANY ng-switch-when="matchValue1">...</ANY>
34645 *   <ANY ng-switch-when="matchValue2">...</ANY>
34646 *   <ANY ng-switch-default>...</ANY>
34647 * </ANY>
34648 * ```
34649 *
34650 *
34651 * @scope
34652 * @priority 1200
34653 * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
34654 * On child elements add:
34655 *
34656 * * `ngSwitchWhen`: the case statement to match against. If match then this
34657 *   case will be displayed. If the same match appears multiple times, all the
34658 *   elements will be displayed. It is possible to associate multiple values to
34659 *   the same `ngSwitchWhen` by defining the optional attribute
34660 *   `ngSwitchWhenSeparator`. The separator will be used to split the value of
34661 *   the `ngSwitchWhen` attribute into multiple tokens, and the element will show
34662 *   if any of the `ngSwitch` evaluates to any of these tokens.
34663 * * `ngSwitchDefault`: the default case when no other case match. If there
34664 *   are multiple default cases, all of them will be displayed when no other
34665 *   case match.
34666 *
34667 *
34668 * @example
34669  <example module="switchExample" deps="angular-animate.js" animations="true" name="ng-switch">
34670    <file name="index.html">
34671      <div ng-controller="ExampleController">
34672        <select ng-model="selection" ng-options="item for item in items">
34673        </select>
34674        <code>selection={{selection}}</code>
34675        <hr/>
34676        <div class="animate-switch-container"
34677          ng-switch on="selection">
34678            <div class="animate-switch" ng-switch-when="settings|options" ng-switch-when-separator="|">Settings Div</div>
34679            <div class="animate-switch" ng-switch-when="home">Home Span</div>
34680            <div class="animate-switch" ng-switch-default>default</div>
34681        </div>
34682      </div>
34683    </file>
34684    <file name="script.js">
34685      angular.module('switchExample', ['ngAnimate'])
34686        .controller('ExampleController', ['$scope', function($scope) {
34687          $scope.items = ['settings', 'home', 'options', 'other'];
34688          $scope.selection = $scope.items[0];
34689        }]);
34690    </file>
34691    <file name="animations.css">
34692      .animate-switch-container {
34693        position:relative;
34694        background:white;
34695        border:1px solid black;
34696        height:40px;
34697        overflow:hidden;
34698      }
34699
34700      .animate-switch {
34701        padding:10px;
34702      }
34703
34704      .animate-switch.ng-animate {
34705        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34706
34707        position:absolute;
34708        top:0;
34709        left:0;
34710        right:0;
34711        bottom:0;
34712      }
34713
34714      .animate-switch.ng-leave.ng-leave-active,
34715      .animate-switch.ng-enter {
34716        top:-50px;
34717      }
34718      .animate-switch.ng-leave,
34719      .animate-switch.ng-enter.ng-enter-active {
34720        top:0;
34721      }
34722    </file>
34723    <file name="protractor.js" type="protractor">
34724      var switchElem = element(by.css('[ng-switch]'));
34725      var select = element(by.model('selection'));
34726
34727      it('should start in settings', function() {
34728        expect(switchElem.getText()).toMatch(/Settings Div/);
34729      });
34730      it('should change to home', function() {
34731        select.all(by.css('option')).get(1).click();
34732        expect(switchElem.getText()).toMatch(/Home Span/);
34733      });
34734      it('should change to settings via "options"', function() {
34735        select.all(by.css('option')).get(2).click();
34736        expect(switchElem.getText()).toMatch(/Settings Div/);
34737      });
34738      it('should select default', function() {
34739        select.all(by.css('option')).get(3).click();
34740        expect(switchElem.getText()).toMatch(/default/);
34741      });
34742    </file>
34743  </example>
34744 */
34745var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
34746  return {
34747    require: 'ngSwitch',
34748
34749    // asks for $scope to fool the BC controller module
34750    controller: ['$scope', function NgSwitchController() {
34751     this.cases = {};
34752    }],
34753    link: function(scope, element, attr, ngSwitchController) {
34754      var watchExpr = attr.ngSwitch || attr.on,
34755          selectedTranscludes = [],
34756          selectedElements = [],
34757          previousLeaveAnimations = [],
34758          selectedScopes = [];
34759
34760      var spliceFactory = function(array, index) {
34761          return function(response) {
34762            if (response !== false) array.splice(index, 1);
34763          };
34764      };
34765
34766      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
34767        var i, ii;
34768
34769        // Start with the last, in case the array is modified during the loop
34770        while (previousLeaveAnimations.length) {
34771          $animate.cancel(previousLeaveAnimations.pop());
34772        }
34773
34774        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
34775          var selected = getBlockNodes(selectedElements[i].clone);
34776          selectedScopes[i].$destroy();
34777          var runner = previousLeaveAnimations[i] = $animate.leave(selected);
34778          runner.done(spliceFactory(previousLeaveAnimations, i));
34779        }
34780
34781        selectedElements.length = 0;
34782        selectedScopes.length = 0;
34783
34784        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
34785          forEach(selectedTranscludes, function(selectedTransclude) {
34786            selectedTransclude.transclude(function(caseElement, selectedScope) {
34787              selectedScopes.push(selectedScope);
34788              var anchor = selectedTransclude.element;
34789              caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
34790              var block = { clone: caseElement };
34791
34792              selectedElements.push(block);
34793              $animate.enter(caseElement, anchor.parent(), anchor);
34794            });
34795          });
34796        }
34797      });
34798    }
34799  };
34800}];
34801
34802var ngSwitchWhenDirective = ngDirective({
34803  transclude: 'element',
34804  priority: 1200,
34805  require: '^ngSwitch',
34806  multiElement: true,
34807  link: function(scope, element, attrs, ctrl, $transclude) {
34808
34809    var cases = attrs.ngSwitchWhen.split(attrs.ngSwitchWhenSeparator).sort().filter(
34810      // Filter duplicate cases
34811      function(element, index, array) { return array[index - 1] !== element; }
34812    );
34813
34814    forEach(cases, function(whenCase) {
34815      ctrl.cases['!' + whenCase] = (ctrl.cases['!' + whenCase] || []);
34816      ctrl.cases['!' + whenCase].push({ transclude: $transclude, element: element });
34817    });
34818  }
34819});
34820
34821var ngSwitchDefaultDirective = ngDirective({
34822  transclude: 'element',
34823  priority: 1200,
34824  require: '^ngSwitch',
34825  multiElement: true,
34826  link: function(scope, element, attr, ctrl, $transclude) {
34827    ctrl.cases['?'] = (ctrl.cases['?'] || []);
34828    ctrl.cases['?'].push({ transclude: $transclude, element: element });
34829   }
34830});
34831
34832/**
34833 * @ngdoc directive
34834 * @name ngTransclude
34835 * @restrict EAC
34836 *
34837 * @description
34838 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
34839 *
34840 * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
34841 * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
34842 *
34843 * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
34844 * content of this element will be removed before the transcluded content is inserted.
34845 * If the transcluded content is empty (or only whitespace), the existing content is left intact. This lets you provide fallback
34846 * content in the case that no transcluded content is provided.
34847 *
34848 * @element ANY
34849 *
34850 * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
34851 *                                               or its value is the same as the name of the attribute then the default slot is used.
34852 *
34853 * @example
34854 * ### Basic transclusion
34855 * This example demonstrates basic transclusion of content into a component directive.
34856 * <example name="simpleTranscludeExample" module="transcludeExample">
34857 *   <file name="index.html">
34858 *     <script>
34859 *       angular.module('transcludeExample', [])
34860 *        .directive('pane', function(){
34861 *           return {
34862 *             restrict: 'E',
34863 *             transclude: true,
34864 *             scope: { title:'@' },
34865 *             template: '<div style="border: 1px solid black;">' +
34866 *                         '<div style="background-color: gray">{{title}}</div>' +
34867 *                         '<ng-transclude></ng-transclude>' +
34868 *                       '</div>'
34869 *           };
34870 *       })
34871 *       .controller('ExampleController', ['$scope', function($scope) {
34872 *         $scope.title = 'Lorem Ipsum';
34873 *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
34874 *       }]);
34875 *     </script>
34876 *     <div ng-controller="ExampleController">
34877 *       <input ng-model="title" aria-label="title"> <br/>
34878 *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
34879 *       <pane title="{{title}}"><span>{{text}}</span></pane>
34880 *     </div>
34881 *   </file>
34882 *   <file name="protractor.js" type="protractor">
34883 *      it('should have transcluded', function() {
34884 *        var titleElement = element(by.model('title'));
34885 *        titleElement.clear();
34886 *        titleElement.sendKeys('TITLE');
34887 *        var textElement = element(by.model('text'));
34888 *        textElement.clear();
34889 *        textElement.sendKeys('TEXT');
34890 *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
34891 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
34892 *      });
34893 *   </file>
34894 * </example>
34895 *
34896 * @example
34897 * ### Transclude fallback content
34898 * This example shows how to use `NgTransclude` with fallback content, that
34899 * is displayed if no transcluded content is provided.
34900 *
34901 * <example module="transcludeFallbackContentExample" name="ng-transclude">
34902 * <file name="index.html">
34903 * <script>
34904 * angular.module('transcludeFallbackContentExample', [])
34905 * .directive('myButton', function(){
34906 *             return {
34907 *               restrict: 'E',
34908 *               transclude: true,
34909 *               scope: true,
34910 *               template: '<button style="cursor: pointer;">' +
34911 *                           '<ng-transclude>' +
34912 *                             '<b style="color: red;">Button1</b>' +
34913 *                           '</ng-transclude>' +
34914 *                         '</button>'
34915 *             };
34916 *         });
34917 * </script>
34918 * <!-- fallback button content -->
34919 * <my-button id="fallback"></my-button>
34920 * <!-- modified button content -->
34921 * <my-button id="modified">
34922 *   <i style="color: green;">Button2</i>
34923 * </my-button>
34924 * </file>
34925 * <file name="protractor.js" type="protractor">
34926 * it('should have different transclude element content', function() {
34927 *          expect(element(by.id('fallback')).getText()).toBe('Button1');
34928 *          expect(element(by.id('modified')).getText()).toBe('Button2');
34929 *        });
34930 * </file>
34931 * </example>
34932 *
34933 * @example
34934 * ### Multi-slot transclusion
34935 * This example demonstrates using multi-slot transclusion in a component directive.
34936 * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
34937 *   <file name="index.html">
34938 *    <style>
34939 *      .title, .footer {
34940 *        background-color: gray
34941 *      }
34942 *    </style>
34943 *    <div ng-controller="ExampleController">
34944 *      <input ng-model="title" aria-label="title"> <br/>
34945 *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
34946 *      <pane>
34947 *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
34948 *        <pane-body><p>{{text}}</p></pane-body>
34949 *      </pane>
34950 *    </div>
34951 *   </file>
34952 *   <file name="app.js">
34953 *    angular.module('multiSlotTranscludeExample', [])
34954 *     .directive('pane', function() {
34955 *        return {
34956 *          restrict: 'E',
34957 *          transclude: {
34958 *            'title': '?paneTitle',
34959 *            'body': 'paneBody',
34960 *            'footer': '?paneFooter'
34961 *          },
34962 *          template: '<div style="border: 1px solid black;">' +
34963 *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
34964 *                      '<div ng-transclude="body"></div>' +
34965 *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
34966 *                    '</div>'
34967 *        };
34968 *    })
34969 *    .controller('ExampleController', ['$scope', function($scope) {
34970 *      $scope.title = 'Lorem Ipsum';
34971 *      $scope.link = 'https://google.com';
34972 *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
34973 *    }]);
34974 *   </file>
34975 *   <file name="protractor.js" type="protractor">
34976 *      it('should have transcluded the title and the body', function() {
34977 *        var titleElement = element(by.model('title'));
34978 *        titleElement.clear();
34979 *        titleElement.sendKeys('TITLE');
34980 *        var textElement = element(by.model('text'));
34981 *        textElement.clear();
34982 *        textElement.sendKeys('TEXT');
34983 *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
34984 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
34985 *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
34986 *      });
34987 *   </file>
34988 * </example>
34989 */
34990var ngTranscludeMinErr = minErr('ngTransclude');
34991var ngTranscludeDirective = ['$compile', function($compile) {
34992  return {
34993    restrict: 'EAC',
34994    compile: function ngTranscludeCompile(tElement) {
34995
34996      // Remove and cache any original content to act as a fallback
34997      var fallbackLinkFn = $compile(tElement.contents());
34998      tElement.empty();
34999
35000      return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {
35001
35002        if (!$transclude) {
35003          throw ngTranscludeMinErr('orphan',
35004          'Illegal use of ngTransclude directive in the template! ' +
35005          'No parent directive that requires a transclusion found. ' +
35006          'Element: {0}',
35007          startingTag($element));
35008        }
35009
35010
35011        // If the attribute is of the form: `ng-transclude="ng-transclude"` then treat it like the default
35012        if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
35013          $attrs.ngTransclude = '';
35014        }
35015        var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
35016
35017        // If the slot is required and no transclusion content is provided then this call will throw an error
35018        $transclude(ngTranscludeCloneAttachFn, null, slotName);
35019
35020        // If the slot is optional and no transclusion content is provided then use the fallback content
35021        if (slotName && !$transclude.isSlotFilled(slotName)) {
35022          useFallbackContent();
35023        }
35024
35025        function ngTranscludeCloneAttachFn(clone, transcludedScope) {
35026          if (clone.length && notWhitespace(clone)) {
35027            $element.append(clone);
35028          } else {
35029            useFallbackContent();
35030            // There is nothing linked against the transcluded scope since no content was available,
35031            // so it should be safe to clean up the generated scope.
35032            transcludedScope.$destroy();
35033          }
35034        }
35035
35036        function useFallbackContent() {
35037          // Since this is the fallback content rather than the transcluded content,
35038          // we link against the scope of this directive rather than the transcluded scope
35039          fallbackLinkFn($scope, function(clone) {
35040            $element.append(clone);
35041          });
35042        }
35043
35044        function notWhitespace(nodes) {
35045          for (var i = 0, ii = nodes.length; i < ii; i++) {
35046            var node = nodes[i];
35047            if (node.nodeType !== NODE_TYPE_TEXT || node.nodeValue.trim()) {
35048              return true;
35049            }
35050          }
35051        }
35052      };
35053    }
35054  };
35055}];
35056
35057/**
35058 * @ngdoc directive
35059 * @name script
35060 * @restrict E
35061 *
35062 * @description
35063 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
35064 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
35065 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
35066 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
35067 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
35068 *
35069 * @param {string} type Must be set to `'text/ng-template'`.
35070 * @param {string} id Cache name of the template.
35071 *
35072 * @example
35073  <example  name="script-tag">
35074    <file name="index.html">
35075      <script type="text/ng-template" id="/tpl.html">
35076        Content of the template.
35077      </script>
35078
35079      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
35080      <div id="tpl-content" ng-include src="currentTpl"></div>
35081    </file>
35082    <file name="protractor.js" type="protractor">
35083      it('should load template defined inside script tag', function() {
35084        element(by.css('#tpl-link')).click();
35085        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
35086      });
35087    </file>
35088  </example>
35089 */
35090var scriptDirective = ['$templateCache', function($templateCache) {
35091  return {
35092    restrict: 'E',
35093    terminal: true,
35094    compile: function(element, attr) {
35095      if (attr.type === 'text/ng-template') {
35096        var templateUrl = attr.id,
35097            text = element[0].text;
35098
35099        $templateCache.put(templateUrl, text);
35100      }
35101    }
35102  };
35103}];
35104
35105/* exported selectDirective, optionDirective */
35106
35107var noopNgModelController = { $setViewValue: noop, $render: noop };
35108
35109function setOptionSelectedStatus(optionEl, value) {
35110  optionEl.prop('selected', value);
35111  /**
35112   * When unselecting an option, setting the property to null / false should be enough
35113   * However, screenreaders might react to the selected attribute instead, see
35114   * https://github.com/angular/angular.js/issues/14419
35115   * Note: "selected" is a boolean attr and will be removed when the "value" arg in attr() is false
35116   * or null
35117   */
35118  optionEl.attr('selected', value);
35119}
35120
35121/**
35122 * @ngdoc type
35123 * @name  select.SelectController
35124 *
35125 * @description
35126 * The controller for the {@link ng.select select} directive. The controller exposes
35127 * a few utility methods that can be used to augment the behavior of a regular or an
35128 * {@link ng.ngOptions ngOptions} select element.
35129 *
35130 * @example
35131 * ### Set a custom error when the unknown option is selected
35132 *
35133 * This example sets a custom error "unknownValue" on the ngModelController
35134 * when the select element's unknown option is selected, i.e. when the model is set to a value
35135 * that is not matched by any option.
35136 *
35137 * <example name="select-unknown-value-error" module="staticSelect">
35138 * <file name="index.html">
35139 * <div ng-controller="ExampleController">
35140 *   <form name="myForm">
35141 *     <label for="testSelect"> Single select: </label><br>
35142 *     <select name="testSelect" ng-model="selected" unknown-value-error>
35143 *       <option value="option-1">Option 1</option>
35144 *       <option value="option-2">Option 2</option>
35145 *     </select><br>
35146 *     <span class="error" ng-if="myForm.testSelect.$error.unknownValue">
35147 *       Error: The current model doesn't match any option</span><br>
35148 *
35149 *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
35150 *   </form>
35151 * </div>
35152 * </file>
35153 * <file name="app.js">
35154 *  angular.module('staticSelect', [])
35155 *    .controller('ExampleController', ['$scope', function($scope) {
35156 *      $scope.selected = null;
35157 *
35158 *      $scope.forceUnknownOption = function() {
35159 *        $scope.selected = 'nonsense';
35160 *      };
35161 *   }])
35162 *   .directive('unknownValueError', function() {
35163 *     return {
35164 *       require: ['ngModel', 'select'],
35165 *       link: function(scope, element, attrs, ctrls) {
35166 *         var ngModelCtrl = ctrls[0];
35167 *         var selectCtrl = ctrls[1];
35168 *
35169 *         ngModelCtrl.$validators.unknownValue = function(modelValue, viewValue) {
35170 *           if (selectCtrl.$isUnknownOptionSelected()) {
35171 *             return false;
35172 *           }
35173 *
35174 *           return true;
35175 *         };
35176 *       }
35177 *
35178 *     };
35179 *   });
35180 * </file>
35181 *</example>
35182 *
35183 *
35184 * @example
35185 * ### Set the "required" error when the unknown option is selected.
35186 *
35187 * By default, the "required" error on the ngModelController is only set on a required select
35188 * when the empty option is selected. This example adds a custom directive that also sets the
35189 * error when the unknown option is selected.
35190 *
35191 * <example name="select-unknown-value-required" module="staticSelect">
35192 * <file name="index.html">
35193 * <div ng-controller="ExampleController">
35194 *   <form name="myForm">
35195 *     <label for="testSelect"> Select: </label><br>
35196 *     <select name="testSelect" ng-model="selected" required unknown-value-required>
35197 *       <option value="option-1">Option 1</option>
35198 *       <option value="option-2">Option 2</option>
35199 *     </select><br>
35200 *     <span class="error" ng-if="myForm.testSelect.$error.required">Error: Please select a value</span><br>
35201 *
35202 *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
35203 *   </form>
35204 * </div>
35205 * </file>
35206 * <file name="app.js">
35207 *  angular.module('staticSelect', [])
35208 *    .controller('ExampleController', ['$scope', function($scope) {
35209 *      $scope.selected = null;
35210 *
35211 *      $scope.forceUnknownOption = function() {
35212 *        $scope.selected = 'nonsense';
35213 *      };
35214 *   }])
35215 *   .directive('unknownValueRequired', function() {
35216 *     return {
35217 *       priority: 1, // This directive must run after the required directive has added its validator
35218 *       require: ['ngModel', 'select'],
35219 *       link: function(scope, element, attrs, ctrls) {
35220 *         var ngModelCtrl = ctrls[0];
35221 *         var selectCtrl = ctrls[1];
35222 *
35223 *         var originalRequiredValidator = ngModelCtrl.$validators.required;
35224 *
35225 *         ngModelCtrl.$validators.required = function() {
35226 *           if (attrs.required && selectCtrl.$isUnknownOptionSelected()) {
35227 *             return false;
35228 *           }
35229 *
35230 *           return originalRequiredValidator.apply(this, arguments);
35231 *         };
35232 *       }
35233 *     };
35234 *   });
35235 * </file>
35236 * <file name="protractor.js" type="protractor">
35237 *  it('should show the error message when the unknown option is selected', function() {
35238
35239      var error = element(by.className('error'));
35240
35241      expect(error.getText()).toBe('Error: Please select a value');
35242
35243      element(by.cssContainingText('option', 'Option 1')).click();
35244
35245      expect(error.isPresent()).toBe(false);
35246
35247      element(by.tagName('button')).click();
35248
35249      expect(error.getText()).toBe('Error: Please select a value');
35250    });
35251 * </file>
35252 *</example>
35253 *
35254 *
35255 */
35256var SelectController =
35257        ['$element', '$scope', /** @this */ function($element, $scope) {
35258
35259  var self = this,
35260      optionsMap = new NgMap();
35261
35262  self.selectValueMap = {}; // Keys are the hashed values, values the original values
35263
35264  // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
35265  self.ngModelCtrl = noopNgModelController;
35266  self.multiple = false;
35267
35268  // The "unknown" option is one that is prepended to the list if the viewValue
35269  // does not match any of the options. When it is rendered the value of the unknown
35270  // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
35271  //
35272  // Support: IE 9 only
35273  // We can't just jqLite('<option>') since jqLite is not smart enough
35274  // to create it in <select> and IE barfs otherwise.
35275  self.unknownOption = jqLite(window.document.createElement('option'));
35276
35277  // The empty option is an option with the value '' that the application developer can
35278  // provide inside the select. It is always selectable and indicates that a "null" selection has
35279  // been made by the user.
35280  // If the select has an empty option, and the model of the select is set to "undefined" or "null",
35281  // the empty option is selected.
35282  // If the model is set to a different unmatched value, the unknown option is rendered and
35283  // selected, i.e both are present, because a "null" selection and an unknown value are different.
35284  self.hasEmptyOption = false;
35285  self.emptyOption = undefined;
35286
35287  self.renderUnknownOption = function(val) {
35288    var unknownVal = self.generateUnknownOptionValue(val);
35289    self.unknownOption.val(unknownVal);
35290    $element.prepend(self.unknownOption);
35291    setOptionSelectedStatus(self.unknownOption, true);
35292    $element.val(unknownVal);
35293  };
35294
35295  self.updateUnknownOption = function(val) {
35296    var unknownVal = self.generateUnknownOptionValue(val);
35297    self.unknownOption.val(unknownVal);
35298    setOptionSelectedStatus(self.unknownOption, true);
35299    $element.val(unknownVal);
35300  };
35301
35302  self.generateUnknownOptionValue = function(val) {
35303    return '? ' + hashKey(val) + ' ?';
35304  };
35305
35306  self.removeUnknownOption = function() {
35307    if (self.unknownOption.parent()) self.unknownOption.remove();
35308  };
35309
35310  self.selectEmptyOption = function() {
35311    if (self.emptyOption) {
35312      $element.val('');
35313      setOptionSelectedStatus(self.emptyOption, true);
35314    }
35315  };
35316
35317  self.unselectEmptyOption = function() {
35318    if (self.hasEmptyOption) {
35319      setOptionSelectedStatus(self.emptyOption, false);
35320    }
35321  };
35322
35323  $scope.$on('$destroy', function() {
35324    // disable unknown option so that we don't do work when the whole select is being destroyed
35325    self.renderUnknownOption = noop;
35326  });
35327
35328  // Read the value of the select control, the implementation of this changes depending
35329  // upon whether the select can have multiple values and whether ngOptions is at work.
35330  self.readValue = function readSingleValue() {
35331    var val = $element.val();
35332    // ngValue added option values are stored in the selectValueMap, normal interpolations are not
35333    var realVal = val in self.selectValueMap ? self.selectValueMap[val] : val;
35334
35335    if (self.hasOption(realVal)) {
35336      return realVal;
35337    }
35338
35339    return null;
35340  };
35341
35342
35343  // Write the value to the select control, the implementation of this changes depending
35344  // upon whether the select can have multiple values and whether ngOptions is at work.
35345  self.writeValue = function writeSingleValue(value) {
35346    // Make sure to remove the selected attribute from the previously selected option
35347    // Otherwise, screen readers might get confused
35348    var currentlySelectedOption = $element[0].options[$element[0].selectedIndex];
35349    if (currentlySelectedOption) setOptionSelectedStatus(jqLite(currentlySelectedOption), false);
35350
35351    if (self.hasOption(value)) {
35352      self.removeUnknownOption();
35353
35354      var hashedVal = hashKey(value);
35355      $element.val(hashedVal in self.selectValueMap ? hashedVal : value);
35356
35357      // Set selected attribute and property on selected option for screen readers
35358      var selectedOption = $element[0].options[$element[0].selectedIndex];
35359      setOptionSelectedStatus(jqLite(selectedOption), true);
35360    } else {
35361      self.selectUnknownOrEmptyOption(value);
35362    }
35363  };
35364
35365
35366  // Tell the select control that an option, with the given value, has been added
35367  self.addOption = function(value, element) {
35368    // Skip comment nodes, as they only pollute the `optionsMap`
35369    if (element[0].nodeType === NODE_TYPE_COMMENT) return;
35370
35371    assertNotHasOwnProperty(value, '"option value"');
35372    if (value === '') {
35373      self.hasEmptyOption = true;
35374      self.emptyOption = element;
35375    }
35376    var count = optionsMap.get(value) || 0;
35377    optionsMap.set(value, count + 1);
35378    // Only render at the end of a digest. This improves render performance when many options
35379    // are added during a digest and ensures all relevant options are correctly marked as selected
35380    scheduleRender();
35381  };
35382
35383  // Tell the select control that an option, with the given value, has been removed
35384  self.removeOption = function(value) {
35385    var count = optionsMap.get(value);
35386    if (count) {
35387      if (count === 1) {
35388        optionsMap.delete(value);
35389        if (value === '') {
35390          self.hasEmptyOption = false;
35391          self.emptyOption = undefined;
35392        }
35393      } else {
35394        optionsMap.set(value, count - 1);
35395      }
35396    }
35397  };
35398
35399  // Check whether the select control has an option matching the given value
35400  self.hasOption = function(value) {
35401    return !!optionsMap.get(value);
35402  };
35403
35404  /**
35405   * @ngdoc method
35406   * @name select.SelectController#$hasEmptyOption
35407   *
35408   * @description
35409   *
35410   * Returns `true` if the select element currently has an empty option
35411   * element, i.e. an option that signifies that the select is empty / the selection is null.
35412   *
35413   */
35414  self.$hasEmptyOption = function() {
35415    return self.hasEmptyOption;
35416  };
35417
35418  /**
35419   * @ngdoc method
35420   * @name select.SelectController#$isUnknownOptionSelected
35421   *
35422   * @description
35423   *
35424   * Returns `true` if the select element's unknown option is selected. The unknown option is added
35425   * and automatically selected whenever the select model doesn't match any option.
35426   *
35427   */
35428  self.$isUnknownOptionSelected = function() {
35429    // Presence of the unknown option means it is selected
35430    return $element[0].options[0] === self.unknownOption[0];
35431  };
35432
35433  /**
35434   * @ngdoc method
35435   * @name select.SelectController#$isEmptyOptionSelected
35436   *
35437   * @description
35438   *
35439   * Returns `true` if the select element has an empty option and this empty option is currently
35440   * selected. Returns `false` if the select element has no empty option or it is not selected.
35441   *
35442   */
35443  self.$isEmptyOptionSelected = function() {
35444    return self.hasEmptyOption && $element[0].options[$element[0].selectedIndex] === self.emptyOption[0];
35445  };
35446
35447  self.selectUnknownOrEmptyOption = function(value) {
35448    if (value == null && self.emptyOption) {
35449      self.removeUnknownOption();
35450      self.selectEmptyOption();
35451    } else if (self.unknownOption.parent().length) {
35452      self.updateUnknownOption(value);
35453    } else {
35454      self.renderUnknownOption(value);
35455    }
35456  };
35457
35458  var renderScheduled = false;
35459  function scheduleRender() {
35460    if (renderScheduled) return;
35461    renderScheduled = true;
35462    $scope.$$postDigest(function() {
35463      renderScheduled = false;
35464      self.ngModelCtrl.$render();
35465    });
35466  }
35467
35468  var updateScheduled = false;
35469  function scheduleViewValueUpdate(renderAfter) {
35470    if (updateScheduled) return;
35471
35472    updateScheduled = true;
35473
35474    $scope.$$postDigest(function() {
35475      if ($scope.$$destroyed) return;
35476
35477      updateScheduled = false;
35478      self.ngModelCtrl.$setViewValue(self.readValue());
35479      if (renderAfter) self.ngModelCtrl.$render();
35480    });
35481  }
35482
35483
35484  self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
35485
35486    if (optionAttrs.$attr.ngValue) {
35487      // The value attribute is set by ngValue
35488      var oldVal, hashedVal;
35489      optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
35490
35491        var removal;
35492        var previouslySelected = optionElement.prop('selected');
35493
35494        if (isDefined(hashedVal)) {
35495          self.removeOption(oldVal);
35496          delete self.selectValueMap[hashedVal];
35497          removal = true;
35498        }
35499
35500        hashedVal = hashKey(newVal);
35501        oldVal = newVal;
35502        self.selectValueMap[hashedVal] = newVal;
35503        self.addOption(newVal, optionElement);
35504        // Set the attribute directly instead of using optionAttrs.$set - this stops the observer
35505        // from firing a second time. Other $observers on value will also get the result of the
35506        // ngValue expression, not the hashed value
35507        optionElement.attr('value', hashedVal);
35508
35509        if (removal && previouslySelected) {
35510          scheduleViewValueUpdate();
35511        }
35512
35513      });
35514    } else if (interpolateValueFn) {
35515      // The value attribute is interpolated
35516      optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
35517        // This method is overwritten in ngOptions and has side-effects!
35518        self.readValue();
35519
35520        var removal;
35521        var previouslySelected = optionElement.prop('selected');
35522
35523        if (isDefined(oldVal)) {
35524          self.removeOption(oldVal);
35525          removal = true;
35526        }
35527        oldVal = newVal;
35528        self.addOption(newVal, optionElement);
35529
35530        if (removal && previouslySelected) {
35531          scheduleViewValueUpdate();
35532        }
35533      });
35534    } else if (interpolateTextFn) {
35535      // The text content is interpolated
35536      optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
35537        optionAttrs.$set('value', newVal);
35538        var previouslySelected = optionElement.prop('selected');
35539        if (oldVal !== newVal) {
35540          self.removeOption(oldVal);
35541        }
35542        self.addOption(newVal, optionElement);
35543
35544        if (oldVal && previouslySelected) {
35545          scheduleViewValueUpdate();
35546        }
35547      });
35548    } else {
35549      // The value attribute is static
35550      self.addOption(optionAttrs.value, optionElement);
35551    }
35552
35553
35554    optionAttrs.$observe('disabled', function(newVal) {
35555
35556      // Since model updates will also select disabled options (like ngOptions),
35557      // we only have to handle options becoming disabled, not enabled
35558
35559      if (newVal === 'true' || newVal && optionElement.prop('selected')) {
35560        if (self.multiple) {
35561          scheduleViewValueUpdate(true);
35562        } else {
35563          self.ngModelCtrl.$setViewValue(null);
35564          self.ngModelCtrl.$render();
35565        }
35566      }
35567    });
35568
35569    optionElement.on('$destroy', function() {
35570      var currentValue = self.readValue();
35571      var removeValue = optionAttrs.value;
35572
35573      self.removeOption(removeValue);
35574      scheduleRender();
35575
35576      if (self.multiple && currentValue && currentValue.indexOf(removeValue) !== -1 ||
35577          currentValue === removeValue
35578      ) {
35579        // When multiple (selected) options are destroyed at the same time, we don't want
35580        // to run a model update for each of them. Instead, run a single update in the $$postDigest
35581        scheduleViewValueUpdate(true);
35582      }
35583    });
35584  };
35585}];
35586
35587/**
35588 * @ngdoc directive
35589 * @name select
35590 * @restrict E
35591 *
35592 * @description
35593 * HTML `select` element with AngularJS data-binding.
35594 *
35595 * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
35596 * between the scope and the `<select>` control (including setting default values).
35597 * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
35598 * {@link ngOptions `ngOptions`} directives.
35599 *
35600 * When an item in the `<select>` menu is selected, the value of the selected option will be bound
35601 * to the model identified by the `ngModel` directive. With static or repeated options, this is
35602 * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
35603 * Value and textContent can be interpolated.
35604 *
35605 * The {@link select.SelectController select controller} exposes utility functions that can be used
35606 * to manipulate the select's behavior.
35607 *
35608 * ## Matching model and option values
35609 *
35610 * In general, the match between the model and an option is evaluated by strictly comparing the model
35611 * value against the value of the available options.
35612 *
35613 * If you are setting the option value with the option's `value` attribute, or textContent, the
35614 * value will always be a `string` which means that the model value must also be a string.
35615 * Otherwise the `select` directive cannot match them correctly.
35616 *
35617 * To bind the model to a non-string value, you can use one of the following strategies:
35618 * - the {@link ng.ngOptions `ngOptions`} directive
35619 *   ({@link ng.select#using-select-with-ngoptions-and-setting-a-default-value})
35620 * - the {@link ng.ngValue `ngValue`} directive, which allows arbitrary expressions to be
35621 *   option values ({@link ng.select#using-ngvalue-to-bind-the-model-to-an-array-of-objects Example})
35622 * - model $parsers / $formatters to convert the string value
35623 *   ({@link ng.select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting Example})
35624 *
35625 * If the viewValue of `ngModel` does not match any of the options, then the control
35626 * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
35627 *
35628 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
35629 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
35630 * option. See example below for demonstration.
35631 *
35632 * ## Choosing between `ngRepeat` and `ngOptions`
35633 *
35634 * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
35635 * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits:
35636 * - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
35637 * comprehension expression
35638 * - reduced memory consumption by not creating a new scope for each repeated instance
35639 * - increased render speed by creating the options in a documentFragment instead of individually
35640 *
35641 * Specifically, select with repeated options slows down significantly starting at 2000 options in
35642 * Chrome and Internet Explorer / Edge.
35643 *
35644 *
35645 * @param {string} ngModel Assignable AngularJS expression to data-bind to.
35646 * @param {string=} name Property name of the form under which the control is published.
35647 * @param {string=} multiple Allows multiple options to be selected. The selected values will be
35648 *     bound to the model as an array.
35649 * @param {string=} required Sets `required` validation error key if the value is not entered.
35650 * @param {string=} ngRequired Adds required attribute and required validation constraint to
35651 * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
35652 * when you want to data-bind to the required attribute.
35653 * @param {string=} ngChange AngularJS expression to be executed when selected option(s) changes due to user
35654 *    interaction with the select element.
35655 * @param {string=} ngOptions sets the options that the select is populated with and defines what is
35656 * set on the model on selection. See {@link ngOptions `ngOptions`}.
35657 * @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
35658 * {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
35659 *
35660 *
35661 * @example
35662 * ### Simple `select` elements with static options
35663 *
35664 * <example name="static-select" module="staticSelect">
35665 * <file name="index.html">
35666 * <div ng-controller="ExampleController">
35667 *   <form name="myForm">
35668 *     <label for="singleSelect"> Single select: </label><br>
35669 *     <select name="singleSelect" ng-model="data.singleSelect">
35670 *       <option value="option-1">Option 1</option>
35671 *       <option value="option-2">Option 2</option>
35672 *     </select><br>
35673 *
35674 *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
35675 *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
35676 *       <option value="">---Please select---</option> <!-- not selected / blank option -->
35677 *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
35678 *       <option value="option-2">Option 2</option>
35679 *     </select><br>
35680 *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
35681 *     <tt>singleSelect = {{data.singleSelect}}</tt>
35682 *
35683 *     <hr>
35684 *     <label for="multipleSelect"> Multiple select: </label><br>
35685 *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
35686 *       <option value="option-1">Option 1</option>
35687 *       <option value="option-2">Option 2</option>
35688 *       <option value="option-3">Option 3</option>
35689 *     </select><br>
35690 *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
35691 *   </form>
35692 * </div>
35693 * </file>
35694 * <file name="app.js">
35695 *  angular.module('staticSelect', [])
35696 *    .controller('ExampleController', ['$scope', function($scope) {
35697 *      $scope.data = {
35698 *       singleSelect: null,
35699 *       multipleSelect: [],
35700 *       option1: 'option-1'
35701 *      };
35702 *
35703 *      $scope.forceUnknownOption = function() {
35704 *        $scope.data.singleSelect = 'nonsense';
35705 *      };
35706 *   }]);
35707 * </file>
35708 *</example>
35709 *
35710 * @example
35711 * ### Using `ngRepeat` to generate `select` options
35712 * <example name="select-ngrepeat" module="ngrepeatSelect">
35713 * <file name="index.html">
35714 * <div ng-controller="ExampleController">
35715 *   <form name="myForm">
35716 *     <label for="repeatSelect"> Repeat select: </label>
35717 *     <select name="repeatSelect" id="repeatSelect" ng-model="data.model">
35718 *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
35719 *     </select>
35720 *   </form>
35721 *   <hr>
35722 *   <tt>model = {{data.model}}</tt><br/>
35723 * </div>
35724 * </file>
35725 * <file name="app.js">
35726 *  angular.module('ngrepeatSelect', [])
35727 *    .controller('ExampleController', ['$scope', function($scope) {
35728 *      $scope.data = {
35729 *       model: null,
35730 *       availableOptions: [
35731 *         {id: '1', name: 'Option A'},
35732 *         {id: '2', name: 'Option B'},
35733 *         {id: '3', name: 'Option C'}
35734 *       ]
35735 *      };
35736 *   }]);
35737 * </file>
35738 *</example>
35739 *
35740 * @example
35741 * ### Using `ngValue` to bind the model to an array of objects
35742 * <example name="select-ngvalue" module="ngvalueSelect">
35743 * <file name="index.html">
35744 * <div ng-controller="ExampleController">
35745 *   <form name="myForm">
35746 *     <label for="ngvalueselect"> ngvalue select: </label>
35747 *     <select size="6" name="ngvalueselect" ng-model="data.model" multiple>
35748 *       <option ng-repeat="option in data.availableOptions" ng-value="option.value">{{option.name}}</option>
35749 *     </select>
35750 *   </form>
35751 *   <hr>
35752 *   <pre>model = {{data.model | json}}</pre><br/>
35753 * </div>
35754 * </file>
35755 * <file name="app.js">
35756 *  angular.module('ngvalueSelect', [])
35757 *    .controller('ExampleController', ['$scope', function($scope) {
35758 *      $scope.data = {
35759 *       model: null,
35760 *       availableOptions: [
35761           {value: 'myString', name: 'string'},
35762           {value: 1, name: 'integer'},
35763           {value: true, name: 'boolean'},
35764           {value: null, name: 'null'},
35765           {value: {prop: 'value'}, name: 'object'},
35766           {value: ['a'], name: 'array'}
35767 *       ]
35768 *      };
35769 *   }]);
35770 * </file>
35771 *</example>
35772 *
35773 * @example
35774 * ### Using `select` with `ngOptions` and setting a default value
35775 * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
35776 *
35777 * <example name="select-with-default-values" module="defaultValueSelect">
35778 * <file name="index.html">
35779 * <div ng-controller="ExampleController">
35780 *   <form name="myForm">
35781 *     <label for="mySelect">Make a choice:</label>
35782 *     <select name="mySelect" id="mySelect"
35783 *       ng-options="option.name for option in data.availableOptions track by option.id"
35784 *       ng-model="data.selectedOption"></select>
35785 *   </form>
35786 *   <hr>
35787 *   <tt>option = {{data.selectedOption}}</tt><br/>
35788 * </div>
35789 * </file>
35790 * <file name="app.js">
35791 *  angular.module('defaultValueSelect', [])
35792 *    .controller('ExampleController', ['$scope', function($scope) {
35793 *      $scope.data = {
35794 *       availableOptions: [
35795 *         {id: '1', name: 'Option A'},
35796 *         {id: '2', name: 'Option B'},
35797 *         {id: '3', name: 'Option C'}
35798 *       ],
35799 *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
35800 *       };
35801 *   }]);
35802 * </file>
35803 *</example>
35804 *
35805 * @example
35806 * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
35807 *
35808 * <example name="select-with-non-string-options" module="nonStringSelect">
35809 *   <file name="index.html">
35810 *     <select ng-model="model.id" convert-to-number>
35811 *       <option value="0">Zero</option>
35812 *       <option value="1">One</option>
35813 *       <option value="2">Two</option>
35814 *     </select>
35815 *     {{ model }}
35816 *   </file>
35817 *   <file name="app.js">
35818 *     angular.module('nonStringSelect', [])
35819 *       .run(function($rootScope) {
35820 *         $rootScope.model = { id: 2 };
35821 *       })
35822 *       .directive('convertToNumber', function() {
35823 *         return {
35824 *           require: 'ngModel',
35825 *           link: function(scope, element, attrs, ngModel) {
35826 *             ngModel.$parsers.push(function(val) {
35827 *               return parseInt(val, 10);
35828 *             });
35829 *             ngModel.$formatters.push(function(val) {
35830 *               return '' + val;
35831 *             });
35832 *           }
35833 *         };
35834 *       });
35835 *   </file>
35836 *   <file name="protractor.js" type="protractor">
35837 *     it('should initialize to model', function() {
35838 *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
35839 *     });
35840 *   </file>
35841 * </example>
35842 *
35843 */
35844var selectDirective = function() {
35845
35846  return {
35847    restrict: 'E',
35848    require: ['select', '?ngModel'],
35849    controller: SelectController,
35850    priority: 1,
35851    link: {
35852      pre: selectPreLink,
35853      post: selectPostLink
35854    }
35855  };
35856
35857  function selectPreLink(scope, element, attr, ctrls) {
35858
35859      var selectCtrl = ctrls[0];
35860      var ngModelCtrl = ctrls[1];
35861
35862      // if ngModel is not defined, we don't need to do anything but set the registerOption
35863      // function to noop, so options don't get added internally
35864      if (!ngModelCtrl) {
35865        selectCtrl.registerOption = noop;
35866        return;
35867      }
35868
35869
35870      selectCtrl.ngModelCtrl = ngModelCtrl;
35871
35872      // When the selected item(s) changes we delegate getting the value of the select control
35873      // to the `readValue` method, which can be changed if the select can have multiple
35874      // selected values or if the options are being generated by `ngOptions`
35875      element.on('change', function() {
35876        selectCtrl.removeUnknownOption();
35877        scope.$apply(function() {
35878          ngModelCtrl.$setViewValue(selectCtrl.readValue());
35879        });
35880      });
35881
35882      // If the select allows multiple values then we need to modify how we read and write
35883      // values from and to the control; also what it means for the value to be empty and
35884      // we have to add an extra watch since ngModel doesn't work well with arrays - it
35885      // doesn't trigger rendering if only an item in the array changes.
35886      if (attr.multiple) {
35887        selectCtrl.multiple = true;
35888
35889        // Read value now needs to check each option to see if it is selected
35890        selectCtrl.readValue = function readMultipleValue() {
35891          var array = [];
35892          forEach(element.find('option'), function(option) {
35893            if (option.selected && !option.disabled) {
35894              var val = option.value;
35895              array.push(val in selectCtrl.selectValueMap ? selectCtrl.selectValueMap[val] : val);
35896            }
35897          });
35898          return array;
35899        };
35900
35901        // Write value now needs to set the selected property of each matching option
35902        selectCtrl.writeValue = function writeMultipleValue(value) {
35903          forEach(element.find('option'), function(option) {
35904            var shouldBeSelected = !!value && (includes(value, option.value) ||
35905                                               includes(value, selectCtrl.selectValueMap[option.value]));
35906            var currentlySelected = option.selected;
35907
35908            // Support: IE 9-11 only, Edge 12-15+
35909            // In IE and Edge adding options to the selection via shift+click/UP/DOWN
35910            // will de-select already selected options if "selected" on those options was set
35911            // more than once (i.e. when the options were already selected)
35912            // So we only modify the selected property if necessary.
35913            // Note: this behavior cannot be replicated via unit tests because it only shows in the
35914            // actual user interface.
35915            if (shouldBeSelected !== currentlySelected) {
35916              setOptionSelectedStatus(jqLite(option), shouldBeSelected);
35917            }
35918
35919          });
35920        };
35921
35922        // we have to do it on each watch since ngModel watches reference, but
35923        // we need to work of an array, so we need to see if anything was inserted/removed
35924        var lastView, lastViewRef = NaN;
35925        scope.$watch(function selectMultipleWatch() {
35926          if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
35927            lastView = shallowCopy(ngModelCtrl.$viewValue);
35928            ngModelCtrl.$render();
35929          }
35930          lastViewRef = ngModelCtrl.$viewValue;
35931        });
35932
35933        // If we are a multiple select then value is now a collection
35934        // so the meaning of $isEmpty changes
35935        ngModelCtrl.$isEmpty = function(value) {
35936          return !value || value.length === 0;
35937        };
35938
35939      }
35940    }
35941
35942    function selectPostLink(scope, element, attrs, ctrls) {
35943      // if ngModel is not defined, we don't need to do anything
35944      var ngModelCtrl = ctrls[1];
35945      if (!ngModelCtrl) return;
35946
35947      var selectCtrl = ctrls[0];
35948
35949      // We delegate rendering to the `writeValue` method, which can be changed
35950      // if the select can have multiple selected values or if the options are being
35951      // generated by `ngOptions`.
35952      // This must be done in the postLink fn to prevent $render to be called before
35953      // all nodes have been linked correctly.
35954      ngModelCtrl.$render = function() {
35955        selectCtrl.writeValue(ngModelCtrl.$viewValue);
35956      };
35957    }
35958};
35959
35960
35961// The option directive is purely designed to communicate the existence (or lack of)
35962// of dynamically created (and destroyed) option elements to their containing select
35963// directive via its controller.
35964var optionDirective = ['$interpolate', function($interpolate) {
35965  return {
35966    restrict: 'E',
35967    priority: 100,
35968    compile: function(element, attr) {
35969      var interpolateValueFn, interpolateTextFn;
35970
35971      if (isDefined(attr.ngValue)) {
35972        // Will be handled by registerOption
35973      } else if (isDefined(attr.value)) {
35974        // If the value attribute is defined, check if it contains an interpolation
35975        interpolateValueFn = $interpolate(attr.value, true);
35976      } else {
35977        // If the value attribute is not defined then we fall back to the
35978        // text content of the option element, which may be interpolated
35979        interpolateTextFn = $interpolate(element.text(), true);
35980        if (!interpolateTextFn) {
35981          attr.$set('value', element.text());
35982        }
35983      }
35984
35985      return function(scope, element, attr) {
35986        // This is an optimization over using ^^ since we don't want to have to search
35987        // all the way to the root of the DOM for every single option element
35988        var selectCtrlName = '$selectController',
35989            parent = element.parent(),
35990            selectCtrl = parent.data(selectCtrlName) ||
35991              parent.parent().data(selectCtrlName); // in case we are in optgroup
35992
35993        if (selectCtrl) {
35994          selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
35995        }
35996      };
35997    }
35998  };
35999}];
36000
36001/**
36002 * @ngdoc directive
36003 * @name ngRequired
36004 * @restrict A
36005 *
36006 * @param {expression} ngRequired AngularJS expression. If it evaluates to `true`, it sets the
36007 *                                `required` attribute to the element and adds the `required`
36008 *                                {@link ngModel.NgModelController#$validators `validator`}.
36009 *
36010 * @description
36011 *
36012 * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
36013 * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
36014 * applied to custom controls.
36015 *
36016 * The directive sets the `required` attribute on the element if the AngularJS expression inside
36017 * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
36018 * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
36019 * for more info.
36020 *
36021 * The validator will set the `required` error key to true if the `required` attribute is set and
36022 * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
36023 * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
36024 * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
36025 * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
36026 *
36027 * @example
36028 * <example name="ngRequiredDirective" module="ngRequiredExample">
36029 *   <file name="index.html">
36030 *     <script>
36031 *       angular.module('ngRequiredExample', [])
36032 *         .controller('ExampleController', ['$scope', function($scope) {
36033 *           $scope.required = true;
36034 *         }]);
36035 *     </script>
36036 *     <div ng-controller="ExampleController">
36037 *       <form name="form">
36038 *         <label for="required">Toggle required: </label>
36039 *         <input type="checkbox" ng-model="required" id="required" />
36040 *         <br>
36041 *         <label for="input">This input must be filled if `required` is true: </label>
36042 *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
36043 *         <hr>
36044 *         required error set? = <code>{{form.input.$error.required}}</code><br>
36045 *         model = <code>{{model}}</code>
36046 *       </form>
36047 *     </div>
36048 *   </file>
36049 *   <file name="protractor.js" type="protractor">
36050       var required = element(by.binding('form.input.$error.required'));
36051       var model = element(by.binding('model'));
36052       var input = element(by.id('input'));
36053
36054       it('should set the required error', function() {
36055         expect(required.getText()).toContain('true');
36056
36057         input.sendKeys('123');
36058         expect(required.getText()).not.toContain('true');
36059         expect(model.getText()).toContain('123');
36060       });
36061 *   </file>
36062 * </example>
36063 */
36064var requiredDirective = ['$parse', function($parse) {
36065  return {
36066    restrict: 'A',
36067    require: '?ngModel',
36068    link: function(scope, elm, attr, ctrl) {
36069      if (!ctrl) return;
36070      // For boolean attributes like required, presence means true
36071      var value = attr.hasOwnProperty('required') || $parse(attr.ngRequired)(scope);
36072
36073      if (!attr.ngRequired) {
36074        // force truthy in case we are on non input element
36075        // (input elements do this automatically for boolean attributes like required)
36076        attr.required = true;
36077      }
36078
36079      ctrl.$validators.required = function(modelValue, viewValue) {
36080        return !value || !ctrl.$isEmpty(viewValue);
36081      };
36082
36083      attr.$observe('required', function(newVal) {
36084
36085        if (value !== newVal) {
36086          value = newVal;
36087          ctrl.$validate();
36088        }
36089      });
36090    }
36091  };
36092}];
36093
36094/**
36095 * @ngdoc directive
36096 * @name ngPattern
36097 * @restrict A
36098 *
36099 * @param {expression|RegExp} ngPattern AngularJS expression that must evaluate to a `RegExp` or a `String`
36100 *                                      parsable into a `RegExp`, or a `RegExp` literal. See above for
36101 *                                      more details.
36102 *
36103 * @description
36104 *
36105 * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
36106 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
36107 *
36108 * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
36109 * does not match a RegExp which is obtained from the `ngPattern` attribute value:
36110 * - the value is an AngularJS expression:
36111 *   - If the expression evaluates to a RegExp object, then this is used directly.
36112 *   - If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
36113 *     in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
36114 * - If the value is a RegExp literal, e.g. `ngPattern="/^\d+$/"`, it is used directly.
36115 *
36116 * <div class="alert alert-info">
36117 * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
36118 * start at the index of the last search's match, thus not taking the whole input value into
36119 * account.
36120 * </div>
36121 *
36122 * <div class="alert alert-info">
36123 * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
36124 * differences:
36125 * <ol>
36126 *   <li>
36127 *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
36128 *     not available.
36129 *   </li>
36130 *   <li>
36131 *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
36132 *     interpolated.
36133 *   </li>
36134 * </ol>
36135 * </div>
36136 *
36137 * @example
36138 * <example name="ngPatternDirective" module="ngPatternExample">
36139 *   <file name="index.html">
36140 *     <script>
36141 *       angular.module('ngPatternExample', [])
36142 *         .controller('ExampleController', ['$scope', function($scope) {
36143 *           $scope.regex = '\\d+';
36144 *         }]);
36145 *     </script>
36146 *     <div ng-controller="ExampleController">
36147 *       <form name="form">
36148 *         <label for="regex">Set a pattern (regex string): </label>
36149 *         <input type="text" ng-model="regex" id="regex" />
36150 *         <br>
36151 *         <label for="input">This input is restricted by the current pattern: </label>
36152 *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
36153 *         <hr>
36154 *         input valid? = <code>{{form.input.$valid}}</code><br>
36155 *         model = <code>{{model}}</code>
36156 *       </form>
36157 *     </div>
36158 *   </file>
36159 *   <file name="protractor.js" type="protractor">
36160       var model = element(by.binding('model'));
36161       var input = element(by.id('input'));
36162
36163       it('should validate the input with the default pattern', function() {
36164         input.sendKeys('aaa');
36165         expect(model.getText()).not.toContain('aaa');
36166
36167         input.clear().then(function() {
36168           input.sendKeys('123');
36169           expect(model.getText()).toContain('123');
36170         });
36171       });
36172 *   </file>
36173 * </example>
36174 */
36175var patternDirective = ['$parse', function($parse) {
36176  return {
36177    restrict: 'A',
36178    require: '?ngModel',
36179    compile: function(tElm, tAttr) {
36180      var patternExp;
36181      var parseFn;
36182
36183      if (tAttr.ngPattern) {
36184        patternExp = tAttr.ngPattern;
36185
36186        // ngPattern might be a scope expression, or an inlined regex, which is not parsable.
36187        // We get value of the attribute here, so we can compare the old and the new value
36188        // in the observer to avoid unnecessary validations
36189        if (tAttr.ngPattern.charAt(0) === '/' && REGEX_STRING_REGEXP.test(tAttr.ngPattern)) {
36190          parseFn = function() { return tAttr.ngPattern; };
36191        } else {
36192          parseFn = $parse(tAttr.ngPattern);
36193        }
36194      }
36195
36196      return function(scope, elm, attr, ctrl) {
36197        if (!ctrl) return;
36198
36199        var attrVal = attr.pattern;
36200
36201        if (attr.ngPattern) {
36202          attrVal = parseFn(scope);
36203        } else {
36204          patternExp = attr.pattern;
36205        }
36206
36207        var regexp = parsePatternAttr(attrVal, patternExp, elm);
36208
36209        attr.$observe('pattern', function(newVal) {
36210          var oldRegexp = regexp;
36211
36212          regexp = parsePatternAttr(newVal, patternExp, elm);
36213
36214          if ((oldRegexp && oldRegexp.toString()) !== (regexp && regexp.toString())) {
36215            ctrl.$validate();
36216          }
36217        });
36218
36219        ctrl.$validators.pattern = function(modelValue, viewValue) {
36220          // HTML5 pattern constraint validates the input value, so we validate the viewValue
36221          return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
36222        };
36223      };
36224    }
36225
36226  };
36227}];
36228
36229/**
36230 * @ngdoc directive
36231 * @name ngMaxlength
36232 * @restrict A
36233 *
36234 * @param {expression} ngMaxlength AngularJS expression that must evaluate to a `Number` or `String`
36235 *                                 parsable into a `Number`. Used as value for the `maxlength`
36236 *                                 {@link ngModel.NgModelController#$validators validator}.
36237 *
36238 * @description
36239 *
36240 * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
36241 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
36242 *
36243 * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
36244 * is longer than the integer obtained by evaluating the AngularJS expression given in the
36245 * `ngMaxlength` attribute value.
36246 *
36247 * <div class="alert alert-info">
36248 * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
36249 * differences:
36250 * <ol>
36251 *   <li>
36252 *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
36253 *     validation is not available.
36254 *   </li>
36255 *   <li>
36256 *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
36257 *     interpolated.
36258 *   </li>
36259 * </ol>
36260 * </div>
36261 *
36262 * @example
36263 * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
36264 *   <file name="index.html">
36265 *     <script>
36266 *       angular.module('ngMaxlengthExample', [])
36267 *         .controller('ExampleController', ['$scope', function($scope) {
36268 *           $scope.maxlength = 5;
36269 *         }]);
36270 *     </script>
36271 *     <div ng-controller="ExampleController">
36272 *       <form name="form">
36273 *         <label for="maxlength">Set a maxlength: </label>
36274 *         <input type="number" ng-model="maxlength" id="maxlength" />
36275 *         <br>
36276 *         <label for="input">This input is restricted by the current maxlength: </label>
36277 *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
36278 *         <hr>
36279 *         input valid? = <code>{{form.input.$valid}}</code><br>
36280 *         model = <code>{{model}}</code>
36281 *       </form>
36282 *     </div>
36283 *   </file>
36284 *   <file name="protractor.js" type="protractor">
36285       var model = element(by.binding('model'));
36286       var input = element(by.id('input'));
36287
36288       it('should validate the input with the default maxlength', function() {
36289         input.sendKeys('abcdef');
36290         expect(model.getText()).not.toContain('abcdef');
36291
36292         input.clear().then(function() {
36293           input.sendKeys('abcde');
36294           expect(model.getText()).toContain('abcde');
36295         });
36296       });
36297 *   </file>
36298 * </example>
36299 */
36300var maxlengthDirective = ['$parse', function($parse) {
36301  return {
36302    restrict: 'A',
36303    require: '?ngModel',
36304    link: function(scope, elm, attr, ctrl) {
36305      if (!ctrl) return;
36306
36307      var maxlength = attr.maxlength || $parse(attr.ngMaxlength)(scope);
36308      var maxlengthParsed = parseLength(maxlength);
36309
36310      attr.$observe('maxlength', function(value) {
36311        if (maxlength !== value) {
36312          maxlengthParsed = parseLength(value);
36313          maxlength = value;
36314          ctrl.$validate();
36315        }
36316      });
36317      ctrl.$validators.maxlength = function(modelValue, viewValue) {
36318        return (maxlengthParsed < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlengthParsed);
36319      };
36320    }
36321  };
36322}];
36323
36324/**
36325 * @ngdoc directive
36326 * @name ngMinlength
36327 * @restrict A
36328 *
36329 * @param {expression} ngMinlength AngularJS expression that must evaluate to a `Number` or `String`
36330 *                                 parsable into a `Number`. Used as value for the `minlength`
36331 *                                 {@link ngModel.NgModelController#$validators validator}.
36332 *
36333 * @description
36334 *
36335 * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
36336 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
36337 *
36338 * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
36339 * is shorter than the integer obtained by evaluating the AngularJS expression given in the
36340 * `ngMinlength` attribute value.
36341 *
36342 * <div class="alert alert-info">
36343 * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
36344 * differences:
36345 * <ol>
36346 *   <li>
36347 *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
36348 *     validation is not available.
36349 *   </li>
36350 *   <li>
36351 *     The `ngMinlength` value must be an expression, while the `minlength` value must be
36352 *     interpolated.
36353 *   </li>
36354 * </ol>
36355 * </div>
36356 *
36357 * @example
36358 * <example name="ngMinlengthDirective" module="ngMinlengthExample">
36359 *   <file name="index.html">
36360 *     <script>
36361 *       angular.module('ngMinlengthExample', [])
36362 *         .controller('ExampleController', ['$scope', function($scope) {
36363 *           $scope.minlength = 3;
36364 *         }]);
36365 *     </script>
36366 *     <div ng-controller="ExampleController">
36367 *       <form name="form">
36368 *         <label for="minlength">Set a minlength: </label>
36369 *         <input type="number" ng-model="minlength" id="minlength" />
36370 *         <br>
36371 *         <label for="input">This input is restricted by the current minlength: </label>
36372 *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
36373 *         <hr>
36374 *         input valid? = <code>{{form.input.$valid}}</code><br>
36375 *         model = <code>{{model}}</code>
36376 *       </form>
36377 *     </div>
36378 *   </file>
36379 *   <file name="protractor.js" type="protractor">
36380       var model = element(by.binding('model'));
36381       var input = element(by.id('input'));
36382
36383       it('should validate the input with the default minlength', function() {
36384         input.sendKeys('ab');
36385         expect(model.getText()).not.toContain('ab');
36386
36387         input.sendKeys('abc');
36388         expect(model.getText()).toContain('abc');
36389       });
36390 *   </file>
36391 * </example>
36392 */
36393var minlengthDirective = ['$parse', function($parse) {
36394  return {
36395    restrict: 'A',
36396    require: '?ngModel',
36397    link: function(scope, elm, attr, ctrl) {
36398      if (!ctrl) return;
36399
36400      var minlength = attr.minlength || $parse(attr.ngMinlength)(scope);
36401      var minlengthParsed = parseLength(minlength) || -1;
36402
36403      attr.$observe('minlength', function(value) {
36404        if (minlength !== value) {
36405          minlengthParsed = parseLength(value) || -1;
36406          minlength = value;
36407          ctrl.$validate();
36408        }
36409
36410      });
36411      ctrl.$validators.minlength = function(modelValue, viewValue) {
36412        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlengthParsed;
36413      };
36414    }
36415  };
36416}];
36417
36418
36419function parsePatternAttr(regex, patternExp, elm) {
36420  if (!regex) return undefined;
36421
36422  if (isString(regex)) {
36423    regex = new RegExp('^' + regex + '$');
36424  }
36425
36426  if (!regex.test) {
36427    throw minErr('ngPattern')('noregexp',
36428      'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
36429      regex, startingTag(elm));
36430  }
36431
36432  return regex;
36433}
36434
36435function parseLength(val) {
36436  var intVal = toInt(val);
36437  return isNumberNaN(intVal) ? -1 : intVal;
36438}
36439
36440if (window.angular.bootstrap) {
36441  // AngularJS is already loaded, so we can return here...
36442  if (window.console) {
36443    console.log('WARNING: Tried to load AngularJS more than once.');
36444  }
36445  return;
36446}
36447
36448// try to bind to jquery now so that one can write jqLite(fn)
36449// but we will rebind on bootstrap again.
36450bindJQuery();
36451
36452publishExternalAPI(angular);
36453
36454angular.module("ngLocale", [], ["$provide", function($provide) {
36455var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
36456function getDecimals(n) {
36457  n = n + '';
36458  var i = n.indexOf('.');
36459  return (i == -1) ? 0 : n.length - i - 1;
36460}
36461
36462function getVF(n, opt_precision) {
36463  var v = opt_precision;
36464
36465  if (undefined === v) {
36466    v = Math.min(getDecimals(n), 3);
36467  }
36468
36469  var base = Math.pow(10, v);
36470  var f = ((n * base) | 0) % base;
36471  return {v: v, f: f};
36472}
36473
36474$provide.value("$locale", {
36475  "DATETIME_FORMATS": {
36476    "AMPMS": [
36477      "AM",
36478      "PM"
36479    ],
36480    "DAY": [
36481      "Sunday",
36482      "Monday",
36483      "Tuesday",
36484      "Wednesday",
36485      "Thursday",
36486      "Friday",
36487      "Saturday"
36488    ],
36489    "ERANAMES": [
36490      "Before Christ",
36491      "Anno Domini"
36492    ],
36493    "ERAS": [
36494      "BC",
36495      "AD"
36496    ],
36497    "FIRSTDAYOFWEEK": 6,
36498    "MONTH": [
36499      "January",
36500      "February",
36501      "March",
36502      "April",
36503      "May",
36504      "June",
36505      "July",
36506      "August",
36507      "September",
36508      "October",
36509      "November",
36510      "December"
36511    ],
36512    "SHORTDAY": [
36513      "Sun",
36514      "Mon",
36515      "Tue",
36516      "Wed",
36517      "Thu",
36518      "Fri",
36519      "Sat"
36520    ],
36521    "SHORTMONTH": [
36522      "Jan",
36523      "Feb",
36524      "Mar",
36525      "Apr",
36526      "May",
36527      "Jun",
36528      "Jul",
36529      "Aug",
36530      "Sep",
36531      "Oct",
36532      "Nov",
36533      "Dec"
36534    ],
36535    "STANDALONEMONTH": [
36536      "January",
36537      "February",
36538      "March",
36539      "April",
36540      "May",
36541      "June",
36542      "July",
36543      "August",
36544      "September",
36545      "October",
36546      "November",
36547      "December"
36548    ],
36549    "WEEKENDRANGE": [
36550      5,
36551      6
36552    ],
36553    "fullDate": "EEEE, MMMM d, y",
36554    "longDate": "MMMM d, y",
36555    "medium": "MMM d, y h:mm:ss a",
36556    "mediumDate": "MMM d, y",
36557    "mediumTime": "h:mm:ss a",
36558    "short": "M/d/yy h:mm a",
36559    "shortDate": "M/d/yy",
36560    "shortTime": "h:mm a"
36561  },
36562  "NUMBER_FORMATS": {
36563    "CURRENCY_SYM": "$",
36564    "DECIMAL_SEP": ".",
36565    "GROUP_SEP": ",",
36566    "PATTERNS": [
36567      {
36568        "gSize": 3,
36569        "lgSize": 3,
36570        "maxFrac": 3,
36571        "minFrac": 0,
36572        "minInt": 1,
36573        "negPre": "-",
36574        "negSuf": "",
36575        "posPre": "",
36576        "posSuf": ""
36577      },
36578      {
36579        "gSize": 3,
36580        "lgSize": 3,
36581        "maxFrac": 2,
36582        "minFrac": 2,
36583        "minInt": 1,
36584        "negPre": "-\u00a4",
36585        "negSuf": "",
36586        "posPre": "\u00a4",
36587        "posSuf": ""
36588      }
36589    ]
36590  },
36591  "id": "en-us",
36592  "localeID": "en_US",
36593  "pluralCat": function(n, opt_precision) {  var i = n | 0;  var vf = getVF(n, opt_precision);  if (i == 1 && vf.v == 0) {    return PLURAL_CATEGORY.ONE;  }  return PLURAL_CATEGORY.OTHER;}
36594});
36595}]);
36596
36597  jqLite(function() {
36598    angularInit(window.document, bootstrap);
36599  });
36600
36601})(window);
36602
36603!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(window.angular.element('<style>').text('@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}'));
36603
vendor: 16,592 bytes, lines 36604-37029
36604/**
36605 * @license AngularJS v1.8.3
36606 * (c) 2010-2020 Google LLC. http://angularjs.org
36607 * License: MIT
36608 */
36609(function(window, angular) {'use strict';
36610
36611/**
36612 * @ngdoc module
36613 * @name ngAria
36614 * @description
36615 *
36616 * The `ngAria` module provides support for common
36617 * [<abbr title="Accessible Rich Internet Applications">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)
36618 * attributes that convey state or semantic information about the application for users
36619 * of assistive technologies, such as screen readers.
36620 *
36621 * ## Usage
36622 *
36623 * For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
36624 * directives are supported:
36625 * `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`,
36626 * `ngClick`, `ngDblClick`, and `ngMessages`.
36627 *
36628 * Below is a more detailed breakdown of the attributes handled by ngAria:
36629 *
36630 * | Directive                                   | Supported Attributes                                                                                |
36631 * |---------------------------------------------|-----------------------------------------------------------------------------------------------------|
36632 * | {@link ng.directive:ngModel ngModel}        | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
36633 * | {@link ng.directive:ngDisabled ngDisabled}  | aria-disabled                                                                                       |
36634 * | {@link ng.directive:ngRequired ngRequired}  | aria-required                                                                                       |
36635 * | {@link ng.directive:ngChecked ngChecked}    | aria-checked                                                                                        |
36636 * | {@link ng.directive:ngReadonly ngReadonly}  | aria-readonly                                                                                       |
36637 * | {@link ng.directive:ngValue ngValue}        | aria-checked                                                                                        |
36638 * | {@link ng.directive:ngShow ngShow}          | aria-hidden                                                                                         |
36639 * | {@link ng.directive:ngHide ngHide}          | aria-hidden                                                                                         |
36640 * | {@link ng.directive:ngDblclick ngDblclick}  | tabindex                                                                                            |
36641 * | {@link module:ngMessages ngMessages}        | aria-live                                                                                           |
36642 * | {@link ng.directive:ngClick ngClick}        | tabindex, keydown event, button role                                                                |
36643 *
36644 * Find out more information about each directive by reading the
36645 * {@link guide/accessibility ngAria Developer Guide}.
36646 *
36647 * ## Example
36648 * Using ngDisabled with ngAria:
36649 * ```html
36650 * <md-checkbox ng-disabled="disabled">
36651 * ```
36652 * Becomes:
36653 * ```html
36654 * <md-checkbox ng-disabled="disabled" aria-disabled="true">
36655 * ```
36656 *
36657 * ## Disabling Specific Attributes
36658 * It is possible to disable individual attributes added by ngAria with the
36659 * {@link ngAria.$ariaProvider#config config} method. For more details, see the
36660 * {@link guide/accessibility Developer Guide}.
36661 *
36662 * ## Disabling `ngAria` on Specific Elements
36663 * It is possible to make `ngAria` ignore a specific element, by adding the `ng-aria-disable`
36664 * attribute on it. Note that only the element itself (and not its child elements) will be ignored.
36665 */
36666var ARIA_DISABLE_ATTR = 'ngAriaDisable';
36667
36668var ngAriaModule = angular.module('ngAria', ['ng']).
36669                        info({ angularVersion: '1.8.3' }).
36670                        provider('$aria', $AriaProvider);
36671
36672/**
36673* Internal Utilities
36674*/
36675var nativeAriaNodeNames = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
36676
36677var isNodeOneOf = function(elem, nodeTypeArray) {
36678  if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
36679    return true;
36680  }
36681};
36682/**
36683 * @ngdoc provider
36684 * @name $ariaProvider
36685 * @this
36686 *
36687 * @description
36688 *
36689 * Used for configuring the ARIA attributes injected and managed by ngAria.
36690 *
36691 * ```js
36692 * angular.module('myApp', ['ngAria'], function config($ariaProvider) {
36693 *   $ariaProvider.config({
36694 *     ariaValue: true,
36695 *     tabindex: false
36696 *   });
36697 * });
36698 *```
36699 *
36700 * ## Dependencies
36701 * Requires the {@link ngAria} module to be installed.
36702 *
36703 */
36704function $AriaProvider() {
36705  var config = {
36706    ariaHidden: true,
36707    ariaChecked: true,
36708    ariaReadonly: true,
36709    ariaDisabled: true,
36710    ariaRequired: true,
36711    ariaInvalid: true,
36712    ariaValue: true,
36713    tabindex: true,
36714    bindKeydown: true,
36715    bindRoleForClick: true
36716  };
36717
36718  /**
36719   * @ngdoc method
36720   * @name $ariaProvider#config
36721   *
36722   * @param {object} config object to enable/disable specific ARIA attributes
36723   *
36724   *  - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
36725   *  - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
36726   *  - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags
36727   *  - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
36728   *  - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
36729   *  - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
36730   *  - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and
36731   *    aria-valuenow tags
36732   *  - **tabindex** – `{boolean}` – Enables/disables tabindex tags
36733   *  - **bindKeydown** – `{boolean}` – Enables/disables keyboard event binding on non-interactive
36734   *    elements (such as `div` or `li`) using ng-click, making them more accessible to users of
36735   *    assistive technologies
36736   *  - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements (such as
36737   *    `div` or `li`) using ng-click, making them more accessible to users of assistive
36738   *    technologies
36739   *
36740   * @description
36741   * Enables/disables various ARIA attributes
36742   */
36743  this.config = function(newConfig) {
36744    config = angular.extend(config, newConfig);
36745  };
36746
36747  function watchExpr(attrName, ariaAttr, nativeAriaNodeNames, negate) {
36748    return function(scope, elem, attr) {
36749      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
36750
36751      var ariaCamelName = attr.$normalize(ariaAttr);
36752      if (config[ariaCamelName] && !isNodeOneOf(elem, nativeAriaNodeNames) && !attr[ariaCamelName]) {
36753        scope.$watch(attr[attrName], function(boolVal) {
36754          // ensure boolean value
36755          boolVal = negate ? !boolVal : !!boolVal;
36756          elem.attr(ariaAttr, boolVal);
36757        });
36758      }
36759    };
36760  }
36761  /**
36762   * @ngdoc service
36763   * @name $aria
36764   *
36765   * @description
36766   *
36767   * The $aria service contains helper methods for applying common
36768   * [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
36769   *
36770   * ngAria injects common accessibility attributes that tell assistive technologies when HTML
36771   * elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,
36772   * let's review a code snippet from ngAria itself:
36773   *
36774   *```js
36775   * ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
36776   *   return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
36777   * }])
36778   *```
36779   * Shown above, the ngAria module creates a directive with the same signature as the
36780   * traditional `ng-disabled` directive. But this ngAria version is dedicated to
36781   * solely managing accessibility attributes on custom elements. The internal `$aria` service is
36782   * used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the
36783   * developer, `aria-disabled` is injected as an attribute with its value synchronized to the
36784   * value in `ngDisabled`.
36785   *
36786   * Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
36787   * anything to enable this feature. The `aria-disabled` attribute is automatically managed
36788   * simply as a silent side-effect of using `ng-disabled` with the ngAria module.
36789   *
36790   * The full list of directives that interface with ngAria:
36791   * * **ngModel**
36792   * * **ngChecked**
36793   * * **ngReadonly**
36794   * * **ngRequired**
36795   * * **ngDisabled**
36796   * * **ngValue**
36797   * * **ngShow**
36798   * * **ngHide**
36799   * * **ngClick**
36800   * * **ngDblclick**
36801   * * **ngMessages**
36802   *
36803   * Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
36804   * directive.
36805   *
36806   *
36807   * ## Dependencies
36808   * Requires the {@link ngAria} module to be installed.
36809   */
36810  this.$get = function() {
36811    return {
36812      config: function(key) {
36813        return config[key];
36814      },
36815      $$watchExpr: watchExpr
36816    };
36817  };
36818}
36819
36820
36821ngAriaModule.directive('ngShow', ['$aria', function($aria) {
36822  return $aria.$$watchExpr('ngShow', 'aria-hidden', [], true);
36823}])
36824.directive('ngHide', ['$aria', function($aria) {
36825  return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
36826}])
36827.directive('ngValue', ['$aria', function($aria) {
36828  return $aria.$$watchExpr('ngValue', 'aria-checked', nativeAriaNodeNames, false);
36829}])
36830.directive('ngChecked', ['$aria', function($aria) {
36831  return $aria.$$watchExpr('ngChecked', 'aria-checked', nativeAriaNodeNames, false);
36832}])
36833.directive('ngReadonly', ['$aria', function($aria) {
36834  return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nativeAriaNodeNames, false);
36835}])
36836.directive('ngRequired', ['$aria', function($aria) {
36837  return $aria.$$watchExpr('ngRequired', 'aria-required', nativeAriaNodeNames, false);
36838}])
36839.directive('ngModel', ['$aria', function($aria) {
36840
36841  function shouldAttachAttr(attr, normalizedAttr, elem, allowNonAriaNodes) {
36842    return $aria.config(normalizedAttr) &&
36843      !elem.attr(attr) &&
36844      (allowNonAriaNodes || !isNodeOneOf(elem, nativeAriaNodeNames)) &&
36845      (elem.attr('type') !== 'hidden' || elem[0].nodeName !== 'INPUT');
36846  }
36847
36848  function shouldAttachRole(role, elem) {
36849    // if element does not have role attribute
36850    // AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
36851    // AND element is not in nativeAriaNodeNames
36852    return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nativeAriaNodeNames);
36853  }
36854
36855  function getShape(attr, elem) {
36856    var type = attr.type,
36857        role = attr.role;
36858
36859    return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
36860           ((type || role) === 'radio'    || role === 'menuitemradio') ? 'radio' :
36861           (type === 'range'              || role === 'progressbar' || role === 'slider') ? 'range' : '';
36862  }
36863
36864  return {
36865    restrict: 'A',
36866    require: 'ngModel',
36867    priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
36868    compile: function(elem, attr) {
36869      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
36870
36871      var shape = getShape(attr, elem);
36872
36873      return {
36874        post: function(scope, elem, attr, ngModel) {
36875          var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
36876
36877          function ngAriaWatchModelValue() {
36878            return ngModel.$modelValue;
36879          }
36880
36881          function getRadioReaction(newVal) {
36882            // Strict comparison would cause a BC
36883            // eslint-disable-next-line eqeqeq
36884            var boolVal = (attr.value == ngModel.$viewValue);
36885            elem.attr('aria-checked', boolVal);
36886          }
36887
36888          function getCheckboxReaction() {
36889            elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
36890          }
36891
36892          switch (shape) {
36893            case 'radio':
36894            case 'checkbox':
36895              if (shouldAttachRole(shape, elem)) {
36896                elem.attr('role', shape);
36897              }
36898              if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
36899                scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
36900                    getRadioReaction : getCheckboxReaction);
36901              }
36902              if (needsTabIndex) {
36903                elem.attr('tabindex', 0);
36904              }
36905              break;
36906            case 'range':
36907              if (shouldAttachRole(shape, elem)) {
36908                elem.attr('role', 'slider');
36909              }
36910              if ($aria.config('ariaValue')) {
36911                var needsAriaValuemin = !elem.attr('aria-valuemin') &&
36912                    (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));
36913                var needsAriaValuemax = !elem.attr('aria-valuemax') &&
36914                    (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));
36915                var needsAriaValuenow = !elem.attr('aria-valuenow');
36916
36917                if (needsAriaValuemin) {
36918                  attr.$observe('min', function ngAriaValueMinReaction(newVal) {
36919                    elem.attr('aria-valuemin', newVal);
36920                  });
36921                }
36922                if (needsAriaValuemax) {
36923                  attr.$observe('max', function ngAriaValueMinReaction(newVal) {
36924                    elem.attr('aria-valuemax', newVal);
36925                  });
36926                }
36927                if (needsAriaValuenow) {
36928                  scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
36929                    elem.attr('aria-valuenow', newVal);
36930                  });
36931                }
36932              }
36933              if (needsTabIndex) {
36934                elem.attr('tabindex', 0);
36935              }
36936              break;
36937          }
36938
36939          if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
36940            && shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
36941            // ngModel.$error.required is undefined on custom controls
36942            attr.$observe('required', function() {
36943              elem.attr('aria-required', !!attr['required']);
36944            });
36945          }
36946
36947          if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
36948            scope.$watch(function ngAriaInvalidWatch() {
36949              return ngModel.$invalid;
36950            }, function ngAriaInvalidReaction(newVal) {
36951              elem.attr('aria-invalid', !!newVal);
36952            });
36953          }
36954        }
36955      };
36956    }
36957  };
36958}])
36959.directive('ngDisabled', ['$aria', function($aria) {
36960  return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
36961}])
36962.directive('ngMessages', function() {
36963  return {
36964    restrict: 'A',
36965    require: '?ngMessages',
36966    link: function(scope, elem, attr, ngMessages) {
36967      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
36968
36969      if (!elem.attr('aria-live')) {
36970        elem.attr('aria-live', 'assertive');
36971      }
36972    }
36973  };
36974})
36975.directive('ngClick',['$aria', '$parse', function($aria, $parse) {
36976  return {
36977    restrict: 'A',
36978    compile: function(elem, attr) {
36979      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
36980
36981      var fn = $parse(attr.ngClick);
36982      return function(scope, elem, attr) {
36983
36984        if (!isNodeOneOf(elem, nativeAriaNodeNames)) {
36985
36986          if ($aria.config('bindRoleForClick') && !elem.attr('role')) {
36987            elem.attr('role', 'button');
36988          }
36989
36990          if ($aria.config('tabindex') && !elem.attr('tabindex')) {
36991            elem.attr('tabindex', 0);
36992          }
36993
36994          if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) {
36995            elem.on('keydown', function(event) {
36996              var keyCode = event.which || event.keyCode;
36997
36998              if (keyCode === 13 || keyCode === 32) {
36999                // If the event is triggered on a non-interactive element ...
37000                if (nativeAriaNodeNames.indexOf(event.target.nodeName) === -1 && !event.target.isContentEditable) {
37001                  // ... prevent the default browser behavior (e.g. scrolling when pressing spacebar)
37002                  // See https://github.com/angular/angular.js/issues/16664
37003                  event.preventDefault();
37004                }
37005                scope.$apply(callback);
37006              }
37007
37008              function callback() {
37009                fn(scope, { $event: event });
37010              }
37011            });
37012          }
37013        }
37014      };
37015    }
37016  };
37017}])
37018.directive('ngDblclick', ['$aria', function($aria) {
37019  return function(scope, elem, attr) {
37020    if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
37021
37022    if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nativeAriaNodeNames)) {
37023      elem.attr('tabindex', 0);
37024    }
37025  };
37026}]);
37027
37028
37029})(window, window.angular);
37030
vendor: 31,501 bytes, lines 37031-37859
37031/**
37032 * @license AngularJS v1.8.3
37033 * (c) 2010-2020 Google LLC. http://angularjs.org
37034 * License: MIT
37035 */
37036(function(window, angular) {'use strict';
37037
37038var forEach;
37039var isArray;
37040var isString;
37041var jqLite;
37042
37043/**
37044 * @ngdoc module
37045 * @name ngMessages
37046 * @description
37047 *
37048 * The `ngMessages` module provides enhanced support for displaying messages within templates
37049 * (typically within forms or when rendering message objects that return key/value data).
37050 * Instead of relying on JavaScript code and/or complex ng-if statements within your form template to
37051 * show and hide error messages specific to the state of an input field, the `ngMessages` and
37052 * `ngMessage` directives are designed to handle the complexity, inheritance and priority
37053 * sequencing based on the order of how the messages are defined in the template.
37054 *
37055 * Currently, the ngMessages module only contains the code for the `ngMessages`, `ngMessagesInclude`
37056 * `ngMessage`, `ngMessageExp` and `ngMessageDefault` directives.
37057 *
37058 * ## Usage
37059 * The `ngMessages` directive allows keys in a key/value collection to be associated with a child element
37060 * (or 'message') that will show or hide based on the truthiness of that key's value in the collection. A common use
37061 * case for `ngMessages` is to display error messages for inputs using the `$error` object exposed by the
37062 * {@link ngModel ngModel} directive.
37063 *
37064 * The child elements of the `ngMessages` directive are matched to the collection keys by a `ngMessage` or
37065 * `ngMessageExp` directive. The value of these attributes must match a key in the collection that is provided by
37066 * the `ngMessages` directive.
37067 *
37068 * Consider the following example, which illustrates a typical use case of `ngMessages`. Within the form `myForm` we
37069 * have a text input named `myField` which is bound to the scope variable `field` using the {@link ngModel ngModel}
37070 * directive.
37071 *
37072 * The `myField` field is a required input of type `email` with a maximum length of 15 characters.
37073 *
37074 * ```html
37075 * <form name="myForm">
37076 *   <label>
37077 *     Enter text:
37078 *     <input type="email" ng-model="field" name="myField" required maxlength="15" />
37079 *   </label>
37080 *   <div ng-messages="myForm.myField.$error" role="alert">
37081 *     <div ng-message="required">Please enter a value for this field.</div>
37082 *     <div ng-message="email">This field must be a valid email address.</div>
37083 *     <div ng-message="maxlength">This field can be at most 15 characters long.</div>
37084 *   </div>
37085 * </form>
37086 * ```
37087 *
37088 * In order to show error messages corresponding to `myField` we first create an element with an `ngMessages` attribute
37089 * set to the `$error` object owned by the `myField` input in our `myForm` form.
37090 *
37091 * Within this element we then create separate elements for each of the possible errors that `myField` could have.
37092 * The `ngMessage` attribute is used to declare which element(s) will appear for which error - for example,
37093 * setting `ng-message="required"` specifies that this particular element should be displayed when there
37094 * is no value present for the required field `myField` (because the key `required` will be `true` in the object
37095 * `myForm.myField.$error`).
37096 *
37097 * ### Message order
37098 *
37099 * By default, `ngMessages` will only display one message for a particular key/value collection at any time. If more
37100 * than one message (or error) key is currently true, then which message is shown is determined by the order of messages
37101 * in the HTML template code (messages declared first are prioritised). This mechanism means the developer does not have
37102 * to prioritize messages using custom JavaScript code.
37103 *
37104 * Given the following error object for our example (which informs us that the field `myField` currently has both the
37105 * `required` and `email` errors):
37106 *
37107 * ```javascript
37108 * <!-- keep in mind that ngModel automatically sets these error flags -->
37109 * myField.$error = { required : true, email: true, maxlength: false };
37110 * ```
37111 * The `required` message will be displayed to the user since it appears before the `email` message in the DOM.
37112 * Once the user types a single character, the `required` message will disappear (since the field now has a value)
37113 * but the `email` message will be visible because it is still applicable.
37114 *
37115 * ### Displaying multiple messages at the same time
37116 *
37117 * While `ngMessages` will by default only display one error element at a time, the `ng-messages-multiple` attribute can
37118 * be applied to the `ngMessages` container element to cause it to display all applicable error messages at once:
37119 *
37120 * ```html
37121 * <!-- attribute-style usage -->
37122 * <div ng-messages="myForm.myField.$error" ng-messages-multiple>...</div>
37123 *
37124 * <!-- element-style usage -->
37125 * <ng-messages for="myForm.myField.$error" multiple>...</ng-messages>
37126 * ```
37127 *
37128 * ## Reusing and Overriding Messages
37129 * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline
37130 * template. This allows for generic collection of messages to be reused across multiple parts of an
37131 * application.
37132 *
37133 * ```html
37134 * <script type="text/ng-template" id="error-messages">
37135 *   <div ng-message="required">This field is required</div>
37136 *   <div ng-message="minlength">This field is too short</div>
37137 * </script>
37138 *
37139 * <div ng-messages="myForm.myField.$error" role="alert">
37140 *   <div ng-messages-include="error-messages"></div>
37141 * </div>
37142 * ```
37143 *
37144 * However, including generic messages may not be useful enough to match all input fields, therefore,
37145 * `ngMessages` provides the ability to override messages defined in the remote template by redefining
37146 * them within the directive container.
37147 *
37148 * ```html
37149 * <!-- a generic template of error messages known as "my-custom-messages" -->
37150 * <script type="text/ng-template" id="my-custom-messages">
37151 *   <div ng-message="required">This field is required</div>
37152 *   <div ng-message="minlength">This field is too short</div>
37153 * </script>
37154 *
37155 * <form name="myForm">
37156 *   <label>
37157 *     Email address
37158 *     <input type="email"
37159 *            id="email"
37160 *            name="myEmail"
37161 *            ng-model="email"
37162 *            minlength="5"
37163 *            required />
37164 *   </label>
37165 *   <!-- any ng-message elements that appear BEFORE the ng-messages-include will
37166 *        override the messages present in the ng-messages-include template -->
37167 *   <div ng-messages="myForm.myEmail.$error" role="alert">
37168 *     <!-- this required message has overridden the template message -->
37169 *     <div ng-message="required">You did not enter your email address</div>
37170 *
37171 *     <!-- this is a brand new message and will appear last in the prioritization -->
37172 *     <div ng-message="email">Your email address is invalid</div>
37173 *
37174 *     <!-- and here are the generic error messages -->
37175 *     <div ng-messages-include="my-custom-messages"></div>
37176 *   </div>
37177 * </form>
37178 * ```
37179 *
37180 * In the example HTML code above the message that is set on required will override the corresponding
37181 * required message defined within the remote template. Therefore, with particular input fields (such
37182 * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied
37183 * while more generic messages can be used to handle other, more general input errors.
37184 *
37185 * ## Dynamic Messaging
37186 * ngMessages also supports using expressions to dynamically change key values. Using arrays and
37187 * repeaters to list messages is also supported. This means that the code below will be able to
37188 * fully adapt itself and display the appropriate message when any of the expression data changes:
37189 *
37190 * ```html
37191 * <form name="myForm">
37192 *   <label>
37193 *     Email address
37194 *     <input type="email"
37195 *            name="myEmail"
37196 *            ng-model="email"
37197 *            minlength="5"
37198 *            required />
37199 *   </label>
37200 *   <div ng-messages="myForm.myEmail.$error" role="alert">
37201 *     <div ng-message="required">You did not enter your email address</div>
37202 *     <div ng-repeat="errorMessage in errorMessages">
37203 *       <!-- use ng-message-exp for a message whose key is given by an expression -->
37204 *       <div ng-message-exp="errorMessage.type">{{ errorMessage.text }}</div>
37205 *     </div>
37206 *   </div>
37207 * </form>
37208 * ```
37209 *
37210 * The `errorMessage.type` expression can be a string value or it can be an array so
37211 * that multiple errors can be associated with a single error message:
37212 *
37213 * ```html
37214 *   <label>
37215 *     Email address
37216 *     <input type="email"
37217 *            ng-model="data.email"
37218 *            name="myEmail"
37219 *            ng-minlength="5"
37220 *            ng-maxlength="100"
37221 *            required />
37222 *   </label>
37223 *   <div ng-messages="myForm.myEmail.$error" role="alert">
37224 *     <div ng-message-exp="'required'">You did not enter your email address</div>
37225 *     <div ng-message-exp="['minlength', 'maxlength']">
37226 *       Your email must be between 5 and 100 characters long
37227 *     </div>
37228 *   </div>
37229 * ```
37230 *
37231 * Feel free to use other structural directives such as ng-if and ng-switch to further control
37232 * what messages are active and when. Be careful, if you place ng-message on the same element
37233 * as these structural directives, AngularJS may not be able to determine if a message is active
37234 * or not. Therefore it is best to place the ng-message on a child element of the structural
37235 * directive.
37236 *
37237 * ```html
37238 * <div ng-messages="myForm.myEmail.$error" role="alert">
37239 *   <div ng-if="showRequiredError">
37240 *     <div ng-message="required">Please enter something</div>
37241 *   </div>
37242 * </div>
37243 * ```
37244 *
37245 * ## Animations
37246 * If the `ngAnimate` module is active within the application then the `ngMessages`, `ngMessage` and
37247 * `ngMessageExp` directives will trigger animations whenever any messages are added and removed from
37248 * the DOM by the `ngMessages` directive.
37249 *
37250 * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS
37251 * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no
37252 * messages present. Therefore, CSS transitions and keyframes as well as JavaScript animations can
37253 * hook into the animations whenever these classes are added/removed.
37254 *
37255 * Let's say that our HTML code for our messages container looks like so:
37256 *
37257 * ```html
37258 * <div ng-messages="myMessages" class="my-messages" role="alert">
37259 *   <div ng-message="alert" class="some-message">...</div>
37260 *   <div ng-message="fail" class="some-message">...</div>
37261 * </div>
37262 * ```
37263 *
37264 * Then the CSS animation code for the message container looks like so:
37265 *
37266 * ```css
37267 * .my-messages {
37268 *   transition:1s linear all;
37269 * }
37270 * .my-messages.ng-active {
37271 *   // messages are visible
37272 * }
37273 * .my-messages.ng-inactive {
37274 *   // messages are hidden
37275 * }
37276 * ```
37277 *
37278 * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter
37279 * and leave animation is triggered for each particular element bound to the `ngMessage` directive.
37280 *
37281 * Therefore, the CSS code for the inner messages looks like so:
37282 *
37283 * ```css
37284 * .some-message {
37285 *   transition:1s linear all;
37286 * }
37287 *
37288 * .some-message.ng-enter {}
37289 * .some-message.ng-enter.ng-enter-active {}
37290 *
37291 * .some-message.ng-leave {}
37292 * .some-message.ng-leave.ng-leave-active {}
37293 * ```
37294 *
37295 * {@link ngAnimate See the ngAnimate docs} to learn how to use JavaScript animations or to learn
37296 * more about ngAnimate.
37297 *
37298 * ## Displaying a default message
37299 * If the ngMessages renders no inner ngMessage directive (i.e. when none of the truthy
37300 * keys are matched by a defined message), then it will render a default message
37301 * using the {@link ngMessageDefault} directive.
37302 * Note that matched messages will always take precedence over unmatched messages. That means
37303 * the default message will not be displayed when another message is matched. This is also
37304 * true for `ng-messages-multiple`.
37305 *
37306 * ```html
37307 * <div ng-messages="myForm.myField.$error" role="alert">
37308 *   <div ng-message="required">This field is required</div>
37309 *   <div ng-message="minlength">This field is too short</div>
37310 *   <div ng-message-default>This field has an input error</div>
37311 * </div>
37312 * ```
37313 *
37314
37315 */
37316angular.module('ngMessages', [], function initAngularHelpers() {
37317  // Access helpers from AngularJS core.
37318  // Do it inside a `config` block to ensure `window.angular` is available.
37319  forEach = angular.forEach;
37320  isArray = angular.isArray;
37321  isString = angular.isString;
37322  jqLite = angular.element;
37323})
37324  .info({ angularVersion: '1.8.3' })
37325
37326  /**
37327   * @ngdoc directive
37328   * @module ngMessages
37329   * @name ngMessages
37330   * @restrict AE
37331   *
37332   * @description
37333   * `ngMessages` is a directive that is designed to show and hide messages based on the state
37334   * of a key/value object that it listens on. The directive itself complements error message
37335   * reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
37336   *
37337   * `ngMessages` manages the state of internal messages within its container element. The internal
37338   * messages use the `ngMessage` directive and will be inserted/removed from the page depending
37339   * on if they're present within the key/value object. By default, only one message will be displayed
37340   * at a time and this depends on the prioritization of the messages within the template. (This can
37341   * be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
37342   *
37343   * A remote template can also be used (With {@link ngMessagesInclude}) to promote message
37344   * reusability and messages can also be overridden.
37345   *
37346   * A default message can also be displayed when no `ngMessage` directive is inserted, using the
37347   * {@link ngMessageDefault} directive.
37348   *
37349   * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
37350   *
37351   * @usage
37352   * ```html
37353   * <!-- using attribute directives -->
37354   * <ANY ng-messages="expression" role="alert">
37355   *   <ANY ng-message="stringValue">...</ANY>
37356   *   <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
37357   *   <ANY ng-message-exp="expressionValue">...</ANY>
37358   *   <ANY ng-message-default>...</ANY>
37359   * </ANY>
37360   *
37361   * <!-- or by using element directives -->
37362   * <ng-messages for="expression" role="alert">
37363   *   <ng-message when="stringValue">...</ng-message>
37364   *   <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
37365   *   <ng-message when-exp="expressionValue">...</ng-message>
37366   *   <ng-message-default>...</ng-message-default>
37367   * </ng-messages>
37368   * ```
37369   *
37370   * @param {string} ngMessages an AngularJS expression evaluating to a key/value object
37371   *                 (this is typically the $error object on an ngModel instance).
37372   * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
37373   *
37374   * @example
37375   * <example name="ngMessages-directive" module="ngMessagesExample"
37376   *          deps="angular-messages.js"
37377   *          animations="true" fixBase="true">
37378   *   <file name="index.html">
37379   *     <form name="myForm">
37380   *       <label>
37381   *         Enter your name:
37382   *         <input type="text"
37383   *                name="myName"
37384   *                ng-model="name"
37385   *                ng-minlength="5"
37386   *                ng-maxlength="20"
37387   *                required />
37388   *       </label>
37389   *       <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
37390   *
37391   *       <div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
37392   *         <div ng-message="required">You did not enter a field</div>
37393   *         <div ng-message="minlength">Your field is too short</div>
37394   *         <div ng-message="maxlength">Your field is too long</div>
37395   *         <div ng-message-default>This field has an input error</div>
37396   *       </div>
37397   *     </form>
37398   *   </file>
37399   *   <file name="script.js">
37400   *     angular.module('ngMessagesExample', ['ngMessages']);
37401   *   </file>
37402   * </example>
37403   */
37404  .directive('ngMessages', ['$animate', function($animate) {
37405    var ACTIVE_CLASS = 'ng-active';
37406    var INACTIVE_CLASS = 'ng-inactive';
37407
37408    return {
37409      require: 'ngMessages',
37410      restrict: 'AE',
37411      controller: ['$element', '$scope', '$attrs', function NgMessagesCtrl($element, $scope, $attrs) {
37412        var ctrl = this;
37413        var latestKey = 0;
37414        var nextAttachId = 0;
37415
37416        this.getAttachId = function getAttachId() { return nextAttachId++; };
37417
37418        var messages = this.messages = {};
37419        var renderLater, cachedCollection;
37420
37421        this.render = function(collection) {
37422          collection = collection || {};
37423
37424          renderLater = false;
37425          cachedCollection = collection;
37426
37427          // this is true if the attribute is empty or if the attribute value is truthy
37428          var multiple = isAttrTruthy($scope, $attrs.ngMessagesMultiple) ||
37429                         isAttrTruthy($scope, $attrs.multiple);
37430
37431          var unmatchedMessages = [];
37432          var matchedKeys = {};
37433          var truthyKeys = 0;
37434          var messageItem = ctrl.head;
37435          var messageFound = false;
37436          var totalMessages = 0;
37437
37438          // we use != instead of !== to allow for both undefined and null values
37439          while (messageItem != null) {
37440            totalMessages++;
37441            var messageCtrl = messageItem.message;
37442
37443            var messageUsed = false;
37444            if (!messageFound) {
37445              forEach(collection, function(value, key) {
37446                if (truthy(value) && !messageUsed) {
37447                  truthyKeys++;
37448
37449                  if (messageCtrl.test(key)) {
37450                    // this is to prevent the same error name from showing up twice
37451                    if (matchedKeys[key]) return;
37452                    matchedKeys[key] = true;
37453
37454                    messageUsed = true;
37455                    messageCtrl.attach();
37456                  }
37457                }
37458              });
37459            }
37460
37461            if (messageUsed) {
37462              // unless we want to display multiple messages then we should
37463              // set a flag here to avoid displaying the next message in the list
37464              messageFound = !multiple;
37465            } else {
37466              unmatchedMessages.push(messageCtrl);
37467            }
37468
37469            messageItem = messageItem.next;
37470          }
37471
37472          forEach(unmatchedMessages, function(messageCtrl) {
37473            messageCtrl.detach();
37474          });
37475
37476          var messageMatched = unmatchedMessages.length !== totalMessages;
37477          var attachDefault = ctrl.default && !messageMatched && truthyKeys > 0;
37478
37479          if (attachDefault) {
37480            ctrl.default.attach();
37481          } else if (ctrl.default) {
37482            ctrl.default.detach();
37483          }
37484
37485          if (messageMatched || attachDefault) {
37486            $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS);
37487          } else {
37488            $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
37489          }
37490        };
37491
37492        $scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
37493
37494        this.reRender = function() {
37495          if (!renderLater) {
37496            renderLater = true;
37497            $scope.$evalAsync(function() {
37498              if (renderLater && cachedCollection) {
37499                ctrl.render(cachedCollection);
37500              }
37501            });
37502          }
37503        };
37504
37505        this.register = function(comment, messageCtrl, isDefault) {
37506          if (isDefault) {
37507            ctrl.default = messageCtrl;
37508          } else {
37509            var nextKey = latestKey.toString();
37510            messages[nextKey] = {
37511              message: messageCtrl
37512            };
37513            insertMessageNode($element[0], comment, nextKey);
37514            comment.$$ngMessageNode = nextKey;
37515            latestKey++;
37516          }
37517
37518          ctrl.reRender();
37519        };
37520
37521        this.deregister = function(comment, isDefault) {
37522          if (isDefault) {
37523            delete ctrl.default;
37524          } else {
37525            var key = comment.$$ngMessageNode;
37526            delete comment.$$ngMessageNode;
37527            removeMessageNode($element[0], comment, key);
37528            delete messages[key];
37529          }
37530          ctrl.reRender();
37531        };
37532
37533        function findPreviousMessage(parent, comment) {
37534          var prevNode = comment;
37535          var parentLookup = [];
37536
37537          while (prevNode && prevNode !== parent) {
37538            var prevKey = prevNode.$$ngMessageNode;
37539            if (prevKey && prevKey.length) {
37540              return messages[prevKey];
37541            }
37542
37543            // dive deeper into the DOM and examine its children for any ngMessage
37544            // comments that may be in an element that appears deeper in the list
37545            if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) === -1) {
37546              parentLookup.push(prevNode);
37547              prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
37548            } else if (prevNode.previousSibling) {
37549              prevNode = prevNode.previousSibling;
37550            } else {
37551              prevNode = prevNode.parentNode;
37552              parentLookup.push(prevNode);
37553            }
37554          }
37555        }
37556
37557        function insertMessageNode(parent, comment, key) {
37558          var messageNode = messages[key];
37559          if (!ctrl.head) {
37560            ctrl.head = messageNode;
37561          } else {
37562            var match = findPreviousMessage(parent, comment);
37563            if (match) {
37564              messageNode.next = match.next;
37565              match.next = messageNode;
37566            } else {
37567              messageNode.next = ctrl.head;
37568              ctrl.head = messageNode;
37569            }
37570          }
37571        }
37572
37573        function removeMessageNode(parent, comment, key) {
37574          var messageNode = messages[key];
37575
37576          // This message node may have already been removed by a call to deregister()
37577          if (!messageNode) return;
37578
37579          var match = findPreviousMessage(parent, comment);
37580          if (match) {
37581            match.next = messageNode.next;
37582          } else {
37583            ctrl.head = messageNode.next;
37584          }
37585        }
37586      }]
37587    };
37588
37589    function isAttrTruthy(scope, attr) {
37590     return (isString(attr) && attr.length === 0) || //empty attribute
37591            truthy(scope.$eval(attr));
37592    }
37593
37594    function truthy(val) {
37595      return isString(val) ? val.length : !!val;
37596    }
37597  }])
37598
37599  /**
37600   * @ngdoc directive
37601   * @name ngMessagesInclude
37602   * @restrict AE
37603   * @scope
37604   *
37605   * @description
37606   * `ngMessagesInclude` is a directive with the purpose to import existing ngMessage template
37607   * code from a remote template and place the downloaded template code into the exact spot
37608   * that the ngMessagesInclude directive is placed within the ngMessages container. This allows
37609   * for a series of pre-defined messages to be reused and also allows for the developer to
37610   * determine what messages are overridden due to the placement of the ngMessagesInclude directive.
37611   *
37612   * @usage
37613   * ```html
37614   * <!-- using attribute directives -->
37615   * <ANY ng-messages="expression" role="alert">
37616   *   <ANY ng-messages-include="remoteTplString">...</ANY>
37617   * </ANY>
37618   *
37619   * <!-- or by using element directives -->
37620   * <ng-messages for="expression" role="alert">
37621   *   <ng-messages-include src="expressionValue1">...</ng-messages-include>
37622   * </ng-messages>
37623   * ```
37624   *
37625   * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
37626   *
37627   * @param {string} ngMessagesInclude|src a string value corresponding to the remote template.
37628   */
37629  .directive('ngMessagesInclude',
37630    ['$templateRequest', '$document', '$compile', function($templateRequest, $document, $compile) {
37631
37632    return {
37633      restrict: 'AE',
37634      require: '^^ngMessages', // we only require this for validation sake
37635      link: function($scope, element, attrs) {
37636        var src = attrs.ngMessagesInclude || attrs.src;
37637        $templateRequest(src).then(function(html) {
37638          if ($scope.$$destroyed) return;
37639
37640          if (isString(html) && !html.trim()) {
37641            // Empty template - nothing to compile
37642            replaceElementWithMarker(element, src);
37643          } else {
37644            // Non-empty template - compile and link
37645            $compile(html)($scope, function(contents) {
37646              element.after(contents);
37647              replaceElementWithMarker(element, src);
37648            });
37649          }
37650        });
37651      }
37652    };
37653
37654    // Helpers
37655    function replaceElementWithMarker(element, src) {
37656      // A comment marker is placed for debugging purposes
37657      var comment = $compile.$$createComment ?
37658          $compile.$$createComment('ngMessagesInclude', src) :
37659          $document[0].createComment(' ngMessagesInclude: ' + src + ' ');
37660      var marker = jqLite(comment);
37661      element.after(marker);
37662
37663      // Don't pollute the DOM anymore by keeping an empty directive element
37664      element.remove();
37665    }
37666  }])
37667
37668  /**
37669   * @ngdoc directive
37670   * @name ngMessage
37671   * @restrict AE
37672   * @scope
37673   * @priority 1
37674   *
37675   * @description
37676   * `ngMessage` is a directive with the purpose to show and hide a particular message.
37677   * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
37678   * must be situated since it determines which messages are visible based on the state
37679   * of the provided key/value map that `ngMessages` listens on.
37680   *
37681   * More information about using `ngMessage` can be found in the
37682   * {@link module:ngMessages `ngMessages` module documentation}.
37683   *
37684   * @usage
37685   * ```html
37686   * <!-- using attribute directives -->
37687   * <ANY ng-messages="expression" role="alert">
37688   *   <ANY ng-message="stringValue">...</ANY>
37689   *   <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
37690   * </ANY>
37691   *
37692   * <!-- or by using element directives -->
37693   * <ng-messages for="expression" role="alert">
37694   *   <ng-message when="stringValue">...</ng-message>
37695   *   <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
37696   * </ng-messages>
37697   * ```
37698   *
37699   * @param {expression} ngMessage|when a string value corresponding to the message key.
37700   */
37701  .directive('ngMessage', ngMessageDirectiveFactory())
37702
37703
37704  /**
37705   * @ngdoc directive
37706   * @name ngMessageExp
37707   * @restrict AE
37708   * @priority 1
37709   * @scope
37710   *
37711   * @description
37712   * `ngMessageExp` is the same as {@link directive:ngMessage `ngMessage`}, but instead of a static
37713   * value, it accepts an expression to be evaluated for the message key.
37714   *
37715   * @usage
37716   * ```html
37717   * <!-- using attribute directives -->
37718   * <ANY ng-messages="expression">
37719   *   <ANY ng-message-exp="expressionValue">...</ANY>
37720   * </ANY>
37721   *
37722   * <!-- or by using element directives -->
37723   * <ng-messages for="expression">
37724   *   <ng-message when-exp="expressionValue">...</ng-message>
37725   * </ng-messages>
37726   * ```
37727   *
37728   * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
37729   *
37730   * @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
37731   */
37732  .directive('ngMessageExp', ngMessageDirectiveFactory())
37733
37734  /**
37735   * @ngdoc directive
37736   * @name ngMessageDefault
37737   * @restrict AE
37738   * @scope
37739   *
37740   * @description
37741   * `ngMessageDefault` is a directive with the purpose to show and hide a default message for
37742   * {@link directive:ngMessages}, when none of provided messages matches.
37743   *
37744   * More information about using `ngMessageDefault` can be found in the
37745   * {@link module:ngMessages `ngMessages` module documentation}.
37746   *
37747   * @usage
37748   * ```html
37749   * <!-- using attribute directives -->
37750   * <ANY ng-messages="expression" role="alert">
37751   *   <ANY ng-message="stringValue">...</ANY>
37752   *   <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
37753   *   <ANY ng-message-default>...</ANY>
37754   * </ANY>
37755   *
37756   * <!-- or by using element directives -->
37757   * <ng-messages for="expression" role="alert">
37758   *   <ng-message when="stringValue">...</ng-message>
37759   *   <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
37760   *   <ng-message-default>...</ng-message-default>
37761   * </ng-messages>
37762   *
37763  */
37764  .directive('ngMessageDefault', ngMessageDirectiveFactory(true));
37765
37766function ngMessageDirectiveFactory(isDefault) {
37767  return ['$animate', function($animate) {
37768    return {
37769      restrict: 'AE',
37770      transclude: 'element',
37771      priority: 1, // must run before ngBind, otherwise the text is set on the comment
37772      terminal: true,
37773      require: '^^ngMessages',
37774      link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
37775        var commentNode, records, staticExp, dynamicExp;
37776
37777        if (!isDefault) {
37778          commentNode = element[0];
37779          staticExp = attrs.ngMessage || attrs.when;
37780          dynamicExp = attrs.ngMessageExp || attrs.whenExp;
37781
37782          var assignRecords = function(items) {
37783            records = items
37784                ? (isArray(items)
37785                      ? items
37786                      : items.split(/[\s,]+/))
37787                : null;
37788            ngMessagesCtrl.reRender();
37789          };
37790
37791          if (dynamicExp) {
37792            assignRecords(scope.$eval(dynamicExp));
37793            scope.$watchCollection(dynamicExp, assignRecords);
37794          } else {
37795            assignRecords(staticExp);
37796          }
37797        }
37798
37799        var currentElement, messageCtrl;
37800        ngMessagesCtrl.register(commentNode, messageCtrl = {
37801          test: function(name) {
37802            return contains(records, name);
37803          },
37804          attach: function() {
37805            if (!currentElement) {
37806              $transclude(function(elm, newScope) {
37807                $animate.enter(elm, null, element);
37808                currentElement = elm;
37809
37810                // Each time we attach this node to a message we get a new id that we can match
37811                // when we are destroying the node later.
37812                var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId();
37813
37814                // in the event that the element or a parent element is destroyed
37815                // by another structural directive then it's time
37816                // to deregister the message from the controller
37817                currentElement.on('$destroy', function() {
37818                  // If the message element was removed via a call to `detach` then `currentElement` will be null
37819                  // So this handler only handles cases where something else removed the message element.
37820                  if (currentElement && currentElement.$$attachId === $$attachId) {
37821                    ngMessagesCtrl.deregister(commentNode, isDefault);
37822                    messageCtrl.detach();
37823                  }
37824                  newScope.$destroy();
37825                });
37826              });
37827            }
37828          },
37829          detach: function() {
37830            if (currentElement) {
37831              var elm = currentElement;
37832              currentElement = null;
37833              $animate.leave(elm);
37834            }
37835          }
37836        }, isDefault);
37837
37838        // We need to ensure that this directive deregisters itself when it no longer exists
37839        // Normally this is done when the attached element is destroyed; but if this directive
37840        // gets removed before we attach the message to the DOM there is nothing to watch
37841        // in which case we must deregister when the containing scope is destroyed.
37842        scope.$on('$destroy', function() {
37843          ngMessagesCtrl.deregister(commentNode, isDefault);
37844        });
37845      }
37846    };
37847  }];
37848
37849  function contains(collection, key) {
37850    if (collection) {
37851      return isArray(collection)
37852          ? collection.indexOf(key) >= 0
37853          : collection.hasOwnProperty(key);
37854    }
37855  }
37856}
37857
37858
37859})(window, window.angular);
37860
vendor: 33,197 bytes, lines 37861-38751
37861/**
37862 * @license AngularJS v1.8.3
37863 * (c) 2010-2020 Google LLC. http://angularjs.org
37864 * License: MIT
37865 */
37866(function(window, angular) {'use strict';
37867
37868/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
37869 *     Any commits to this file should be reviewed with security in mind.  *
37870 *   Changes to this file can potentially create security vulnerabilities. *
37871 *          An approval from 2 Core members with history of modifying      *
37872 *                         this file is required.                          *
37873 *                                                                         *
37874 *  Does the change somehow allow for arbitrary javascript to be executed? *
37875 *    Or allows for someone to change the prototype of built-in objects?   *
37876 *     Or gives undesired access to variables likes document or window?    *
37877 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
37878
37879var $sanitizeMinErr = angular.$$minErr('$sanitize');
37880var bind;
37881var extend;
37882var forEach;
37883var isArray;
37884var isDefined;
37885var lowercase;
37886var noop;
37887var nodeContains;
37888var htmlParser;
37889var htmlSanitizeWriter;
37890
37891/**
37892 * @ngdoc module
37893 * @name ngSanitize
37894 * @description
37895 *
37896 * The `ngSanitize` module provides functionality to sanitize HTML.
37897 *
37898 * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
37899 */
37900
37901/**
37902 * @ngdoc service
37903 * @name $sanitize
37904 * @kind function
37905 *
37906 * @description
37907 *   Sanitizes an html string by stripping all potentially dangerous tokens.
37908 *
37909 *   The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI list) are
37910 *   then serialized back to a properly escaped HTML string. This means that no unsafe input can make
37911 *   it into the returned string.
37912 *
37913 *   The trusted URIs for URL sanitization of attribute values is configured using the functions
37914 *   `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}.
37915 *
37916 *   The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
37917 *
37918 * @param {string} html HTML input.
37919 * @returns {string} Sanitized HTML.
37920 *
37921 * @example
37922   <example module="sanitizeExample" deps="angular-sanitize.js" name="sanitize-service">
37923   <file name="index.html">
37924     <script>
37925         angular.module('sanitizeExample', ['ngSanitize'])
37926           .controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
37927             $scope.snippet =
37928               '<p style="color:blue">an html\n' +
37929               '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
37930               'snippet</p>';
37931             $scope.deliberatelyTrustDangerousSnippet = function() {
37932               return $sce.trustAsHtml($scope.snippet);
37933             };
37934           }]);
37935     </script>
37936     <div ng-controller="ExampleController">
37937        Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
37938       <table>
37939         <tr>
37940           <td>Directive</td>
37941           <td>How</td>
37942           <td>Source</td>
37943           <td>Rendered</td>
37944         </tr>
37945         <tr id="bind-html-with-sanitize">
37946           <td>ng-bind-html</td>
37947           <td>Automatically uses $sanitize</td>
37948           <td><pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
37949           <td><div ng-bind-html="snippet"></div></td>
37950         </tr>
37951         <tr id="bind-html-with-trust">
37952           <td>ng-bind-html</td>
37953           <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
37954           <td>
37955           <pre>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
37956&lt;/div&gt;</pre>
37957           </td>
37958           <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
37959         </tr>
37960         <tr id="bind-default">
37961           <td>ng-bind</td>
37962           <td>Automatically escapes</td>
37963           <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
37964           <td><div ng-bind="snippet"></div></td>
37965         </tr>
37966       </table>
37967       </div>
37968   </file>
37969   <file name="protractor.js" type="protractor">
37970     it('should sanitize the html snippet by default', function() {
37971       expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
37972         toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
37973     });
37974
37975     it('should inline raw snippet if bound to a trusted value', function() {
37976       expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).
37977         toBe("<p style=\"color:blue\">an html\n" +
37978              "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
37979              "snippet</p>");
37980     });
37981
37982     it('should escape snippet without any filter', function() {
37983       expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).
37984         toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
37985              "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
37986              "snippet&lt;/p&gt;");
37987     });
37988
37989     it('should update', function() {
37990       element(by.model('snippet')).clear();
37991       element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
37992       expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
37993         toBe('new <b>text</b>');
37994       expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe(
37995         'new <b onclick="alert(1)">text</b>');
37996       expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe(
37997         "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
37998     });
37999   </file>
38000   </example>
38001 */
38002
38003
38004/**
38005 * @ngdoc provider
38006 * @name $sanitizeProvider
38007 * @this
38008 *
38009 * @description
38010 * Creates and configures {@link $sanitize} instance.
38011 */
38012function $SanitizeProvider() {
38013  var hasBeenInstantiated = false;
38014  var svgEnabled = false;
38015
38016  this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
38017    hasBeenInstantiated = true;
38018    if (svgEnabled) {
38019      extend(validElements, svgElements);
38020    }
38021    return function(html) {
38022      var buf = [];
38023      htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
38024        return !/^unsafe:/.test($$sanitizeUri(uri, isImage));
38025      }));
38026      return buf.join('');
38027    };
38028  }];
38029
38030
38031  /**
38032   * @ngdoc method
38033   * @name $sanitizeProvider#enableSvg
38034   * @kind function
38035   *
38036   * @description
38037   * Enables a subset of svg to be supported by the sanitizer.
38038   *
38039   * <div class="alert alert-warning">
38040   *   <p>By enabling this setting without taking other precautions, you might expose your
38041   *   application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned
38042   *   outside of the containing element and be rendered over other elements on the page (e.g. a login
38043   *   link). Such behavior can then result in phishing incidents.</p>
38044   *
38045   *   <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
38046   *   tags within the sanitized content:</p>
38047   *
38048   *   <br>
38049   *
38050   *   <pre><code>
38051   *   .rootOfTheIncludedContent svg {
38052   *     overflow: hidden !important;
38053   *   }
38054   *   </code></pre>
38055   * </div>
38056   *
38057   * @param {boolean=} flag Enable or disable SVG support in the sanitizer.
38058   * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called
38059   *    without an argument or self for chaining otherwise.
38060   */
38061  this.enableSvg = function(enableSvg) {
38062    if (isDefined(enableSvg)) {
38063      svgEnabled = enableSvg;
38064      return this;
38065    } else {
38066      return svgEnabled;
38067    }
38068  };
38069
38070
38071  /**
38072   * @ngdoc method
38073   * @name $sanitizeProvider#addValidElements
38074   * @kind function
38075   *
38076   * @description
38077   * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe
38078   * and are not stripped off during sanitization. You can extend the following lists of elements:
38079   *
38080   * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML
38081   *   elements. HTML elements considered safe will not be removed during sanitization. All other
38082   *   elements will be stripped off.
38083   *
38084   * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as
38085   *   "void elements" (similar to HTML
38086   *   [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These
38087   *   elements have no end tag and cannot have content.
38088   *
38089   * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only
38090   *   taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for
38091   *   `$sanitize`.
38092   *
38093   * <div class="alert alert-info">
38094   *   This method must be called during the {@link angular.Module#config config} phase. Once the
38095   *   `$sanitize` service has been instantiated, this method has no effect.
38096   * </div>
38097   *
38098   * <div class="alert alert-warning">
38099   *   Keep in mind that extending the built-in lists of elements may expose your app to XSS or
38100   *   other vulnerabilities. Be very mindful of the elements you add.
38101   * </div>
38102   *
38103   * @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or
38104   *   more of the following properties:
38105   *   - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of
38106   *     HTML elements.
38107   *   - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of
38108   *     void HTML elements; i.e. elements that do not have an end tag.
38109   *   - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG
38110   *     elements. The list of SVG elements is only taken into account if SVG is
38111   *     {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`.
38112   *
38113   * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`.
38114   *
38115   * @return {$sanitizeProvider} Returns self for chaining.
38116   */
38117  this.addValidElements = function(elements) {
38118    if (!hasBeenInstantiated) {
38119      if (isArray(elements)) {
38120        elements = {htmlElements: elements};
38121      }
38122
38123      addElementsTo(svgElements, elements.svgElements);
38124      addElementsTo(voidElements, elements.htmlVoidElements);
38125      addElementsTo(validElements, elements.htmlVoidElements);
38126      addElementsTo(validElements, elements.htmlElements);
38127    }
38128
38129    return this;
38130  };
38131
38132
38133  /**
38134   * @ngdoc method
38135   * @name $sanitizeProvider#addValidAttrs
38136   * @kind function
38137   *
38138   * @description
38139   * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are
38140   * not stripped off during sanitization.
38141   *
38142   * **Note**:
38143   * The new attributes will not be treated as URI attributes, which means their values will not be
38144   * sanitized as URIs using `$compileProvider`'s
38145   * {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and
38146   * {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}.
38147   *
38148   * <div class="alert alert-info">
38149   *   This method must be called during the {@link angular.Module#config config} phase. Once the
38150   *   `$sanitize` service has been instantiated, this method has no effect.
38151   * </div>
38152   *
38153   * <div class="alert alert-warning">
38154   *   Keep in mind that extending the built-in list of attributes may expose your app to XSS or
38155   *   other vulnerabilities. Be very mindful of the attributes you add.
38156   * </div>
38157   *
38158   * @param {Array<String>} attrs - A list of valid attributes.
38159   *
38160   * @returns {$sanitizeProvider} Returns self for chaining.
38161   */
38162  this.addValidAttrs = function(attrs) {
38163    if (!hasBeenInstantiated) {
38164      extend(validAttrs, arrayToMap(attrs, true));
38165    }
38166    return this;
38167  };
38168
38169  //////////////////////////////////////////////////////////////////////////////////////////////////
38170  // Private stuff
38171  //////////////////////////////////////////////////////////////////////////////////////////////////
38172
38173  bind = angular.bind;
38174  extend = angular.extend;
38175  forEach = angular.forEach;
38176  isArray = angular.isArray;
38177  isDefined = angular.isDefined;
38178  lowercase = angular.$$lowercase;
38179  noop = angular.noop;
38180
38181  htmlParser = htmlParserImpl;
38182  htmlSanitizeWriter = htmlSanitizeWriterImpl;
38183
38184  nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
38185    // eslint-disable-next-line no-bitwise
38186    return !!(this.compareDocumentPosition(arg) & 16);
38187  };
38188
38189  // Regular Expressions for parsing tags and attributes
38190  var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
38191    // Match everything outside of normal chars and " (quote character)
38192    NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;
38193
38194
38195  // Good source of info about elements and attributes
38196  // http://dev.w3.org/html5/spec/Overview.html#semantics
38197  // http://simon.html5.org/html-elements
38198
38199  // Safe Void Elements - HTML5
38200  // http://dev.w3.org/html5/spec/Overview.html#void-elements
38201  var voidElements = stringToMap('area,br,col,hr,img,wbr');
38202
38203  // Elements that you can, intentionally, leave open (and which close themselves)
38204  // http://dev.w3.org/html5/spec/Overview.html#optional-tags
38205  var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'),
38206      optionalEndTagInlineElements = stringToMap('rp,rt'),
38207      optionalEndTagElements = extend({},
38208                                              optionalEndTagInlineElements,
38209                                              optionalEndTagBlockElements);
38210
38211  // Safe Block Elements - HTML5
38212  var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' +
38213          'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
38214          'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul'));
38215
38216  // Inline Elements - HTML5
38217  var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' +
38218          'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' +
38219          'samp,small,span,strike,strong,sub,sup,time,tt,u,var'));
38220
38221  // SVG Elements
38222  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
38223  // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
38224  // They can potentially allow for arbitrary javascript to be executed. See #11290
38225  var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' +
38226          'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' +
38227          'radialGradient,rect,stop,svg,switch,text,title,tspan');
38228
38229  // Blocked Elements (will be stripped)
38230  var blockedElements = stringToMap('script,style');
38231
38232  var validElements = extend({},
38233                                     voidElements,
38234                                     blockElements,
38235                                     inlineElements,
38236                                     optionalEndTagElements);
38237
38238  //Attributes that have href and hence need to be sanitized
38239  var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base');
38240
38241  var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
38242      'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
38243      'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
38244      'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
38245      'valign,value,vspace,width');
38246
38247  // SVG attributes (without "id" and "name" attributes)
38248  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
38249  var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
38250      'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
38251      'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
38252      'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
38253      'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
38254      'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
38255      'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
38256      'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
38257      'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
38258      'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
38259      'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
38260      'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
38261      'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
38262      'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
38263      'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
38264
38265  var validAttrs = extend({},
38266                                  uriAttrs,
38267                                  svgAttrs,
38268                                  htmlAttrs);
38269
38270  function stringToMap(str, lowercaseKeys) {
38271    return arrayToMap(str.split(','), lowercaseKeys);
38272  }
38273
38274  function arrayToMap(items, lowercaseKeys) {
38275    var obj = {}, i;
38276    for (i = 0; i < items.length; i++) {
38277      obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
38278    }
38279    return obj;
38280  }
38281
38282  function addElementsTo(elementsMap, newElements) {
38283    if (newElements && newElements.length) {
38284      extend(elementsMap, arrayToMap(newElements));
38285    }
38286  }
38287
38288  /**
38289   * Create an inert document that contains the dirty HTML that needs sanitizing.
38290   * We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not
38291   * available.
38292   */
38293  var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) {
38294    if (isDOMParserAvailable()) {
38295      return getInertBodyElement_DOMParser;
38296    }
38297
38298    if (!document || !document.implementation) {
38299      throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document');
38300    }
38301    var inertDocument = document.implementation.createHTMLDocument('inert');
38302    var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body');
38303    return getInertBodyElement_InertDocument;
38304
38305    function isDOMParserAvailable() {
38306      try {
38307        return !!getInertBodyElement_DOMParser('');
38308      } catch (e) {
38309        return false;
38310      }
38311    }
38312
38313    function getInertBodyElement_DOMParser(html) {
38314      // We add this dummy element to ensure that the rest of the content is parsed as expected
38315      // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
38316      html = '<remove></remove>' + html;
38317      try {
38318        var body = new window.DOMParser().parseFromString(html, 'text/html').body;
38319        body.firstChild.remove();
38320        return body;
38321      } catch (e) {
38322        return undefined;
38323      }
38324    }
38325
38326    function getInertBodyElement_InertDocument(html) {
38327      inertBodyElement.innerHTML = html;
38328
38329      // Support: IE 9-11 only
38330      // strip custom-namespaced attributes on IE<=11
38331      if (document.documentMode) {
38332        stripCustomNsAttrs(inertBodyElement);
38333      }
38334
38335      return inertBodyElement;
38336    }
38337  })(window, window.document);
38338
38339  /**
38340   * @example
38341   * htmlParser(htmlString, {
38342   *     start: function(tag, attrs) {},
38343   *     end: function(tag) {},
38344   *     chars: function(text) {},
38345   *     comment: function(text) {}
38346   * });
38347   *
38348   * @param {string} html string
38349   * @param {object} handler
38350   */
38351  function htmlParserImpl(html, handler) {
38352    if (html === null || html === undefined) {
38353      html = '';
38354    } else if (typeof html !== 'string') {
38355      html = '' + html;
38356    }
38357
38358    var inertBodyElement = getInertBodyElement(html);
38359    if (!inertBodyElement) return '';
38360
38361    //mXSS protection
38362    var mXSSAttempts = 5;
38363    do {
38364      if (mXSSAttempts === 0) {
38365        throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable');
38366      }
38367      mXSSAttempts--;
38368
38369      // trigger mXSS if it is going to happen by reading and writing the innerHTML
38370      html = inertBodyElement.innerHTML;
38371      inertBodyElement = getInertBodyElement(html);
38372    } while (html !== inertBodyElement.innerHTML);
38373
38374    var node = inertBodyElement.firstChild;
38375    while (node) {
38376      switch (node.nodeType) {
38377        case 1: // ELEMENT_NODE
38378          handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
38379          break;
38380        case 3: // TEXT NODE
38381          handler.chars(node.textContent);
38382          break;
38383      }
38384
38385      var nextNode;
38386      if (!(nextNode = node.firstChild)) {
38387        if (node.nodeType === 1) {
38388          handler.end(node.nodeName.toLowerCase());
38389        }
38390        nextNode = getNonDescendant('nextSibling', node);
38391        if (!nextNode) {
38392          while (nextNode == null) {
38393            node = getNonDescendant('parentNode', node);
38394            if (node === inertBodyElement) break;
38395            nextNode = getNonDescendant('nextSibling', node);
38396            if (node.nodeType === 1) {
38397              handler.end(node.nodeName.toLowerCase());
38398            }
38399          }
38400        }
38401      }
38402      node = nextNode;
38403    }
38404
38405    while ((node = inertBodyElement.firstChild)) {
38406      inertBodyElement.removeChild(node);
38407    }
38408  }
38409
38410  function attrToMap(attrs) {
38411    var map = {};
38412    for (var i = 0, ii = attrs.length; i < ii; i++) {
38413      var attr = attrs[i];
38414      map[attr.name] = attr.value;
38415    }
38416    return map;
38417  }
38418
38419
38420  /**
38421   * Escapes all potentially dangerous characters, so that the
38422   * resulting string can be safely inserted into attribute or
38423   * element text.
38424   * @param value
38425   * @returns {string} escaped text
38426   */
38427  function encodeEntities(value) {
38428    return value.
38429      replace(/&/g, '&amp;').
38430      replace(SURROGATE_PAIR_REGEXP, function(value) {
38431        var hi = value.charCodeAt(0);
38432        var low = value.charCodeAt(1);
38433        return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
38434      }).
38435      replace(NON_ALPHANUMERIC_REGEXP, function(value) {
38436        return '&#' + value.charCodeAt(0) + ';';
38437      }).
38438      replace(/</g, '&lt;').
38439      replace(/>/g, '&gt;');
38440  }
38441
38442  /**
38443   * create an HTML/XML writer which writes to buffer
38444   * @param {Array} buf use buf.join('') to get out sanitized html string
38445   * @returns {object} in the form of {
38446   *     start: function(tag, attrs) {},
38447   *     end: function(tag) {},
38448   *     chars: function(text) {},
38449   *     comment: function(text) {}
38450   * }
38451   */
38452  function htmlSanitizeWriterImpl(buf, uriValidator) {
38453    var ignoreCurrentElement = false;
38454    var out = bind(buf, buf.push);
38455    return {
38456      start: function(tag, attrs) {
38457        tag = lowercase(tag);
38458        if (!ignoreCurrentElement && blockedElements[tag]) {
38459          ignoreCurrentElement = tag;
38460        }
38461        if (!ignoreCurrentElement && validElements[tag] === true) {
38462          out('<');
38463          out(tag);
38464          forEach(attrs, function(value, key) {
38465            var lkey = lowercase(key);
38466            var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
38467            if (validAttrs[lkey] === true &&
38468              (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
38469              out(' ');
38470              out(key);
38471              out('="');
38472              out(encodeEntities(value));
38473              out('"');
38474            }
38475          });
38476          out('>');
38477        }
38478      },
38479      end: function(tag) {
38480        tag = lowercase(tag);
38481        if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
38482          out('</');
38483          out(tag);
38484          out('>');
38485        }
38486        // eslint-disable-next-line eqeqeq
38487        if (tag == ignoreCurrentElement) {
38488          ignoreCurrentElement = false;
38489        }
38490      },
38491      chars: function(chars) {
38492        if (!ignoreCurrentElement) {
38493          out(encodeEntities(chars));
38494        }
38495      }
38496    };
38497  }
38498
38499
38500  /**
38501   * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
38502   * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
38503   * to allow any of these custom attributes. This method strips them all.
38504   *
38505   * @param node Root element to process
38506   */
38507  function stripCustomNsAttrs(node) {
38508    while (node) {
38509      if (node.nodeType === window.Node.ELEMENT_NODE) {
38510        var attrs = node.attributes;
38511        for (var i = 0, l = attrs.length; i < l; i++) {
38512          var attrNode = attrs[i];
38513          var attrName = attrNode.name.toLowerCase();
38514          if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
38515            node.removeAttributeNode(attrNode);
38516            i--;
38517            l--;
38518          }
38519        }
38520      }
38521
38522      var nextNode = node.firstChild;
38523      if (nextNode) {
38524        stripCustomNsAttrs(nextNode);
38525      }
38526
38527      node = getNonDescendant('nextSibling', node);
38528    }
38529  }
38530
38531  function getNonDescendant(propName, node) {
38532    // An element is clobbered if its `propName` property points to one of its descendants
38533    var nextNode = node[propName];
38534    if (nextNode && nodeContains.call(node, nextNode)) {
38535      throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
38536    }
38537    return nextNode;
38538  }
38539}
38540
38541function sanitizeText(chars) {
38542  var buf = [];
38543  var writer = htmlSanitizeWriter(buf, noop);
38544  writer.chars(chars);
38545  return buf.join('');
38546}
38547
38548
38549// define ngSanitize module and register $sanitize service
38550angular.module('ngSanitize', [])
38551  .provider('$sanitize', $SanitizeProvider)
38552  .info({ angularVersion: '1.8.3' });
38553
38554/**
38555 * @ngdoc filter
38556 * @name linky
38557 * @kind function
38558 *
38559 * @description
38560 * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and
38561 * plain email address links.
38562 *
38563 * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
38564 *
38565 * @param {string} text Input text.
38566 * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in.
38567 * @param {object|function(url)} [attributes] Add custom attributes to the link element.
38568 *
38569 *    Can be one of:
38570 *
38571 *    - `object`: A map of attributes
38572 *    - `function`: Takes the url as a parameter and returns a map of attributes
38573 *
38574 *    If the map of attributes contains a value for `target`, it overrides the value of
38575 *    the target parameter.
38576 *
38577 *
38578 * @returns {string} Html-linkified and {@link $sanitize sanitized} text.
38579 *
38580 * @usage
38581   <span ng-bind-html="linky_expression | linky"></span>
38582 *
38583 * @example
38584   <example module="linkyExample" deps="angular-sanitize.js" name="linky-filter">
38585     <file name="index.html">
38586       <div ng-controller="ExampleController">
38587       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
38588       <table>
38589         <tr>
38590           <th>Filter</th>
38591           <th>Source</th>
38592           <th>Rendered</th>
38593         </tr>
38594         <tr id="linky-filter">
38595           <td>linky filter</td>
38596           <td>
38597             <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
38598           </td>
38599           <td>
38600             <div ng-bind-html="snippet | linky"></div>
38601           </td>
38602         </tr>
38603         <tr id="linky-target">
38604          <td>linky target</td>
38605          <td>
38606            <pre>&lt;div ng-bind-html="snippetWithSingleURL | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
38607          </td>
38608          <td>
38609            <div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div>
38610          </td>
38611         </tr>
38612         <tr id="linky-custom-attributes">
38613          <td>linky custom attributes</td>
38614          <td>
38615            <pre>&lt;div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"&gt;<br>&lt;/div&gt;</pre>
38616          </td>
38617          <td>
38618            <div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></div>
38619          </td>
38620         </tr>
38621         <tr id="escaped-html">
38622           <td>no filter</td>
38623           <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
38624           <td><div ng-bind="snippet"></div></td>
38625         </tr>
38626       </table>
38627     </file>
38628     <file name="script.js">
38629       angular.module('linkyExample', ['ngSanitize'])
38630         .controller('ExampleController', ['$scope', function($scope) {
38631           $scope.snippet =
38632             'Pretty text with some links:\n' +
38633             'http://angularjs.org/,\n' +
38634             'mailto:[email protected],\n' +
38635             '[email protected],\n' +
38636             'and one more: ftp://127.0.0.1/.';
38637           $scope.snippetWithSingleURL = 'http://angularjs.org/';
38638         }]);
38639     </file>
38640     <file name="protractor.js" type="protractor">
38641       it('should linkify the snippet with urls', function() {
38642         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
38643             toBe('Pretty text with some links: http://angularjs.org/, [email protected], ' +
38644                  '[email protected], and one more: ftp://127.0.0.1/.');
38645         expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
38646       });
38647
38648       it('should not linkify snippet without the linky filter', function() {
38649         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
38650             toBe('Pretty text with some links: http://angularjs.org/, mailto:[email protected], ' +
38651                  '[email protected], and one more: ftp://127.0.0.1/.');
38652         expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
38653       });
38654
38655       it('should update', function() {
38656         element(by.model('snippet')).clear();
38657         element(by.model('snippet')).sendKeys('new http://link.');
38658         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
38659             toBe('new http://link.');
38660         expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
38661         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
38662             .toBe('new http://link.');
38663       });
38664
38665       it('should work with the target property', function() {
38666        expect(element(by.id('linky-target')).
38667            element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
38668            toBe('http://angularjs.org/');
38669        expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
38670       });
38671
38672       it('should optionally add custom attributes', function() {
38673        expect(element(by.id('linky-custom-attributes')).
38674            element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
38675            toBe('http://angularjs.org/');
38676        expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
38677       });
38678     </file>
38679   </example>
38680 */
38681angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
38682  var LINKY_URL_REGEXP =
38683        /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
38684      MAILTO_REGEXP = /^mailto:/i;
38685
38686  var linkyMinErr = angular.$$minErr('linky');
38687  var isDefined = angular.isDefined;
38688  var isFunction = angular.isFunction;
38689  var isObject = angular.isObject;
38690  var isString = angular.isString;
38691
38692  return function(text, target, attributes) {
38693    if (text == null || text === '') return text;
38694    if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text);
38695
38696    var attributesFn =
38697      isFunction(attributes) ? attributes :
38698      isObject(attributes) ? function getAttributesObject() {return attributes;} :
38699      function getEmptyAttributesObject() {return {};};
38700
38701    var match;
38702    var raw = text;
38703    var html = [];
38704    var url;
38705    var i;
38706    while ((match = raw.match(LINKY_URL_REGEXP))) {
38707      // We can not end in these as they are sometimes found at the end of the sentence
38708      url = match[0];
38709      // if we did not match ftp/http/www/mailto then assume mailto
38710      if (!match[2] && !match[4]) {
38711        url = (match[3] ? 'http://' : 'mailto:') + url;
38712      }
38713      i = match.index;
38714      addText(raw.substr(0, i));
38715      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
38716      raw = raw.substring(i + match[0].length);
38717    }
38718    addText(raw);
38719    return $sanitize(html.join(''));
38720
38721    function addText(text) {
38722      if (!text) {
38723        return;
38724      }
38725      html.push(sanitizeText(text));
38726    }
38727
38728    function addLink(url, text) {
38729      var key, linkAttributes = attributesFn(url);
38730      html.push('<a ');
38731
38732      for (key in linkAttributes) {
38733        html.push(key + '="' + linkAttributes[key] + '" ');
38734      }
38735
38736      if (isDefined(target) && !('target' in linkAttributes)) {
38737        html.push('target="',
38738                  target,
38739                  '" ');
38740      }
38741      html.push('href="',
38742                url.replace(/"/g, '&quot;'),
38743                '">');
38744      addText(text);
38745      html.push('</a>');
38746    }
38747  };
38748}]);
38749
38750
38751})(window, window.angular);
38752
38753/**
38754 * Bunch of useful filters for angularJS(with no external dependencies!)
38755 * @version v0.5.17 - 2017-09-22 * @link https://github.com/a8m/angular-filter
38756 * @author Ariel Mashraki <[email protected]>
38757 * @license MIT License, http://www.opensource.org/licenses/MIT
38758 */!function(a,b,c){"use strict";function d(a){return E(a)?a:Object.keys(a).map(function(b){return a[b]})}function e(a){return null===a}function f(a,b){var d=Object.keys(a);return d.map(function(d){return b[d]!==c&&b[d]==a[d]}).indexOf(!1)==-1}function g(a,b){function c(a,b,c){for(var d=0;b+d<=a.length;){if(a.charAt(b+d)==c)return d;d++}return-1}for(var d=0,e=0;e<=b.length;e++){var f=c(a,d,b.charAt(e));if(f==-1)return!1;d+=f+1}return!0}function h(a,b,c){var d=0;return a.filter(function(a){var e=y(c)?d<b&&c(a):d<b;return d=e?d+1:d,e})}function i(a,b){return Math.round(a*Math.pow(10,b))/Math.pow(10,b)}function j(a,b,c){b=b||[];var d=Object.keys(a);return d.forEach(function(d){if(D(a[d])&&!E(a[d])){var e=c?c+"."+d:c;j(a[d],b,e||d)}else{var f=c?c+"."+d:d;b.push(f)}}),b}function k(a){return a&&a.$evalAsync&&a.$watch}function l(){return function(a,b){return a>b}}function m(){return function(a,b){return a>=b}}function n(){return function(a,b){return a<b}}function o(){return function(a,b){return a<=b}}function p(){return function(a,b){return a==b}}function q(){return function(a,b){return a!=b}}function r(){return function(a,b){return a===b}}function s(){return function(a,b){return a!==b}}function t(a){return function(b,c){return b=D(b)?d(b):b,!(!E(b)||z(c))&&b.some(function(b){return B(c)&&D(b)||A(c)?a(c)(b):b===c})}}function u(a,b){return b=b||0,b>=a.length?a:E(a[b])?u(a.slice(0,b).concat(a[b],a.slice(b+1)),b):u(a,b+1)}function v(a){return function(b,c){function e(a,b){return!z(b)&&a.some(function(a){return I(a,b)})}if(b=D(b)?d(b):b,!E(b))return b;var f=[],g=a(c);return z(c)?b.filter(function(a,b,c){return c.indexOf(a)===b}):b.filter(function(a){var b=g(a);return!e(f,b)&&(f.push(b),!0)})}}function w(a,b,c){return b?a+c+w(a,--b,c):a}function x(){return function(a){return B(a)?a.split(" ").map(function(a){return a.charAt(0).toUpperCase()+a.substring(1)}).join(" "):a}}var y=b.isDefined,z=b.isUndefined,A=b.isFunction,B=b.isString,C=b.isNumber,D=b.isObject,E=b.isArray,F=b.forEach,G=b.extend,H=b.copy,I=b.equals;String.prototype.contains||(String.prototype.contains=function(){return String.prototype.indexOf.apply(this,arguments)!==-1}),b.module("a8m.angular",[]).filter("isUndefined",function(){return function(a){return b.isUndefined(a)}}).filter("isDefined",function(){return function(a){return b.isDefined(a)}}).filter("isFunction",function(){return function(a){return b.isFunction(a)}}).filter("isString",function(){return function(a){return b.isString(a)}}).filter("isNumber",function(){return function(a){return b.isNumber(a)}}).filter("isArray",function(){return function(a){return b.isArray(a)}}).filter("isObject",function(){return function(a){return b.isObject(a)}}).filter("isEqual",function(){return function(a,c){return b.equals(a,c)}}),b.module("a8m.conditions",[]).filter({isGreaterThan:l,">":l,isGreaterThanOrEqualTo:m,">=":m,isLessThan:n,"<":n,isLessThanOrEqualTo:o,"<=":o,isEqualTo:p,"==":p,isNotEqualTo:q,"!=":q,isIdenticalTo:r,"===":r,isNotIdenticalTo:s,"!==":s}),b.module("a8m.is-null",[]).filter("isNull",function(){return function(a){return e(a)}}),b.module("a8m.after-where",[]).filter("afterWhere",function(){return function(a,b){if(a=D(a)?d(a):a,!E(a)||z(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(c===-1?0:c)}}),b.module("a8m.after",[]).filter("after",function(){return function(a,b){return a=D(a)?d(a):a,E(a)?a.slice(b):a}}),b.module("a8m.before-where",[]).filter("beforeWhere",function(){return function(a,b){if(a=D(a)?d(a):a,!E(a)||z(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(0,c===-1?a.length:++c)}}),b.module("a8m.before",[]).filter("before",function(){return function(a,b){return a=D(a)?d(a):a,E(a)?a.slice(0,b?--b:b):a}}),b.module("a8m.chunk-by",["a8m.filter-watcher"]).filter("chunkBy",["filterWatcher",function(a){return function(b,c,d){function e(a,b){for(var c=[];a--;)c[a]=b;return c}function f(a,b,c){return E(a)?a.map(function(a,d,f){return d*=b,a=f.slice(d,d+b),!z
38758(c)&&a.length<b?a.concat(e(b-a.length,c)):a}).slice(0,Math.ceil(a.length/b)):a}return a.isMemoized("chunkBy",arguments)||a.memoize("chunkBy",arguments,this,f(b,c,d))}}]),b.module("a8m.concat",[]).filter("concat",[function(){return function(a,b){if(z(b))return a;if(E(a))return D(b)?a.concat(d(b)):a.concat(b);if(D(a)){var c=d(a);return D(b)?c.concat(d(b)):c.concat(b)}return a}}]),b.module("a8m.contains",[]).filter({contains:["$parse",t],some:["$parse",t]}),b.module("a8m.count-by",[]).filter("countBy",["$parse",function(a){return function(b,c){var e,f={},g=a(c);return b=D(b)?d(b):b,!E(b)||z(c)?b:(b.forEach(function(a){e=g(a),f[e]||(f[e]=0),f[e]++}),f)}}]),b.module("a8m.defaults",[]).filter("defaults",["$parse",function(a){return function(b,c){if(b=D(b)?d(b):b,!E(b)||!D(c))return b;var e=j(c);return b.forEach(function(b){e.forEach(function(d){var e=a(d),f=e.assign;z(e(b))&&f(b,e(c))})}),b}}]),b.module("a8m.every",[]).filter("every",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!(E(b)&&!z(c))||b.every(function(b){return D(b)||A(c)?a(c)(b):b===c})}}]),b.module("a8m.filter-by",[]).filter("filterBy",["$parse",function(a){return function(b,e,f,g){var h;return f=B(f)||C(f)?String(f).toLowerCase():c,b=D(b)?d(b):b,!E(b)||z(f)?b:b.filter(function(b){return e.some(function(c){if(~c.indexOf("+")){var d=c.replace(/\s+/g,"").split("+");h=d.map(function(c){return a(c)(b)}).join(" ")}else h=a(c)(b);return!(!B(h)&&!C(h))&&(h=String(h).toLowerCase(),g?h===f:h.contains(f))})})}}]),b.module("a8m.first",[]).filter("first",["$parse",function(a){return function(b){var e,f,g;return b=D(b)?d(b):b,E(b)?(g=Array.prototype.slice.call(arguments,1),e=C(g[0])?g[0]:1,f=C(g[0])?C(g[1])?c:g[1]:g[0],g.length?h(b,e,f?a(f):f):b[0]):b}}]),b.module("a8m.flatten",[]).filter("flatten",function(){return function(a,b){return b=b||!1,a=D(a)?d(a):a,E(a)?b?[].concat.apply([],a):u(a,0):a}}),b.module("a8m.fuzzy-by",[]).filter("fuzzyBy",["$parse",function(a){return function(b,c,e,f){var h,i,j=f||!1;return b=D(b)?d(b):b,!E(b)||z(c)||z(e)?b:(i=a(c),b.filter(function(a){return h=i(a),!!B(h)&&(h=j?h:h.toLowerCase(),e=j?e:e.toLowerCase(),g(h,e)!==!1)}))}}]),b.module("a8m.fuzzy",[]).filter("fuzzy",function(){return function(a,b,c){function e(a,b){var c,d,e=Object.keys(a);return 0<e.filter(function(e){return c=a[e],!!d||!!B(c)&&(c=f?c:c.toLowerCase(),d=g(c,b)!==!1)}).length}var f=c||!1;return a=D(a)?d(a):a,!E(a)||z(b)?a:(b=f?b:b.toLowerCase(),a.filter(function(a){return B(a)?(a=f?a:a.toLowerCase(),g(a,b)!==!1):!!D(a)&&e(a,b)}))}}),b.module("a8m.group-by",["a8m.filter-watcher"]).filter("groupBy",["$parse","filterWatcher",function(a,b){return function(c,d){function e(a,b){var c,d={};
38758return F(a,function(a){c=b(a),d[c]||(d[c]=[]),d[c].push(a)}),d}return!D(c)||z(d)?c:b.isMemoized("groupBy",arguments)||b.memoize("groupBy",arguments,this,e(c,a(d)))}}]),b.module("a8m.is-empty",[]).filter("isEmpty",function(){return function(a){return D(a)?!d(a).length:!a.length}}),b.module("a8m.join",[]).filter("join",function(){return function(a,b){return z(a)||!E(a)?a:(z(b)&&(b=" "),a.join(b))}}),b.module("a8m.last",[]).filter("last",["$parse",function(a){return function(b){var e,f,g,i=H(b);return i=D(i)?d(i):i,E(i)?(g=Array.prototype.slice.call(arguments,1),e=C(g[0])?g[0]:1,f=C(g[0])?C(g[1])?c:g[1]:g[0],g.length?h(i.reverse(),e,f?a(f):f).reverse():i[i.length-1]):i}}]),b.module("a8m.map",[]).filter("map",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.map(function(b){return a(c)(b)})}}]),b.module("a8m.omit",[]).filter("omit",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.filter(function(b){return!a(c)(b)})}}]),b.module("a8m.pick",[]).filter("pick",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.filter(function(b){return a(c)(b)})}}]),b.module("a8m.range",[]).filter("range",function(){return function(a,b,c,d,e){c=c||0,d=d||1;for(var f=0;f<parseInt(b);f++){var g=c+f*d;a.push(A(e)?e(g):g)}return a}}),b.module("a8m.remove-with",[]).filter("removeWith",function(){return function(a,b){return z(b)?a:(a=D(a)?d(a):a,a.filter(function(a){return!f(b,a)}))}}),b.module("a8m.remove",[]).filter("remove",function(){return function(a){a=D(a)?d(a):a;var b=Array.prototype.slice.call(arguments,1);return E(a)?a.filter(function(a){return!b.some(function(b){return I(b,a)})}):a}}),b.module("a8m.reverse",[]).filter("reverse",[function(){return function(a){return a=D(a)?d(a):a,B(a)?a.split("").reverse().join(""):E(a)?a.slice().reverse():a}}]),b.module("a8m.search-field",[]).filter("searchField",["$parse",function(a){return function(b){var c,e;b=D(b)?d(b):b;var f=Array.prototype.slice.call(arguments,1);return E(b)&&f.length?b.map(function(b){return e=f.map(function(d){return(c=a(d))(b)}).join(" "),G(b,{searchField:e})}):b}}]),b.module("a8m.to-array",[]).filter("toArray",function(){return function(a,b){return D(a)?b?Object.keys(a).map(function(b){return G(a[b],{$key:b})}):d(a):a}}),b.module("a8m.unique",[]).filter({unique:["$parse",v],uniq:["$parse",v]}),b.module("a8m.where",[]).filter("where",function(){return function(a,b){return z(b)?a:(a=D(a)?d(a):a,a.filter(function(a){return f(b,a)}))}}),b.module("a8m.xor",[]).filter("xor",["$parse",function(a){return function(b,c,e){function f(b,c){var d=a(e);return c.some(function(a){return e?I(d(a),d(b)):I(a,b)})}return e=e||!1,b=D(b)?d(b):b,c=D(c)?d(c):c,E(b)&&E(c)?b.concat(c).filter(function(a){return!(f(a,b)&&f(a,c))}):b}}]),b.module("a8m.math.abs",[]).filter("abs",function(){return function(a){return Math.abs(a)}}),b.module("a8m.math.byteFmt",[]).filter("byteFmt",function(){var a=[{str:"B",val:1024}];return["KB","MB","GB","TB","PB","EB","ZB","YB"].forEach(function(b,c){a.push({str:b,val:1024*a[c].val})}),function(b,c){if(C(c)&&isFinite(c)&&c%1===0&&c>=0&&C(b)&&isFinite(b)){for(var d=0;d<a.length-1&&b>=a[d].val;)d++;return b/=d>0?a[d-1].val:1,i(b,c)+" "+a[d].str}return"NaN"}}),b.module("a8m.math.degrees",[]).filter("degrees",function(){return function(a,b){if(C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)){var c=180*a/Math.PI;return Math.round(c*Math.pow(10,b))/Math.pow(10,b)}return"NaN"}}),b.module("a8m.math.kbFmt",[]).filter("kbFmt",function(){var a=[{str:"KB",val:1024}];return["MB","GB","TB","PB","EB","ZB","YB"].forEach(function(b,c){a.push({str:b,val:1024*a[c].val})}),function(b,c){if(C(c)&&isFinite(c)&&c%1===0&&c>=0&&C(b)&&isFinite(b)){for(var d=0;d<a.length-1&&b>=a[d].val;)d++;return b/=d>0?a[d-1].val:1,i(b,c)+" "+a[d].str}return"NaN"}}),b.module("a8m.math.max",[]).filter("max",["$parse",function(a){function b(b,c){var d=b.map(function(b){return a(c)(b)});return d.indexOf(Math.max.apply(Math,d))}return function(a,c){return E(a)?z(c)?Math.max.apply(Math,a):a[b(a,c)]:a}}]),b.module("a8m.math.min",[]).filter("min",["$parse",function(a){function b(b,c){var d=b.map(function(b){return a(c)(b)});return d.indexOf(Math.min.apply(Math,d))}return function(a,c){return E(a)?z(c)?Math.min.apply(Math,a):a[b(a,c)]:a}}]),b.module("a8m.math.percent",[]).filter("percent",function(){return function(a,b,c){var d=B(a)?Number(a):a;return b=b||100,c=c||!1,!C(d)||isNaN(d)?a:c?Math.round(d/b*100):d/b*100}}),b.module("a8m.math.radians",[]).filter("radians",function(){return function(a,b){if(C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)){var c=3.14159265359*a/180;return Math.round(c*Math.pow(10,b))/Math.pow(10,b)}return"NaN"}}),b.module("a8m.math.radix",[]).filter("radix",function(){return function(a,b){var c=/^[2-9]$|^[1-2]\d$|^3[0-6]$/;return C(a)&&c.test(b)?a.toString(b).toUpperCase():a}}),b.module("a8m.math.shortFmt",[]).filter("shortFmt",function(){return function(a,b){return C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)?a<1e3?""+a:a<1e6?i(a/1e3,b)+" K":a<1e9?i(a/1e6,b)+" M":i(a/1e9,b)+" B":"NaN"}}),b.module("a8m.math.sum",[]).filter("sum",function(){return function(a,b){return E(a)?a.reduce(function(a,b){return a+b},b||0):a}}),b.module("a8m.ends-with",[]).filter("endsWith",function(){return function(a,b,c){var d,e=c||!1;return!B(a)||z(b)?a:(a=e?a:a.toLowerCase(),d=a.length-b.length,a.indexOf(e?b:b.toLowerCase(),d)!==-1)}}),b.module("a8m.latinize",[]).filter("latinize",[function(){function a(a){return a.replace(/[^\u
387580000-\u007E]/g,function(a){return c[a]||a})}for(var b=[{base:"A",letters:"AⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ"},{base:"AA",letters:"Ꜳ"},{base:"AE",letters:"ÆǼǢ"},{base:"AO",letters:"Ꜵ"},{base:"AU",letters:"Ꜷ"},{base:"AV",letters:"ꜸꜺ"},{base:"AY",letters:"Ꜽ"},{base:"B",letters:"BⒷBḂḄḆɃƂƁ"},{base:"C",letters:"CⒸCĆĈĊČÇḈƇȻꜾ"},{base:"D",letters:"DⒹDḊĎḌḐḒḎĐƋƊƉꝹ"},{base:"DZ",letters:"DZDŽ"},{base:"Dz",letters:"DzDž"},{base:"E",letters:"EⒺEÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎ"},{base:"F",letters:"FⒻFḞƑꝻ"},{base:"G",letters:"GⒼGǴĜḠĞĠǦĢǤƓꞠꝽꝾ"},{base:"H",letters:"HⒽHĤḢḦȞḤḨḪĦⱧⱵꞍ"},{base:"I",letters:"IⒾIÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ"},{base:"J",letters:"JⒿJĴɈ"},{base:"K",letters:"KⓀKḰǨḲĶḴƘⱩꝀꝂꝄꞢ"},{base:"L",letters:"LⓁLĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ"},{base:"LJ",letters:"LJ"},{base:"Lj",letters:"Lj"},{base:"M",letters:"MⓂMḾṀṂⱮƜ"},{base:"N",letters:"NⓃNǸŃÑṄŇṆŅṊṈȠƝꞐꞤ"},{base:"NJ",letters:"NJ"},{base:"Nj",letters:"Nj"},{base:"O",letters:"OⓄOÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ"},{base:"OI",letters:"Ƣ"},{base:"OO",letters:"Ꝏ"},{base:"OU",letters:"Ȣ"},{base:"OE",letters:"ŒŒ"},{base:"oe",letters:"œœ"},{base:"P",letters:"PⓅPṔṖƤⱣꝐꝒꝔ"},{base:"Q",letters:"QⓆQꝖꝘɊ"},{base:"R",letters:"RⓇRŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ"},{base:"S",letters:"SⓈSẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ"},{base:"T",letters:"TⓉTṪŤṬȚŢṰṮŦƬƮȾꞆ"},{base:"TZ",letters:"Ꜩ"},{base:"U",letters:"UⓊUÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ"},{base:"V",letters:"VⓋVṼṾƲꝞɅ"},{base:"VY",letters:"Ꝡ"},{base:"W",letters:"WⓌWẀẂŴẆẄẈⱲ"},{base:"X",letters:"XⓍXẊẌ"},{base:"Y",letters:"YⓎYỲÝŶỸȲẎŸỶỴƳɎỾ"},{base:"Z",letters:"ZⓏZŹẐŻŽẒẔƵȤⱿⱫꝢ"},{base:"a",letters:"aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ"},{base:"aa",letters:"ꜳ"},{base:"ae",letters:"æǽǣ"},{base:"ao",letters:"ꜵ"},{base:"au",letters:"ꜷ"},{base:"av",letters:"ꜹꜻ"},{base:"ay",letters:"ꜽ"},{base:"b",letters:"bⓑbḃḅḇƀƃɓ"},{base:"c",letters:"cⓒcćĉċčçḉƈȼꜿↄ"},{base:"d",letters:"dⓓdḋďḍḑḓḏđƌɖɗꝺ"},{base:"dz",letters:"dzdž"},{base:"e",letters:"eⓔeèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ"},{base:"f",letters:"fⓕfḟƒꝼ"},{base:"g",letters:"gⓖgǵĝḡğġǧģǥɠꞡᵹꝿ"},{base:"h",letters:"hⓗhĥḣḧȟḥḩḫẖħⱨⱶɥ"},{base:"hv",letters:"ƕ"},{base:"i",letters:"iⓘiìíîĩīĭïḯỉǐȉȋịįḭɨı"},{base:"j",letters:"jⓙjĵǰɉ"},{base:"k",letters:"kⓚkḱǩḳķḵƙⱪꝁꝃꝅꞣ"},{base:"l",letters:"lⓛlŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇ"},{base:"lj",letters:"lj"},{base:"m",letters:"mⓜmḿṁṃɱɯ"},{base:"n",letters:"nⓝnǹńñṅňṇņṋṉƞɲʼnꞑꞥ"},{base:"nj",letters:"nj"},{base:"o",letters:"oⓞoòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔꝋꝍɵ"},{base:"oi",letters:"ƣ"},{base:"ou",letters:"ȣ"},{base:"oo",letters:"ꝏ"},{base:"p",letters:"pⓟpṕṗƥᵽꝑꝓꝕ"},{base:"q",letters:"qⓠqɋꝗꝙ"},{base:"r",letters:"rⓡrŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ"},{base:"s",letters:"sⓢsßśṥŝṡšṧṣṩșşȿꞩꞅẛ"},{base:"t",letters:"tⓣtṫẗťṭțţṱṯŧƭʈⱦꞇ"},{base:"tz",letters:"ꜩ"},{base:"u",letters:"uⓤuùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ"},{base:"v",letters:"vⓥvṽṿʋꝟʌ"},{base:"vy",letters:"ꝡ"},{base:"w",letters:"wⓦwẁẃŵẇẅẘẉⱳ"},{base:"x",letters:"xⓧxẋẍ"},{base:"y",letters:"yⓨyỳýŷỹȳẏÿỷẙỵƴɏỿ"},{base:"z",letters:"zⓩzźẑżžẓẕƶȥɀⱬꝣ"}],c={},d=0;d<b.length;d++)for(var e=b[d].letters.split(""),f=0;f<e.length;f++)c[e[f]]=b[d].base;return function(b){return B(b)?a(b):b}}]),b.module("a8m.ltrim",[]).filter("ltrim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp("^"+c+"+"),""):a}}),b.module("a8m.match",[]).filter("match",function(){return function(a,b,c){var d=new RegExp(b,c);return B(a)?a.match(d):null}}),b.module("a8m.phoneUS",[]).filter("phoneUS",function(){return function(a){return a+="","("+a.slice(0,3)+") "+a.slice(3,6)+"-"+a.slice(6)}}),b.module("a8m.repeat",[]).filter("repeat",[function(){return function(a,b,c){var d=~~b;return B(a)&&d?w(a,--b,c||""):a}}]),b.module("a8m.rtrim",[]).filter("rtrim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp(c+"+$"),""):a}}),b.module("a8m.slugify",[]).filter("slugify",[function(){return function(a,b){var c=z(b)?"-":b;return B(a)?a.toLowerCase().replace(/\s+/g,c):a}}]),b.module("a8m.split",[]).filter("split",function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}return function(b,c,d){var f,g,h,i;return z(b)||!B(b)?null:(z(c)&&(c=""),isNaN(d)&&(d=0),f=new RegExp(a(c),"g"),g=b.match(f),e(g)||d>=g.length?[b]:0===d?b.split(c):(h=b.split(c),i=h.splice(0,d+1),h.unshift(i.join(c)),h))}}),b.module("a8m.starts-with",[]).filter("startsWith",function(){return function(a,b,c){var d=c||!1;return!B(a)||z(b)?a:(a=d?a:a.toLowerCase(),!a.indexOf(d?b:b.toLowerCase()))}}),b.module("a8m.stringular",[]).filter("stringular",function(){return function(a){var b=Array.prototype.slice.call(arguments,1
38758);return a.replace(/{(\d+)}/g,function(a,c){return z(b[c])?a:b[c]})}}),b.module("a8m.strip-tags",[]).filter("stripTags",function(){return function(a){return B(a)?a.replace(/<\S[^><]*>/g,""):a}}),b.module("a8m.test",[]).filter("test",function(){return function(a,b,c){var d=new RegExp(b,c);return B(a)?d.test(a):a}}),b.module("a8m.trim",[]).filter("trim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp("^"+c+"+|"+c+"+$","g"),""):a}}),b.module("a8m.truncate",[]).filter("truncate",function(){return function(a,b,c,d){return b=z(b)?a.length:b,d=d||!1,c=c||"",!B(a)||a.length<=b?a:a.substring(0,d?a.indexOf(" ",b)===-1?a.length:a.indexOf(" ",b):b)+c}}),b.module("a8m.ucfirst",[]).filter({ucfirst:x,titleize:x}),b.module("a8m.uri-component-encode",[]).filter("uriComponentEncode",["$window",function(a){return function(b){return B(b)?a.encodeURIComponent(b):b}}]),b.module("a8m.uri-encode",[]).filter("uriEncode",["$window",function(a){return function(b){return B(b)?a.encodeURI(b):b}}]),b.module("a8m.wrap",[]).filter("wrap",function(){return function(a,b,c){return B(a)&&y(b)?[b,a,c||b].join(""):a}}),b.module("a8m.filter-watcher",[]).provider("filterWatcher",function(){this.$get=["$window","$rootScope",function(a,b){function c(b,c){function d(){var b=[];return function(c,d){if(D(d)&&!e(d)){if(~b.indexOf(d))return"[Circular]";b.push(d)}return a==d?"$WINDOW":a.document==d?"$DOCUMENT":k(d)?"$SCOPE":d}}return[b,JSON.stringify(c,d())].join("#").replace(/"/g,"")}function d(a){var b=a.targetScope.$id;F(l[b],function(a){delete j[a]}),delete l[b]}function f(){m(function(){b.$$phase||(j={})},2e3)}function g(a,b){var c=a.$id;return z(l[c])&&(a.$on("$destroy",d),l[c]=[]),l[c].push(b)}function h(a,b){var d=c(a,b);return j[d]}function i(a,b,d,e){var h=c(a,b);return j[h]=e,k(d)?g(d,h):f(),e}var j={},l={},m=a.setTimeout;return{isMemoized:h,memoize:i}}]}),b.module("angular.filter",["a8m.ucfirst","a8m.uri-encode","a8m.uri-component-encode","a8m.slugify","a8m.latinize","a8m.strip-tags","a8m.stringular","a8m.truncate","a8m.starts-with","a8m.ends-with","a8m.wrap","a8m.trim","a8m.ltrim","a8m.rtrim","a8m.repeat","a8m.test","a8m.match","a8m.split","a8m.phoneUS","a8m.to-array","a8m.concat","a8m.contains","a8m.unique","a8m.is-empty","a8m.after","a8m.after-where","a8m.before","a8m.before-where","a8m.defaults","a8m.where","a8m.reverse","a8m.remove","a8m.remove-with","a8m.group-by","a8m.count-by","a8m.chunk-by","a8m.search-field","a8m.fuzzy-by","a8m.fuzzy","a8m.omit","a8m.pick","a8m.every","a8m.filter-by","a8m.xor","a8m.map","a8m.first","a8m.last","a8m.flatten","a8m.join","a8m.range","a8m.math.max","a8m.math.min","a8m.math.abs","a8m.math.percent","a8m.math.radix","a8m.math.sum","a8m.math.degrees","a8m.math.radians","a8m.math.byteFmt","a8m.math.kbFmt","a8m.math.shortFmt","a8m.angular","a8m.conditions","a8m.is-null","a8m.filter-watcher"])}(window,window.angular);
38759//# sourceMappingURL=angular.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.