From 3e36684b9c022d20646f648c041360814b318161 Mon Sep 17 00:00:00 2001 From: Plastiquewind Date: Thu, 18 Jan 2018 12:59:29 +0500 Subject: [PATCH] Added missing builds --- app.8570cccfc468cea9ae26.js | 40 +++++++++++++++++++ app.8570cccfc468cea9ae26.js.map | 1 + hub.8570cccfc468cea9ae26.js | 2 + hub.8570cccfc468cea9ae26.js.map | 1 + vendor.8570cccfc468cea9ae26.js | 62 ++++++++++++++++++++++++++++++ vendor.8570cccfc468cea9ae26.js.map | 1 + 6 files changed, 107 insertions(+) create mode 100644 app.8570cccfc468cea9ae26.js create mode 100644 app.8570cccfc468cea9ae26.js.map create mode 100644 hub.8570cccfc468cea9ae26.js create mode 100644 hub.8570cccfc468cea9ae26.js.map create mode 100644 vendor.8570cccfc468cea9ae26.js create mode 100644 vendor.8570cccfc468cea9ae26.js.map diff --git a/app.8570cccfc468cea9ae26.js b/app.8570cccfc468cea9ae26.js new file mode 100644 index 0000000..84a27d8 --- /dev/null +++ b/app.8570cccfc468cea9ae26.js @@ -0,0 +1,40 @@ +webpackJsonp([0],[function(e,t,n){"use strict";function a(e,t,n){"ngInject";n.state("app",{redirectTo:"app.main","abstract":!0,component:"app"}),e.html5Mode(!0),t.otherwise("/")}function r(e){"ngInject";e.theme("default").primaryPalette("blue").accentPalette("red")}function s(){o.options.positionClass="toast-bottom-right",o.options.closeButton=!0}a.$inject=["$locationProvider","$urlRouterProvider","$stateProvider"],r.$inject=["$mdThemingProvider"],Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),o=n(3),d=n(6),u=n(8),l=n(215);n(228);var _=i.module("app",["ui.router","ngMessages","ngMaterial","ngAria","ngAnimate",u["default"].name,l["default"].name]).config(a).config(r).config(s).component("app",new d.AppComponent);t["default"]=_},,,function(e,t,n){var a,r;!function(s){a=[n(4)],r=function(e){return function(){function t(e,t,n){return f({type:Y.error,iconClass:h().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=h()),M=e("#"+t.containerId),M.length?M:(n&&(M=_(t)),M)}function a(e,t,n){return f({type:Y.info,iconClass:h().iconClasses.info,message:e,optionsOverride:n,title:t})}function r(e){y=e}function s(e,t,n){return f({type:Y.success,iconClass:h().iconClasses.success,message:e,optionsOverride:n,title:t})}function i(e,t,n){return f({type:Y.warning,iconClass:h().iconClasses.warning,message:e,optionsOverride:n,title:t})}function o(e,t){var a=h();M||n(a),l(e,a,t)||u(a)}function d(t){var a=h();return M||n(a),t&&0===e(":focus",t).length?void p(t):void(M.children().length&&M.remove())}function u(t){for(var n=M.children(),a=n.length-1;a>=0;a--)l(e(n[a]),t)}function l(t,n,a){var r=!(!a||!a.force)&&a.force;return!(!t||!r&&0!==e(":focus",t).length)&&(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){p(t)}}),!0)}function _(t){return M=e("
").attr("id",t.containerId).addClass(t.positionClass),M.appendTo(e(t.target)),M}function c(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,closeMethod:!1,closeDuration:!1,closeEasing:!1,closeOnHover:!0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",escapeHtml:!1,target:"body",closeHtml:'',closeClass:"toast-close-button",newestOnTop:!0,preventDuplicates:!1,progressBar:!1,progressClass:"toast-progress",rtl:!1}}function m(e){y&&y(e)}function f(t){function a(e){return null==e&&(e=""),e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function r(){d(),l(),_(),c(),f(),y(),u(),s()}function s(){var e="";switch(t.iconClass){case"toast-success":case"toast-info":e="polite";break;default:e="assertive"}x.attr("aria-live",e)}function i(){w.closeOnHover&&x.hover(D,k),!w.onclick&&w.tapToDismiss&&x.click(v),w.closeButton&&P&&P.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),w.onCloseClick&&w.onCloseClick(e),v(!0)}),w.onclick&&x.click(function(e){w.onclick(e),v()})}function o(){x.hide(),x[w.showMethod]({duration:w.showDuration,easing:w.showEasing,complete:w.onShown}),w.timeOut>0&&(S=setTimeout(v,w.timeOut),A.maxHideTime=parseFloat(w.timeOut),A.hideEta=(new Date).getTime()+A.maxHideTime,w.progressBar&&(A.intervalId=setInterval(T,10)))}function d(){t.iconClass&&x.addClass(w.toastClass).addClass(b)}function u(){w.newestOnTop?M.prepend(x):M.append(x)}function l(){if(t.title){var e=t.title;w.escapeHtml&&(e=a(t.title)),j.append(e).addClass(w.titleClass),x.append(j)}}function _(){if(t.message){var e=t.message;w.escapeHtml&&(e=a(t.message)),H.append(e).addClass(w.messageClass),x.append(H)}}function c(){w.closeButton&&(P.addClass(w.closeClass).attr("role","button"),x.prepend(P))}function f(){w.progressBar&&(O.addClass(w.progressClass),x.prepend(O))}function y(){w.rtl&&x.addClass("rtl")}function Y(e,t){if(e.preventDuplicates){if(t.message===L)return!0;L=t.message}return!1}function v(t){var n=t&&w.closeMethod!==!1?w.closeMethod:w.hideMethod,a=t&&w.closeDuration!==!1?w.closeDuration:w.hideDuration,r=t&&w.closeEasing!==!1?w.closeEasing:w.hideEasing;if(!e(":focus",x).length||t)return clearTimeout(A.intervalId),x[n]({duration:a,easing:r,complete:function(){p(x),clearTimeout(S),w.onHidden&&"hidden"!==E.state&&w.onHidden(),E.state="hidden",E.endTime=new Date,m(E)}})}function k(){(w.timeOut>0||w.extendedTimeOut>0)&&(S=setTimeout(v,w.extendedTimeOut),A.maxHideTime=parseFloat(w.extendedTimeOut),A.hideEta=(new Date).getTime()+A.maxHideTime)}function D(){clearTimeout(S),A.hideEta=0,x.stop(!0,!0)[w.showMethod]({duration:w.showDuration,easing:w.showEasing})}function T(){var e=(A.hideEta-(new Date).getTime())/A.maxHideTime*100;O.width(e+"%")}var w=h(),b=t.iconClass||w.iconClass;if("undefined"!=typeof t.optionsOverride&&(w=e.extend(w,t.optionsOverride),b=t.optionsOverride.iconClass||b),!Y(w,t)){g++,M=n(w,!0);var S=null,x=e("
"),j=e("
"),H=e("
"),O=e("
"),P=e(w.closeHtml),A={intervalId:null,hideEta:null,maxHideTime:null},E={toastId:g,state:"visible",startTime:new Date,options:w,map:t};return r(),o(),i(),m(E),w.debug&&console&&console.log(E),x}}function h(){return e.extend({},c(),v.options)}function p(e){M||(M=n()),e.is(":visible")||(e.remove(),e=null,0===M.children().length&&(M.remove(),L=void 0))}var M,y,L,g=0,Y={error:"error",info:"info",success:"success",warning:"warning"},v={clear:o,remove:d,error:t,getContainer:n,info:a,options:{},subscribe:r,success:s,version:"2.1.4",warning:i};return v}()}.apply(t,a),!(void 0!==r&&(e.exports=r))}(n(5))},function(e,t,n){var a,r;/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +!function(t,n){"use strict";"object"==typeof e&&"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,function(n,s){"use strict";function i(e,t){t=t||ie;var n=t.createElement("script");n.text=e,t.head.appendChild(n).parentNode.removeChild(n)}function o(e){var t=!!e&&"length"in e&&e.length,n=Le.type(e);return"function"!==n&&!Le.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function d(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}function u(e,t,n){return Le.isFunction(t)?Le.grep(e,function(e,a){return!!t.call(e,a,e)!==n}):t.nodeType?Le.grep(e,function(e){return e===t!==n}):"string"!=typeof t?Le.grep(e,function(e){return _e.call(t,e)>-1!==n}):xe.test(t)?Le.filter(t,e,n):(t=Le.filter(t,e),Le.grep(e,function(e){return _e.call(t,e)>-1!==n&&1===e.nodeType}))}function l(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function _(e){var t={};return Le.each(e.match(Ee)||[],function(e,n){t[n]=!0}),t}function c(e){return e}function m(e){throw e}function f(e,t,n,a){var r;try{e&&Le.isFunction(r=e.promise)?r.call(e).done(t).fail(n):e&&Le.isFunction(r=e.then)?r.call(e,t,n):t.apply(void 0,[e].slice(a))}catch(e){n.apply(void 0,[e])}}function h(){ie.removeEventListener("DOMContentLoaded",h),n.removeEventListener("load",h),Le.ready()}function p(){this.expando=Le.expando+p.uid++}function M(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:ze.test(e)?JSON.parse(e):e)}function y(e,t,n){var a;if(void 0===n&&1===e.nodeType)if(a="data-"+t.replace(Re,"-$&").toLowerCase(),n=e.getAttribute(a),"string"==typeof n){try{n=M(n)}catch(r){}Ie.set(e,t,n)}else n=void 0;return n}function L(e,t,n,a){var r,s=1,i=20,o=a?function(){return a.cur()}:function(){return Le.css(e,t,"")},d=o(),u=n&&n[3]||(Le.cssNumber[t]?"":"px"),l=(Le.cssNumber[t]||"px"!==u&&+d)&&Ue.exec(Le.css(e,t));if(l&&l[3]!==u){u=u||l[3],n=n||[],l=+d||1;do s=s||".5",l/=s,Le.style(e,t,l+u);while(s!==(s=o()/d)&&1!==s&&--i)}return n&&(l=+l||+d||0,r=n[1]?l+(n[1]+1)*n[2]:+n[2],a&&(a.unit=u,a.start=l,a.end=r)),r}function g(e){var t,n=e.ownerDocument,a=e.nodeName,r=Ve[a];return r?r:(t=n.body.appendChild(n.createElement(a)),r=Le.css(t,"display"),t.parentNode.removeChild(t),"none"===r&&(r="block"),Ve[a]=r,r)}function Y(e,t){for(var n,a,r=[],s=0,i=e.length;s-1)r&&r.push(s);else if(u=Le.contains(s.ownerDocument,s),i=v(_.appendChild(s),"script"),u&&k(i),n)for(l=0;s=i[l++];)Qe.test(s.type||"")&&n.push(s);return _}function T(){return!0}function w(){return!1}function b(){try{return ie.activeElement}catch(e){}}function S(e,t,n,a,r,s){var i,o;if("object"==typeof t){"string"!=typeof n&&(a=a||n,n=void 0);for(o in t)S(e,o,n,a,t[o],s);return e}if(null==a&&null==r?(r=n,a=n=void 0):null==r&&("string"==typeof n?(r=a,a=void 0):(r=a,a=n,n=void 0)),r===!1)r=w;else if(!r)return e;return 1===s&&(i=r,r=function(e){return Le().off(e),i.apply(this,arguments)},r.guid=i.guid||(i.guid=Le.guid++)),e.each(function(){Le.event.add(this,t,r,a,n)})}function x(e,t){return d(e,"table")&&d(11!==t.nodeType?t:t.firstChild,"tr")?Le(">tbody",e)[0]||e:e}function j(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function H(e){var t=dt.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function O(e,t){var n,a,r,s,i,o,d,u;if(1===t.nodeType){if(Ne.hasData(e)&&(s=Ne.access(e),i=Ne.set(t,s),u=s.events)){delete i.handle,i.events={};for(r in u)for(n=0,a=u[r].length;n1&&"string"==typeof f&&!Me.checkClone&&ot.test(f))return e.each(function(r){var s=e.eq(r);h&&(t[0]=f.call(this,r,s.html())),A(s,t,n,a)});if(c&&(r=D(t,e[0].ownerDocument,!1,e,a),s=r.firstChild,1===r.childNodes.length&&(r=s),s||a)){for(o=Le.map(v(r,"script"),j),d=o.length;_=0&&nk.cacheLength&&delete e[t.shift()],e[n+" "]=a}var t=[];return e}function a(e){return e[N]=!0,e}function r(e){var t=P.createElement("fieldset");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function s(e,t){for(var n=e.split("|"),a=n.length;a--;)k.attrHandle[n[a]]=t}function i(e,t){var n=t&&e,a=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(a)return a;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function o(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function d(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function u(e){return function(t){return"form"in t?t.parentNode&&t.disabled===!1?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&De(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function l(e){return a(function(t){return t=+t,a(function(n,a){for(var r,s=e([],n.length,t),i=s.length;i--;)n[r=s[i]]&&(n[r]=!(a[r]=n[r]))})})}function _(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function c(){}function m(e){for(var t=0,n=e.length,a="";t1?function(t,n,a){for(var r=e.length;r--;)if(!e[r](t,n,a))return!1;return!0}:e[0]}function p(e,n,a){for(var r=0,s=n.length;r-1&&(a[u]=!(i[u]=_))}}else L=M(L===i?L.splice(f,L.length):L),s?s(null,i,L,d):Q.apply(i,L)})}function L(e){for(var t,n,a,r=e.length,s=k.relative[e[0].type],i=s||k.relative[" "],o=s?1:0,d=f(function(e){return e===t},i,!0),u=f(function(e){return ee(t,e)>-1},i,!0),l=[function(e,n,a){var r=!s&&(a||n!==x)||((t=n).nodeType?d(e,n,a):u(e,n,a));return t=null,r}];o1&&h(l),o>1&&m(e.slice(0,o-1).concat({value:" "===e[o-2].type?"*":""})).replace(oe,"$1"),n,o0,s=e.length>0,i=function(a,i,o,d,u){var l,_,c,m=0,f="0",h=a&&[],p=[],y=x,L=a||s&&k.find.TAG("*",u),g=z+=null==y?1:Math.random()||.1,Y=L.length;for(u&&(x=i===P||i||u);f!==Y&&null!=(l=L[f]);f++){if(s&&l){for(_=0,i||l.ownerDocument===P||(O(l),o=!E);c=e[_++];)if(c(l,i||P,o)){d.push(l);break}u&&(z=g)}r&&((l=!c&&l)&&m--,a&&h.push(l))}if(m+=f,r&&f!==m){for(_=0;c=n[_++];)c(h,p,i,o);if(a){if(m>0)for(;f--;)h[f]||p[f]||(p[f]=Z.call(d));p=M(p)}Q.apply(d,p),u&&!a&&p.length>0&&m+n.length>1&&t.uniqueSort(d)}return u&&(z=g,x=y),h};return r?a(i):i}var Y,v,k,D,T,w,b,S,x,j,H,O,P,A,E,F,C,W,$,N="sizzle"+1*new Date,I=e.document,z=0,R=0,J=n(),U=n(),q=n(),G=function(e,t){return e===t&&(H=!0),0},B={}.hasOwnProperty,V=[],Z=V.pop,K=V.push,Q=V.push,X=V.slice,ee=function(e,t){for(var n=0,a=e.length;n+~]|"+ne+")"+ne+"*"),le=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),_e=new RegExp(se),ce=new RegExp("^"+ae+"$"),me={ID:new RegExp("^#("+ae+")"),CLASS:new RegExp("^\\.("+ae+")"),TAG:new RegExp("^("+ae+"|[*])"),ATTR:new RegExp("^"+re),PSEUDO:new RegExp("^"+se),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},fe=/^(?:input|select|textarea|button)$/i,he=/^h\d$/i,pe=/^[^{]+\{\s*\[native \w/,Me=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ye=/[+~]/,Le=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),ge=function(e,t,n){var a="0x"+t-65536;return a!==a||n?t:a<0?String.fromCharCode(a+65536):String.fromCharCode(a>>10|55296,1023&a|56320)},Ye=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ve=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},ke=function(){O()},De=f(function(e){return e.disabled===!0&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{Q.apply(V=X.call(I.childNodes),I.childNodes),V[I.childNodes.length].nodeType}catch(Te){Q={apply:V.length?function(e,t){K.apply(e,X.call(t))}:function(e,t){for(var n=e.length,a=0;e[n++]=t[a++];);e.length=n-1}}}v=t.support={},T=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},O=t.setDocument=function(e){var t,n,a=e?e.ownerDocument||e:I;return a!==P&&9===a.nodeType&&a.documentElement?(P=a,A=P.documentElement,E=!T(P),I!==P&&(n=P.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",ke,!1):n.attachEvent&&n.attachEvent("onunload",ke)),v.attributes=r(function(e){return e.className="i",!e.getAttribute("className")}),v.getElementsByTagName=r(function(e){return e.appendChild(P.createComment("")),!e.getElementsByTagName("*").length}),v.getElementsByClassName=pe.test(P.getElementsByClassName),v.getById=r(function(e){return A.appendChild(e).id=N,!P.getElementsByName||!P.getElementsByName(N).length}),v.getById?(k.filter.ID=function(e){var t=e.replace(Le,ge);return function(e){return e.getAttribute("id")===t}},k.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(k.filter.ID=function(e){var t=e.replace(Le,ge);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},k.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,a,r,s=t.getElementById(e);if(s){if(n=s.getAttributeNode("id"),n&&n.value===e)return[s];for(r=t.getElementsByName(e),a=0;s=r[a++];)if(n=s.getAttributeNode("id"),n&&n.value===e)return[s]}return[]}}),k.find.TAG=v.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):v.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,a=[],r=0,s=t.getElementsByTagName(e);if("*"===e){for(;n=s[r++];)1===n.nodeType&&a.push(n);return a}return s},k.find.CLASS=v.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},C=[],F=[],(v.qsa=pe.test(P.querySelectorAll))&&(r(function(e){A.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+N+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+N+"+*").length||F.push(".#.+[+~]")}),r(function(e){e.innerHTML="";var t=P.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&F.push(":enabled",":disabled"),A.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(v.matchesSelector=pe.test(W=A.matches||A.webkitMatchesSelector||A.mozMatchesSelector||A.oMatchesSelector||A.msMatchesSelector))&&r(function(e){v.disconnectedMatch=W.call(e,"*"),W.call(e,"[s!='']:x"),C.push("!=",se)}),F=F.length&&new RegExp(F.join("|")),C=C.length&&new RegExp(C.join("|")),t=pe.test(A.compareDocumentPosition),$=t||pe.test(A.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,a=t&&t.parentNode;return e===a||!(!a||1!==a.nodeType||!(n.contains?n.contains(a):e.compareDocumentPosition&&16&e.compareDocumentPosition(a)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},G=t?function(e,t){if(e===t)return H=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!v.sortDetached&&t.compareDocumentPosition(e)===n?e===P||e.ownerDocument===I&&$(I,e)?-1:t===P||t.ownerDocument===I&&$(I,t)?1:j?ee(j,e)-ee(j,t):0:4&n?-1:1)}:function(e,t){if(e===t)return H=!0,0;var n,a=0,r=e.parentNode,s=t.parentNode,o=[e],d=[t];if(!r||!s)return e===P?-1:t===P?1:r?-1:s?1:j?ee(j,e)-ee(j,t):0;if(r===s)return i(e,t);for(n=e;n=n.parentNode;)o.unshift(n);for(n=t;n=n.parentNode;)d.unshift(n);for(;o[a]===d[a];)a++;return a?i(o[a],d[a]):o[a]===I?-1:d[a]===I?1:0},P):P},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==P&&O(e),n=n.replace(le,"='$1']"),v.matchesSelector&&E&&!q[n+" "]&&(!C||!C.test(n))&&(!F||!F.test(n)))try{var a=W.call(e,n);if(a||v.disconnectedMatch||e.document&&11!==e.document.nodeType)return a}catch(r){}return t(n,P,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==P&&O(e),$(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==P&&O(e);var n=k.attrHandle[t.toLowerCase()],a=n&&B.call(k.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==a?a:v.attributes||!E?e.getAttribute(t):(a=e.getAttributeNode(t))&&a.specified?a.value:null},t.escape=function(e){return(e+"").replace(Ye,ve)},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],a=0,r=0;if(H=!v.detectDuplicates,j=!v.sortStable&&e.slice(0),e.sort(G),H){for(;t=e[r++];)t===e[r]&&(a=n.push(r));for(;a--;)e.splice(n[a],1)}return j=null,e},D=t.getText=function(e){var t,n="",a=0,r=e.nodeType;if(r){if(1===r||9===r||11===r){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=D(e)}else if(3===r||4===r)return e.nodeValue}else for(;t=e[a++];)n+=D(t);return n},k=t.selectors={cacheLength:50,createPseudo:a,match:me,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(Le,ge),e[3]=(e[3]||e[4]||e[5]||"").replace(Le,ge),"~="===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]||t.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]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return me.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&_e.test(n)&&(t=w(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(Le,ge).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=J[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&J(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,a){return function(r){var s=t.attr(r,e);return null==s?"!="===n:!n||(s+="","="===n?s===a:"!="===n?s!==a:"^="===n?a&&0===s.indexOf(a):"*="===n?a&&s.indexOf(a)>-1:"$="===n?a&&s.slice(-a.length)===a:"~="===n?(" "+s.replace(ie," ")+" ").indexOf(a)>-1:"|="===n&&(s===a||s.slice(0,a.length+1)===a+"-"))}},CHILD:function(e,t,n,a,r){var s="nth"!==e.slice(0,3),i="last"!==e.slice(-4),o="of-type"===t;return 1===a&&0===r?function(e){return!!e.parentNode}:function(t,n,d){var u,l,_,c,m,f,h=s!==i?"nextSibling":"previousSibling",p=t.parentNode,M=o&&t.nodeName.toLowerCase(),y=!d&&!o,L=!1;if(p){if(s){for(;h;){for(c=t;c=c[h];)if(o?c.nodeName.toLowerCase()===M:1===c.nodeType)return!1;f=h="only"===e&&!f&&"nextSibling"}return!0}if(f=[i?p.firstChild:p.lastChild],i&&y){for(c=p,_=c[N]||(c[N]={}),l=_[c.uniqueID]||(_[c.uniqueID]={}),u=l[e]||[],m=u[0]===z&&u[1],L=m&&u[2],c=m&&p.childNodes[m];c=++m&&c&&c[h]||(L=m=0)||f.pop();)if(1===c.nodeType&&++L&&c===t){l[e]=[z,m,L];break}}else if(y&&(c=t,_=c[N]||(c[N]={}),l=_[c.uniqueID]||(_[c.uniqueID]={}),u=l[e]||[],m=u[0]===z&&u[1],L=m),L===!1)for(;(c=++m&&c&&c[h]||(L=m=0)||f.pop())&&((o?c.nodeName.toLowerCase()!==M:1!==c.nodeType)||!++L||(y&&(_=c[N]||(c[N]={}),l=_[c.uniqueID]||(_[c.uniqueID]={}),l[e]=[z,L]),c!==t)););return L-=r,L===a||L%a===0&&L/a>=0}}},PSEUDO:function(e,n){var r,s=k.pseudos[e]||k.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return s[N]?s(n):s.length>1?(r=[e,e,"",n],k.setFilters.hasOwnProperty(e.toLowerCase())?a(function(e,t){for(var a,r=s(e,n),i=r.length;i--;)a=ee(e,r[i]),e[a]=!(t[a]=r[i])}):function(e){return s(e,0,r)}):s}},pseudos:{not:a(function(e){var t=[],n=[],r=b(e.replace(oe,"$1"));return r[N]?a(function(e,t,n,a){for(var s,i=r(e,null,a,[]),o=e.length;o--;)(s=i[o])&&(e[o]=!(t[o]=s))}):function(e,a,s){return t[0]=e,r(t,null,s,n),t[0]=null,!n.pop()}}),has:a(function(e){return function(n){return t(e,n).length>0}}),contains:a(function(e){return e=e.replace(Le,ge),function(t){return(t.textContent||t.innerText||D(t)).indexOf(e)>-1}}),lang:a(function(e){return ce.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(Le,ge).toLowerCase(),function(t){var n;do if(n=E?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===A},focus:function(e){return e===P.activeElement&&(!P.hasFocus||P.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:u(!1),disabled:u(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!k.pseudos.empty(e)},header:function(e){return he.test(e.nodeName)},input:function(e){return fe.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(a);return e}),gt:l(function(e,t,n){for(var a=n<0?n+t:n;++a2&&"ID"===(i=s[0]).type&&9===t.nodeType&&E&&k.relative[s[1].type]){if(t=(k.find.ID(i.matches[0].replace(Le,ge),t)||[])[0],!t)return n;u&&(t=t.parentNode),e=e.slice(s.shift().value.length)}for(r=me.needsContext.test(e)?0:s.length;r--&&(i=s[r],!k.relative[o=i.type]);)if((d=k.find[o])&&(a=d(i.matches[0].replace(Le,ge),ye.test(s[0].type)&&_(t.parentNode)||t))){if(s.splice(r,1),e=a.length&&m(s),!e)return Q.apply(n,a),n;break}}return(u||b(e,l))(a,t,!E,n,!t||ye.test(e)&&_(t.parentNode)||t),n},v.sortStable=N.split("").sort(G).join("")===N,v.detectDuplicates=!!H,O(),v.sortDetached=r(function(e){return 1&e.compareDocumentPosition(P.createElement("fieldset"))}),r(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||s("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),v.attributes&&r(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||s("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),r(function(e){return null==e.getAttribute("disabled")})||s(te,function(e,t,n){var a;if(!n)return e[t]===!0?t.toLowerCase():(a=e.getAttributeNode(t))&&a.specified?a.value:null}),t}(n);Le.find=De,Le.expr=De.selectors,Le.expr[":"]=Le.expr.pseudos,Le.uniqueSort=Le.unique=De.uniqueSort,Le.text=De.getText,Le.isXMLDoc=De.isXML,Le.contains=De.contains,Le.escapeSelector=De.escape;var Te=function(e,t,n){for(var a=[],r=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(r&&Le(e).is(n))break;a.push(e)}return a},we=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},be=Le.expr.match.needsContext,Se=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,xe=/^.[^:#\[\.,]*$/;Le.filter=function(e,t,n){var a=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===a.nodeType?Le.find.matchesSelector(a,e)?[a]:[]:Le.find.matches(e,Le.grep(t,function(e){return 1===e.nodeType}))},Le.fn.extend({find:function(e){var t,n,a=this.length,r=this;if("string"!=typeof e)return this.pushStack(Le(e).filter(function(){for(t=0;t1?Le.uniqueSort(n):n},filter:function(e){return this.pushStack(u(this,e||[],!1))},not:function(e){return this.pushStack(u(this,e||[],!0))},is:function(e){return!!u(this,"string"==typeof e&&be.test(e)?Le(e):e||[],!1).length}});var je,He=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,Oe=Le.fn.init=function(e,t,n){var a,r;if(!e)return this;if(n=n||je,"string"==typeof e){if(a="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:He.exec(e),!a||!a[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(a[1]){if(t=t instanceof Le?t[0]:t,Le.merge(this,Le.parseHTML(a[1],t&&t.nodeType?t.ownerDocument||t:ie,!0)),Se.test(a[1])&&Le.isPlainObject(t))for(a in t)Le.isFunction(this[a])?this[a](t[a]):this.attr(a,t[a]);return this}return r=ie.getElementById(a[2]),r&&(this[0]=r,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):Le.isFunction(e)?void 0!==n.ready?n.ready(e):e(Le):Le.makeArray(e,this)};Oe.prototype=Le.fn,je=Le(ie);var Pe=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};Le.fn.extend({has:function(e){var t=Le(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&Le.find.matchesSelector(n,e))){s.push(n);break}return this.pushStack(s.length>1?Le.uniqueSort(s):s)},index:function(e){return e?"string"==typeof e?_e.call(Le(e),this[0]):_e.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(Le.uniqueSort(Le.merge(this.get(),Le(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),Le.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return Te(e,"parentNode")},parentsUntil:function(e,t,n){return Te(e,"parentNode",n)},next:function(e){return l(e,"nextSibling")},prev:function(e){return l(e,"previousSibling")},nextAll:function(e){return Te(e,"nextSibling")},prevAll:function(e){return Te(e,"previousSibling")},nextUntil:function(e,t,n){return Te(e,"nextSibling",n)},prevUntil:function(e,t,n){return Te(e,"previousSibling",n)},siblings:function(e){return we((e.parentNode||{}).firstChild,e)},children:function(e){return we(e.firstChild)},contents:function(e){return d(e,"iframe")?e.contentDocument:(d(e,"template")&&(e=e.content||e),Le.merge([],e.childNodes))}},function(e,t){Le.fn[e]=function(n,a){var r=Le.map(this,t,n);return"Until"!==e.slice(-5)&&(a=n),a&&"string"==typeof a&&(r=Le.filter(a,r)),this.length>1&&(Ae[e]||Le.uniqueSort(r),Pe.test(e)&&r.reverse()),this.pushStack(r)}});var Ee=/[^\x20\t\r\n\f]+/g;Le.Callbacks=function(e){e="string"==typeof e?_(e):Le.extend({},e);var t,n,a,r,s=[],i=[],o=-1,d=function(){for(r=r||e.once,a=t=!0;i.length;o=-1)for(n=i.shift();++o-1;)s.splice(n,1),n<=o&&o--}),this},has:function(e){return e?Le.inArray(e,s)>-1:s.length>0},empty:function(){return s&&(s=[]),this},disable:function(){return r=i=[],s=n="",this},disabled:function(){return!s},lock:function(){return r=i=[],n||t||(s=n=""),this},locked:function(){return!!r},fireWith:function(e,n){return r||(n=n||[],n=[e,n.slice?n.slice():n],i.push(n),t||d()),this},fire:function(){return u.fireWith(this,arguments),this},fired:function(){return!!a}};return u},Le.extend({Deferred:function(e){var t=[["notify","progress",Le.Callbacks("memory"),Le.Callbacks("memory"),2],["resolve","done",Le.Callbacks("once memory"),Le.Callbacks("once memory"),0,"resolved"],["reject","fail",Le.Callbacks("once memory"),Le.Callbacks("once memory"),1,"rejected"]],a="pending",r={state:function(){return a},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return r.then(null,e)},pipe:function(){var e=arguments;return Le.Deferred(function(n){Le.each(t,function(t,a){var r=Le.isFunction(e[a[4]])&&e[a[4]];s[a[1]](function(){var e=r&&r.apply(this,arguments);e&&Le.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[a[0]+"With"](this,r?[e]:arguments)})}),e=null}).promise()},then:function(e,a,r){function s(e,t,a,r){return function(){var o=this,d=arguments,u=function(){var n,u;if(!(e=i&&(a!==m&&(o=void 0,d=[n]),t.rejectWith(o,d))}};e?l():(Le.Deferred.getStackHook&&(l.stackTrace=Le.Deferred.getStackHook()),n.setTimeout(l))}}var i=0;return Le.Deferred(function(n){t[0][3].add(s(0,n,Le.isFunction(r)?r:c,n.notifyWith)),t[1][3].add(s(0,n,Le.isFunction(e)?e:c)),t[2][3].add(s(0,n,Le.isFunction(a)?a:m))}).promise()},promise:function(e){return null!=e?Le.extend(e,r):r}},s={};return Le.each(t,function(e,n){var i=n[2],o=n[5];r[n[1]]=i.add,o&&i.add(function(){a=o},t[3-e][2].disable,t[0][2].lock),i.add(n[3].fire),s[n[0]]=function(){return s[n[0]+"With"](this===s?void 0:this,arguments),this},s[n[0]+"With"]=i.fireWith}),r.promise(s),e&&e.call(s,s),s},when:function(e){var t=arguments.length,n=t,a=Array(n),r=de.call(arguments),s=Le.Deferred(),i=function(e){return function(n){a[e]=this,r[e]=arguments.length>1?de.call(arguments):n,--t||s.resolveWith(a,r)}};if(t<=1&&(f(e,s.done(i(n)).resolve,s.reject,!t),"pending"===s.state()||Le.isFunction(r[n]&&r[n].then)))return s.then();for(;n--;)f(r[n],i(n),s.reject);return s.promise()}});var Fe=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;Le.Deferred.exceptionHook=function(e,t){n.console&&n.console.warn&&e&&Fe.test(e.name)&&n.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},Le.readyException=function(e){n.setTimeout(function(){throw e})};var Ce=Le.Deferred();Le.fn.ready=function(e){return Ce.then(e)["catch"](function(e){Le.readyException(e)}),this},Le.extend({isReady:!1,readyWait:1,ready:function(e){(e===!0?--Le.readyWait:Le.isReady)||(Le.isReady=!0,e!==!0&&--Le.readyWait>0||Ce.resolveWith(ie,[Le]))}}),Le.ready.then=Ce.then,"complete"===ie.readyState||"loading"!==ie.readyState&&!ie.documentElement.doScroll?n.setTimeout(Le.ready):(ie.addEventListener("DOMContentLoaded",h),n.addEventListener("load",h));var We=function(e,t,n,a,r,s,i){var o=0,d=e.length,u=null==n;if("object"===Le.type(n)){r=!0;for(o in n)We(e,t,o,n[o],!0,s,i)}else if(void 0!==a&&(r=!0,Le.isFunction(a)||(i=!0),u&&(i?(t.call(e,a),t=null):(u=t,t=function(e,t,n){return u.call(Le(e),n)})),t))for(;o1,null,!0)},removeData:function(e){return this.each(function(){Ie.remove(this,e)})}}),Le.extend({queue:function(e,t,n){var a;if(e)return t=(t||"fx")+"queue",a=Ne.get(e,t),n&&(!a||Array.isArray(n)?a=Ne.access(e,t,Le.makeArray(n)):a.push(n)),a||[]},dequeue:function(e,t){t=t||"fx";var n=Le.queue(e,t),a=n.length,r=n.shift(),s=Le._queueHooks(e,t),i=function(){Le.dequeue(e,t)};"inprogress"===r&&(r=n.shift(),a--),r&&("fx"===t&&n.unshift("inprogress"),delete s.stop,r.call(e,i,s)),!a&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Ne.get(e,n)||Ne.access(e,n,{empty:Le.Callbacks("once memory").add(function(){Ne.remove(e,[t+"queue",n])})})}}),Le.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,Qe=/^$|\/(?:java|ecma)script/i,Xe={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead, +Xe.th=Xe.td;var et=/<|&#?\w+;/;!function(){var e=ie.createDocumentFragment(),t=e.appendChild(ie.createElement("div")),n=ie.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),Me.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="",Me.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();var tt=ie.documentElement,nt=/^key/,at=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,rt=/^([^.]*)(?:\.(.+)|)/;Le.event={global:{},add:function(e,t,n,a,r){var s,i,o,d,u,l,_,c,m,f,h,p=Ne.get(e);if(p)for(n.handler&&(s=n,n=s.handler,r=s.selector),r&&Le.find.matchesSelector(tt,r),n.guid||(n.guid=Le.guid++),(d=p.events)||(d=p.events={}),(i=p.handle)||(i=p.handle=function(t){return"undefined"!=typeof Le&&Le.event.triggered!==t.type?Le.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(Ee)||[""],u=t.length;u--;)o=rt.exec(t[u])||[],m=h=o[1],f=(o[2]||"").split(".").sort(),m&&(_=Le.event.special[m]||{},m=(r?_.delegateType:_.bindType)||m,_=Le.event.special[m]||{},l=Le.extend({type:m,origType:h,data:a,handler:n,guid:n.guid,selector:r,needsContext:r&&Le.expr.match.needsContext.test(r),namespace:f.join(".")},s),(c=d[m])||(c=d[m]=[],c.delegateCount=0,_.setup&&_.setup.call(e,a,f,i)!==!1||e.addEventListener&&e.addEventListener(m,i)),_.add&&(_.add.call(e,l),l.handler.guid||(l.handler.guid=n.guid)),r?c.splice(c.delegateCount++,0,l):c.push(l),Le.event.global[m]=!0)},remove:function(e,t,n,a,r){var s,i,o,d,u,l,_,c,m,f,h,p=Ne.hasData(e)&&Ne.get(e);if(p&&(d=p.events)){for(t=(t||"").match(Ee)||[""],u=t.length;u--;)if(o=rt.exec(t[u])||[],m=h=o[1],f=(o[2]||"").split(".").sort(),m){for(_=Le.event.special[m]||{},m=(a?_.delegateType:_.bindType)||m,c=d[m]||[],o=o[2]&&new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=s=c.length;s--;)l=c[s],!r&&h!==l.origType||n&&n.guid!==l.guid||o&&!o.test(l.namespace)||a&&a!==l.selector&&("**"!==a||!l.selector)||(c.splice(s,1),l.selector&&c.delegateCount--,_.remove&&_.remove.call(e,l));i&&!c.length&&(_.teardown&&_.teardown.call(e,f,p.handle)!==!1||Le.removeEvent(e,m,p.handle),delete d[m])}else for(m in d)Le.event.remove(e,m+t[u],n,a,!0);Le.isEmptyObject(d)&&Ne.remove(e,"handle events")}},dispatch:function(e){var t,n,a,r,s,i,o=Le.event.fix(e),d=new Array(arguments.length),u=(Ne.get(this,"events")||{})[o.type]||[],l=Le.event.special[o.type]||{};for(d[0]=o,t=1;t=1))for(;u!==this;u=u.parentNode||this)if(1===u.nodeType&&("click"!==e.type||u.disabled!==!0)){for(s=[],i={},n=0;n-1:Le.find(r,this,null,[u]).length),i[r]&&s.push(a);s.length&&o.push({elem:u,handlers:s})}return u=this,d\x20\t\r\n\f]*)[^>]*)\/>/gi,it=/\s*$/g;Le.extend({htmlPrefilter:function(e){return e.replace(st,"<$1>")},clone:function(e,t,n){var a,r,s,i,o=e.cloneNode(!0),d=Le.contains(e.ownerDocument,e);if(!(Me.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||Le.isXMLDoc(e)))for(i=v(o),s=v(e),a=0,r=s.length;a0&&k(i,!d&&v(e,"script")),o},cleanData:function(e){for(var t,n,a,r=Le.event.special,s=0;void 0!==(n=e[s]);s++)if($e(n)){if(t=n[Ne.expando]){if(t.events)for(a in t.events)r[a]?Le.event.remove(n,a):Le.removeEvent(n,a,t.handle);n[Ne.expando]=void 0}n[Ie.expando]&&(n[Ie.expando]=void 0)}}}),Le.fn.extend({detach:function(e){return E(this,e,!0)},remove:function(e){return E(this,e)},text:function(e){return We(this,function(e){return void 0===e?Le.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 A(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=x(this,e);t.appendChild(e)}})},prepend:function(){return A(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=x(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return A(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return A(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&&(Le.cleanData(v(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return Le.clone(this,e,t)})},html:function(e){return We(this,function(e){var t=this[0]||{},n=0,a=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!Xe[(Ke.exec(e)||["",""])[1].toLowerCase()]){e=Le.htmlPrefilter(e);try{for(;n1)}}),Le.Tween=R,R.prototype={constructor:R,init:function(e,t,n,a,r,s){this.elem=e,this.prop=n,this.easing=r||Le.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=a,this.unit=s||(Le.cssNumber[n]?"":"px")},cur:function(){var e=R.propHooks[this.prop];return e&&e.get?e.get(this):R.propHooks._default.get(this)},run:function(e){var t,n=R.propHooks[this.prop];return this.options.duration?this.pos=t=Le.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):R.propHooks._default.set(this),this}},R.prototype.init.prototype=R.prototype,R.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=Le.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){Le.fx.step[e.prop]?Le.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[Le.cssProps[e.prop]]&&!Le.cssHooks[e.prop]?e.elem[e.prop]=e.now:Le.style(e.elem,e.prop,e.now+e.unit)}}},R.propHooks.scrollTop=R.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},Le.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},Le.fx=R.prototype.init,Le.fx.step={};var Lt,gt,Yt=/^(?:toggle|show|hide)$/,vt=/queueHooks$/;Le.Animation=Le.extend(Z,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return L(n.elem,e,Ue.exec(t),n),n}]},tweener:function(e,t){Le.isFunction(e)?(t=e,e=["*"]):e=e.match(Ee);for(var n,a=0,r=e.length;a1)},removeAttr:function(e){return this.each(function(){Le.removeAttr(this,e)})}}),Le.extend({attr:function(e,t,n){var a,r,s=e.nodeType;if(3!==s&&8!==s&&2!==s)return"undefined"==typeof e.getAttribute?Le.prop(e,t,n):(1===s&&Le.isXMLDoc(e)||(r=Le.attrHooks[t.toLowerCase()]||(Le.expr.match.bool.test(t)?kt:void 0)),void 0!==n?null===n?void Le.removeAttr(e,t):r&&"set"in r&&void 0!==(a=r.set(e,n,t))?a:(e.setAttribute(t,n+""),n):r&&"get"in r&&null!==(a=r.get(e,t))?a:(a=Le.find.attr(e,t),null==a?void 0:a))},attrHooks:{type:{set:function(e,t){if(!Me.radioValue&&"radio"===t&&d(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,a=0,r=t&&t.match(Ee);if(r&&1===e.nodeType)for(;n=r[a++];)e.removeAttribute(n)}}),kt={set:function(e,t,n){return t===!1?Le.removeAttr(e,n):e.setAttribute(n,n),n}},Le.each(Le.expr.match.bool.source.match(/\w+/g),function(e,t){var n=Dt[t]||Le.find.attr;Dt[t]=function(e,t,a){var r,s,i=t.toLowerCase();return a||(s=Dt[i],Dt[i]=r,r=null!=n(e,t,a)?i:null,Dt[i]=s),r}});var Tt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;Le.fn.extend({prop:function(e,t){return We(this,Le.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[Le.propFix[e]||e]})}}),Le.extend({prop:function(e,t,n){var a,r,s=e.nodeType;if(3!==s&&8!==s&&2!==s)return 1===s&&Le.isXMLDoc(e)||(t=Le.propFix[t]||t,r=Le.propHooks[t]),void 0!==n?r&&"set"in r&&void 0!==(a=r.set(e,n,t))?a:e[t]=n:r&&"get"in r&&null!==(a=r.get(e,t))?a:e[t]},propHooks:{tabIndex:{get:function(e){var t=Le.find.attr(e,"tabindex");return t?parseInt(t,10):Tt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),Me.optSelected||(Le.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)}}),Le.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){Le.propFix[this.toLowerCase()]=this}),Le.fn.extend({addClass:function(e){var t,n,a,r,s,i,o,d=0;if(Le.isFunction(e))return this.each(function(t){Le(this).addClass(e.call(this,t,Q(this)))});if("string"==typeof e&&e)for(t=e.match(Ee)||[];n=this[d++];)if(r=Q(n),a=1===n.nodeType&&" "+K(r)+" "){for(i=0;s=t[i++];)a.indexOf(" "+s+" ")<0&&(a+=s+" ");o=K(a),r!==o&&n.setAttribute("class",o)}return this},removeClass:function(e){var t,n,a,r,s,i,o,d=0;if(Le.isFunction(e))return this.each(function(t){Le(this).removeClass(e.call(this,t,Q(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(Ee)||[];n=this[d++];)if(r=Q(n),a=1===n.nodeType&&" "+K(r)+" "){for(i=0;s=t[i++];)for(;a.indexOf(" "+s+" ")>-1;)a=a.replace(" "+s+" "," ");o=K(a),r!==o&&n.setAttribute("class",o)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):Le.isFunction(e)?this.each(function(n){Le(this).toggleClass(e.call(this,n,Q(this),t),t)}):this.each(function(){var t,a,r,s;if("string"===n)for(a=0,r=Le(this),s=e.match(Ee)||[];t=s[a++];)r.hasClass(t)?r.removeClass(t):r.addClass(t);else void 0!==e&&"boolean"!==n||(t=Q(this),t&&Ne.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||e===!1?"":Ne.get(this,"__className__")||""))})},hasClass:function(e){var t,n,a=0;for(t=" "+e+" ";n=this[a++];)if(1===n.nodeType&&(" "+K(Q(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;Le.fn.extend({val:function(e){var t,n,a,r=this[0];{if(arguments.length)return a=Le.isFunction(e),this.each(function(n){var r;1===this.nodeType&&(r=a?e.call(this,n,Le(this).val()):e,null==r?r="":"number"==typeof r?r+="":Array.isArray(r)&&(r=Le.map(r,function(e){return null==e?"":e+""})),t=Le.valHooks[this.type]||Le.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,r,"value")||(this.value=r))});if(r)return t=Le.valHooks[r.type]||Le.valHooks[r.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(r,"value"))?n:(n=r.value,"string"==typeof n?n.replace(bt,""):null==n?"":n)}}}),Le.extend({valHooks:{option:{get:function(e){var t=Le.find.attr(e,"value");return null!=t?t:K(Le.text(e))}},select:{get:function(e){var t,n,a,r=e.options,s=e.selectedIndex,i="select-one"===e.type,o=i?null:[],u=i?s+1:r.length;for(a=s<0?u:i?s:0;a-1)&&(n=!0);return n||(e.selectedIndex=-1),s}}}}),Le.each(["radio","checkbox"],function(){Le.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=Le.inArray(Le(e).val(),t)>-1}},Me.checkOn||(Le.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var St=/^(?:focusinfocus|focusoutblur)$/;Le.extend(Le.event,{trigger:function(e,t,a,r){var s,i,o,d,u,l,_,c=[a||ie],m=fe.call(e,"type")?e.type:e,f=fe.call(e,"namespace")?e.namespace.split("."):[];if(i=o=a=a||ie,3!==a.nodeType&&8!==a.nodeType&&!St.test(m+Le.event.triggered)&&(m.indexOf(".")>-1&&(f=m.split("."),m=f.shift(),f.sort()),u=m.indexOf(":")<0&&"on"+m,e=e[Le.expando]?e:new Le.Event(m,"object"==typeof e&&e),e.isTrigger=r?2:3,e.namespace=f.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=a),t=null==t?[e]:Le.makeArray(t,[e]),_=Le.event.special[m]||{},r||!_.trigger||_.trigger.apply(a,t)!==!1)){if(!r&&!_.noBubble&&!Le.isWindow(a)){for(d=_.delegateType||m,St.test(d+m)||(i=i.parentNode);i;i=i.parentNode)c.push(i),o=i;o===(a.ownerDocument||ie)&&c.push(o.defaultView||o.parentWindow||n)}for(s=0;(i=c[s++])&&!e.isPropagationStopped();)e.type=s>1?d:_.bindType||m,l=(Ne.get(i,"events")||{})[e.type]&&Ne.get(i,"handle"),l&&l.apply(i,t),l=u&&i[u],l&&l.apply&&$e(i)&&(e.result=l.apply(i,t),e.result===!1&&e.preventDefault());return e.type=m,r||e.isDefaultPrevented()||_._default&&_._default.apply(c.pop(),t)!==!1||!$e(a)||u&&Le.isFunction(a[m])&&!Le.isWindow(a)&&(o=a[u],o&&(a[u]=null),Le.event.triggered=m,a[m](),Le.event.triggered=void 0,o&&(a[u]=o)),e.result}},simulate:function(e,t,n){var a=Le.extend(new Le.Event,n,{type:e,isSimulated:!0});Le.event.trigger(a,null,t)}}),Le.fn.extend({trigger:function(e,t){return this.each(function(){Le.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return Le.event.trigger(e,t,n,!0)}}),Le.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,t){Le.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),Le.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),Me.focusin="onfocusin"in n,Me.focusin||Le.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){Le.event.simulate(t,e.target,Le.event.fix(e))};Le.event.special[t]={setup:function(){var a=this.ownerDocument||this,r=Ne.access(a,t);r||a.addEventListener(e,n,!0),Ne.access(a,t,(r||0)+1)},teardown:function(){var a=this.ownerDocument||this,r=Ne.access(a,t)-1;r?Ne.access(a,t,r):(a.removeEventListener(e,n,!0),Ne.remove(a,t))}}});var xt=n.location,jt=Le.now(),Ht=/\?/;Le.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(a){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||Le.error("Invalid XML: "+e),t};var Ot=/\[\]$/,Pt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Et=/^(?:input|select|textarea|keygen)/i;Le.param=function(e,t){var n,a=[],r=function(e,t){var n=Le.isFunction(t)?t():t;a[a.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!Le.isPlainObject(e))Le.each(e,function(){r(this.name,this.value)});else for(n in e)X(n,e[n],t,r);return a.join("&")},Le.fn.extend({serialize:function(){return Le.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=Le.prop(this,"elements");return e?Le.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!Le(this).is(":disabled")&&Et.test(this.nodeName)&&!At.test(e)&&(this.checked||!Ze.test(e))}).map(function(e,t){var n=Le(this).val();return null==n?null:Array.isArray(n)?Le.map(n,function(e){return{name:t.name,value:e.replace(Pt,"\r\n")}}):{name:t.name,value:n.replace(Pt,"\r\n")}}).get()}});var Ft=/%20/g,Ct=/#.*$/,Wt=/([?&])_=[^&]*/,$t=/^(.*?):[ \t]*([^\r\n]*)$/gm,Nt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,It=/^(?:GET|HEAD)$/,zt=/^\/\//,Rt={},Jt={},Ut="*/".concat("*"),qt=ie.createElement("a");qt.href=xt.href,Le.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:xt.href,type:"GET",isLocal:Nt.test(xt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Ut,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":Le.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?ne(ne(e,Le.ajaxSettings),t):ne(Le.ajaxSettings,e)},ajaxPrefilter:ee(Rt),ajaxTransport:ee(Jt),ajax:function(e,t){function a(e,t,a,o){var u,c,m,g,Y,v=t;l||(l=!0,d&&n.clearTimeout(d),r=void 0,i=o||"",k.readyState=e>0?4:0,u=e>=200&&e<300||304===e,a&&(g=ae(f,k,a)),g=re(f,g,k,u),u?(f.ifModified&&(Y=k.getResponseHeader("Last-Modified"),Y&&(Le.lastModified[s]=Y),Y=k.getResponseHeader("etag"),Y&&(Le.etag[s]=Y)),204===e||"HEAD"===f.type?v="nocontent":304===e?v="notmodified":(v=g.state,c=g.data,m=g.error,u=!m)):(m=v,!e&&v||(v="error",e<0&&(e=0))),k.status=e,k.statusText=(t||v)+"",u?M.resolveWith(h,[c,v,k]):M.rejectWith(h,[k,v,m]),k.statusCode(L),L=void 0,_&&p.trigger(u?"ajaxSuccess":"ajaxError",[k,f,u?c:m]),y.fireWith(h,[k,v]),_&&(p.trigger("ajaxComplete",[k,f]),--Le.active||Le.event.trigger("ajaxStop")))}"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,s,i,o,d,u,l,_,c,m,f=Le.ajaxSetup({},t),h=f.context||f,p=f.context&&(h.nodeType||h.jquery)?Le(h):Le.event,M=Le.Deferred(),y=Le.Callbacks("once memory"),L=f.statusCode||{},g={},Y={},v="canceled",k={readyState:0,getResponseHeader:function(e){var t;if(l){if(!o)for(o={};t=$t.exec(i);)o[t[1].toLowerCase()]=t[2];t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return l?i:null},setRequestHeader:function(e,t){return null==l&&(e=Y[e.toLowerCase()]=Y[e.toLowerCase()]||e,g[e]=t),this},overrideMimeType:function(e){return null==l&&(f.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)k.always(e[k.status]);else for(t in e)L[t]=[L[t],e[t]];return this},abort:function(e){var t=e||v;return r&&r.abort(t),a(0,t),this}};if(M.promise(k),f.url=((e||f.url||xt.href)+"").replace(zt,xt.protocol+"//"),f.type=t.method||t.type||f.method||f.type,f.dataTypes=(f.dataType||"*").toLowerCase().match(Ee)||[""],null==f.crossDomain){u=ie.createElement("a");try{u.href=f.url,u.href=u.href,f.crossDomain=qt.protocol+"//"+qt.host!=u.protocol+"//"+u.host}catch(D){f.crossDomain=!0}}if(f.data&&f.processData&&"string"!=typeof f.data&&(f.data=Le.param(f.data,f.traditional)),te(Rt,f,t,k),l)return k;_=Le.event&&f.global,_&&0===Le.active++&&Le.event.trigger("ajaxStart"),f.type=f.type.toUpperCase(),f.hasContent=!It.test(f.type),s=f.url.replace(Ct,""),f.hasContent?f.data&&f.processData&&0===(f.contentType||"").indexOf("application/x-www-form-urlencoded")&&(f.data=f.data.replace(Ft,"+")):(m=f.url.slice(s.length),f.data&&(s+=(Ht.test(s)?"&":"?")+f.data,delete f.data),f.cache===!1&&(s=s.replace(Wt,"$1"),m=(Ht.test(s)?"&":"?")+"_="+jt++ +m),f.url=s+m),f.ifModified&&(Le.lastModified[s]&&k.setRequestHeader("If-Modified-Since",Le.lastModified[s]),Le.etag[s]&&k.setRequestHeader("If-None-Match",Le.etag[s])),(f.data&&f.hasContent&&f.contentType!==!1||t.contentType)&&k.setRequestHeader("Content-Type",f.contentType),k.setRequestHeader("Accept",f.dataTypes[0]&&f.accepts[f.dataTypes[0]]?f.accepts[f.dataTypes[0]]+("*"!==f.dataTypes[0]?", "+Ut+"; q=0.01":""):f.accepts["*"]);for(c in f.headers)k.setRequestHeader(c,f.headers[c]);if(f.beforeSend&&(f.beforeSend.call(h,k,f)===!1||l))return k.abort();if(v="abort",y.add(f.complete),k.done(f.success),k.fail(f.error),r=te(Jt,f,t,k)){if(k.readyState=1,_&&p.trigger("ajaxSend",[k,f]),l)return k;f.async&&f.timeout>0&&(d=n.setTimeout(function(){k.abort("timeout")},f.timeout));try{l=!1,r.send(g,a)}catch(D){if(l)throw D;a(-1,D)}}else a(-1,"No Transport");return k},getJSON:function(e,t,n){return Le.get(e,t,n,"json")},getScript:function(e,t){return Le.get(e,void 0,t,"script")}}),Le.each(["get","post"],function(e,t){Le[t]=function(e,n,a,r){return Le.isFunction(n)&&(r=r||a,a=n,n=void 0),Le.ajax(Le.extend({url:e,type:t,dataType:r,data:n,success:a},Le.isPlainObject(e)&&e))}}),Le._evalUrl=function(e){return Le.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},Le.fn.extend({wrapAll:function(e){var t;return this[0]&&(Le.isFunction(e)&&(e=e.call(this[0])),t=Le(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return Le.isFunction(e)?this.each(function(t){Le(this).wrapInner(e.call(this,t))}):this.each(function(){var t=Le(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=Le.isFunction(e);return this.each(function(n){Le(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){Le(this).replaceWith(this.childNodes)}),this}}),Le.expr.pseudos.hidden=function(e){return!Le.expr.pseudos.visible(e)},Le.expr.pseudos.visible=function(e){ +return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},Le.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var Gt={0:200,1223:204},Bt=Le.ajaxSettings.xhr();Me.cors=!!Bt&&"withCredentials"in Bt,Me.ajax=Bt=!!Bt,Le.ajaxTransport(function(e){var t,a;if(Me.cors||Bt&&!e.crossDomain)return{send:function(r,s){var i,o=e.xhr();if(o.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)o[i]=e.xhrFields[i];e.mimeType&&o.overrideMimeType&&o.overrideMimeType(e.mimeType),e.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(i in r)o.setRequestHeader(i,r[i]);t=function(e){return function(){t&&(t=a=o.onload=o.onerror=o.onabort=o.onreadystatechange=null,"abort"===e?o.abort():"error"===e?"number"!=typeof o.status?s(0,"error"):s(o.status,o.statusText):s(Gt[o.status]||o.status,o.statusText,"text"!==(o.responseType||"text")||"string"!=typeof o.responseText?{binary:o.response}:{text:o.responseText},o.getAllResponseHeaders()))}},o.onload=t(),a=o.onerror=t("error"),void 0!==o.onabort?o.onabort=a:o.onreadystatechange=function(){4===o.readyState&&n.setTimeout(function(){t&&a()})},t=t("abort");try{o.send(e.hasContent&&e.data||null)}catch(d){if(t)throw d}},abort:function(){t&&t()}}}),Le.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),Le.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 Le.globalEval(e),e}}}),Le.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),Le.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(a,r){t=Le("\n\t * \n\t * \n\t * \n\t * ```\n\t *\n\t * @param {DOMElement} element DOM element which is the root of angular application.\n\t * @param {Array=} modules an array of modules to load into the application.\n\t * Each item in the array should be the name of a predefined module or a (DI annotated)\n\t * function that will be invoked by the injector as a `config` block.\n\t * See: {@link angular.module modules}\n\t * @param {Object=} config an object for defining configuration options for the application. The\n\t * following keys are supported:\n\t *\n\t * * `strictDi` - disable automatic function annotation for the application. This is meant to\n\t * assist in finding bugs which break minified code. Defaults to `false`.\n\t *\n\t * @returns {auto.$injector} Returns the newly created injector for this app.\n\t */\n\tfunction bootstrap(element, modules, config) {\n\t if (!isObject(config)) config = {};\n\t var defaultConfig = {\n\t strictDi: false\n\t };\n\t config = extend(defaultConfig, config);\n\t var doBootstrap = function() {\n\t element = jqLite(element);\n\t\n\t if (element.injector()) {\n\t var tag = (element[0] === window.document) ? 'document' : startingTag(element);\n\t // Encode angle brackets to prevent input from being sanitized to empty string #8683.\n\t throw ngMinErr(\n\t 'btstrpd',\n\t \"App already bootstrapped with this element '{0}'\",\n\t tag.replace(//,'>'));\n\t }\n\t\n\t modules = modules || [];\n\t modules.unshift(['$provide', function($provide) {\n\t $provide.value('$rootElement', element);\n\t }]);\n\t\n\t if (config.debugInfoEnabled) {\n\t // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.\n\t modules.push(['$compileProvider', function($compileProvider) {\n\t $compileProvider.debugInfoEnabled(true);\n\t }]);\n\t }\n\t\n\t modules.unshift('ng');\n\t var injector = createInjector(modules, config.strictDi);\n\t injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',\n\t function bootstrapApply(scope, element, compile, injector) {\n\t scope.$apply(function() {\n\t element.data('$injector', injector);\n\t compile(element)(scope);\n\t });\n\t }]\n\t );\n\t return injector;\n\t };\n\t\n\t var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;\n\t var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;\n\t\n\t if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {\n\t config.debugInfoEnabled = true;\n\t window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');\n\t }\n\t\n\t if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {\n\t return doBootstrap();\n\t }\n\t\n\t window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');\n\t angular.resumeBootstrap = function(extraModules) {\n\t forEach(extraModules, function(module) {\n\t modules.push(module);\n\t });\n\t return doBootstrap();\n\t };\n\t\n\t if (isFunction(angular.resumeDeferredBootstrap)) {\n\t angular.resumeDeferredBootstrap();\n\t }\n\t}\n\t\n\t/**\n\t * @ngdoc function\n\t * @name angular.reloadWithDebugInfo\n\t * @module ng\n\t * @description\n\t * Use this function to reload the current application with debug information turned on.\n\t * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.\n\t *\n\t * See {@link ng.$compileProvider#debugInfoEnabled} for more.\n\t */\n\tfunction reloadWithDebugInfo() {\n\t window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;\n\t window.location.reload();\n\t}\n\t\n\t/**\n\t * @name angular.getTestability\n\t * @module ng\n\t * @description\n\t * Get the testability service for the instance of Angular on the given\n\t * element.\n\t * @param {DOMElement} element DOM element which is the root of angular application.\n\t */\n\tfunction getTestability(rootElement) {\n\t var injector = angular.element(rootElement).injector();\n\t if (!injector) {\n\t throw ngMinErr('test',\n\t 'no injector found for element argument to getTestability');\n\t }\n\t return injector.get('$$testability');\n\t}\n\t\n\tvar SNAKE_CASE_REGEXP = /[A-Z]/g;\n\tfunction snake_case(name, separator) {\n\t separator = separator || '_';\n\t return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {\n\t return (pos ? separator : '') + letter.toLowerCase();\n\t });\n\t}\n\t\n\tvar bindJQueryFired = false;\n\tfunction bindJQuery() {\n\t var originalCleanData;\n\t\n\t if (bindJQueryFired) {\n\t return;\n\t }\n\t\n\t // bind to jQuery if present;\n\t var jqName = jq();\n\t jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)\n\t !jqName ? undefined : // use jqLite\n\t window[jqName]; // use jQuery specified by `ngJq`\n\t\n\t // Use jQuery if it exists with proper functionality, otherwise default to us.\n\t // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.\n\t // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older\n\t // versions. It will not work for sure with jQuery <1.7, though.\n\t if (jQuery && jQuery.fn.on) {\n\t jqLite = jQuery;\n\t extend(jQuery.fn, {\n\t scope: JQLitePrototype.scope,\n\t isolateScope: JQLitePrototype.isolateScope,\n\t controller: JQLitePrototype.controller,\n\t injector: JQLitePrototype.injector,\n\t inheritedData: JQLitePrototype.inheritedData\n\t });\n\t\n\t // All nodes removed from the DOM via various jQuery APIs like .remove()\n\t // are passed through jQuery.cleanData. Monkey-patch this method to fire\n\t // the $destroy event on all removed nodes.\n\t originalCleanData = jQuery.cleanData;\n\t jQuery.cleanData = function(elems) {\n\t var events;\n\t for (var i = 0, elem; (elem = elems[i]) != null; i++) {\n\t events = jQuery._data(elem, \"events\");\n\t if (events && events.$destroy) {\n\t jQuery(elem).triggerHandler('$destroy');\n\t }\n\t }\n\t originalCleanData(elems);\n\t };\n\t } else {\n\t jqLite = JQLite;\n\t }\n\t\n\t angular.element = jqLite;\n\t\n\t // Prevent double-proxying.\n\t bindJQueryFired = true;\n\t}\n\t\n\t/**\n\t * throw error if the argument is falsy.\n\t */\n\tfunction assertArg(arg, name, reason) {\n\t if (!arg) {\n\t throw ngMinErr('areq', \"Argument '{0}' is {1}\", (name || '?'), (reason || \"required\"));\n\t }\n\t return arg;\n\t}\n\t\n\tfunction assertArgFn(arg, name, acceptArrayAnnotation) {\n\t if (acceptArrayAnnotation && isArray(arg)) {\n\t arg = arg[arg.length - 1];\n\t }\n\t\n\t assertArg(isFunction(arg), name, 'not a function, got ' +\n\t (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));\n\t return arg;\n\t}\n\t\n\t/**\n\t * throw error if the name given is hasOwnProperty\n\t * @param {String} name the name to test\n\t * @param {String} context the context in which the name is used, such as module or directive\n\t */\n\tfunction assertNotHasOwnProperty(name, context) {\n\t if (name === 'hasOwnProperty') {\n\t throw ngMinErr('badname', \"hasOwnProperty is not a valid {0} name\", context);\n\t }\n\t}\n\t\n\t/**\n\t * Return the value accessible from the object by path. Any undefined traversals are ignored\n\t * @param {Object} obj starting object\n\t * @param {String} path path to traverse\n\t * @param {boolean} [bindFnToScope=true]\n\t * @returns {Object} value as accessible by path\n\t */\n\t//TODO(misko): this function needs to be removed\n\tfunction getter(obj, path, bindFnToScope) {\n\t if (!path) return obj;\n\t var keys = path.split('.');\n\t var key;\n\t var lastInstance = obj;\n\t var len = keys.length;\n\t\n\t for (var i = 0; i < len; i++) {\n\t key = keys[i];\n\t if (obj) {\n\t obj = (lastInstance = obj)[key];\n\t }\n\t }\n\t if (!bindFnToScope && isFunction(obj)) {\n\t return bind(lastInstance, obj);\n\t }\n\t return obj;\n\t}\n\t\n\t/**\n\t * Return the DOM siblings between the first and last node in the given array.\n\t * @param {Array} array like object\n\t * @returns {Array} the inputted object or a jqLite collection containing the nodes\n\t */\n\tfunction getBlockNodes(nodes) {\n\t // TODO(perf): update `nodes` instead of creating a new object?\n\t var node = nodes[0];\n\t var endNode = nodes[nodes.length - 1];\n\t var blockNodes;\n\t\n\t for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {\n\t if (blockNodes || nodes[i] !== node) {\n\t if (!blockNodes) {\n\t blockNodes = jqLite(slice.call(nodes, 0, i));\n\t }\n\t blockNodes.push(node);\n\t }\n\t }\n\t\n\t return blockNodes || nodes;\n\t}\n\t\n\t\n\t/**\n\t * Creates a new object without a prototype. This object is useful for lookup without having to\n\t * guard against prototypically inherited properties via hasOwnProperty.\n\t *\n\t * Related micro-benchmarks:\n\t * - http://jsperf.com/object-create2\n\t * - http://jsperf.com/proto-map-lookup/2\n\t * - http://jsperf.com/for-in-vs-object-keys2\n\t *\n\t * @returns {Object}\n\t */\n\tfunction createMap() {\n\t return Object.create(null);\n\t}\n\t\n\tvar NODE_TYPE_ELEMENT = 1;\n\tvar NODE_TYPE_ATTRIBUTE = 2;\n\tvar NODE_TYPE_TEXT = 3;\n\tvar NODE_TYPE_COMMENT = 8;\n\tvar NODE_TYPE_DOCUMENT = 9;\n\tvar NODE_TYPE_DOCUMENT_FRAGMENT = 11;\n\t\n\t/**\n\t * @ngdoc type\n\t * @name angular.Module\n\t * @module ng\n\t * @description\n\t *\n\t * Interface for configuring angular {@link angular.module modules}.\n\t */\n\t\n\tfunction setupModuleLoader(window) {\n\t\n\t var $injectorMinErr = minErr('$injector');\n\t var ngMinErr = minErr('ng');\n\t\n\t function ensure(obj, name, factory) {\n\t return obj[name] || (obj[name] = factory());\n\t }\n\t\n\t var angular = ensure(window, 'angular', Object);\n\t\n\t // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap\n\t angular.$$minErr = angular.$$minErr || minErr;\n\t\n\t return ensure(angular, 'module', function() {\n\t /** @type {Object.} */\n\t var modules = {};\n\t\n\t /**\n\t * @ngdoc function\n\t * @name angular.module\n\t * @module ng\n\t * @description\n\t *\n\t * The `angular.module` is a global place for creating, registering and retrieving Angular\n\t * modules.\n\t * All modules (angular core or 3rd party) that should be available to an application must be\n\t * registered using this mechanism.\n\t *\n\t * Passing one argument retrieves an existing {@link angular.Module},\n\t * whereas passing more than one argument creates a new {@link angular.Module}\n\t *\n\t *\n\t * # Module\n\t *\n\t * A module is a collection of services, directives, controllers, filters, and configuration information.\n\t * `angular.module` is used to configure the {@link auto.$injector $injector}.\n\t *\n\t * ```js\n\t * // Create a new module\n\t * var myModule = angular.module('myModule', []);\n\t *\n\t * // register a new service\n\t * myModule.value('appName', 'MyCoolApp');\n\t *\n\t * // configure existing services inside initialization blocks.\n\t * myModule.config(['$locationProvider', function($locationProvider) {\n\t * // Configure existing providers\n\t * $locationProvider.hashPrefix('!');\n\t * }]);\n\t * ```\n\t *\n\t * Then you can create an injector and load your modules like this:\n\t *\n\t * ```js\n\t * var injector = angular.injector(['ng', 'myModule'])\n\t * ```\n\t *\n\t * However it's more likely that you'll just use\n\t * {@link ng.directive:ngApp ngApp} or\n\t * {@link angular.bootstrap} to simplify this process for you.\n\t *\n\t * @param {!string} name The name of the module to create or retrieve.\n\t * @param {!Array.=} requires If specified then new module is being created. If\n\t * unspecified then the module is being retrieved for further configuration.\n\t * @param {Function=} configFn Optional configuration function for the module. Same as\n\t * {@link angular.Module#config Module#config()}.\n\t * @returns {angular.Module} new module with the {@link angular.Module} api.\n\t */\n\t return function module(name, requires, configFn) {\n\t var assertNotHasOwnProperty = function(name, context) {\n\t if (name === 'hasOwnProperty') {\n\t throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);\n\t }\n\t };\n\t\n\t assertNotHasOwnProperty(name, 'module');\n\t if (requires && modules.hasOwnProperty(name)) {\n\t modules[name] = null;\n\t }\n\t return ensure(modules, name, function() {\n\t if (!requires) {\n\t throw $injectorMinErr('nomod', \"Module '{0}' is not available! You either misspelled \" +\n\t \"the module name or forgot to load it. If registering a module ensure that you \" +\n\t \"specify the dependencies as the second argument.\", name);\n\t }\n\t\n\t /** @type {!Array.>} */\n\t var invokeQueue = [];\n\t\n\t /** @type {!Array.} */\n\t var configBlocks = [];\n\t\n\t /** @type {!Array.} */\n\t var runBlocks = [];\n\t\n\t var config = invokeLater('$injector', 'invoke', 'push', configBlocks);\n\t\n\t /** @type {angular.Module} */\n\t var moduleInstance = {\n\t // Private state\n\t _invokeQueue: invokeQueue,\n\t _configBlocks: configBlocks,\n\t _runBlocks: runBlocks,\n\t\n\t /**\n\t * @ngdoc property\n\t * @name angular.Module#requires\n\t * @module ng\n\t *\n\t * @description\n\t * Holds the list of modules which the injector will load before the current module is\n\t * loaded.\n\t */\n\t requires: requires,\n\t\n\t /**\n\t * @ngdoc property\n\t * @name angular.Module#name\n\t * @module ng\n\t *\n\t * @description\n\t * Name of the module.\n\t */\n\t name: name,\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#provider\n\t * @module ng\n\t * @param {string} name service name\n\t * @param {Function} providerType Construction function for creating new instance of the\n\t * service.\n\t * @description\n\t * See {@link auto.$provide#provider $provide.provider()}.\n\t */\n\t provider: invokeLaterAndSetModuleName('$provide', 'provider'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#factory\n\t * @module ng\n\t * @param {string} name service name\n\t * @param {Function} providerFunction Function for creating new instance of the service.\n\t * @description\n\t * See {@link auto.$provide#factory $provide.factory()}.\n\t */\n\t factory: invokeLaterAndSetModuleName('$provide', 'factory'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#service\n\t * @module ng\n\t * @param {string} name service name\n\t * @param {Function} constructor A constructor function that will be instantiated.\n\t * @description\n\t * See {@link auto.$provide#service $provide.service()}.\n\t */\n\t service: invokeLaterAndSetModuleName('$provide', 'service'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#value\n\t * @module ng\n\t * @param {string} name service name\n\t * @param {*} object Service instance object.\n\t * @description\n\t * See {@link auto.$provide#value $provide.value()}.\n\t */\n\t value: invokeLater('$provide', 'value'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#constant\n\t * @module ng\n\t * @param {string} name constant name\n\t * @param {*} object Constant value.\n\t * @description\n\t * Because the constants are fixed, they get applied before other provide methods.\n\t * See {@link auto.$provide#constant $provide.constant()}.\n\t */\n\t constant: invokeLater('$provide', 'constant', 'unshift'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#decorator\n\t * @module ng\n\t * @param {string} name The name of the service to decorate.\n\t * @param {Function} decorFn This function will be invoked when the service needs to be\n\t * instantiated and should return the decorated service instance.\n\t * @description\n\t * See {@link auto.$provide#decorator $provide.decorator()}.\n\t */\n\t decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#animation\n\t * @module ng\n\t * @param {string} name animation name\n\t * @param {Function} animationFactory Factory function for creating new instance of an\n\t * animation.\n\t * @description\n\t *\n\t * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.\n\t *\n\t *\n\t * Defines an animation hook that can be later used with\n\t * {@link $animate $animate} service and directives that use this service.\n\t *\n\t * ```js\n\t * module.animation('.animation-name', function($inject1, $inject2) {\n\t * return {\n\t * eventName : function(element, done) {\n\t * //code to run the animation\n\t * //once complete, then run done()\n\t * return function cancellationFunction(element) {\n\t * //code to cancel the animation\n\t * }\n\t * }\n\t * }\n\t * })\n\t * ```\n\t *\n\t * See {@link ng.$animateProvider#register $animateProvider.register()} and\n\t * {@link ngAnimate ngAnimate module} for more information.\n\t */\n\t animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#filter\n\t * @module ng\n\t * @param {string} name Filter name - this must be a valid angular expression identifier\n\t * @param {Function} filterFactory Factory function for creating new instance of filter.\n\t * @description\n\t * See {@link ng.$filterProvider#register $filterProvider.register()}.\n\t *\n\t *
\n\t * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.\n\t * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace\n\t * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores\n\t * (`myapp_subsection_filterx`).\n\t *
\n\t */\n\t filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#controller\n\t * @module ng\n\t * @param {string|Object} name Controller name, or an object map of controllers where the\n\t * keys are the names and the values are the constructors.\n\t * @param {Function} constructor Controller constructor function.\n\t * @description\n\t * See {@link ng.$controllerProvider#register $controllerProvider.register()}.\n\t */\n\t controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#directive\n\t * @module ng\n\t * @param {string|Object} name Directive name, or an object map of directives where the\n\t * keys are the names and the values are the factories.\n\t * @param {Function} directiveFactory Factory function for creating new instance of\n\t * directives.\n\t * @description\n\t * See {@link ng.$compileProvider#directive $compileProvider.directive()}.\n\t */\n\t directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#component\n\t * @module ng\n\t * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)\n\t * @param {Object} options Component definition object (a simplified\n\t * {@link ng.$compile#directive-definition-object directive definition object})\n\t *\n\t * @description\n\t * See {@link ng.$compileProvider#component $compileProvider.component()}.\n\t */\n\t component: invokeLaterAndSetModuleName('$compileProvider', 'component'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#config\n\t * @module ng\n\t * @param {Function} configFn Execute this function on module load. Useful for service\n\t * configuration.\n\t * @description\n\t * Use this method to register work which needs to be performed on module loading.\n\t * For more about how to configure services, see\n\t * {@link providers#provider-recipe Provider Recipe}.\n\t */\n\t config: config,\n\t\n\t /**\n\t * @ngdoc method\n\t * @name angular.Module#run\n\t * @module ng\n\t * @param {Function} initializationFn Execute this function after injector creation.\n\t * Useful for application initialization.\n\t * @description\n\t * Use this method to register work which should be performed when the injector is done\n\t * loading all modules.\n\t */\n\t run: function(block) {\n\t runBlocks.push(block);\n\t return this;\n\t }\n\t };\n\t\n\t if (configFn) {\n\t config(configFn);\n\t }\n\t\n\t return moduleInstance;\n\t\n\t /**\n\t * @param {string} provider\n\t * @param {string} method\n\t * @param {String=} insertMethod\n\t * @returns {angular.Module}\n\t */\n\t function invokeLater(provider, method, insertMethod, queue) {\n\t if (!queue) queue = invokeQueue;\n\t return function() {\n\t queue[insertMethod || 'push']([provider, method, arguments]);\n\t return moduleInstance;\n\t };\n\t }\n\t\n\t /**\n\t * @param {string} provider\n\t * @param {string} method\n\t * @returns {angular.Module}\n\t */\n\t function invokeLaterAndSetModuleName(provider, method) {\n\t return function(recipeName, factoryFunction) {\n\t if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;\n\t invokeQueue.push([provider, method, arguments]);\n\t return moduleInstance;\n\t };\n\t }\n\t });\n\t };\n\t });\n\t\n\t}\n\t\n\t/* global shallowCopy: true */\n\t\n\t/**\n\t * Creates a shallow copy of an object, an array or a primitive.\n\t *\n\t * Assumes that there are no proto properties for objects.\n\t */\n\tfunction shallowCopy(src, dst) {\n\t if (isArray(src)) {\n\t dst = dst || [];\n\t\n\t for (var i = 0, ii = src.length; i < ii; i++) {\n\t dst[i] = src[i];\n\t }\n\t } else if (isObject(src)) {\n\t dst = dst || {};\n\t\n\t for (var key in src) {\n\t if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {\n\t dst[key] = src[key];\n\t }\n\t }\n\t }\n\t\n\t return dst || src;\n\t}\n\t\n\t/* global toDebugString: true */\n\t\n\tfunction serializeObject(obj) {\n\t var seen = [];\n\t\n\t return JSON.stringify(obj, function(key, val) {\n\t val = toJsonReplacer(key, val);\n\t if (isObject(val)) {\n\t\n\t if (seen.indexOf(val) >= 0) return '...';\n\t\n\t seen.push(val);\n\t }\n\t return val;\n\t });\n\t}\n\t\n\tfunction toDebugString(obj) {\n\t if (typeof obj === 'function') {\n\t return obj.toString().replace(/ \\{[\\s\\S]*$/, '');\n\t } else if (isUndefined(obj)) {\n\t return 'undefined';\n\t } else if (typeof obj !== 'string') {\n\t return serializeObject(obj);\n\t }\n\t return obj;\n\t}\n\t\n\t/* global angularModule: true,\n\t version: true,\n\t\n\t $CompileProvider,\n\t\n\t htmlAnchorDirective,\n\t inputDirective,\n\t inputDirective,\n\t formDirective,\n\t scriptDirective,\n\t selectDirective,\n\t styleDirective,\n\t optionDirective,\n\t ngBindDirective,\n\t ngBindHtmlDirective,\n\t ngBindTemplateDirective,\n\t ngClassDirective,\n\t ngClassEvenDirective,\n\t ngClassOddDirective,\n\t ngCloakDirective,\n\t ngControllerDirective,\n\t ngFormDirective,\n\t ngHideDirective,\n\t ngIfDirective,\n\t ngIncludeDirective,\n\t ngIncludeFillContentDirective,\n\t ngInitDirective,\n\t ngNonBindableDirective,\n\t ngPluralizeDirective,\n\t ngRepeatDirective,\n\t ngShowDirective,\n\t ngStyleDirective,\n\t ngSwitchDirective,\n\t ngSwitchWhenDirective,\n\t ngSwitchDefaultDirective,\n\t ngOptionsDirective,\n\t ngTranscludeDirective,\n\t ngModelDirective,\n\t ngListDirective,\n\t ngChangeDirective,\n\t patternDirective,\n\t patternDirective,\n\t requiredDirective,\n\t requiredDirective,\n\t minlengthDirective,\n\t minlengthDirective,\n\t maxlengthDirective,\n\t maxlengthDirective,\n\t ngValueDirective,\n\t ngModelOptionsDirective,\n\t ngAttributeAliasDirectives,\n\t ngEventDirectives,\n\t\n\t $AnchorScrollProvider,\n\t $AnimateProvider,\n\t $CoreAnimateCssProvider,\n\t $$CoreAnimateJsProvider,\n\t $$CoreAnimateQueueProvider,\n\t $$AnimateRunnerFactoryProvider,\n\t $$AnimateAsyncRunFactoryProvider,\n\t $BrowserProvider,\n\t $CacheFactoryProvider,\n\t $ControllerProvider,\n\t $DateProvider,\n\t $DocumentProvider,\n\t $ExceptionHandlerProvider,\n\t $FilterProvider,\n\t $$ForceReflowProvider,\n\t $InterpolateProvider,\n\t $IntervalProvider,\n\t $$HashMapProvider,\n\t $HttpProvider,\n\t $HttpParamSerializerProvider,\n\t $HttpParamSerializerJQLikeProvider,\n\t $HttpBackendProvider,\n\t $xhrFactoryProvider,\n\t $jsonpCallbacksProvider,\n\t $LocationProvider,\n\t $LogProvider,\n\t $ParseProvider,\n\t $RootScopeProvider,\n\t $QProvider,\n\t $$QProvider,\n\t $$SanitizeUriProvider,\n\t $SceProvider,\n\t $SceDelegateProvider,\n\t $SnifferProvider,\n\t $TemplateCacheProvider,\n\t $TemplateRequestProvider,\n\t $$TestabilityProvider,\n\t $TimeoutProvider,\n\t $$RAFProvider,\n\t $WindowProvider,\n\t $$jqLiteProvider,\n\t $$CookieReaderProvider\n\t*/\n\t\n\t\n\t/**\n\t * @ngdoc object\n\t * @name angular.version\n\t * @module ng\n\t * @description\n\t * An object that contains information about the current AngularJS version.\n\t *\n\t * This object has the following properties:\n\t *\n\t * - `full` – `{string}` – Full version string, such as \"0.9.18\".\n\t * - `major` – `{number}` – Major version number, such as \"0\".\n\t * - `minor` – `{number}` – Minor version number, such as \"9\".\n\t * - `dot` – `{number}` – Dot version number, such as \"18\".\n\t * - `codeName` – `{string}` – Code name of the release, such as \"jiggling-armfat\".\n\t */\n\tvar version = {\n\t full: '1.5.8', // all of these placeholder strings will be replaced by grunt's\n\t major: 1, // package task\n\t minor: 5,\n\t dot: 8,\n\t codeName: 'arbitrary-fallbacks'\n\t};\n\t\n\t\n\tfunction publishExternalAPI(angular) {\n\t extend(angular, {\n\t 'bootstrap': bootstrap,\n\t 'copy': copy,\n\t 'extend': extend,\n\t 'merge': merge,\n\t 'equals': equals,\n\t 'element': jqLite,\n\t 'forEach': forEach,\n\t 'injector': createInjector,\n\t 'noop': noop,\n\t 'bind': bind,\n\t 'toJson': toJson,\n\t 'fromJson': fromJson,\n\t 'identity': identity,\n\t 'isUndefined': isUndefined,\n\t 'isDefined': isDefined,\n\t 'isString': isString,\n\t 'isFunction': isFunction,\n\t 'isObject': isObject,\n\t 'isNumber': isNumber,\n\t 'isElement': isElement,\n\t 'isArray': isArray,\n\t 'version': version,\n\t 'isDate': isDate,\n\t 'lowercase': lowercase,\n\t 'uppercase': uppercase,\n\t 'callbacks': {$$counter: 0},\n\t 'getTestability': getTestability,\n\t '$$minErr': minErr,\n\t '$$csp': csp,\n\t 'reloadWithDebugInfo': reloadWithDebugInfo\n\t });\n\t\n\t angularModule = setupModuleLoader(window);\n\t\n\t angularModule('ng', ['ngLocale'], ['$provide',\n\t function ngModule($provide) {\n\t // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.\n\t $provide.provider({\n\t $$sanitizeUri: $$SanitizeUriProvider\n\t });\n\t $provide.provider('$compile', $CompileProvider).\n\t directive({\n\t a: htmlAnchorDirective,\n\t input: inputDirective,\n\t textarea: inputDirective,\n\t form: formDirective,\n\t script: scriptDirective,\n\t select: selectDirective,\n\t style: styleDirective,\n\t option: optionDirective,\n\t ngBind: ngBindDirective,\n\t ngBindHtml: ngBindHtmlDirective,\n\t ngBindTemplate: ngBindTemplateDirective,\n\t ngClass: ngClassDirective,\n\t ngClassEven: ngClassEvenDirective,\n\t ngClassOdd: ngClassOddDirective,\n\t ngCloak: ngCloakDirective,\n\t ngController: ngControllerDirective,\n\t ngForm: ngFormDirective,\n\t ngHide: ngHideDirective,\n\t ngIf: ngIfDirective,\n\t ngInclude: ngIncludeDirective,\n\t ngInit: ngInitDirective,\n\t ngNonBindable: ngNonBindableDirective,\n\t ngPluralize: ngPluralizeDirective,\n\t ngRepeat: ngRepeatDirective,\n\t ngShow: ngShowDirective,\n\t ngStyle: ngStyleDirective,\n\t ngSwitch: ngSwitchDirective,\n\t ngSwitchWhen: ngSwitchWhenDirective,\n\t ngSwitchDefault: ngSwitchDefaultDirective,\n\t ngOptions: ngOptionsDirective,\n\t ngTransclude: ngTranscludeDirective,\n\t ngModel: ngModelDirective,\n\t ngList: ngListDirective,\n\t ngChange: ngChangeDirective,\n\t pattern: patternDirective,\n\t ngPattern: patternDirective,\n\t required: requiredDirective,\n\t ngRequired: requiredDirective,\n\t minlength: minlengthDirective,\n\t ngMinlength: minlengthDirective,\n\t maxlength: maxlengthDirective,\n\t ngMaxlength: maxlengthDirective,\n\t ngValue: ngValueDirective,\n\t ngModelOptions: ngModelOptionsDirective\n\t }).\n\t directive({\n\t ngInclude: ngIncludeFillContentDirective\n\t }).\n\t directive(ngAttributeAliasDirectives).\n\t directive(ngEventDirectives);\n\t $provide.provider({\n\t $anchorScroll: $AnchorScrollProvider,\n\t $animate: $AnimateProvider,\n\t $animateCss: $CoreAnimateCssProvider,\n\t $$animateJs: $$CoreAnimateJsProvider,\n\t $$animateQueue: $$CoreAnimateQueueProvider,\n\t $$AnimateRunner: $$AnimateRunnerFactoryProvider,\n\t $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,\n\t $browser: $BrowserProvider,\n\t $cacheFactory: $CacheFactoryProvider,\n\t $controller: $ControllerProvider,\n\t $document: $DocumentProvider,\n\t $exceptionHandler: $ExceptionHandlerProvider,\n\t $filter: $FilterProvider,\n\t $$forceReflow: $$ForceReflowProvider,\n\t $interpolate: $InterpolateProvider,\n\t $interval: $IntervalProvider,\n\t $http: $HttpProvider,\n\t $httpParamSerializer: $HttpParamSerializerProvider,\n\t $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,\n\t $httpBackend: $HttpBackendProvider,\n\t $xhrFactory: $xhrFactoryProvider,\n\t $jsonpCallbacks: $jsonpCallbacksProvider,\n\t $location: $LocationProvider,\n\t $log: $LogProvider,\n\t $parse: $ParseProvider,\n\t $rootScope: $RootScopeProvider,\n\t $q: $QProvider,\n\t $$q: $$QProvider,\n\t $sce: $SceProvider,\n\t $sceDelegate: $SceDelegateProvider,\n\t $sniffer: $SnifferProvider,\n\t $templateCache: $TemplateCacheProvider,\n\t $templateRequest: $TemplateRequestProvider,\n\t $$testability: $$TestabilityProvider,\n\t $timeout: $TimeoutProvider,\n\t $window: $WindowProvider,\n\t $$rAF: $$RAFProvider,\n\t $$jqLite: $$jqLiteProvider,\n\t $$HashMap: $$HashMapProvider,\n\t $$cookieReader: $$CookieReaderProvider\n\t });\n\t }\n\t ]);\n\t}\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Any commits to this file should be reviewed with security in mind. *\n\t * Changes to this file can potentially create security vulnerabilities. *\n\t * An approval from 2 Core members with history of modifying *\n\t * this file is required. *\n\t * *\n\t * Does the change somehow allow for arbitrary javascript to be executed? *\n\t * Or allows for someone to change the prototype of built-in objects? *\n\t * Or gives undesired access to variables likes document or window? *\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\t/* global JQLitePrototype: true,\n\t addEventListenerFn: true,\n\t removeEventListenerFn: true,\n\t BOOLEAN_ATTR: true,\n\t ALIASED_ATTR: true,\n\t*/\n\t\n\t//////////////////////////////////\n\t//JQLite\n\t//////////////////////////////////\n\t\n\t/**\n\t * @ngdoc function\n\t * @name angular.element\n\t * @module ng\n\t * @kind function\n\t *\n\t * @description\n\t * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.\n\t *\n\t * If jQuery is available, `angular.element` is an alias for the\n\t * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`\n\t * delegates to Angular's built-in subset of jQuery, called \"jQuery lite\" or **jqLite**.\n\t *\n\t * jqLite is a tiny, API-compatible subset of jQuery that allows\n\t * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most\n\t * commonly needed functionality with the goal of having a very small footprint.\n\t *\n\t * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the\n\t * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a\n\t * specific version of jQuery if multiple versions exist on the page.\n\t *\n\t *
**Note:** All element references in Angular are always wrapped with jQuery or\n\t * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.
\n\t *\n\t *
**Note:** Keep in mind that this function will not find elements\n\t * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`\n\t * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.
\n\t *\n\t * ## Angular's jqLite\n\t * jqLite provides only the following jQuery methods:\n\t *\n\t * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument\n\t * - [`after()`](http://api.jquery.com/after/)\n\t * - [`append()`](http://api.jquery.com/append/)\n\t * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters\n\t * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData\n\t * - [`children()`](http://api.jquery.com/children/) - Does not support selectors\n\t * - [`clone()`](http://api.jquery.com/clone/)\n\t * - [`contents()`](http://api.jquery.com/contents/)\n\t * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.\n\t * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.\n\t * - [`data()`](http://api.jquery.com/data/)\n\t * - [`detach()`](http://api.jquery.com/detach/)\n\t * - [`empty()`](http://api.jquery.com/empty/)\n\t * - [`eq()`](http://api.jquery.com/eq/)\n\t * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name\n\t * - [`hasClass()`](http://api.jquery.com/hasClass/)\n\t * - [`html()`](http://api.jquery.com/html/)\n\t * - [`next()`](http://api.jquery.com/next/) - Does not support selectors\n\t * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData\n\t * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter\n\t * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors\n\t * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors\n\t * - [`prepend()`](http://api.jquery.com/prepend/)\n\t * - [`prop()`](http://api.jquery.com/prop/)\n\t * - [`ready()`](http://api.jquery.com/ready/)\n\t * - [`remove()`](http://api.jquery.com/remove/)\n\t * - [`removeAttr()`](http://api.jquery.com/removeAttr/)\n\t * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument\n\t * - [`removeData()`](http://api.jquery.com/removeData/)\n\t * - [`replaceWith()`](http://api.jquery.com/replaceWith/)\n\t * - [`text()`](http://api.jquery.com/text/)\n\t * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument\n\t * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers\n\t * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter\n\t * - [`val()`](http://api.jquery.com/val/)\n\t * - [`wrap()`](http://api.jquery.com/wrap/)\n\t *\n\t * ## jQuery/jqLite Extras\n\t * Angular also provides the following additional methods and events to both jQuery and jqLite:\n\t *\n\t * ### Events\n\t * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event\n\t * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM\n\t * element before it is removed.\n\t *\n\t * ### Methods\n\t * - `controller(name)` - retrieves the controller of the current element or its parent. By default\n\t * retrieves controller associated with the `ngController` directive. If `name` is provided as\n\t * camelCase directive name, then the controller for this directive will be retrieved (e.g.\n\t * `'ngModel'`).\n\t * - `injector()` - retrieves the injector of the current element or its parent.\n\t * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current\n\t * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to\n\t * be enabled.\n\t * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the\n\t * current element. This getter should be used only on elements that contain a directive which starts a new isolate\n\t * scope. Calling `scope()` on this element always returns the original non-isolate scope.\n\t * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.\n\t * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top\n\t * parent element is reached.\n\t *\n\t * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See\n\t * https://github.com/angular/angular.js/issues/14251 for more information.\n\t *\n\t * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.\n\t * @returns {Object} jQuery object.\n\t */\n\t\n\tJQLite.expando = 'ng339';\n\t\n\tvar jqCache = JQLite.cache = {},\n\t jqId = 1,\n\t addEventListenerFn = function(element, type, fn) {\n\t element.addEventListener(type, fn, false);\n\t },\n\t removeEventListenerFn = function(element, type, fn) {\n\t element.removeEventListener(type, fn, false);\n\t };\n\t\n\t/*\n\t * !!! This is an undocumented \"private\" function !!!\n\t */\n\tJQLite._data = function(node) {\n\t //jQuery always returns an object on cache miss\n\t return this.cache[node[this.expando]] || {};\n\t};\n\t\n\tfunction jqNextId() { return ++jqId; }\n\t\n\t\n\tvar SPECIAL_CHARS_REGEXP = /([\\:\\-\\_]+(.))/g;\n\tvar MOZ_HACK_REGEXP = /^moz([A-Z])/;\n\tvar MOUSE_EVENT_MAP= { mouseleave: \"mouseout\", mouseenter: \"mouseover\"};\n\tvar jqLiteMinErr = minErr('jqLite');\n\t\n\t/**\n\t * Converts snake_case to camelCase.\n\t * Also there is special case for Moz prefix starting with upper case letter.\n\t * @param name Name to normalize\n\t */\n\tfunction camelCase(name) {\n\t return name.\n\t replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {\n\t return offset ? letter.toUpperCase() : letter;\n\t }).\n\t replace(MOZ_HACK_REGEXP, 'Moz$1');\n\t}\n\t\n\tvar SINGLE_TAG_REGEXP = /^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/;\n\tvar HTML_REGEXP = /<|&#?\\w+;/;\n\tvar TAG_NAME_REGEXP = /<([\\w:-]+)/;\n\tvar XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi;\n\t\n\tvar wrapMap = {\n\t 'option': [1, ''],\n\t\n\t 'thead': [1, '', '
'],\n\t 'col': [2, '', '
'],\n\t 'tr': [2, '', '
'],\n\t 'td': [3, '', '
'],\n\t '_default': [0, \"\", \"\"]\n\t};\n\t\n\twrapMap.optgroup = wrapMap.option;\n\twrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\n\twrapMap.th = wrapMap.td;\n\t\n\t\n\tfunction jqLiteIsTextNode(html) {\n\t return !HTML_REGEXP.test(html);\n\t}\n\t\n\tfunction jqLiteAcceptsData(node) {\n\t // The window object can accept data but has no nodeType\n\t // Otherwise we are only interested in elements (1) and documents (9)\n\t var nodeType = node.nodeType;\n\t return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;\n\t}\n\t\n\tfunction jqLiteHasData(node) {\n\t for (var key in jqCache[node.ng339]) {\n\t return true;\n\t }\n\t return false;\n\t}\n\t\n\tfunction jqLiteCleanData(nodes) {\n\t for (var i = 0, ii = nodes.length; i < ii; i++) {\n\t jqLiteRemoveData(nodes[i]);\n\t }\n\t}\n\t\n\tfunction jqLiteBuildFragment(html, context) {\n\t var tmp, tag, wrap,\n\t fragment = context.createDocumentFragment(),\n\t nodes = [], i;\n\t\n\t if (jqLiteIsTextNode(html)) {\n\t // Convert non-html into a text node\n\t nodes.push(context.createTextNode(html));\n\t } else {\n\t // Convert html into DOM nodes\n\t tmp = fragment.appendChild(context.createElement(\"div\"));\n\t tag = (TAG_NAME_REGEXP.exec(html) || [\"\", \"\"])[1].toLowerCase();\n\t wrap = wrapMap[tag] || wrapMap._default;\n\t tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, \"<$1>\") + wrap[2];\n\t\n\t // Descend through wrappers to the right content\n\t i = wrap[0];\n\t while (i--) {\n\t tmp = tmp.lastChild;\n\t }\n\t\n\t nodes = concat(nodes, tmp.childNodes);\n\t\n\t tmp = fragment.firstChild;\n\t tmp.textContent = \"\";\n\t }\n\t\n\t // Remove wrapper from fragment\n\t fragment.textContent = \"\";\n\t fragment.innerHTML = \"\"; // Clear inner HTML\n\t forEach(nodes, function(node) {\n\t fragment.appendChild(node);\n\t });\n\t\n\t return fragment;\n\t}\n\t\n\tfunction jqLiteParseHTML(html, context) {\n\t context = context || window.document;\n\t var parsed;\n\t\n\t if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {\n\t return [context.createElement(parsed[1])];\n\t }\n\t\n\t if ((parsed = jqLiteBuildFragment(html, context))) {\n\t return parsed.childNodes;\n\t }\n\t\n\t return [];\n\t}\n\t\n\tfunction jqLiteWrapNode(node, wrapper) {\n\t var parent = node.parentNode;\n\t\n\t if (parent) {\n\t parent.replaceChild(wrapper, node);\n\t }\n\t\n\t wrapper.appendChild(node);\n\t}\n\t\n\t\n\t// IE9-11 has no method \"contains\" in SVG element and in Node.prototype. Bug #10259.\n\tvar jqLiteContains = window.Node.prototype.contains || function(arg) {\n\t // jshint bitwise: false\n\t return !!(this.compareDocumentPosition(arg) & 16);\n\t // jshint bitwise: true\n\t};\n\t\n\t/////////////////////////////////////////////\n\tfunction JQLite(element) {\n\t if (element instanceof JQLite) {\n\t return element;\n\t }\n\t\n\t var argIsString;\n\t\n\t if (isString(element)) {\n\t element = trim(element);\n\t argIsString = true;\n\t }\n\t if (!(this instanceof JQLite)) {\n\t if (argIsString && element.charAt(0) != '<') {\n\t throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');\n\t }\n\t return new JQLite(element);\n\t }\n\t\n\t if (argIsString) {\n\t jqLiteAddNodes(this, jqLiteParseHTML(element));\n\t } else {\n\t jqLiteAddNodes(this, element);\n\t }\n\t}\n\t\n\tfunction jqLiteClone(element) {\n\t return element.cloneNode(true);\n\t}\n\t\n\tfunction jqLiteDealoc(element, onlyDescendants) {\n\t if (!onlyDescendants) jqLiteRemoveData(element);\n\t\n\t if (element.querySelectorAll) {\n\t var descendants = element.querySelectorAll('*');\n\t for (var i = 0, l = descendants.length; i < l; i++) {\n\t jqLiteRemoveData(descendants[i]);\n\t }\n\t }\n\t}\n\t\n\tfunction jqLiteOff(element, type, fn, unsupported) {\n\t if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');\n\t\n\t var expandoStore = jqLiteExpandoStore(element);\n\t var events = expandoStore && expandoStore.events;\n\t var handle = expandoStore && expandoStore.handle;\n\t\n\t if (!handle) return; //no listeners registered\n\t\n\t if (!type) {\n\t for (type in events) {\n\t if (type !== '$destroy') {\n\t removeEventListenerFn(element, type, handle);\n\t }\n\t delete events[type];\n\t }\n\t } else {\n\t\n\t var removeHandler = function(type) {\n\t var listenerFns = events[type];\n\t if (isDefined(fn)) {\n\t arrayRemove(listenerFns || [], fn);\n\t }\n\t if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {\n\t removeEventListenerFn(element, type, handle);\n\t delete events[type];\n\t }\n\t };\n\t\n\t forEach(type.split(' '), function(type) {\n\t removeHandler(type);\n\t if (MOUSE_EVENT_MAP[type]) {\n\t removeHandler(MOUSE_EVENT_MAP[type]);\n\t }\n\t });\n\t }\n\t}\n\t\n\tfunction jqLiteRemoveData(element, name) {\n\t var expandoId = element.ng339;\n\t var expandoStore = expandoId && jqCache[expandoId];\n\t\n\t if (expandoStore) {\n\t if (name) {\n\t delete expandoStore.data[name];\n\t return;\n\t }\n\t\n\t if (expandoStore.handle) {\n\t if (expandoStore.events.$destroy) {\n\t expandoStore.handle({}, '$destroy');\n\t }\n\t jqLiteOff(element);\n\t }\n\t delete jqCache[expandoId];\n\t element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it\n\t }\n\t}\n\t\n\t\n\tfunction jqLiteExpandoStore(element, createIfNecessary) {\n\t var expandoId = element.ng339,\n\t expandoStore = expandoId && jqCache[expandoId];\n\t\n\t if (createIfNecessary && !expandoStore) {\n\t element.ng339 = expandoId = jqNextId();\n\t expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};\n\t }\n\t\n\t return expandoStore;\n\t}\n\t\n\t\n\tfunction jqLiteData(element, key, value) {\n\t if (jqLiteAcceptsData(element)) {\n\t\n\t var isSimpleSetter = isDefined(value);\n\t var isSimpleGetter = !isSimpleSetter && key && !isObject(key);\n\t var massGetter = !key;\n\t var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);\n\t var data = expandoStore && expandoStore.data;\n\t\n\t if (isSimpleSetter) { // data('key', value)\n\t data[key] = value;\n\t } else {\n\t if (massGetter) { // data()\n\t return data;\n\t } else {\n\t if (isSimpleGetter) { // data('key')\n\t // don't force creation of expandoStore if it doesn't exist yet\n\t return data && data[key];\n\t } else { // mass-setter: data({key1: val1, key2: val2})\n\t extend(data, key);\n\t }\n\t }\n\t }\n\t }\n\t}\n\t\n\tfunction jqLiteHasClass(element, selector) {\n\t if (!element.getAttribute) return false;\n\t return ((\" \" + (element.getAttribute('class') || '') + \" \").replace(/[\\n\\t]/g, \" \").\n\t indexOf(\" \" + selector + \" \") > -1);\n\t}\n\t\n\tfunction jqLiteRemoveClass(element, cssClasses) {\n\t if (cssClasses && element.setAttribute) {\n\t forEach(cssClasses.split(' '), function(cssClass) {\n\t element.setAttribute('class', trim(\n\t (\" \" + (element.getAttribute('class') || '') + \" \")\n\t .replace(/[\\n\\t]/g, \" \")\n\t .replace(\" \" + trim(cssClass) + \" \", \" \"))\n\t );\n\t });\n\t }\n\t}\n\t\n\tfunction jqLiteAddClass(element, cssClasses) {\n\t if (cssClasses && element.setAttribute) {\n\t var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')\n\t .replace(/[\\n\\t]/g, \" \");\n\t\n\t forEach(cssClasses.split(' '), function(cssClass) {\n\t cssClass = trim(cssClass);\n\t if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {\n\t existingClasses += cssClass + ' ';\n\t }\n\t });\n\t\n\t element.setAttribute('class', trim(existingClasses));\n\t }\n\t}\n\t\n\t\n\tfunction jqLiteAddNodes(root, elements) {\n\t // THIS CODE IS VERY HOT. Don't make changes without benchmarking.\n\t\n\t if (elements) {\n\t\n\t // if a Node (the most common case)\n\t if (elements.nodeType) {\n\t root[root.length++] = elements;\n\t } else {\n\t var length = elements.length;\n\t\n\t // if an Array or NodeList and not a Window\n\t if (typeof length === 'number' && elements.window !== elements) {\n\t if (length) {\n\t for (var i = 0; i < length; i++) {\n\t root[root.length++] = elements[i];\n\t }\n\t }\n\t } else {\n\t root[root.length++] = elements;\n\t }\n\t }\n\t }\n\t}\n\t\n\t\n\tfunction jqLiteController(element, name) {\n\t return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');\n\t}\n\t\n\tfunction jqLiteInheritedData(element, name, value) {\n\t // if element is the document object work with the html element instead\n\t // this makes $(document).scope() possible\n\t if (element.nodeType == NODE_TYPE_DOCUMENT) {\n\t element = element.documentElement;\n\t }\n\t var names = isArray(name) ? name : [name];\n\t\n\t while (element) {\n\t for (var i = 0, ii = names.length; i < ii; i++) {\n\t if (isDefined(value = jqLite.data(element, names[i]))) return value;\n\t }\n\t\n\t // If dealing with a document fragment node with a host element, and no parent, use the host\n\t // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM\n\t // to lookup parent controllers.\n\t element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);\n\t }\n\t}\n\t\n\tfunction jqLiteEmpty(element) {\n\t jqLiteDealoc(element, true);\n\t while (element.firstChild) {\n\t element.removeChild(element.firstChild);\n\t }\n\t}\n\t\n\tfunction jqLiteRemove(element, keepData) {\n\t if (!keepData) jqLiteDealoc(element);\n\t var parent = element.parentNode;\n\t if (parent) parent.removeChild(element);\n\t}\n\t\n\t\n\tfunction jqLiteDocumentLoaded(action, win) {\n\t win = win || window;\n\t if (win.document.readyState === 'complete') {\n\t // Force the action to be run async for consistent behavior\n\t // from the action's point of view\n\t // i.e. it will definitely not be in a $apply\n\t win.setTimeout(action);\n\t } else {\n\t // No need to unbind this handler as load is only ever called once\n\t jqLite(win).on('load', action);\n\t }\n\t}\n\t\n\t//////////////////////////////////////////\n\t// Functions which are declared directly.\n\t//////////////////////////////////////////\n\tvar JQLitePrototype = JQLite.prototype = {\n\t ready: function(fn) {\n\t var fired = false;\n\t\n\t function trigger() {\n\t if (fired) return;\n\t fired = true;\n\t fn();\n\t }\n\t\n\t // check if document is already loaded\n\t if (window.document.readyState === 'complete') {\n\t window.setTimeout(trigger);\n\t } else {\n\t this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9\n\t // we can not use jqLite since we are not done loading and jQuery could be loaded later.\n\t // jshint -W064\n\t JQLite(window).on('load', trigger); // fallback to window.onload for others\n\t // jshint +W064\n\t }\n\t },\n\t toString: function() {\n\t var value = [];\n\t forEach(this, function(e) { value.push('' + e);});\n\t return '[' + value.join(', ') + ']';\n\t },\n\t\n\t eq: function(index) {\n\t return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);\n\t },\n\t\n\t length: 0,\n\t push: push,\n\t sort: [].sort,\n\t splice: [].splice\n\t};\n\t\n\t//////////////////////////////////////////\n\t// Functions iterating getter/setters.\n\t// these functions return self on setter and\n\t// value on get.\n\t//////////////////////////////////////////\n\tvar BOOLEAN_ATTR = {};\n\tforEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {\n\t BOOLEAN_ATTR[lowercase(value)] = value;\n\t});\n\tvar BOOLEAN_ELEMENTS = {};\n\tforEach('input,select,option,textarea,button,form,details'.split(','), function(value) {\n\t BOOLEAN_ELEMENTS[value] = true;\n\t});\n\tvar ALIASED_ATTR = {\n\t 'ngMinlength': 'minlength',\n\t 'ngMaxlength': 'maxlength',\n\t 'ngMin': 'min',\n\t 'ngMax': 'max',\n\t 'ngPattern': 'pattern'\n\t};\n\t\n\tfunction getBooleanAttrName(element, name) {\n\t // check dom last since we will most likely fail on name\n\t var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];\n\t\n\t // booleanAttr is here twice to minimize DOM access\n\t return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;\n\t}\n\t\n\tfunction getAliasedAttrName(name) {\n\t return ALIASED_ATTR[name];\n\t}\n\t\n\tforEach({\n\t data: jqLiteData,\n\t removeData: jqLiteRemoveData,\n\t hasData: jqLiteHasData,\n\t cleanData: jqLiteCleanData\n\t}, function(fn, name) {\n\t JQLite[name] = fn;\n\t});\n\t\n\tforEach({\n\t data: jqLiteData,\n\t inheritedData: jqLiteInheritedData,\n\t\n\t scope: function(element) {\n\t // Can't use jqLiteData here directly so we stay compatible with jQuery!\n\t return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);\n\t },\n\t\n\t isolateScope: function(element) {\n\t // Can't use jqLiteData here directly so we stay compatible with jQuery!\n\t return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');\n\t },\n\t\n\t controller: jqLiteController,\n\t\n\t injector: function(element) {\n\t return jqLiteInheritedData(element, '$injector');\n\t },\n\t\n\t removeAttr: function(element, name) {\n\t element.removeAttribute(name);\n\t },\n\t\n\t hasClass: jqLiteHasClass,\n\t\n\t css: function(element, name, value) {\n\t name = camelCase(name);\n\t\n\t if (isDefined(value)) {\n\t element.style[name] = value;\n\t } else {\n\t return element.style[name];\n\t }\n\t },\n\t\n\t attr: function(element, name, value) {\n\t var nodeType = element.nodeType;\n\t if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {\n\t return;\n\t }\n\t var lowercasedName = lowercase(name);\n\t if (BOOLEAN_ATTR[lowercasedName]) {\n\t if (isDefined(value)) {\n\t if (!!value) {\n\t element[name] = true;\n\t element.setAttribute(name, lowercasedName);\n\t } else {\n\t element[name] = false;\n\t element.removeAttribute(lowercasedName);\n\t }\n\t } else {\n\t return (element[name] ||\n\t (element.attributes.getNamedItem(name) || noop).specified)\n\t ? lowercasedName\n\t : undefined;\n\t }\n\t } else if (isDefined(value)) {\n\t element.setAttribute(name, value);\n\t } else if (element.getAttribute) {\n\t // the extra argument \"2\" is to get the right thing for a.href in IE, see jQuery code\n\t // some elements (e.g. Document) don't have get attribute, so return undefined\n\t var ret = element.getAttribute(name, 2);\n\t // normalize non-existing attributes to undefined (as jQuery)\n\t return ret === null ? undefined : ret;\n\t }\n\t },\n\t\n\t prop: function(element, name, value) {\n\t if (isDefined(value)) {\n\t element[name] = value;\n\t } else {\n\t return element[name];\n\t }\n\t },\n\t\n\t text: (function() {\n\t getText.$dv = '';\n\t return getText;\n\t\n\t function getText(element, value) {\n\t if (isUndefined(value)) {\n\t var nodeType = element.nodeType;\n\t return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';\n\t }\n\t element.textContent = value;\n\t }\n\t })(),\n\t\n\t val: function(element, value) {\n\t if (isUndefined(value)) {\n\t if (element.multiple && nodeName_(element) === 'select') {\n\t var result = [];\n\t forEach(element.options, function(option) {\n\t if (option.selected) {\n\t result.push(option.value || option.text);\n\t }\n\t });\n\t return result.length === 0 ? null : result;\n\t }\n\t return element.value;\n\t }\n\t element.value = value;\n\t },\n\t\n\t html: function(element, value) {\n\t if (isUndefined(value)) {\n\t return element.innerHTML;\n\t }\n\t jqLiteDealoc(element, true);\n\t element.innerHTML = value;\n\t },\n\t\n\t empty: jqLiteEmpty\n\t}, function(fn, name) {\n\t /**\n\t * Properties: writes return selection, reads return first value\n\t */\n\t JQLite.prototype[name] = function(arg1, arg2) {\n\t var i, key;\n\t var nodeCount = this.length;\n\t\n\t // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it\n\t // in a way that survives minification.\n\t // jqLiteEmpty takes no arguments but is a setter.\n\t if (fn !== jqLiteEmpty &&\n\t (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {\n\t if (isObject(arg1)) {\n\t\n\t // we are a write, but the object properties are the key/values\n\t for (i = 0; i < nodeCount; i++) {\n\t if (fn === jqLiteData) {\n\t // data() takes the whole object in jQuery\n\t fn(this[i], arg1);\n\t } else {\n\t for (key in arg1) {\n\t fn(this[i], key, arg1[key]);\n\t }\n\t }\n\t }\n\t // return self for chaining\n\t return this;\n\t } else {\n\t // we are a read, so read the first child.\n\t // TODO: do we still need this?\n\t var value = fn.$dv;\n\t // Only if we have $dv do we iterate over all, otherwise it is just the first element.\n\t var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;\n\t for (var j = 0; j < jj; j++) {\n\t var nodeValue = fn(this[j], arg1, arg2);\n\t value = value ? value + nodeValue : nodeValue;\n\t }\n\t return value;\n\t }\n\t } else {\n\t // we are a write, so apply to all children\n\t for (i = 0; i < nodeCount; i++) {\n\t fn(this[i], arg1, arg2);\n\t }\n\t // return self for chaining\n\t return this;\n\t }\n\t };\n\t});\n\t\n\tfunction createEventHandler(element, events) {\n\t var eventHandler = function(event, type) {\n\t // jQuery specific api\n\t event.isDefaultPrevented = function() {\n\t return event.defaultPrevented;\n\t };\n\t\n\t var eventFns = events[type || event.type];\n\t var eventFnsLength = eventFns ? eventFns.length : 0;\n\t\n\t if (!eventFnsLength) return;\n\t\n\t if (isUndefined(event.immediatePropagationStopped)) {\n\t var originalStopImmediatePropagation = event.stopImmediatePropagation;\n\t event.stopImmediatePropagation = function() {\n\t event.immediatePropagationStopped = true;\n\t\n\t if (event.stopPropagation) {\n\t event.stopPropagation();\n\t }\n\t\n\t if (originalStopImmediatePropagation) {\n\t originalStopImmediatePropagation.call(event);\n\t }\n\t };\n\t }\n\t\n\t event.isImmediatePropagationStopped = function() {\n\t return event.immediatePropagationStopped === true;\n\t };\n\t\n\t // Some events have special handlers that wrap the real handler\n\t var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;\n\t\n\t // Copy event handlers in case event handlers array is modified during execution.\n\t if ((eventFnsLength > 1)) {\n\t eventFns = shallowCopy(eventFns);\n\t }\n\t\n\t for (var i = 0; i < eventFnsLength; i++) {\n\t if (!event.isImmediatePropagationStopped()) {\n\t handlerWrapper(element, event, eventFns[i]);\n\t }\n\t }\n\t };\n\t\n\t // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all\n\t // events on `element`\n\t eventHandler.elem = element;\n\t return eventHandler;\n\t}\n\t\n\tfunction defaultHandlerWrapper(element, event, handler) {\n\t handler.call(element, event);\n\t}\n\t\n\tfunction specialMouseHandlerWrapper(target, event, handler) {\n\t // Refer to jQuery's implementation of mouseenter & mouseleave\n\t // Read about mouseenter and mouseleave:\n\t // http://www.quirksmode.org/js/events_mouse.html#link8\n\t var related = event.relatedTarget;\n\t // For mousenter/leave call the handler if related is outside the target.\n\t // NB: No relatedTarget if the mouse left/entered the browser window\n\t if (!related || (related !== target && !jqLiteContains.call(target, related))) {\n\t handler.call(target, event);\n\t }\n\t}\n\t\n\t//////////////////////////////////////////\n\t// Functions iterating traversal.\n\t// These functions chain results into a single\n\t// selector.\n\t//////////////////////////////////////////\n\tforEach({\n\t removeData: jqLiteRemoveData,\n\t\n\t on: function jqLiteOn(element, type, fn, unsupported) {\n\t if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');\n\t\n\t // Do not add event handlers to non-elements because they will not be cleaned up.\n\t if (!jqLiteAcceptsData(element)) {\n\t return;\n\t }\n\t\n\t var expandoStore = jqLiteExpandoStore(element, true);\n\t var events = expandoStore.events;\n\t var handle = expandoStore.handle;\n\t\n\t if (!handle) {\n\t handle = expandoStore.handle = createEventHandler(element, events);\n\t }\n\t\n\t // http://jsperf.com/string-indexof-vs-split\n\t var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];\n\t var i = types.length;\n\t\n\t var addHandler = function(type, specialHandlerWrapper, noEventListener) {\n\t var eventFns = events[type];\n\t\n\t if (!eventFns) {\n\t eventFns = events[type] = [];\n\t eventFns.specialHandlerWrapper = specialHandlerWrapper;\n\t if (type !== '$destroy' && !noEventListener) {\n\t addEventListenerFn(element, type, handle);\n\t }\n\t }\n\t\n\t eventFns.push(fn);\n\t };\n\t\n\t while (i--) {\n\t type = types[i];\n\t if (MOUSE_EVENT_MAP[type]) {\n\t addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);\n\t addHandler(type, undefined, true);\n\t } else {\n\t addHandler(type);\n\t }\n\t }\n\t },\n\t\n\t off: jqLiteOff,\n\t\n\t one: function(element, type, fn) {\n\t element = jqLite(element);\n\t\n\t //add the listener twice so that when it is called\n\t //you can remove the original function and still be\n\t //able to call element.off(ev, fn) normally\n\t element.on(type, function onFn() {\n\t element.off(type, fn);\n\t element.off(type, onFn);\n\t });\n\t element.on(type, fn);\n\t },\n\t\n\t replaceWith: function(element, replaceNode) {\n\t var index, parent = element.parentNode;\n\t jqLiteDealoc(element);\n\t forEach(new JQLite(replaceNode), function(node) {\n\t if (index) {\n\t parent.insertBefore(node, index.nextSibling);\n\t } else {\n\t parent.replaceChild(node, element);\n\t }\n\t index = node;\n\t });\n\t },\n\t\n\t children: function(element) {\n\t var children = [];\n\t forEach(element.childNodes, function(element) {\n\t if (element.nodeType === NODE_TYPE_ELEMENT) {\n\t children.push(element);\n\t }\n\t });\n\t return children;\n\t },\n\t\n\t contents: function(element) {\n\t return element.contentDocument || element.childNodes || [];\n\t },\n\t\n\t append: function(element, node) {\n\t var nodeType = element.nodeType;\n\t if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;\n\t\n\t node = new JQLite(node);\n\t\n\t for (var i = 0, ii = node.length; i < ii; i++) {\n\t var child = node[i];\n\t element.appendChild(child);\n\t }\n\t },\n\t\n\t prepend: function(element, node) {\n\t if (element.nodeType === NODE_TYPE_ELEMENT) {\n\t var index = element.firstChild;\n\t forEach(new JQLite(node), function(child) {\n\t element.insertBefore(child, index);\n\t });\n\t }\n\t },\n\t\n\t wrap: function(element, wrapNode) {\n\t jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);\n\t },\n\t\n\t remove: jqLiteRemove,\n\t\n\t detach: function(element) {\n\t jqLiteRemove(element, true);\n\t },\n\t\n\t after: function(element, newElement) {\n\t var index = element, parent = element.parentNode;\n\t newElement = new JQLite(newElement);\n\t\n\t for (var i = 0, ii = newElement.length; i < ii; i++) {\n\t var node = newElement[i];\n\t parent.insertBefore(node, index.nextSibling);\n\t index = node;\n\t }\n\t },\n\t\n\t addClass: jqLiteAddClass,\n\t removeClass: jqLiteRemoveClass,\n\t\n\t toggleClass: function(element, selector, condition) {\n\t if (selector) {\n\t forEach(selector.split(' '), function(className) {\n\t var classCondition = condition;\n\t if (isUndefined(classCondition)) {\n\t classCondition = !jqLiteHasClass(element, className);\n\t }\n\t (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);\n\t });\n\t }\n\t },\n\t\n\t parent: function(element) {\n\t var parent = element.parentNode;\n\t return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;\n\t },\n\t\n\t next: function(element) {\n\t return element.nextElementSibling;\n\t },\n\t\n\t find: function(element, selector) {\n\t if (element.getElementsByTagName) {\n\t return element.getElementsByTagName(selector);\n\t } else {\n\t return [];\n\t }\n\t },\n\t\n\t clone: jqLiteClone,\n\t\n\t triggerHandler: function(element, event, extraParameters) {\n\t\n\t var dummyEvent, eventFnsCopy, handlerArgs;\n\t var eventName = event.type || event;\n\t var expandoStore = jqLiteExpandoStore(element);\n\t var events = expandoStore && expandoStore.events;\n\t var eventFns = events && events[eventName];\n\t\n\t if (eventFns) {\n\t // Create a dummy event to pass to the handlers\n\t dummyEvent = {\n\t preventDefault: function() { this.defaultPrevented = true; },\n\t isDefaultPrevented: function() { return this.defaultPrevented === true; },\n\t stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },\n\t isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },\n\t stopPropagation: noop,\n\t type: eventName,\n\t target: element\n\t };\n\t\n\t // If a custom event was provided then extend our dummy event with it\n\t if (event.type) {\n\t dummyEvent = extend(dummyEvent, event);\n\t }\n\t\n\t // Copy event handlers in case event handlers array is modified during execution.\n\t eventFnsCopy = shallowCopy(eventFns);\n\t handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];\n\t\n\t forEach(eventFnsCopy, function(fn) {\n\t if (!dummyEvent.isImmediatePropagationStopped()) {\n\t fn.apply(element, handlerArgs);\n\t }\n\t });\n\t }\n\t }\n\t}, function(fn, name) {\n\t /**\n\t * chaining functions\n\t */\n\t JQLite.prototype[name] = function(arg1, arg2, arg3) {\n\t var value;\n\t\n\t for (var i = 0, ii = this.length; i < ii; i++) {\n\t if (isUndefined(value)) {\n\t value = fn(this[i], arg1, arg2, arg3);\n\t if (isDefined(value)) {\n\t // any function which returns a value needs to be wrapped\n\t value = jqLite(value);\n\t }\n\t } else {\n\t jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));\n\t }\n\t }\n\t return isDefined(value) ? value : this;\n\t };\n\t\n\t // bind legacy bind/unbind to on/off\n\t JQLite.prototype.bind = JQLite.prototype.on;\n\t JQLite.prototype.unbind = JQLite.prototype.off;\n\t});\n\t\n\t\n\t// Provider for private $$jqLite service\n\tfunction $$jqLiteProvider() {\n\t this.$get = function $$jqLite() {\n\t return extend(JQLite, {\n\t hasClass: function(node, classes) {\n\t if (node.attr) node = node[0];\n\t return jqLiteHasClass(node, classes);\n\t },\n\t addClass: function(node, classes) {\n\t if (node.attr) node = node[0];\n\t return jqLiteAddClass(node, classes);\n\t },\n\t removeClass: function(node, classes) {\n\t if (node.attr) node = node[0];\n\t return jqLiteRemoveClass(node, classes);\n\t }\n\t });\n\t };\n\t}\n\t\n\t/**\n\t * Computes a hash of an 'obj'.\n\t * Hash of a:\n\t * string is string\n\t * number is number as string\n\t * object is either result of calling $$hashKey function on the object or uniquely generated id,\n\t * that is also assigned to the $$hashKey property of the object.\n\t *\n\t * @param obj\n\t * @returns {string} hash string such that the same input will have the same hash string.\n\t * The resulting string key is in 'type:hashKey' format.\n\t */\n\tfunction hashKey(obj, nextUidFn) {\n\t var key = obj && obj.$$hashKey;\n\t\n\t if (key) {\n\t if (typeof key === 'function') {\n\t key = obj.$$hashKey();\n\t }\n\t return key;\n\t }\n\t\n\t var objType = typeof obj;\n\t if (objType == 'function' || (objType == 'object' && obj !== null)) {\n\t key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();\n\t } else {\n\t key = objType + ':' + obj;\n\t }\n\t\n\t return key;\n\t}\n\t\n\t/**\n\t * HashMap which can use objects as keys\n\t */\n\tfunction HashMap(array, isolatedUid) {\n\t if (isolatedUid) {\n\t var uid = 0;\n\t this.nextUid = function() {\n\t return ++uid;\n\t };\n\t }\n\t forEach(array, this.put, this);\n\t}\n\tHashMap.prototype = {\n\t /**\n\t * Store key value pair\n\t * @param key key to store can be any type\n\t * @param value value to store can be any type\n\t */\n\t put: function(key, value) {\n\t this[hashKey(key, this.nextUid)] = value;\n\t },\n\t\n\t /**\n\t * @param key\n\t * @returns {Object} the value for the key\n\t */\n\t get: function(key) {\n\t return this[hashKey(key, this.nextUid)];\n\t },\n\t\n\t /**\n\t * Remove the key/value pair\n\t * @param key\n\t */\n\t remove: function(key) {\n\t var value = this[key = hashKey(key, this.nextUid)];\n\t delete this[key];\n\t return value;\n\t }\n\t};\n\t\n\tvar $$HashMapProvider = [function() {\n\t this.$get = [function() {\n\t return HashMap;\n\t }];\n\t}];\n\t\n\t/**\n\t * @ngdoc function\n\t * @module ng\n\t * @name angular.injector\n\t * @kind function\n\t *\n\t * @description\n\t * Creates an injector object that can be used for retrieving services as well as for\n\t * dependency injection (see {@link guide/di dependency injection}).\n\t *\n\t * @param {Array.} modules A list of module functions or their aliases. See\n\t * {@link angular.module}. The `ng` module must be explicitly added.\n\t * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which\n\t * disallows argument name annotation inference.\n\t * @returns {injector} Injector object. See {@link auto.$injector $injector}.\n\t *\n\t * @example\n\t * Typical usage\n\t * ```js\n\t * // create an injector\n\t * var $injector = angular.injector(['ng']);\n\t *\n\t * // use the injector to kick off your application\n\t * // use the type inference to auto inject arguments, or use implicit injection\n\t * $injector.invoke(function($rootScope, $compile, $document) {\n\t * $compile($document)($rootScope);\n\t * $rootScope.$digest();\n\t * });\n\t * ```\n\t *\n\t * Sometimes you want to get access to the injector of a currently running Angular app\n\t * from outside Angular. Perhaps, you want to inject and compile some markup after the\n\t * application has been bootstrapped. You can do this using the extra `injector()` added\n\t * to JQuery/jqLite elements. See {@link angular.element}.\n\t *\n\t * *This is fairly rare but could be the case if a third party library is injecting the\n\t * markup.*\n\t *\n\t * In the following example a new block of HTML containing a `ng-controller`\n\t * directive is added to the end of the document body by JQuery. We then compile and link\n\t * it into the current AngularJS scope.\n\t *\n\t * ```js\n\t * var $div = $('
{{content.label}}
');\n\t * $(document.body).append($div);\n\t *\n\t * angular.element(document).injector().invoke(function($compile) {\n\t * var scope = angular.element($div).scope();\n\t * $compile($div)(scope);\n\t * });\n\t * ```\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc module\n\t * @name auto\n\t * @installation\n\t * @description\n\t *\n\t * Implicit module which gets automatically added to each {@link auto.$injector $injector}.\n\t */\n\t\n\tvar ARROW_ARG = /^([^\\(]+?)=>/;\n\tvar FN_ARGS = /^[^\\(]*\\(\\s*([^\\)]*)\\)/m;\n\tvar FN_ARG_SPLIT = /,/;\n\tvar FN_ARG = /^\\s*(_?)(\\S+?)\\1\\s*$/;\n\tvar STRIP_COMMENTS = /((\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/))/mg;\n\tvar $injectorMinErr = minErr('$injector');\n\t\n\tfunction stringifyFn(fn) {\n\t // Support: Chrome 50-51 only\n\t // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51\n\t // (See https://github.com/angular/angular.js/issues/14487.)\n\t // TODO (gkalpak): Remove workaround when Chrome v52 is released\n\t return Function.prototype.toString.call(fn) + ' ';\n\t}\n\t\n\tfunction extractArgs(fn) {\n\t var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),\n\t args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);\n\t return args;\n\t}\n\t\n\tfunction anonFn(fn) {\n\t // For anonymous functions, showing at the very least the function signature can help in\n\t // debugging.\n\t var args = extractArgs(fn);\n\t if (args) {\n\t return 'function(' + (args[1] || '').replace(/[\\s\\r\\n]+/, ' ') + ')';\n\t }\n\t return 'fn';\n\t}\n\t\n\tfunction annotate(fn, strictDi, name) {\n\t var $inject,\n\t argDecl,\n\t last;\n\t\n\t if (typeof fn === 'function') {\n\t if (!($inject = fn.$inject)) {\n\t $inject = [];\n\t if (fn.length) {\n\t if (strictDi) {\n\t if (!isString(name) || !name) {\n\t name = fn.name || anonFn(fn);\n\t }\n\t throw $injectorMinErr('strictdi',\n\t '{0} is not using explicit annotation and cannot be invoked in strict mode', name);\n\t }\n\t argDecl = extractArgs(fn);\n\t forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {\n\t arg.replace(FN_ARG, function(all, underscore, name) {\n\t $inject.push(name);\n\t });\n\t });\n\t }\n\t fn.$inject = $inject;\n\t }\n\t } else if (isArray(fn)) {\n\t last = fn.length - 1;\n\t assertArgFn(fn[last], 'fn');\n\t $inject = fn.slice(0, last);\n\t } else {\n\t assertArgFn(fn, 'fn', true);\n\t }\n\t return $inject;\n\t}\n\t\n\t///////////////////////////////////////\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $injector\n\t *\n\t * @description\n\t *\n\t * `$injector` is used to retrieve object instances as defined by\n\t * {@link auto.$provide provider}, instantiate types, invoke methods,\n\t * and load modules.\n\t *\n\t * The following always holds true:\n\t *\n\t * ```js\n\t * var $injector = angular.injector();\n\t * expect($injector.get('$injector')).toBe($injector);\n\t * expect($injector.invoke(function($injector) {\n\t * return $injector;\n\t * })).toBe($injector);\n\t * ```\n\t *\n\t * # Injection Function Annotation\n\t *\n\t * JavaScript does not have annotations, and annotations are needed for dependency injection. The\n\t * following are all valid ways of annotating function with injection arguments and are equivalent.\n\t *\n\t * ```js\n\t * // inferred (only works if code not minified/obfuscated)\n\t * $injector.invoke(function(serviceA){});\n\t *\n\t * // annotated\n\t * function explicit(serviceA) {};\n\t * explicit.$inject = ['serviceA'];\n\t * $injector.invoke(explicit);\n\t *\n\t * // inline\n\t * $injector.invoke(['serviceA', function(serviceA){}]);\n\t * ```\n\t *\n\t * ## Inference\n\t *\n\t * In JavaScript calling `toString()` on a function returns the function definition. The definition\n\t * can then be parsed and the function arguments can be extracted. This method of discovering\n\t * annotations is disallowed when the injector is in strict mode.\n\t * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the\n\t * argument names.\n\t *\n\t * ## `$inject` Annotation\n\t * By adding an `$inject` property onto a function the injection parameters can be specified.\n\t *\n\t * ## Inline\n\t * As an array of injection names, where the last item in the array is the function to call.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $injector#get\n\t *\n\t * @description\n\t * Return an instance of the service.\n\t *\n\t * @param {string} name The name of the instance to retrieve.\n\t * @param {string=} caller An optional string to provide the origin of the function call for error messages.\n\t * @return {*} The instance.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $injector#invoke\n\t *\n\t * @description\n\t * Invoke the method and supply the method arguments from the `$injector`.\n\t *\n\t * @param {Function|Array.} fn The injectable function to invoke. Function parameters are\n\t * injected according to the {@link guide/di $inject Annotation} rules.\n\t * @param {Object=} self The `this` for the invoked method.\n\t * @param {Object=} locals Optional object. If preset then any argument names are read from this\n\t * object first, before the `$injector` is consulted.\n\t * @returns {*} the value returned by the invoked `fn` function.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $injector#has\n\t *\n\t * @description\n\t * Allows the user to query if the particular service exists.\n\t *\n\t * @param {string} name Name of the service to query.\n\t * @returns {boolean} `true` if injector has given service.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $injector#instantiate\n\t * @description\n\t * Create a new instance of JS type. The method takes a constructor function, invokes the new\n\t * operator, and supplies all of the arguments to the constructor function as specified by the\n\t * constructor annotation.\n\t *\n\t * @param {Function} Type Annotated constructor function.\n\t * @param {Object=} locals Optional object. If preset then any argument names are read from this\n\t * object first, before the `$injector` is consulted.\n\t * @returns {Object} new instance of `Type`.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $injector#annotate\n\t *\n\t * @description\n\t * Returns an array of service names which the function is requesting for injection. This API is\n\t * used by the injector to determine which services need to be injected into the function when the\n\t * function is invoked. There are three ways in which the function can be annotated with the needed\n\t * dependencies.\n\t *\n\t * # Argument names\n\t *\n\t * The simplest form is to extract the dependencies from the arguments of the function. This is done\n\t * by converting the function into a string using `toString()` method and extracting the argument\n\t * names.\n\t * ```js\n\t * // Given\n\t * function MyController($scope, $route) {\n\t * // ...\n\t * }\n\t *\n\t * // Then\n\t * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);\n\t * ```\n\t *\n\t * You can disallow this method by using strict injection mode.\n\t *\n\t * This method does not work with code minification / obfuscation. For this reason the following\n\t * annotation strategies are supported.\n\t *\n\t * # The `$inject` property\n\t *\n\t * If a function has an `$inject` property and its value is an array of strings, then the strings\n\t * represent names of services to be injected into the function.\n\t * ```js\n\t * // Given\n\t * var MyController = function(obfuscatedScope, obfuscatedRoute) {\n\t * // ...\n\t * }\n\t * // Define function dependencies\n\t * MyController['$inject'] = ['$scope', '$route'];\n\t *\n\t * // Then\n\t * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);\n\t * ```\n\t *\n\t * # The array notation\n\t *\n\t * It is often desirable to inline Injected functions and that's when setting the `$inject` property\n\t * is very inconvenient. In these situations using the array notation to specify the dependencies in\n\t * a way that survives minification is a better choice:\n\t *\n\t * ```js\n\t * // We wish to write this (not minification / obfuscation safe)\n\t * injector.invoke(function($compile, $rootScope) {\n\t * // ...\n\t * });\n\t *\n\t * // We are forced to write break inlining\n\t * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {\n\t * // ...\n\t * };\n\t * tmpFn.$inject = ['$compile', '$rootScope'];\n\t * injector.invoke(tmpFn);\n\t *\n\t * // To better support inline function the inline annotation is supported\n\t * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {\n\t * // ...\n\t * }]);\n\t *\n\t * // Therefore\n\t * expect(injector.annotate(\n\t * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])\n\t * ).toEqual(['$compile', '$rootScope']);\n\t * ```\n\t *\n\t * @param {Function|Array.} fn Function for which dependent service names need to\n\t * be retrieved as described above.\n\t *\n\t * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.\n\t *\n\t * @returns {Array.} The names of the services which the function requires.\n\t */\n\t\n\t\n\t\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $provide\n\t *\n\t * @description\n\t *\n\t * The {@link auto.$provide $provide} service has a number of methods for registering components\n\t * with the {@link auto.$injector $injector}. Many of these functions are also exposed on\n\t * {@link angular.Module}.\n\t *\n\t * An Angular **service** is a singleton object created by a **service factory**. These **service\n\t * factories** are functions which, in turn, are created by a **service provider**.\n\t * The **service providers** are constructor functions. When instantiated they must contain a\n\t * property called `$get`, which holds the **service factory** function.\n\t *\n\t * When you request a service, the {@link auto.$injector $injector} is responsible for finding the\n\t * correct **service provider**, instantiating it and then calling its `$get` **service factory**\n\t * function to get the instance of the **service**.\n\t *\n\t * Often services have no configuration options and there is no need to add methods to the service\n\t * provider. The provider will be no more than a constructor function with a `$get` property. For\n\t * these cases the {@link auto.$provide $provide} service has additional helper methods to register\n\t * services without specifying a provider.\n\t *\n\t * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the\n\t * {@link auto.$injector $injector}\n\t * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by\n\t * providers and services.\n\t * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by\n\t * services, not providers.\n\t * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**\n\t * that will be wrapped in a **service provider** object, whose `$get` property will contain the\n\t * given factory function.\n\t * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**\n\t * that will be wrapped in a **service provider** object, whose `$get` property will instantiate\n\t * a new object using the given constructor function.\n\t * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that\n\t * will be able to modify or replace the implementation of another service.\n\t *\n\t * See the individual methods for more information and examples.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#provider\n\t * @description\n\t *\n\t * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions\n\t * are constructor functions, whose instances are responsible for \"providing\" a factory for a\n\t * service.\n\t *\n\t * Service provider names start with the name of the service they provide followed by `Provider`.\n\t * For example, the {@link ng.$log $log} service has a provider called\n\t * {@link ng.$logProvider $logProvider}.\n\t *\n\t * Service provider objects can have additional methods which allow configuration of the provider\n\t * and its service. Importantly, you can configure what kind of service is created by the `$get`\n\t * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a\n\t * method {@link ng.$logProvider#debugEnabled debugEnabled}\n\t * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the\n\t * console or not.\n\t *\n\t * @param {string} name The name of the instance. NOTE: the provider will be available under `name +\n\t 'Provider'` key.\n\t * @param {(Object|function())} provider If the provider is:\n\t *\n\t * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using\n\t * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.\n\t * - `Constructor`: a new instance of the provider will be created using\n\t * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.\n\t *\n\t * @returns {Object} registered provider instance\n\t\n\t * @example\n\t *\n\t * The following example shows how to create a simple event tracking service and register it using\n\t * {@link auto.$provide#provider $provide.provider()}.\n\t *\n\t * ```js\n\t * // Define the eventTracker provider\n\t * function EventTrackerProvider() {\n\t * var trackingUrl = '/track';\n\t *\n\t * // A provider method for configuring where the tracked events should been saved\n\t * this.setTrackingUrl = function(url) {\n\t * trackingUrl = url;\n\t * };\n\t *\n\t * // The service factory function\n\t * this.$get = ['$http', function($http) {\n\t * var trackedEvents = {};\n\t * return {\n\t * // Call this to track an event\n\t * event: function(event) {\n\t * var count = trackedEvents[event] || 0;\n\t * count += 1;\n\t * trackedEvents[event] = count;\n\t * return count;\n\t * },\n\t * // Call this to save the tracked events to the trackingUrl\n\t * save: function() {\n\t * $http.post(trackingUrl, trackedEvents);\n\t * }\n\t * };\n\t * }];\n\t * }\n\t *\n\t * describe('eventTracker', function() {\n\t * var postSpy;\n\t *\n\t * beforeEach(module(function($provide) {\n\t * // Register the eventTracker provider\n\t * $provide.provider('eventTracker', EventTrackerProvider);\n\t * }));\n\t *\n\t * beforeEach(module(function(eventTrackerProvider) {\n\t * // Configure eventTracker provider\n\t * eventTrackerProvider.setTrackingUrl('/custom-track');\n\t * }));\n\t *\n\t * it('tracks events', inject(function(eventTracker) {\n\t * expect(eventTracker.event('login')).toEqual(1);\n\t * expect(eventTracker.event('login')).toEqual(2);\n\t * }));\n\t *\n\t * it('saves to the tracking url', inject(function(eventTracker, $http) {\n\t * postSpy = spyOn($http, 'post');\n\t * eventTracker.event('login');\n\t * eventTracker.save();\n\t * expect(postSpy).toHaveBeenCalled();\n\t * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');\n\t * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');\n\t * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });\n\t * }));\n\t * });\n\t * ```\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#factory\n\t * @description\n\t *\n\t * Register a **service factory**, which will be called to return the service instance.\n\t * This is short for registering a service where its provider consists of only a `$get` property,\n\t * which is the given service factory function.\n\t * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to\n\t * configure your service in a provider.\n\t *\n\t * @param {string} name The name of the instance.\n\t * @param {Function|Array.} $getFn The injectable $getFn for the instance creation.\n\t * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.\n\t * @returns {Object} registered provider instance\n\t *\n\t * @example\n\t * Here is an example of registering a service\n\t * ```js\n\t * $provide.factory('ping', ['$http', function($http) {\n\t * return function ping() {\n\t * return $http.send('/ping');\n\t * };\n\t * }]);\n\t * ```\n\t * You would then inject and use this service like this:\n\t * ```js\n\t * someModule.controller('Ctrl', ['ping', function(ping) {\n\t * ping();\n\t * }]);\n\t * ```\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#service\n\t * @description\n\t *\n\t * Register a **service constructor**, which will be invoked with `new` to create the service\n\t * instance.\n\t * This is short for registering a service where its provider's `$get` property is a factory\n\t * function that returns an instance instantiated by the injector from the service constructor\n\t * function.\n\t *\n\t * Internally it looks a bit like this:\n\t *\n\t * ```\n\t * {\n\t * $get: function() {\n\t * return $injector.instantiate(constructor);\n\t * }\n\t * }\n\t * ```\n\t *\n\t *\n\t * You should use {@link auto.$provide#service $provide.service(class)} if you define your service\n\t * as a type/class.\n\t *\n\t * @param {string} name The name of the instance.\n\t * @param {Function|Array.} constructor An injectable class (constructor function)\n\t * that will be instantiated.\n\t * @returns {Object} registered provider instance\n\t *\n\t * @example\n\t * Here is an example of registering a service using\n\t * {@link auto.$provide#service $provide.service(class)}.\n\t * ```js\n\t * var Ping = function($http) {\n\t * this.$http = $http;\n\t * };\n\t *\n\t * Ping.$inject = ['$http'];\n\t *\n\t * Ping.prototype.send = function() {\n\t * return this.$http.get('/ping');\n\t * };\n\t * $provide.service('ping', Ping);\n\t * ```\n\t * You would then inject and use this service like this:\n\t * ```js\n\t * someModule.controller('Ctrl', ['ping', function(ping) {\n\t * ping.send();\n\t * }]);\n\t * ```\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#value\n\t * @description\n\t *\n\t * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a\n\t * number, an array, an object or a function. This is short for registering a service where its\n\t * provider's `$get` property is a factory function that takes no arguments and returns the **value\n\t * service**. That also means it is not possible to inject other services into a value service.\n\t *\n\t * Value services are similar to constant services, except that they cannot be injected into a\n\t * module configuration function (see {@link angular.Module#config}) but they can be overridden by\n\t * an Angular {@link auto.$provide#decorator decorator}.\n\t *\n\t * @param {string} name The name of the instance.\n\t * @param {*} value The value.\n\t * @returns {Object} registered provider instance\n\t *\n\t * @example\n\t * Here are some examples of creating value services.\n\t * ```js\n\t * $provide.value('ADMIN_USER', 'admin');\n\t *\n\t * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });\n\t *\n\t * $provide.value('halfOf', function(value) {\n\t * return value / 2;\n\t * });\n\t * ```\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#constant\n\t * @description\n\t *\n\t * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,\n\t * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not\n\t * possible to inject other services into a constant.\n\t *\n\t * But unlike {@link auto.$provide#value value}, a constant can be\n\t * injected into a module configuration function (see {@link angular.Module#config}) and it cannot\n\t * be overridden by an Angular {@link auto.$provide#decorator decorator}.\n\t *\n\t * @param {string} name The name of the constant.\n\t * @param {*} value The constant value.\n\t * @returns {Object} registered instance\n\t *\n\t * @example\n\t * Here a some examples of creating constants:\n\t * ```js\n\t * $provide.constant('SHARD_HEIGHT', 306);\n\t *\n\t * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);\n\t *\n\t * $provide.constant('double', function(value) {\n\t * return value * 2;\n\t * });\n\t * ```\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $provide#decorator\n\t * @description\n\t *\n\t * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function\n\t * intercepts the creation of a service, allowing it to override or modify the behavior of the\n\t * service. The return value of the decorator function may be the original service, or a new service\n\t * that replaces (or wraps and delegates to) the original service.\n\t *\n\t * You can find out more about using decorators in the {@link guide/decorators} guide.\n\t *\n\t * @param {string} name The name of the service to decorate.\n\t * @param {Function|Array.} decorator This function will be invoked when the service needs to be\n\t * provided and should return the decorated service instance. The function is called using\n\t * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.\n\t * Local injection arguments:\n\t *\n\t * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,\n\t * decorated or delegated to.\n\t *\n\t * @example\n\t * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting\n\t * calls to {@link ng.$log#error $log.warn()}.\n\t * ```js\n\t * $provide.decorator('$log', ['$delegate', function($delegate) {\n\t * $delegate.warn = $delegate.error;\n\t * return $delegate;\n\t * }]);\n\t * ```\n\t */\n\t\n\t\n\tfunction createInjector(modulesToLoad, strictDi) {\n\t strictDi = (strictDi === true);\n\t var INSTANTIATING = {},\n\t providerSuffix = 'Provider',\n\t path = [],\n\t loadedModules = new HashMap([], true),\n\t providerCache = {\n\t $provide: {\n\t provider: supportObject(provider),\n\t factory: supportObject(factory),\n\t service: supportObject(service),\n\t value: supportObject(value),\n\t constant: supportObject(constant),\n\t decorator: decorator\n\t }\n\t },\n\t providerInjector = (providerCache.$injector =\n\t createInternalInjector(providerCache, function(serviceName, caller) {\n\t if (angular.isString(caller)) {\n\t path.push(caller);\n\t }\n\t throw $injectorMinErr('unpr', \"Unknown provider: {0}\", path.join(' <- '));\n\t })),\n\t instanceCache = {},\n\t protoInstanceInjector =\n\t createInternalInjector(instanceCache, function(serviceName, caller) {\n\t var provider = providerInjector.get(serviceName + providerSuffix, caller);\n\t return instanceInjector.invoke(\n\t provider.$get, provider, undefined, serviceName);\n\t }),\n\t instanceInjector = protoInstanceInjector;\n\t\n\t providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };\n\t var runBlocks = loadModules(modulesToLoad);\n\t instanceInjector = protoInstanceInjector.get('$injector');\n\t instanceInjector.strictDi = strictDi;\n\t forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });\n\t\n\t return instanceInjector;\n\t\n\t ////////////////////////////////////\n\t // $provider\n\t ////////////////////////////////////\n\t\n\t function supportObject(delegate) {\n\t return function(key, value) {\n\t if (isObject(key)) {\n\t forEach(key, reverseParams(delegate));\n\t } else {\n\t return delegate(key, value);\n\t }\n\t };\n\t }\n\t\n\t function provider(name, provider_) {\n\t assertNotHasOwnProperty(name, 'service');\n\t if (isFunction(provider_) || isArray(provider_)) {\n\t provider_ = providerInjector.instantiate(provider_);\n\t }\n\t if (!provider_.$get) {\n\t throw $injectorMinErr('pget', \"Provider '{0}' must define $get factory method.\", name);\n\t }\n\t return providerCache[name + providerSuffix] = provider_;\n\t }\n\t\n\t function enforceReturnValue(name, factory) {\n\t return function enforcedReturnValue() {\n\t var result = instanceInjector.invoke(factory, this);\n\t if (isUndefined(result)) {\n\t throw $injectorMinErr('undef', \"Provider '{0}' must return a value from $get factory method.\", name);\n\t }\n\t return result;\n\t };\n\t }\n\t\n\t function factory(name, factoryFn, enforce) {\n\t return provider(name, {\n\t $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn\n\t });\n\t }\n\t\n\t function service(name, constructor) {\n\t return factory(name, ['$injector', function($injector) {\n\t return $injector.instantiate(constructor);\n\t }]);\n\t }\n\t\n\t function value(name, val) { return factory(name, valueFn(val), false); }\n\t\n\t function constant(name, value) {\n\t assertNotHasOwnProperty(name, 'constant');\n\t providerCache[name] = value;\n\t instanceCache[name] = value;\n\t }\n\t\n\t function decorator(serviceName, decorFn) {\n\t var origProvider = providerInjector.get(serviceName + providerSuffix),\n\t orig$get = origProvider.$get;\n\t\n\t origProvider.$get = function() {\n\t var origInstance = instanceInjector.invoke(orig$get, origProvider);\n\t return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});\n\t };\n\t }\n\t\n\t ////////////////////////////////////\n\t // Module Loading\n\t ////////////////////////////////////\n\t function loadModules(modulesToLoad) {\n\t assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');\n\t var runBlocks = [], moduleFn;\n\t forEach(modulesToLoad, function(module) {\n\t if (loadedModules.get(module)) return;\n\t loadedModules.put(module, true);\n\t\n\t function runInvokeQueue(queue) {\n\t var i, ii;\n\t for (i = 0, ii = queue.length; i < ii; i++) {\n\t var invokeArgs = queue[i],\n\t provider = providerInjector.get(invokeArgs[0]);\n\t\n\t provider[invokeArgs[1]].apply(provider, invokeArgs[2]);\n\t }\n\t }\n\t\n\t try {\n\t if (isString(module)) {\n\t moduleFn = angularModule(module);\n\t runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);\n\t runInvokeQueue(moduleFn._invokeQueue);\n\t runInvokeQueue(moduleFn._configBlocks);\n\t } else if (isFunction(module)) {\n\t runBlocks.push(providerInjector.invoke(module));\n\t } else if (isArray(module)) {\n\t runBlocks.push(providerInjector.invoke(module));\n\t } else {\n\t assertArgFn(module, 'module');\n\t }\n\t } catch (e) {\n\t if (isArray(module)) {\n\t module = module[module.length - 1];\n\t }\n\t if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {\n\t // Safari & FF's stack traces don't contain error.message content\n\t // unlike those of Chrome and IE\n\t // So if stack doesn't contain message, we create a new string that contains both.\n\t // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.\n\t /* jshint -W022 */\n\t e = e.message + '\\n' + e.stack;\n\t }\n\t throw $injectorMinErr('modulerr', \"Failed to instantiate module {0} due to:\\n{1}\",\n\t module, e.stack || e.message || e);\n\t }\n\t });\n\t return runBlocks;\n\t }\n\t\n\t ////////////////////////////////////\n\t // internal Injector\n\t ////////////////////////////////////\n\t\n\t function createInternalInjector(cache, factory) {\n\t\n\t function getService(serviceName, caller) {\n\t if (cache.hasOwnProperty(serviceName)) {\n\t if (cache[serviceName] === INSTANTIATING) {\n\t throw $injectorMinErr('cdep', 'Circular dependency found: {0}',\n\t serviceName + ' <- ' + path.join(' <- '));\n\t }\n\t return cache[serviceName];\n\t } else {\n\t try {\n\t path.unshift(serviceName);\n\t cache[serviceName] = INSTANTIATING;\n\t return cache[serviceName] = factory(serviceName, caller);\n\t } catch (err) {\n\t if (cache[serviceName] === INSTANTIATING) {\n\t delete cache[serviceName];\n\t }\n\t throw err;\n\t } finally {\n\t path.shift();\n\t }\n\t }\n\t }\n\t\n\t\n\t function injectionArgs(fn, locals, serviceName) {\n\t var args = [],\n\t $inject = createInjector.$$annotate(fn, strictDi, serviceName);\n\t\n\t for (var i = 0, length = $inject.length; i < length; i++) {\n\t var key = $inject[i];\n\t if (typeof key !== 'string') {\n\t throw $injectorMinErr('itkn',\n\t 'Incorrect injection token! Expected service name as string, got {0}', key);\n\t }\n\t args.push(locals && locals.hasOwnProperty(key) ? locals[key] :\n\t getService(key, serviceName));\n\t }\n\t return args;\n\t }\n\t\n\t function isClass(func) {\n\t // IE 9-11 do not support classes and IE9 leaks with the code below.\n\t if (msie <= 11) {\n\t return false;\n\t }\n\t // Support: Edge 12-13 only\n\t // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/\n\t return typeof func === 'function'\n\t && /^(?:class\\b|constructor\\()/.test(stringifyFn(func));\n\t }\n\t\n\t function invoke(fn, self, locals, serviceName) {\n\t if (typeof locals === 'string') {\n\t serviceName = locals;\n\t locals = null;\n\t }\n\t\n\t var args = injectionArgs(fn, locals, serviceName);\n\t if (isArray(fn)) {\n\t fn = fn[fn.length - 1];\n\t }\n\t\n\t if (!isClass(fn)) {\n\t // http://jsperf.com/angularjs-invoke-apply-vs-switch\n\t // #5388\n\t return fn.apply(self, args);\n\t } else {\n\t args.unshift(null);\n\t return new (Function.prototype.bind.apply(fn, args))();\n\t }\n\t }\n\t\n\t\n\t function instantiate(Type, locals, serviceName) {\n\t // Check if Type is annotated and use just the given function at n-1 as parameter\n\t // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);\n\t var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);\n\t var args = injectionArgs(Type, locals, serviceName);\n\t // Empty object at position 0 is ignored for invocation with `new`, but required.\n\t args.unshift(null);\n\t return new (Function.prototype.bind.apply(ctor, args))();\n\t }\n\t\n\t\n\t return {\n\t invoke: invoke,\n\t instantiate: instantiate,\n\t get: getService,\n\t annotate: createInjector.$$annotate,\n\t has: function(name) {\n\t return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);\n\t }\n\t };\n\t }\n\t}\n\t\n\tcreateInjector.$$annotate = annotate;\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $anchorScrollProvider\n\t *\n\t * @description\n\t * Use `$anchorScrollProvider` to disable automatic scrolling whenever\n\t * {@link ng.$location#hash $location.hash()} changes.\n\t */\n\tfunction $AnchorScrollProvider() {\n\t\n\t var autoScrollingEnabled = true;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $anchorScrollProvider#disableAutoScrolling\n\t *\n\t * @description\n\t * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to\n\t * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
\n\t * Use this method to disable automatic scrolling.\n\t *\n\t * If automatic scrolling is disabled, one must explicitly call\n\t * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the\n\t * current hash.\n\t */\n\t this.disableAutoScrolling = function() {\n\t autoScrollingEnabled = false;\n\t };\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $anchorScroll\n\t * @kind function\n\t * @requires $window\n\t * @requires $location\n\t * @requires $rootScope\n\t *\n\t * @description\n\t * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the\n\t * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified\n\t * in the\n\t * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).\n\t *\n\t * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to\n\t * match any anchor whenever it changes. This can be disabled by calling\n\t * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.\n\t *\n\t * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a\n\t * vertical scroll-offset (either fixed or dynamic).\n\t *\n\t * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of\n\t * {@link ng.$location#hash $location.hash()} will be used.\n\t *\n\t * @property {(number|function|jqLite)} yOffset\n\t * If set, specifies a vertical scroll-offset. This is often useful when there are fixed\n\t * positioned elements at the top of the page, such as navbars, headers etc.\n\t *\n\t * `yOffset` can be specified in various ways:\n\t * - **number**: A fixed number of pixels to be used as offset.

\n\t * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return\n\t * a number representing the offset (in pixels).

\n\t * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from\n\t * the top of the page to the element's bottom will be used as offset.
\n\t * **Note**: The element will be taken into account only as long as its `position` is set to\n\t * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust\n\t * their height and/or positioning according to the viewport's size.\n\t *\n\t *
\n\t *
\n\t * In order for `yOffset` to work properly, scrolling should take place on the document's root and\n\t * not some child element.\n\t *
\n\t *\n\t * @example\n\t \n\t \n\t
\n\t Go to bottom\n\t You're at the bottom!\n\t
\n\t
\n\t \n\t angular.module('anchorScrollExample', [])\n\t .controller('ScrollController', ['$scope', '$location', '$anchorScroll',\n\t function ($scope, $location, $anchorScroll) {\n\t $scope.gotoBottom = function() {\n\t // set the location.hash to the id of\n\t // the element you wish to scroll to.\n\t $location.hash('bottom');\n\t\n\t // call $anchorScroll()\n\t $anchorScroll();\n\t };\n\t }]);\n\t \n\t \n\t #scrollArea {\n\t height: 280px;\n\t overflow: auto;\n\t }\n\t\n\t #bottom {\n\t display: block;\n\t margin-top: 2000px;\n\t }\n\t \n\t
\n\t *\n\t *
\n\t * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).\n\t * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t Anchor {{x}} of 5\n\t
\n\t
\n\t \n\t angular.module('anchorScrollOffsetExample', [])\n\t .run(['$anchorScroll', function($anchorScroll) {\n\t $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels\n\t }])\n\t .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',\n\t function ($anchorScroll, $location, $scope) {\n\t $scope.gotoAnchor = function(x) {\n\t var newHash = 'anchor' + x;\n\t if ($location.hash() !== newHash) {\n\t // set the $location.hash to `newHash` and\n\t // $anchorScroll will automatically scroll to it\n\t $location.hash('anchor' + x);\n\t } else {\n\t // call $anchorScroll() explicitly,\n\t // since $location.hash hasn't changed\n\t $anchorScroll();\n\t }\n\t };\n\t }\n\t ]);\n\t \n\t \n\t body {\n\t padding-top: 50px;\n\t }\n\t\n\t .anchor {\n\t border: 2px dashed DarkOrchid;\n\t padding: 10px 10px 200px 10px;\n\t }\n\t\n\t .fixed-header {\n\t background-color: rgba(0, 0, 0, 0.2);\n\t height: 50px;\n\t position: fixed;\n\t top: 0; left: 0; right: 0;\n\t }\n\t\n\t .fixed-header > a {\n\t display: inline-block;\n\t margin: 5px 15px;\n\t }\n\t \n\t
\n\t */\n\t this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {\n\t var document = $window.document;\n\t\n\t // Helper function to get first anchor from a NodeList\n\t // (using `Array#some()` instead of `angular#forEach()` since it's more performant\n\t // and working in all supported browsers.)\n\t function getFirstAnchor(list) {\n\t var result = null;\n\t Array.prototype.some.call(list, function(element) {\n\t if (nodeName_(element) === 'a') {\n\t result = element;\n\t return true;\n\t }\n\t });\n\t return result;\n\t }\n\t\n\t function getYOffset() {\n\t\n\t var offset = scroll.yOffset;\n\t\n\t if (isFunction(offset)) {\n\t offset = offset();\n\t } else if (isElement(offset)) {\n\t var elem = offset[0];\n\t var style = $window.getComputedStyle(elem);\n\t if (style.position !== 'fixed') {\n\t offset = 0;\n\t } else {\n\t offset = elem.getBoundingClientRect().bottom;\n\t }\n\t } else if (!isNumber(offset)) {\n\t offset = 0;\n\t }\n\t\n\t return offset;\n\t }\n\t\n\t function scrollTo(elem) {\n\t if (elem) {\n\t elem.scrollIntoView();\n\t\n\t var offset = getYOffset();\n\t\n\t if (offset) {\n\t // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.\n\t // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the\n\t // top of the viewport.\n\t //\n\t // IF the number of pixels from the top of `elem` to the end of the page's content is less\n\t // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some\n\t // way down the page.\n\t //\n\t // This is often the case for elements near the bottom of the page.\n\t //\n\t // In such cases we do not need to scroll the whole `offset` up, just the difference between\n\t // the top of the element and the offset, which is enough to align the top of `elem` at the\n\t // desired position.\n\t var elemTop = elem.getBoundingClientRect().top;\n\t $window.scrollBy(0, elemTop - offset);\n\t }\n\t } else {\n\t $window.scrollTo(0, 0);\n\t }\n\t }\n\t\n\t function scroll(hash) {\n\t hash = isString(hash) ? hash : $location.hash();\n\t var elm;\n\t\n\t // empty hash, scroll to the top of the page\n\t if (!hash) scrollTo(null);\n\t\n\t // element with given id\n\t else if ((elm = document.getElementById(hash))) scrollTo(elm);\n\t\n\t // first anchor with given name :-D\n\t else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);\n\t\n\t // no element and hash == 'top', scroll to the top of the page\n\t else if (hash === 'top') scrollTo(null);\n\t }\n\t\n\t // does not scroll when user clicks on anchor link that is currently on\n\t // (no url change, no $location.hash() change), browser native does scroll\n\t if (autoScrollingEnabled) {\n\t $rootScope.$watch(function autoScrollWatch() {return $location.hash();},\n\t function autoScrollWatchAction(newVal, oldVal) {\n\t // skip the initial scroll if $location.hash is empty\n\t if (newVal === oldVal && newVal === '') return;\n\t\n\t jqLiteDocumentLoaded(function() {\n\t $rootScope.$evalAsync(scroll);\n\t });\n\t });\n\t }\n\t\n\t return scroll;\n\t }];\n\t}\n\t\n\tvar $animateMinErr = minErr('$animate');\n\tvar ELEMENT_NODE = 1;\n\tvar NG_ANIMATE_CLASSNAME = 'ng-animate';\n\t\n\tfunction mergeClasses(a,b) {\n\t if (!a && !b) return '';\n\t if (!a) return b;\n\t if (!b) return a;\n\t if (isArray(a)) a = a.join(' ');\n\t if (isArray(b)) b = b.join(' ');\n\t return a + ' ' + b;\n\t}\n\t\n\tfunction extractElementNode(element) {\n\t for (var i = 0; i < element.length; i++) {\n\t var elm = element[i];\n\t if (elm.nodeType === ELEMENT_NODE) {\n\t return elm;\n\t }\n\t }\n\t}\n\t\n\tfunction splitClasses(classes) {\n\t if (isString(classes)) {\n\t classes = classes.split(' ');\n\t }\n\t\n\t // Use createMap() to prevent class assumptions involving property names in\n\t // Object.prototype\n\t var obj = createMap();\n\t forEach(classes, function(klass) {\n\t // sometimes the split leaves empty string values\n\t // incase extra spaces were applied to the options\n\t if (klass.length) {\n\t obj[klass] = true;\n\t }\n\t });\n\t return obj;\n\t}\n\t\n\t// if any other type of options value besides an Object value is\n\t// passed into the $animate.method() animation then this helper code\n\t// will be run which will ignore it. While this patch is not the\n\t// greatest solution to this, a lot of existing plugins depend on\n\t// $animate to either call the callback (< 1.2) or return a promise\n\t// that can be changed. This helper function ensures that the options\n\t// are wiped clean incase a callback function is provided.\n\tfunction prepareAnimateOptions(options) {\n\t return isObject(options)\n\t ? options\n\t : {};\n\t}\n\t\n\tvar $$CoreAnimateJsProvider = function() {\n\t this.$get = noop;\n\t};\n\t\n\t// this is prefixed with Core since it conflicts with\n\t// the animateQueueProvider defined in ngAnimate/animateQueue.js\n\tvar $$CoreAnimateQueueProvider = function() {\n\t var postDigestQueue = new HashMap();\n\t var postDigestElements = [];\n\t\n\t this.$get = ['$$AnimateRunner', '$rootScope',\n\t function($$AnimateRunner, $rootScope) {\n\t return {\n\t enabled: noop,\n\t on: noop,\n\t off: noop,\n\t pin: noop,\n\t\n\t push: function(element, event, options, domOperation) {\n\t domOperation && domOperation();\n\t\n\t options = options || {};\n\t options.from && element.css(options.from);\n\t options.to && element.css(options.to);\n\t\n\t if (options.addClass || options.removeClass) {\n\t addRemoveClassesPostDigest(element, options.addClass, options.removeClass);\n\t }\n\t\n\t var runner = new $$AnimateRunner(); // jshint ignore:line\n\t\n\t // since there are no animations to run the runner needs to be\n\t // notified that the animation call is complete.\n\t runner.complete();\n\t return runner;\n\t }\n\t };\n\t\n\t\n\t function updateData(data, classes, value) {\n\t var changed = false;\n\t if (classes) {\n\t classes = isString(classes) ? classes.split(' ') :\n\t isArray(classes) ? classes : [];\n\t forEach(classes, function(className) {\n\t if (className) {\n\t changed = true;\n\t data[className] = value;\n\t }\n\t });\n\t }\n\t return changed;\n\t }\n\t\n\t function handleCSSClassChanges() {\n\t forEach(postDigestElements, function(element) {\n\t var data = postDigestQueue.get(element);\n\t if (data) {\n\t var existing = splitClasses(element.attr('class'));\n\t var toAdd = '';\n\t var toRemove = '';\n\t forEach(data, function(status, className) {\n\t var hasClass = !!existing[className];\n\t if (status !== hasClass) {\n\t if (status) {\n\t toAdd += (toAdd.length ? ' ' : '') + className;\n\t } else {\n\t toRemove += (toRemove.length ? ' ' : '') + className;\n\t }\n\t }\n\t });\n\t\n\t forEach(element, function(elm) {\n\t toAdd && jqLiteAddClass(elm, toAdd);\n\t toRemove && jqLiteRemoveClass(elm, toRemove);\n\t });\n\t postDigestQueue.remove(element);\n\t }\n\t });\n\t postDigestElements.length = 0;\n\t }\n\t\n\t\n\t function addRemoveClassesPostDigest(element, add, remove) {\n\t var data = postDigestQueue.get(element) || {};\n\t\n\t var classesAdded = updateData(data, add, true);\n\t var classesRemoved = updateData(data, remove, false);\n\t\n\t if (classesAdded || classesRemoved) {\n\t\n\t postDigestQueue.put(element, data);\n\t postDigestElements.push(element);\n\t\n\t if (postDigestElements.length === 1) {\n\t $rootScope.$$postDigest(handleCSSClassChanges);\n\t }\n\t }\n\t }\n\t }];\n\t};\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $animateProvider\n\t *\n\t * @description\n\t * Default implementation of $animate that doesn't perform any animations, instead just\n\t * synchronously performs DOM updates and resolves the returned runner promise.\n\t *\n\t * In order to enable animations the `ngAnimate` module has to be loaded.\n\t *\n\t * To see the functional implementation check out `src/ngAnimate/animate.js`.\n\t */\n\tvar $AnimateProvider = ['$provide', function($provide) {\n\t var provider = this;\n\t\n\t this.$$registeredAnimations = Object.create(null);\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animateProvider#register\n\t *\n\t * @description\n\t * Registers a new injectable animation factory function. The factory function produces the\n\t * animation object which contains callback functions for each event that is expected to be\n\t * animated.\n\t *\n\t * * `eventFn`: `function(element, ... , doneFunction, options)`\n\t * The element to animate, the `doneFunction` and the options fed into the animation. Depending\n\t * on the type of animation additional arguments will be injected into the animation function. The\n\t * list below explains the function signatures for the different animation methods:\n\t *\n\t * - setClass: function(element, addedClasses, removedClasses, doneFunction, options)\n\t * - addClass: function(element, addedClasses, doneFunction, options)\n\t * - removeClass: function(element, removedClasses, doneFunction, options)\n\t * - enter, leave, move: function(element, doneFunction, options)\n\t * - animate: function(element, fromStyles, toStyles, doneFunction, options)\n\t *\n\t * Make sure to trigger the `doneFunction` once the animation is fully complete.\n\t *\n\t * ```js\n\t * return {\n\t * //enter, leave, move signature\n\t * eventFn : function(element, done, options) {\n\t * //code to run the animation\n\t * //once complete, then run done()\n\t * return function endFunction(wasCancelled) {\n\t * //code to cancel the animation\n\t * }\n\t * }\n\t * }\n\t * ```\n\t *\n\t * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).\n\t * @param {Function} factory The factory function that will be executed to return the animation\n\t * object.\n\t */\n\t this.register = function(name, factory) {\n\t if (name && name.charAt(0) !== '.') {\n\t throw $animateMinErr('notcsel', \"Expecting class selector starting with '.' got '{0}'.\", name);\n\t }\n\t\n\t var key = name + '-animation';\n\t provider.$$registeredAnimations[name.substr(1)] = key;\n\t $provide.factory(key, factory);\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animateProvider#classNameFilter\n\t *\n\t * @description\n\t * Sets and/or returns the CSS class regular expression that is checked when performing\n\t * an animation. Upon bootstrap the classNameFilter value is not set at all and will\n\t * therefore enable $animate to attempt to perform an animation on any element that is triggered.\n\t * When setting the `classNameFilter` value, animations will only be performed on elements\n\t * that successfully match the filter expression. This in turn can boost performance\n\t * for low-powered devices as well as applications containing a lot of structural operations.\n\t * @param {RegExp=} expression The className expression which will be checked against all animations\n\t * @return {RegExp} The current CSS className expression value. If null then there is no expression value\n\t */\n\t this.classNameFilter = function(expression) {\n\t if (arguments.length === 1) {\n\t this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;\n\t if (this.$$classNameFilter) {\n\t var reservedRegex = new RegExp(\"(\\\\s+|\\\\/)\" + NG_ANIMATE_CLASSNAME + \"(\\\\s+|\\\\/)\");\n\t if (reservedRegex.test(this.$$classNameFilter.toString())) {\n\t throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the \"{0}\" CSS class.', NG_ANIMATE_CLASSNAME);\n\t\n\t }\n\t }\n\t }\n\t return this.$$classNameFilter;\n\t };\n\t\n\t this.$get = ['$$animateQueue', function($$animateQueue) {\n\t function domInsert(element, parentElement, afterElement) {\n\t // if for some reason the previous element was removed\n\t // from the dom sometime before this code runs then let's\n\t // just stick to using the parent element as the anchor\n\t if (afterElement) {\n\t var afterNode = extractElementNode(afterElement);\n\t if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {\n\t afterElement = null;\n\t }\n\t }\n\t afterElement ? afterElement.after(element) : parentElement.prepend(element);\n\t }\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $animate\n\t * @description The $animate service exposes a series of DOM utility methods that provide support\n\t * for animation hooks. The default behavior is the application of DOM operations, however,\n\t * when an animation is detected (and animations are enabled), $animate will do the heavy lifting\n\t * to ensure that animation runs with the triggered DOM operation.\n\t *\n\t * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't\n\t * included and only when it is active then the animation hooks that `$animate` triggers will be\n\t * functional. Once active then all structural `ng-` directives will trigger animations as they perform\n\t * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,\n\t * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.\n\t *\n\t * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.\n\t *\n\t * To learn more about enabling animation support, click here to visit the\n\t * {@link ngAnimate ngAnimate module page}.\n\t */\n\t return {\n\t // we don't call it directly since non-existant arguments may\n\t // be interpreted as null within the sub enabled function\n\t\n\t /**\n\t *\n\t * @ngdoc method\n\t * @name $animate#on\n\t * @kind function\n\t * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)\n\t * has fired on the given element or among any of its children. Once the listener is fired, the provided callback\n\t * is fired with the following params:\n\t *\n\t * ```js\n\t * $animate.on('enter', container,\n\t * function callback(element, phase) {\n\t * // cool we detected an enter animation within the container\n\t * }\n\t * );\n\t * ```\n\t *\n\t * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)\n\t * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself\n\t * as well as among its children\n\t * @param {Function} callback the callback function that will be fired when the listener is triggered\n\t *\n\t * The arguments present in the callback function are:\n\t * * `element` - The captured DOM element that the animation was fired on.\n\t * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).\n\t */\n\t on: $$animateQueue.on,\n\t\n\t /**\n\t *\n\t * @ngdoc method\n\t * @name $animate#off\n\t * @kind function\n\t * @description Deregisters an event listener based on the event which has been associated with the provided element. This method\n\t * can be used in three different ways depending on the arguments:\n\t *\n\t * ```js\n\t * // remove all the animation event listeners listening for `enter`\n\t * $animate.off('enter');\n\t *\n\t * // remove listeners for all animation events from the container element\n\t * $animate.off(container);\n\t *\n\t * // remove all the animation event listeners listening for `enter` on the given element and its children\n\t * $animate.off('enter', container);\n\t *\n\t * // remove the event listener function provided by `callback` that is set\n\t * // to listen for `enter` on the given `container` as well as its children\n\t * $animate.off('enter', container, callback);\n\t * ```\n\t *\n\t * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,\n\t * addClass, removeClass, etc...), or the container element. If it is the element, all other\n\t * arguments are ignored.\n\t * @param {DOMElement=} container the container element the event listener was placed on\n\t * @param {Function=} callback the callback function that was registered as the listener\n\t */\n\t off: $$animateQueue.off,\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#pin\n\t * @kind function\n\t * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists\n\t * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the\n\t * element despite being outside the realm of the application or within another application. Say for example if the application\n\t * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated\n\t * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind\n\t * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.\n\t *\n\t * Note that this feature is only active when the `ngAnimate` module is used.\n\t *\n\t * @param {DOMElement} element the external element that will be pinned\n\t * @param {DOMElement} parentElement the host parent element that will be associated with the external element\n\t */\n\t pin: $$animateQueue.pin,\n\t\n\t /**\n\t *\n\t * @ngdoc method\n\t * @name $animate#enabled\n\t * @kind function\n\t * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This\n\t * function can be called in four ways:\n\t *\n\t * ```js\n\t * // returns true or false\n\t * $animate.enabled();\n\t *\n\t * // changes the enabled state for all animations\n\t * $animate.enabled(false);\n\t * $animate.enabled(true);\n\t *\n\t * // returns true or false if animations are enabled for an element\n\t * $animate.enabled(element);\n\t *\n\t * // changes the enabled state for an element and its children\n\t * $animate.enabled(element, true);\n\t * $animate.enabled(element, false);\n\t * ```\n\t *\n\t * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state\n\t * @param {boolean=} enabled whether or not the animations will be enabled for the element\n\t *\n\t * @return {boolean} whether or not animations are enabled\n\t */\n\t enabled: $$animateQueue.enabled,\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#cancel\n\t * @kind function\n\t * @description Cancels the provided animation.\n\t *\n\t * @param {Promise} animationPromise The animation promise that is returned when an animation is started.\n\t */\n\t cancel: function(runner) {\n\t runner.end && runner.end();\n\t },\n\t\n\t /**\n\t *\n\t * @ngdoc method\n\t * @name $animate#enter\n\t * @kind function\n\t * @description Inserts the element into the DOM either after the `after` element (if provided) or\n\t * as the first child within the `parent` element and then triggers an animation.\n\t * A promise is returned that will be resolved during the next digest once the animation\n\t * has completed.\n\t *\n\t * @param {DOMElement} element the element which will be inserted into the DOM\n\t * @param {DOMElement} parent the parent element which will append the element as\n\t * a child (so long as the after element is not present)\n\t * @param {DOMElement=} after the sibling element after which the element will be appended\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t enter: function(element, parent, after, options) {\n\t parent = parent && jqLite(parent);\n\t after = after && jqLite(after);\n\t parent = parent || after.parent();\n\t domInsert(element, parent, after);\n\t return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));\n\t },\n\t\n\t /**\n\t *\n\t * @ngdoc method\n\t * @name $animate#move\n\t * @kind function\n\t * @description Inserts (moves) the element into its new position in the DOM either after\n\t * the `after` element (if provided) or as the first child within the `parent` element\n\t * and then triggers an animation. A promise is returned that will be resolved\n\t * during the next digest once the animation has completed.\n\t *\n\t * @param {DOMElement} element the element which will be moved into the new DOM position\n\t * @param {DOMElement} parent the parent element which will append the element as\n\t * a child (so long as the after element is not present)\n\t * @param {DOMElement=} after the sibling element after which the element will be appended\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t move: function(element, parent, after, options) {\n\t parent = parent && jqLite(parent);\n\t after = after && jqLite(after);\n\t parent = parent || after.parent();\n\t domInsert(element, parent, after);\n\t return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#leave\n\t * @kind function\n\t * @description Triggers an animation and then removes the element from the DOM.\n\t * When the function is called a promise is returned that will be resolved during the next\n\t * digest once the animation has completed.\n\t *\n\t * @param {DOMElement} element the element which will be removed from the DOM\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t leave: function(element, options) {\n\t return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {\n\t element.remove();\n\t });\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#addClass\n\t * @kind function\n\t *\n\t * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon\n\t * execution, the addClass operation will only be handled after the next digest and it will not trigger an\n\t * animation if element already contains the CSS class or if the class is removed at a later step.\n\t * Note that class-based animations are treated differently compared to structural animations\n\t * (like enter, move and leave) since the CSS classes may be added/removed at different points\n\t * depending if CSS or JavaScript animations are used.\n\t *\n\t * @param {DOMElement} element the element which the CSS classes will be applied to\n\t * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t addClass: function(element, className, options) {\n\t options = prepareAnimateOptions(options);\n\t options.addClass = mergeClasses(options.addclass, className);\n\t return $$animateQueue.push(element, 'addClass', options);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#removeClass\n\t * @kind function\n\t *\n\t * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon\n\t * execution, the removeClass operation will only be handled after the next digest and it will not trigger an\n\t * animation if element does not contain the CSS class or if the class is added at a later step.\n\t * Note that class-based animations are treated differently compared to structural animations\n\t * (like enter, move and leave) since the CSS classes may be added/removed at different points\n\t * depending if CSS or JavaScript animations are used.\n\t *\n\t * @param {DOMElement} element the element which the CSS classes will be applied to\n\t * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t removeClass: function(element, className, options) {\n\t options = prepareAnimateOptions(options);\n\t options.removeClass = mergeClasses(options.removeClass, className);\n\t return $$animateQueue.push(element, 'removeClass', options);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#setClass\n\t * @kind function\n\t *\n\t * @description Performs both the addition and removal of a CSS classes on an element and (during the process)\n\t * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and\n\t * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has\n\t * passed. Note that class-based animations are treated differently compared to structural animations\n\t * (like enter, move and leave) since the CSS classes may be added/removed at different points\n\t * depending if CSS or JavaScript animations are used.\n\t *\n\t * @param {DOMElement} element the element which the CSS classes will be applied to\n\t * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)\n\t * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t setClass: function(element, add, remove, options) {\n\t options = prepareAnimateOptions(options);\n\t options.addClass = mergeClasses(options.addClass, add);\n\t options.removeClass = mergeClasses(options.removeClass, remove);\n\t return $$animateQueue.push(element, 'setClass', options);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $animate#animate\n\t * @kind function\n\t *\n\t * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.\n\t * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take\n\t * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and\n\t * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding\n\t * style in `to`, the style in `from` is applied immediately, and no animation is run.\n\t * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`\n\t * method (or as part of the `options` parameter):\n\t *\n\t * ```js\n\t * ngModule.animation('.my-inline-animation', function() {\n\t * return {\n\t * animate : function(element, from, to, done, options) {\n\t * //animation\n\t * done();\n\t * }\n\t * }\n\t * });\n\t * ```\n\t *\n\t * @param {DOMElement} element the element which the CSS styles will be applied to\n\t * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.\n\t * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.\n\t * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If\n\t * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.\n\t * (Note that if no animation is detected then this value will not be applied to the element.)\n\t * @param {object=} options an optional collection of options/styles that will be applied to the element.\n\t * The object can have the following properties:\n\t *\n\t * - **addClass** - `{string}` - space-separated CSS classes to add to element\n\t * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`\n\t * - **removeClass** - `{string}` - space-separated CSS classes to remove from element\n\t * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`\n\t *\n\t * @return {Promise} the animation callback promise\n\t */\n\t animate: function(element, from, to, className, options) {\n\t options = prepareAnimateOptions(options);\n\t options.from = options.from ? extend(options.from, from) : from;\n\t options.to = options.to ? extend(options.to, to) : to;\n\t\n\t className = className || 'ng-inline-animate';\n\t options.tempClasses = mergeClasses(options.tempClasses, className);\n\t return $$animateQueue.push(element, 'animate', options);\n\t }\n\t };\n\t }];\n\t}];\n\t\n\tvar $$AnimateAsyncRunFactoryProvider = function() {\n\t this.$get = ['$$rAF', function($$rAF) {\n\t var waitQueue = [];\n\t\n\t function waitForTick(fn) {\n\t waitQueue.push(fn);\n\t if (waitQueue.length > 1) return;\n\t $$rAF(function() {\n\t for (var i = 0; i < waitQueue.length; i++) {\n\t waitQueue[i]();\n\t }\n\t waitQueue = [];\n\t });\n\t }\n\t\n\t return function() {\n\t var passed = false;\n\t waitForTick(function() {\n\t passed = true;\n\t });\n\t return function(callback) {\n\t passed ? callback() : waitForTick(callback);\n\t };\n\t };\n\t }];\n\t};\n\t\n\tvar $$AnimateRunnerFactoryProvider = function() {\n\t this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',\n\t function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {\n\t\n\t var INITIAL_STATE = 0;\n\t var DONE_PENDING_STATE = 1;\n\t var DONE_COMPLETE_STATE = 2;\n\t\n\t AnimateRunner.chain = function(chain, callback) {\n\t var index = 0;\n\t\n\t next();\n\t function next() {\n\t if (index === chain.length) {\n\t callback(true);\n\t return;\n\t }\n\t\n\t chain[index](function(response) {\n\t if (response === false) {\n\t callback(false);\n\t return;\n\t }\n\t index++;\n\t next();\n\t });\n\t }\n\t };\n\t\n\t AnimateRunner.all = function(runners, callback) {\n\t var count = 0;\n\t var status = true;\n\t forEach(runners, function(runner) {\n\t runner.done(onProgress);\n\t });\n\t\n\t function onProgress(response) {\n\t status = status && response;\n\t if (++count === runners.length) {\n\t callback(status);\n\t }\n\t }\n\t };\n\t\n\t function AnimateRunner(host) {\n\t this.setHost(host);\n\t\n\t var rafTick = $$animateAsyncRun();\n\t var timeoutTick = function(fn) {\n\t $timeout(fn, 0, false);\n\t };\n\t\n\t this._doneCallbacks = [];\n\t this._tick = function(fn) {\n\t var doc = $document[0];\n\t\n\t // the document may not be ready or attached\n\t // to the module for some internal tests\n\t if (doc && doc.hidden) {\n\t timeoutTick(fn);\n\t } else {\n\t rafTick(fn);\n\t }\n\t };\n\t this._state = 0;\n\t }\n\t\n\t AnimateRunner.prototype = {\n\t setHost: function(host) {\n\t this.host = host || {};\n\t },\n\t\n\t done: function(fn) {\n\t if (this._state === DONE_COMPLETE_STATE) {\n\t fn();\n\t } else {\n\t this._doneCallbacks.push(fn);\n\t }\n\t },\n\t\n\t progress: noop,\n\t\n\t getPromise: function() {\n\t if (!this.promise) {\n\t var self = this;\n\t this.promise = $q(function(resolve, reject) {\n\t self.done(function(status) {\n\t status === false ? reject() : resolve();\n\t });\n\t });\n\t }\n\t return this.promise;\n\t },\n\t\n\t then: function(resolveHandler, rejectHandler) {\n\t return this.getPromise().then(resolveHandler, rejectHandler);\n\t },\n\t\n\t 'catch': function(handler) {\n\t return this.getPromise()['catch'](handler);\n\t },\n\t\n\t 'finally': function(handler) {\n\t return this.getPromise()['finally'](handler);\n\t },\n\t\n\t pause: function() {\n\t if (this.host.pause) {\n\t this.host.pause();\n\t }\n\t },\n\t\n\t resume: function() {\n\t if (this.host.resume) {\n\t this.host.resume();\n\t }\n\t },\n\t\n\t end: function() {\n\t if (this.host.end) {\n\t this.host.end();\n\t }\n\t this._resolve(true);\n\t },\n\t\n\t cancel: function() {\n\t if (this.host.cancel) {\n\t this.host.cancel();\n\t }\n\t this._resolve(false);\n\t },\n\t\n\t complete: function(response) {\n\t var self = this;\n\t if (self._state === INITIAL_STATE) {\n\t self._state = DONE_PENDING_STATE;\n\t self._tick(function() {\n\t self._resolve(response);\n\t });\n\t }\n\t },\n\t\n\t _resolve: function(response) {\n\t if (this._state !== DONE_COMPLETE_STATE) {\n\t forEach(this._doneCallbacks, function(fn) {\n\t fn(response);\n\t });\n\t this._doneCallbacks.length = 0;\n\t this._state = DONE_COMPLETE_STATE;\n\t }\n\t }\n\t };\n\t\n\t return AnimateRunner;\n\t }];\n\t};\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $animateCss\n\t * @kind object\n\t *\n\t * @description\n\t * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,\n\t * then the `$animateCss` service will actually perform animations.\n\t *\n\t * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.\n\t */\n\tvar $CoreAnimateCssProvider = function() {\n\t this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {\n\t\n\t return function(element, initialOptions) {\n\t // all of the animation functions should create\n\t // a copy of the options data, however, if a\n\t // parent service has already created a copy then\n\t // we should stick to using that\n\t var options = initialOptions || {};\n\t if (!options.$$prepared) {\n\t options = copy(options);\n\t }\n\t\n\t // there is no point in applying the styles since\n\t // there is no animation that goes on at all in\n\t // this version of $animateCss.\n\t if (options.cleanupStyles) {\n\t options.from = options.to = null;\n\t }\n\t\n\t if (options.from) {\n\t element.css(options.from);\n\t options.from = null;\n\t }\n\t\n\t /* jshint newcap: false */\n\t var closed, runner = new $$AnimateRunner();\n\t return {\n\t start: run,\n\t end: run\n\t };\n\t\n\t function run() {\n\t $$rAF(function() {\n\t applyAnimationContents();\n\t if (!closed) {\n\t runner.complete();\n\t }\n\t closed = true;\n\t });\n\t return runner;\n\t }\n\t\n\t function applyAnimationContents() {\n\t if (options.addClass) {\n\t element.addClass(options.addClass);\n\t options.addClass = null;\n\t }\n\t if (options.removeClass) {\n\t element.removeClass(options.removeClass);\n\t options.removeClass = null;\n\t }\n\t if (options.to) {\n\t element.css(options.to);\n\t options.to = null;\n\t }\n\t }\n\t };\n\t }];\n\t};\n\t\n\t/* global stripHash: true */\n\t\n\t/**\n\t * ! This is a private undocumented service !\n\t *\n\t * @name $browser\n\t * @requires $log\n\t * @description\n\t * This object has two goals:\n\t *\n\t * - hide all the global state in the browser caused by the window object\n\t * - abstract away all the browser specific features and inconsistencies\n\t *\n\t * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`\n\t * service, which can be used for convenient testing of the application without the interaction with\n\t * the real browser apis.\n\t */\n\t/**\n\t * @param {object} window The global window object.\n\t * @param {object} document jQuery wrapped document.\n\t * @param {object} $log window.console or an object with the same interface.\n\t * @param {object} $sniffer $sniffer service\n\t */\n\tfunction Browser(window, document, $log, $sniffer) {\n\t var self = this,\n\t location = window.location,\n\t history = window.history,\n\t setTimeout = window.setTimeout,\n\t clearTimeout = window.clearTimeout,\n\t pendingDeferIds = {};\n\t\n\t self.isMock = false;\n\t\n\t var outstandingRequestCount = 0;\n\t var outstandingRequestCallbacks = [];\n\t\n\t // TODO(vojta): remove this temporary api\n\t self.$$completeOutstandingRequest = completeOutstandingRequest;\n\t self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };\n\t\n\t /**\n\t * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`\n\t * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.\n\t */\n\t function completeOutstandingRequest(fn) {\n\t try {\n\t fn.apply(null, sliceArgs(arguments, 1));\n\t } finally {\n\t outstandingRequestCount--;\n\t if (outstandingRequestCount === 0) {\n\t while (outstandingRequestCallbacks.length) {\n\t try {\n\t outstandingRequestCallbacks.pop()();\n\t } catch (e) {\n\t $log.error(e);\n\t }\n\t }\n\t }\n\t }\n\t }\n\t\n\t function getHash(url) {\n\t var index = url.indexOf('#');\n\t return index === -1 ? '' : url.substr(index);\n\t }\n\t\n\t /**\n\t * @private\n\t * Note: this method is used only by scenario runner\n\t * TODO(vojta): prefix this method with $$ ?\n\t * @param {function()} callback Function that will be called when no outstanding request\n\t */\n\t self.notifyWhenNoOutstandingRequests = function(callback) {\n\t if (outstandingRequestCount === 0) {\n\t callback();\n\t } else {\n\t outstandingRequestCallbacks.push(callback);\n\t }\n\t };\n\t\n\t //////////////////////////////////////////////////////////////\n\t // URL API\n\t //////////////////////////////////////////////////////////////\n\t\n\t var cachedState, lastHistoryState,\n\t lastBrowserUrl = location.href,\n\t baseElement = document.find('base'),\n\t pendingLocation = null,\n\t getCurrentState = !$sniffer.history ? noop : function getCurrentState() {\n\t try {\n\t return history.state;\n\t } catch (e) {\n\t // MSIE can reportedly throw when there is no state (UNCONFIRMED).\n\t }\n\t };\n\t\n\t cacheState();\n\t lastHistoryState = cachedState;\n\t\n\t /**\n\t * @name $browser#url\n\t *\n\t * @description\n\t * GETTER:\n\t * Without any argument, this method just returns current value of location.href.\n\t *\n\t * SETTER:\n\t * With at least one argument, this method sets url to new value.\n\t * If html5 history api supported, pushState/replaceState is used, otherwise\n\t * location.href/location.replace is used.\n\t * Returns its own instance to allow chaining\n\t *\n\t * NOTE: this api is intended for use only by the $location service. Please use the\n\t * {@link ng.$location $location service} to change url.\n\t *\n\t * @param {string} url New url (when used as setter)\n\t * @param {boolean=} replace Should new url replace current history record?\n\t * @param {object=} state object to use with pushState/replaceState\n\t */\n\t self.url = function(url, replace, state) {\n\t // In modern browsers `history.state` is `null` by default; treating it separately\n\t // from `undefined` would cause `$browser.url('/foo')` to change `history.state`\n\t // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.\n\t if (isUndefined(state)) {\n\t state = null;\n\t }\n\t\n\t // Android Browser BFCache causes location, history reference to become stale.\n\t if (location !== window.location) location = window.location;\n\t if (history !== window.history) history = window.history;\n\t\n\t // setter\n\t if (url) {\n\t var sameState = lastHistoryState === state;\n\t\n\t // Don't change anything if previous and current URLs and states match. This also prevents\n\t // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.\n\t // See https://github.com/angular/angular.js/commit/ffb2701\n\t if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {\n\t return self;\n\t }\n\t var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);\n\t lastBrowserUrl = url;\n\t lastHistoryState = state;\n\t // Don't use history API if only the hash changed\n\t // due to a bug in IE10/IE11 which leads\n\t // to not firing a `hashchange` nor `popstate` event\n\t // in some cases (see #9143).\n\t if ($sniffer.history && (!sameBase || !sameState)) {\n\t history[replace ? 'replaceState' : 'pushState'](state, '', url);\n\t cacheState();\n\t // Do the assignment again so that those two variables are referentially identical.\n\t lastHistoryState = cachedState;\n\t } else {\n\t if (!sameBase) {\n\t pendingLocation = url;\n\t }\n\t if (replace) {\n\t location.replace(url);\n\t } else if (!sameBase) {\n\t location.href = url;\n\t } else {\n\t location.hash = getHash(url);\n\t }\n\t if (location.href !== url) {\n\t pendingLocation = url;\n\t }\n\t }\n\t if (pendingLocation) {\n\t pendingLocation = url;\n\t }\n\t return self;\n\t // getter\n\t } else {\n\t // - pendingLocation is needed as browsers don't allow to read out\n\t // the new location.href if a reload happened or if there is a bug like in iOS 9 (see\n\t // https://openradar.appspot.com/22186109).\n\t // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172\n\t return pendingLocation || location.href.replace(/%27/g,\"'\");\n\t }\n\t };\n\t\n\t /**\n\t * @name $browser#state\n\t *\n\t * @description\n\t * This method is a getter.\n\t *\n\t * Return history.state or null if history.state is undefined.\n\t *\n\t * @returns {object} state\n\t */\n\t self.state = function() {\n\t return cachedState;\n\t };\n\t\n\t var urlChangeListeners = [],\n\t urlChangeInit = false;\n\t\n\t function cacheStateAndFireUrlChange() {\n\t pendingLocation = null;\n\t cacheState();\n\t fireUrlChange();\n\t }\n\t\n\t // This variable should be used *only* inside the cacheState function.\n\t var lastCachedState = null;\n\t function cacheState() {\n\t // This should be the only place in $browser where `history.state` is read.\n\t cachedState = getCurrentState();\n\t cachedState = isUndefined(cachedState) ? null : cachedState;\n\t\n\t // Prevent callbacks fo fire twice if both hashchange & popstate were fired.\n\t if (equals(cachedState, lastCachedState)) {\n\t cachedState = lastCachedState;\n\t }\n\t lastCachedState = cachedState;\n\t }\n\t\n\t function fireUrlChange() {\n\t if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {\n\t return;\n\t }\n\t\n\t lastBrowserUrl = self.url();\n\t lastHistoryState = cachedState;\n\t forEach(urlChangeListeners, function(listener) {\n\t listener(self.url(), cachedState);\n\t });\n\t }\n\t\n\t /**\n\t * @name $browser#onUrlChange\n\t *\n\t * @description\n\t * Register callback function that will be called, when url changes.\n\t *\n\t * It's only called when the url is changed from outside of angular:\n\t * - user types different url into address bar\n\t * - user clicks on history (forward/back) button\n\t * - user clicks on a link\n\t *\n\t * It's not called when url is changed by $browser.url() method\n\t *\n\t * The listener gets called with new url as parameter.\n\t *\n\t * NOTE: this api is intended for use only by the $location service. Please use the\n\t * {@link ng.$location $location service} to monitor url changes in angular apps.\n\t *\n\t * @param {function(string)} listener Listener function to be called when url changes.\n\t * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.\n\t */\n\t self.onUrlChange = function(callback) {\n\t // TODO(vojta): refactor to use node's syntax for events\n\t if (!urlChangeInit) {\n\t // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)\n\t // don't fire popstate when user change the address bar and don't fire hashchange when url\n\t // changed by push/replaceState\n\t\n\t // html5 history api - popstate event\n\t if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);\n\t // hashchange event\n\t jqLite(window).on('hashchange', cacheStateAndFireUrlChange);\n\t\n\t urlChangeInit = true;\n\t }\n\t\n\t urlChangeListeners.push(callback);\n\t return callback;\n\t };\n\t\n\t /**\n\t * @private\n\t * Remove popstate and hashchange handler from window.\n\t *\n\t * NOTE: this api is intended for use only by $rootScope.\n\t */\n\t self.$$applicationDestroyed = function() {\n\t jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);\n\t };\n\t\n\t /**\n\t * Checks whether the url has changed outside of Angular.\n\t * Needs to be exported to be able to check for changes that have been done in sync,\n\t * as hashchange/popstate events fire in async.\n\t */\n\t self.$$checkUrlChange = fireUrlChange;\n\t\n\t //////////////////////////////////////////////////////////////\n\t // Misc API\n\t //////////////////////////////////////////////////////////////\n\t\n\t /**\n\t * @name $browser#baseHref\n\t *\n\t * @description\n\t * Returns current \n\t * (always relative - without domain)\n\t *\n\t * @returns {string} The current base href\n\t */\n\t self.baseHref = function() {\n\t var href = baseElement.attr('href');\n\t return href ? href.replace(/^(https?\\:)?\\/\\/[^\\/]*/, '') : '';\n\t };\n\t\n\t /**\n\t * @name $browser#defer\n\t * @param {function()} fn A function, who's execution should be deferred.\n\t * @param {number=} [delay=0] of milliseconds to defer the function execution.\n\t * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.\n\t *\n\t * @description\n\t * Executes a fn asynchronously via `setTimeout(fn, delay)`.\n\t *\n\t * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using\n\t * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed\n\t * via `$browser.defer.flush()`.\n\t *\n\t */\n\t self.defer = function(fn, delay) {\n\t var timeoutId;\n\t outstandingRequestCount++;\n\t timeoutId = setTimeout(function() {\n\t delete pendingDeferIds[timeoutId];\n\t completeOutstandingRequest(fn);\n\t }, delay || 0);\n\t pendingDeferIds[timeoutId] = true;\n\t return timeoutId;\n\t };\n\t\n\t\n\t /**\n\t * @name $browser#defer.cancel\n\t *\n\t * @description\n\t * Cancels a deferred task identified with `deferId`.\n\t *\n\t * @param {*} deferId Token returned by the `$browser.defer` function.\n\t * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully\n\t * canceled.\n\t */\n\t self.defer.cancel = function(deferId) {\n\t if (pendingDeferIds[deferId]) {\n\t delete pendingDeferIds[deferId];\n\t clearTimeout(deferId);\n\t completeOutstandingRequest(noop);\n\t return true;\n\t }\n\t return false;\n\t };\n\t\n\t}\n\t\n\tfunction $BrowserProvider() {\n\t this.$get = ['$window', '$log', '$sniffer', '$document',\n\t function($window, $log, $sniffer, $document) {\n\t return new Browser($window, $document, $log, $sniffer);\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $cacheFactory\n\t *\n\t * @description\n\t * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to\n\t * them.\n\t *\n\t * ```js\n\t *\n\t * var cache = $cacheFactory('cacheId');\n\t * expect($cacheFactory.get('cacheId')).toBe(cache);\n\t * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();\n\t *\n\t * cache.put(\"key\", \"value\");\n\t * cache.put(\"another key\", \"another value\");\n\t *\n\t * // We've specified no options on creation\n\t * expect(cache.info()).toEqual({id: 'cacheId', size: 2});\n\t *\n\t * ```\n\t *\n\t *\n\t * @param {string} cacheId Name or id of the newly created cache.\n\t * @param {object=} options Options object that specifies the cache behavior. Properties:\n\t *\n\t * - `{number=}` `capacity` — turns the cache into LRU cache.\n\t *\n\t * @returns {object} Newly created cache object with the following set of methods:\n\t *\n\t * - `{object}` `info()` — Returns id, size, and options of cache.\n\t * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns\n\t * it.\n\t * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.\n\t * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.\n\t * - `{void}` `removeAll()` — Removes all cached values.\n\t * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t \n\t \n\t\n\t

Cached Values

\n\t
\n\t \n\t : \n\t \n\t
\n\t\n\t

Cache Info

\n\t
\n\t \n\t : \n\t \n\t
\n\t
\n\t
\n\t \n\t angular.module('cacheExampleApp', []).\n\t controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {\n\t $scope.keys = [];\n\t $scope.cache = $cacheFactory('cacheId');\n\t $scope.put = function(key, value) {\n\t if (angular.isUndefined($scope.cache.get(key))) {\n\t $scope.keys.push(key);\n\t }\n\t $scope.cache.put(key, angular.isUndefined(value) ? null : value);\n\t };\n\t }]);\n\t \n\t \n\t p {\n\t margin: 10px 0 3px;\n\t }\n\t \n\t
\n\t */\n\tfunction $CacheFactoryProvider() {\n\t\n\t this.$get = function() {\n\t var caches = {};\n\t\n\t function cacheFactory(cacheId, options) {\n\t if (cacheId in caches) {\n\t throw minErr('$cacheFactory')('iid', \"CacheId '{0}' is already taken!\", cacheId);\n\t }\n\t\n\t var size = 0,\n\t stats = extend({}, options, {id: cacheId}),\n\t data = createMap(),\n\t capacity = (options && options.capacity) || Number.MAX_VALUE,\n\t lruHash = createMap(),\n\t freshEnd = null,\n\t staleEnd = null;\n\t\n\t /**\n\t * @ngdoc type\n\t * @name $cacheFactory.Cache\n\t *\n\t * @description\n\t * A cache object used to store and retrieve data, primarily used by\n\t * {@link $http $http} and the {@link ng.directive:script script} directive to cache\n\t * templates and other data.\n\t *\n\t * ```js\n\t * angular.module('superCache')\n\t * .factory('superCache', ['$cacheFactory', function($cacheFactory) {\n\t * return $cacheFactory('super-cache');\n\t * }]);\n\t * ```\n\t *\n\t * Example test:\n\t *\n\t * ```js\n\t * it('should behave like a cache', inject(function(superCache) {\n\t * superCache.put('key', 'value');\n\t * superCache.put('another key', 'another value');\n\t *\n\t * expect(superCache.info()).toEqual({\n\t * id: 'super-cache',\n\t * size: 2\n\t * });\n\t *\n\t * superCache.remove('another key');\n\t * expect(superCache.get('another key')).toBeUndefined();\n\t *\n\t * superCache.removeAll();\n\t * expect(superCache.info()).toEqual({\n\t * id: 'super-cache',\n\t * size: 0\n\t * });\n\t * }));\n\t * ```\n\t */\n\t return caches[cacheId] = {\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#put\n\t * @kind function\n\t *\n\t * @description\n\t * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be\n\t * retrieved later, and incrementing the size of the cache if the key was not already\n\t * present in the cache. If behaving like an LRU cache, it will also remove stale\n\t * entries from the set.\n\t *\n\t * It will not insert undefined values into the cache.\n\t *\n\t * @param {string} key the key under which the cached data is stored.\n\t * @param {*} value the value to store alongside the key. If it is undefined, the key\n\t * will not be stored.\n\t * @returns {*} the value stored.\n\t */\n\t put: function(key, value) {\n\t if (isUndefined(value)) return;\n\t if (capacity < Number.MAX_VALUE) {\n\t var lruEntry = lruHash[key] || (lruHash[key] = {key: key});\n\t\n\t refresh(lruEntry);\n\t }\n\t\n\t if (!(key in data)) size++;\n\t data[key] = value;\n\t\n\t if (size > capacity) {\n\t this.remove(staleEnd.key);\n\t }\n\t\n\t return value;\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#get\n\t * @kind function\n\t *\n\t * @description\n\t * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.\n\t *\n\t * @param {string} key the key of the data to be retrieved\n\t * @returns {*} the value stored.\n\t */\n\t get: function(key) {\n\t if (capacity < Number.MAX_VALUE) {\n\t var lruEntry = lruHash[key];\n\t\n\t if (!lruEntry) return;\n\t\n\t refresh(lruEntry);\n\t }\n\t\n\t return data[key];\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#remove\n\t * @kind function\n\t *\n\t * @description\n\t * Removes an entry from the {@link $cacheFactory.Cache Cache} object.\n\t *\n\t * @param {string} key the key of the entry to be removed\n\t */\n\t remove: function(key) {\n\t if (capacity < Number.MAX_VALUE) {\n\t var lruEntry = lruHash[key];\n\t\n\t if (!lruEntry) return;\n\t\n\t if (lruEntry == freshEnd) freshEnd = lruEntry.p;\n\t if (lruEntry == staleEnd) staleEnd = lruEntry.n;\n\t link(lruEntry.n,lruEntry.p);\n\t\n\t delete lruHash[key];\n\t }\n\t\n\t if (!(key in data)) return;\n\t\n\t delete data[key];\n\t size--;\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#removeAll\n\t * @kind function\n\t *\n\t * @description\n\t * Clears the cache object of any entries.\n\t */\n\t removeAll: function() {\n\t data = createMap();\n\t size = 0;\n\t lruHash = createMap();\n\t freshEnd = staleEnd = null;\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#destroy\n\t * @kind function\n\t *\n\t * @description\n\t * Destroys the {@link $cacheFactory.Cache Cache} object entirely,\n\t * removing it from the {@link $cacheFactory $cacheFactory} set.\n\t */\n\t destroy: function() {\n\t data = null;\n\t stats = null;\n\t lruHash = null;\n\t delete caches[cacheId];\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory.Cache#info\n\t * @kind function\n\t *\n\t * @description\n\t * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.\n\t *\n\t * @returns {object} an object with the following properties:\n\t *
    \n\t *
  • **id**: the id of the cache instance
  • \n\t *
  • **size**: the number of entries kept in the cache instance
  • \n\t *
  • **...**: any additional properties from the options object when creating the\n\t * cache.
  • \n\t *
\n\t */\n\t info: function() {\n\t return extend({}, stats, {size: size});\n\t }\n\t };\n\t\n\t\n\t /**\n\t * makes the `entry` the freshEnd of the LRU linked list\n\t */\n\t function refresh(entry) {\n\t if (entry != freshEnd) {\n\t if (!staleEnd) {\n\t staleEnd = entry;\n\t } else if (staleEnd == entry) {\n\t staleEnd = entry.n;\n\t }\n\t\n\t link(entry.n, entry.p);\n\t link(entry, freshEnd);\n\t freshEnd = entry;\n\t freshEnd.n = null;\n\t }\n\t }\n\t\n\t\n\t /**\n\t * bidirectionally links two entries of the LRU linked list\n\t */\n\t function link(nextEntry, prevEntry) {\n\t if (nextEntry != prevEntry) {\n\t if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify\n\t if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify\n\t }\n\t }\n\t }\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory#info\n\t *\n\t * @description\n\t * Get information about all the caches that have been created\n\t *\n\t * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`\n\t */\n\t cacheFactory.info = function() {\n\t var info = {};\n\t forEach(caches, function(cache, cacheId) {\n\t info[cacheId] = cache.info();\n\t });\n\t return info;\n\t };\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $cacheFactory#get\n\t *\n\t * @description\n\t * Get access to a cache object by the `cacheId` used when it was created.\n\t *\n\t * @param {string} cacheId Name or id of a cache to access.\n\t * @returns {object} Cache object identified by the cacheId or undefined if no such cache.\n\t */\n\t cacheFactory.get = function(cacheId) {\n\t return caches[cacheId];\n\t };\n\t\n\t\n\t return cacheFactory;\n\t };\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $templateCache\n\t *\n\t * @description\n\t * The first time a template is used, it is loaded in the template cache for quick retrieval. You\n\t * can load templates directly into the cache in a `script` tag, or by consuming the\n\t * `$templateCache` service directly.\n\t *\n\t * Adding via the `script` tag:\n\t *\n\t * ```html\n\t * \n\t * ```\n\t *\n\t * **Note:** the `script` tag containing the template does not need to be included in the `head` of\n\t * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,\n\t * element with ng-app attribute), otherwise the template will be ignored.\n\t *\n\t * Adding via the `$templateCache` service:\n\t *\n\t * ```js\n\t * var myApp = angular.module('myApp', []);\n\t * myApp.run(function($templateCache) {\n\t * $templateCache.put('templateId.html', 'This is the content of the template');\n\t * });\n\t * ```\n\t *\n\t * To retrieve the template later, simply use it in your HTML:\n\t * ```html\n\t *
\n\t * ```\n\t *\n\t * or get it via Javascript:\n\t * ```js\n\t * $templateCache.get('templateId.html')\n\t * ```\n\t *\n\t * See {@link ng.$cacheFactory $cacheFactory}.\n\t *\n\t */\n\tfunction $TemplateCacheProvider() {\n\t this.$get = ['$cacheFactory', function($cacheFactory) {\n\t return $cacheFactory('templates');\n\t }];\n\t}\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Any commits to this file should be reviewed with security in mind. *\n\t * Changes to this file can potentially create security vulnerabilities. *\n\t * An approval from 2 Core members with history of modifying *\n\t * this file is required. *\n\t * *\n\t * Does the change somehow allow for arbitrary javascript to be executed? *\n\t * Or allows for someone to change the prototype of built-in objects? *\n\t * Or gives undesired access to variables likes document or window? *\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\t/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!\n\t *\n\t * DOM-related variables:\n\t *\n\t * - \"node\" - DOM Node\n\t * - \"element\" - DOM Element or Node\n\t * - \"$node\" or \"$element\" - jqLite-wrapped node or element\n\t *\n\t *\n\t * Compiler related stuff:\n\t *\n\t * - \"linkFn\" - linking fn of a single directive\n\t * - \"nodeLinkFn\" - function that aggregates all linking fns for a particular node\n\t * - \"childLinkFn\" - function that aggregates all linking fns for child nodes of a particular node\n\t * - \"compositeLinkFn\" - function that aggregates all linking fns for a compilation root (nodeList)\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $compile\n\t * @kind function\n\t *\n\t * @description\n\t * Compiles an HTML string or DOM into a template and produces a template function, which\n\t * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.\n\t *\n\t * The compilation is a process of walking the DOM tree and matching DOM elements to\n\t * {@link ng.$compileProvider#directive directives}.\n\t *\n\t *
\n\t * **Note:** This document is an in-depth reference of all directive options.\n\t * For a gentle introduction to directives with examples of common use cases,\n\t * see the {@link guide/directive directive guide}.\n\t *
\n\t *\n\t * ## Comprehensive Directive API\n\t *\n\t * There are many different options for a directive.\n\t *\n\t * The difference resides in the return value of the factory function.\n\t * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}\n\t * that defines the directive properties, or just the `postLink` function (all other properties will have\n\t * the default values).\n\t *\n\t *
\n\t * **Best Practice:** It's recommended to use the \"directive definition object\" form.\n\t *
\n\t *\n\t * Here's an example directive declared with a Directive Definition Object:\n\t *\n\t * ```js\n\t * var myModule = angular.module(...);\n\t *\n\t * myModule.directive('directiveName', function factory(injectables) {\n\t * var directiveDefinitionObject = {\n\t * priority: 0,\n\t * template: '
', // or // function(tElement, tAttrs) { ... },\n\t * // or\n\t * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },\n\t * transclude: false,\n\t * restrict: 'A',\n\t * templateNamespace: 'html',\n\t * scope: false,\n\t * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },\n\t * controllerAs: 'stringIdentifier',\n\t * bindToController: false,\n\t * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],\n\t * compile: function compile(tElement, tAttrs, transclude) {\n\t * return {\n\t * pre: function preLink(scope, iElement, iAttrs, controller) { ... },\n\t * post: function postLink(scope, iElement, iAttrs, controller) { ... }\n\t * }\n\t * // or\n\t * // return function postLink( ... ) { ... }\n\t * },\n\t * // or\n\t * // link: {\n\t * // pre: function preLink(scope, iElement, iAttrs, controller) { ... },\n\t * // post: function postLink(scope, iElement, iAttrs, controller) { ... }\n\t * // }\n\t * // or\n\t * // link: function postLink( ... ) { ... }\n\t * };\n\t * return directiveDefinitionObject;\n\t * });\n\t * ```\n\t *\n\t *
\n\t * **Note:** Any unspecified options will use the default value. You can see the default values below.\n\t *
\n\t *\n\t * Therefore the above can be simplified as:\n\t *\n\t * ```js\n\t * var myModule = angular.module(...);\n\t *\n\t * myModule.directive('directiveName', function factory(injectables) {\n\t * var directiveDefinitionObject = {\n\t * link: function postLink(scope, iElement, iAttrs) { ... }\n\t * };\n\t * return directiveDefinitionObject;\n\t * // or\n\t * // return function postLink(scope, iElement, iAttrs) { ... }\n\t * });\n\t * ```\n\t *\n\t * ### Life-cycle hooks\n\t * Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the\n\t * directive:\n\t * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and\n\t * had their bindings initialized (and before the pre & post linking functions for the directives on\n\t * this element). This is a good place to put initialization code for your controller.\n\t * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The\n\t * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an\n\t * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a\n\t * component such as cloning the bound value to prevent accidental mutation of the outer value.\n\t * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on\n\t * changes. Any actions that you wish to take in response to the changes that you detect must be\n\t * invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook\n\t * could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not\n\t * be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;\n\t * if detecting changes, you must store the previous value(s) for comparison to the current values.\n\t * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing\n\t * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in\n\t * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent\n\t * components will have their `$onDestroy()` hook called before child components.\n\t * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link\n\t * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.\n\t * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since\n\t * they are waiting for their template to load asynchronously and their own compilation and linking has been\n\t * suspended until that occurs.\n\t *\n\t * #### Comparison with Angular 2 life-cycle hooks\n\t * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are\n\t * some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2:\n\t *\n\t * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.\n\t * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.\n\t * In Angular 2 you can only define hooks on the prototype of the Component class.\n\t * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to\n\t * `ngDoCheck` in Angular 2\n\t * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be\n\t * propagated throughout the application.\n\t * Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an\n\t * error or do nothing depending upon the state of `enableProdMode()`.\n\t *\n\t * #### Life-cycle hook examples\n\t *\n\t * This example shows how you can check for mutations to a Date object even though the identity of the object\n\t * has not changed.\n\t *\n\t * \n\t * \n\t * angular.module('do-check-module', [])\n\t * .component('app', {\n\t * template:\n\t * 'Month: ' +\n\t * 'Date: {{ $ctrl.date }}' +\n\t * '',\n\t * controller: function() {\n\t * this.date = new Date();\n\t * this.month = this.date.getMonth();\n\t * this.updateDate = function() {\n\t * this.date.setMonth(this.month);\n\t * };\n\t * }\n\t * })\n\t * .component('test', {\n\t * bindings: { date: '<' },\n\t * template:\n\t * '
{{ $ctrl.log | json }}
',\n\t * controller: function() {\n\t * var previousValue;\n\t * this.log = [];\n\t * this.$doCheck = function() {\n\t * var currentValue = this.date && this.date.valueOf();\n\t * if (previousValue !== currentValue) {\n\t * this.log.push('doCheck: date mutated: ' + this.date);\n\t * previousValue = currentValue;\n\t * }\n\t * };\n\t * }\n\t * });\n\t *
\n\t * \n\t * \n\t * \n\t *
\n\t *\n\t * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the\n\t * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large\n\t * arrays or objects can have a negative impact on your application performance)\n\t *\n\t * \n\t * \n\t *
\n\t * \n\t * \n\t *
{{ items }}
\n\t * \n\t *
\n\t *
\n\t * \n\t * angular.module('do-check-module', [])\n\t * .component('test', {\n\t * bindings: { items: '<' },\n\t * template:\n\t * '
{{ $ctrl.log | json }}
',\n\t * controller: function() {\n\t * this.log = [];\n\t *\n\t * this.$doCheck = function() {\n\t * if (this.items_ref !== this.items) {\n\t * this.log.push('doCheck: items changed');\n\t * this.items_ref = this.items;\n\t * }\n\t * if (!angular.equals(this.items_clone, this.items)) {\n\t * this.log.push('doCheck: items mutated');\n\t * this.items_clone = angular.copy(this.items);\n\t * }\n\t * };\n\t * }\n\t * });\n\t *
\n\t *
\n\t *\n\t *\n\t * ### Directive Definition Object\n\t *\n\t * The directive definition object provides instructions to the {@link ng.$compile\n\t * compiler}. The attributes are:\n\t *\n\t * #### `multiElement`\n\t * When this property is set to true, the HTML compiler will collect DOM nodes between\n\t * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them\n\t * together as the directive elements. It is recommended that this feature be used on directives\n\t * which are not strictly behavioral (such as {@link ngClick}), and which\n\t * do not manipulate or replace child nodes (such as {@link ngInclude}).\n\t *\n\t * #### `priority`\n\t * When there are multiple directives defined on a single DOM element, sometimes it\n\t * is necessary to specify the order in which the directives are applied. The `priority` is used\n\t * to sort the directives before their `compile` functions get called. Priority is defined as a\n\t * number. Directives with greater numerical `priority` are compiled first. Pre-link functions\n\t * are also run in priority order, but post-link functions are run in reverse order. The order\n\t * of directives with the same priority is undefined. The default priority is `0`.\n\t *\n\t * #### `terminal`\n\t * If set to true then the current `priority` will be the last set of directives\n\t * which will execute (any directives at the current priority will still execute\n\t * as the order of execution on same `priority` is undefined). Note that expressions\n\t * and other directives used in the directive's template will also be excluded from execution.\n\t *\n\t * #### `scope`\n\t * The scope property can be `true`, an object or a falsy value:\n\t *\n\t * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.\n\t *\n\t * * **`true`:** A new child scope that prototypically inherits from its parent will be created for\n\t * the directive's element. If multiple directives on the same element request a new scope,\n\t * only one new scope is created. The new scope rule does not apply for the root of the template\n\t * since the root of the template always gets a new scope.\n\t *\n\t * * **`{...}` (an object hash):** A new \"isolate\" scope is created for the directive's element. The\n\t * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent\n\t * scope. This is useful when creating reusable components, which should not accidentally read or modify\n\t * data in the parent scope.\n\t *\n\t * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the\n\t * directive's element. These local properties are useful for aliasing values for templates. The keys in\n\t * the object hash map to the name of the property on the isolate scope; the values define how the property\n\t * is bound to the parent scope, via matching attributes on the directive's element:\n\t *\n\t * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is\n\t * always a string since DOM attributes are strings. If no `attr` name is specified then the\n\t * attribute name is assumed to be the same as the local name. Given `` and the isolate scope definition `scope: { localName:'@myAttr' }`,\n\t * the directive's scope property `localName` will reflect the interpolated value of `hello\n\t * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's\n\t * scope. The `name` is read from the parent scope (not the directive's scope).\n\t *\n\t * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression\n\t * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.\n\t * If no `attr` name is specified then the attribute name is assumed to be the same as the local\n\t * name. Given `` and the isolate scope definition `scope: {\n\t * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the\n\t * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in\n\t * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:\n\t * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't\n\t * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})\n\t * will be thrown upon discovering changes to the local value, since it will be impossible to sync\n\t * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}\n\t * method is used for tracking changes, and the equality check is based on object identity.\n\t * However, if an object literal or an array literal is passed as the binding expression, the\n\t * equality check is done by value (using the {@link angular.equals} function). It's also possible\n\t * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection\n\t * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).\n\t *\n\t * * `<` or `` and directive definition of\n\t * `scope: { localModel:'` and the isolate scope definition `scope: {\n\t * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for\n\t * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope\n\t * via an expression to the parent scope. This can be done by passing a map of local variable names\n\t * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`\n\t * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.\n\t *\n\t * In general it's possible to apply more than one directive to one element, but there might be limitations\n\t * depending on the type of scope required by the directives. The following points will help explain these limitations.\n\t * For simplicity only two directives are taken into account, but it is also applicable for several directives:\n\t *\n\t * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope\n\t * * **child scope** + **no scope** => Both directives will share one single child scope\n\t * * **child scope** + **child scope** => Both directives will share one single child scope\n\t * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use\n\t * its parent's scope\n\t * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot\n\t * be applied to the same element.\n\t * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives\n\t * cannot be applied to the same element.\n\t *\n\t *\n\t * #### `bindToController`\n\t * This property is used to bind scope properties directly to the controller. It can be either\n\t * `true` or an object hash with the same format as the `scope` property. Additionally, a controller\n\t * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller\n\t * definition: `controller: 'myCtrl as myAlias'`.\n\t *\n\t * When an isolate scope is used for a directive (see above), `bindToController: true` will\n\t * allow a component to have its properties bound to the controller, rather than to scope.\n\t *\n\t * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller\n\t * properties. You can access these bindings once they have been initialized by providing a controller method called\n\t * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings\n\t * initialized.\n\t *\n\t *
\n\t * **Deprecation warning:** although bindings for non-ES6 class controllers are currently\n\t * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization\n\t * code that relies upon bindings inside a `$onInit` method on the controller, instead.\n\t *
\n\t *\n\t * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.\n\t * This will set up the scope bindings to the controller directly. Note that `scope` can still be used\n\t * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate\n\t * scope (useful for component directives).\n\t *\n\t * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.\n\t *\n\t *\n\t * #### `controller`\n\t * Controller constructor function. The controller is instantiated before the\n\t * pre-linking phase and can be accessed by other directives (see\n\t * `require` attribute). This allows the directives to communicate with each other and augment\n\t * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:\n\t *\n\t * * `$scope` - Current scope associated with the element\n\t * * `$element` - Current element\n\t * * `$attrs` - Current attributes object for the element\n\t * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:\n\t * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:\n\t * * `scope`: (optional) override the scope.\n\t * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.\n\t * * `futureParentElement` (optional):\n\t * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.\n\t * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.\n\t * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)\n\t * and when the `cloneLinkinFn` is passed,\n\t * as those elements need to created and cloned in a special way when they are defined outside their\n\t * usual containers (e.g. like ``).\n\t * * See also the `directive.templateNamespace` property.\n\t * * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)\n\t * then the default translusion is provided.\n\t * The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns\n\t * `true` if the specified slot contains content (i.e. one or more DOM nodes).\n\t *\n\t * #### `require`\n\t * Require another directive and inject its controller as the fourth argument to the linking function. The\n\t * `require` property can be a string, an array or an object:\n\t * * a **string** containing the name of the directive to pass to the linking function\n\t * * an **array** containing the names of directives to pass to the linking function. The argument passed to the\n\t * linking function will be an array of controllers in the same order as the names in the `require` property\n\t * * an **object** whose property values are the names of the directives to pass to the linking function. The argument\n\t * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding\n\t * controllers.\n\t *\n\t * If the `require` property is an object and `bindToController` is truthy, then the required controllers are\n\t * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers\n\t * have been constructed but before `$onInit` is called.\n\t * If the name of the required controller is the same as the local name (the key), the name can be\n\t * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.\n\t * See the {@link $compileProvider#component} helper for an example of how this can be used.\n\t * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is\n\t * raised (unless no link function is specified and the required controllers are not being bound to the directive\n\t * controller, in which case error checking is skipped). The name can be prefixed with:\n\t *\n\t * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.\n\t * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.\n\t * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.\n\t * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.\n\t * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass\n\t * `null` to the `link` fn if not found.\n\t * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass\n\t * `null` to the `link` fn if not found.\n\t *\n\t *\n\t * #### `controllerAs`\n\t * Identifier name for a reference to the controller in the directive's scope.\n\t * This allows the controller to be referenced from the directive template. This is especially\n\t * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible\n\t * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the\n\t * `controllerAs` reference might overwrite a property that already exists on the parent scope.\n\t *\n\t *\n\t * #### `restrict`\n\t * String of subset of `EACM` which restricts the directive to a specific directive\n\t * declaration style. If omitted, the defaults (elements and attributes) are used.\n\t *\n\t * * `E` - Element name (default): ``\n\t * * `A` - Attribute (default): `
`\n\t * * `C` - Class: `
`\n\t * * `M` - Comment: ``\n\t *\n\t *\n\t * #### `templateNamespace`\n\t * String representing the document type used by the markup in the template.\n\t * AngularJS needs this information as those elements need to be created and cloned\n\t * in a special way when they are defined outside their usual containers like `` and ``.\n\t *\n\t * * `html` - All root nodes in the template are HTML. Root nodes may also be\n\t * top-level elements such as `` or ``.\n\t * * `svg` - The root nodes in the template are SVG elements (excluding ``).\n\t * * `math` - The root nodes in the template are MathML elements (excluding ``).\n\t *\n\t * If no `templateNamespace` is specified, then the namespace is considered to be `html`.\n\t *\n\t * #### `template`\n\t * HTML markup that may:\n\t * * Replace the contents of the directive's element (default).\n\t * * Replace the directive's element itself (if `replace` is true - DEPRECATED).\n\t * * Wrap the contents of the directive's element (if `transclude` is true).\n\t *\n\t * Value may be:\n\t *\n\t * * A string. For example `
{{delete_str}}
`.\n\t * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`\n\t * function api below) and returns a string value.\n\t *\n\t *\n\t * #### `templateUrl`\n\t * This is similar to `template` but the template is loaded from the specified URL, asynchronously.\n\t *\n\t * Because template loading is asynchronous the compiler will suspend compilation of directives on that element\n\t * for later when the template has been resolved. In the meantime it will continue to compile and link\n\t * sibling and parent elements as though this element had not contained any directives.\n\t *\n\t * The compiler does not suspend the entire compilation to wait for templates to be loaded because this\n\t * would result in the whole app \"stalling\" until all templates are loaded asynchronously - even in the\n\t * case when only one deeply nested directive has `templateUrl`.\n\t *\n\t * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}\n\t *\n\t * You can specify `templateUrl` as a string representing the URL or as a function which takes two\n\t * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns\n\t * a string value representing the url. In either case, the template URL is passed through {@link\n\t * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.\n\t *\n\t *\n\t * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)\n\t * specify what the template should replace. Defaults to `false`.\n\t *\n\t * * `true` - the template will replace the directive's element.\n\t * * `false` - the template will replace the contents of the directive's element.\n\t *\n\t * The replacement process migrates all of the attributes / classes from the old element to the new\n\t * one. See the {@link guide/directive#template-expanding-directive\n\t * Directives Guide} for an example.\n\t *\n\t * There are very few scenarios where element replacement is required for the application function,\n\t * the main one being reusable custom components that are used within SVG contexts\n\t * (because SVG doesn't work with custom elements in the DOM tree).\n\t *\n\t * #### `transclude`\n\t * Extract the contents of the element where the directive appears and make it available to the directive.\n\t * The contents are compiled and provided to the directive as a **transclusion function**. See the\n\t * {@link $compile#transclusion Transclusion} section below.\n\t *\n\t *\n\t * #### `compile`\n\t *\n\t * ```js\n\t * function compile(tElement, tAttrs, transclude) { ... }\n\t * ```\n\t *\n\t * The compile function deals with transforming the template DOM. Since most directives do not do\n\t * template transformation, it is not used often. The compile function takes the following arguments:\n\t *\n\t * * `tElement` - template element - The element where the directive has been declared. It is\n\t * safe to do template transformation on the element and child elements only.\n\t *\n\t * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared\n\t * between all directive compile functions.\n\t *\n\t * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`\n\t *\n\t *
\n\t * **Note:** The template instance and the link instance may be different objects if the template has\n\t * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that\n\t * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration\n\t * should be done in a linking function rather than in a compile function.\n\t *
\n\t\n\t *
\n\t * **Note:** The compile function cannot handle directives that recursively use themselves in their\n\t * own templates or compile functions. Compiling these directives results in an infinite loop and\n\t * stack overflow errors.\n\t *\n\t * This can be avoided by manually using $compile in the postLink function to imperatively compile\n\t * a directive's template instead of relying on automatic template compilation via `template` or\n\t * `templateUrl` declaration or manual compilation inside the compile function.\n\t *
\n\t *\n\t *
\n\t * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it\n\t * e.g. does not know about the right outer scope. Please use the transclude function that is passed\n\t * to the link function instead.\n\t *
\n\t\n\t * A compile function can have a return value which can be either a function or an object.\n\t *\n\t * * returning a (post-link) function - is equivalent to registering the linking function via the\n\t * `link` property of the config object when the compile function is empty.\n\t *\n\t * * returning an object with function(s) registered via `pre` and `post` properties - allows you to\n\t * control when a linking function should be called during the linking phase. See info about\n\t * pre-linking and post-linking functions below.\n\t *\n\t *\n\t * #### `link`\n\t * This property is used only if the `compile` property is not defined.\n\t *\n\t * ```js\n\t * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }\n\t * ```\n\t *\n\t * The link function is responsible for registering DOM listeners as well as updating the DOM. It is\n\t * executed after the template has been cloned. This is where most of the directive logic will be\n\t * put.\n\t *\n\t * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the\n\t * directive for registering {@link ng.$rootScope.Scope#$watch watches}.\n\t *\n\t * * `iElement` - instance element - The element where the directive is to be used. It is safe to\n\t * manipulate the children of the element only in `postLink` function since the children have\n\t * already been linked.\n\t *\n\t * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared\n\t * between all directive linking functions.\n\t *\n\t * * `controller` - the directive's required controller instance(s) - Instances are shared\n\t * among all directives, which allows the directives to use the controllers as a communication\n\t * channel. The exact value depends on the directive's `require` property:\n\t * * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one\n\t * * `string`: the controller instance\n\t * * `array`: array of controller instances\n\t *\n\t * If a required controller cannot be found, and it is optional, the instance is `null`,\n\t * otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.\n\t *\n\t * Note that you can also require the directive's own controller - it will be made available like\n\t * any other controller.\n\t *\n\t * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.\n\t * This is the same as the `$transclude` parameter of directive controllers,\n\t * see {@link ng.$compile#-controller- the controller section for details}.\n\t * `function([scope], cloneLinkingFn, futureParentElement)`.\n\t *\n\t * #### Pre-linking function\n\t *\n\t * Executed before the child elements are linked. Not safe to do DOM transformation since the\n\t * compiler linking function will fail to locate the correct elements for linking.\n\t *\n\t * #### Post-linking function\n\t *\n\t * Executed after the child elements are linked.\n\t *\n\t * Note that child elements that contain `templateUrl` directives will not have been compiled\n\t * and linked since they are waiting for their template to load asynchronously and their own\n\t * compilation and linking has been suspended until that occurs.\n\t *\n\t * It is safe to do DOM transformation in the post-linking function on elements that are not waiting\n\t * for their async templates to be resolved.\n\t *\n\t *\n\t * ### Transclusion\n\t *\n\t * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and\n\t * copying them to another part of the DOM, while maintaining their connection to the original AngularJS\n\t * scope from where they were taken.\n\t *\n\t * Transclusion is used (often with {@link ngTransclude}) to insert the\n\t * original contents of a directive's element into a specified place in the template of the directive.\n\t * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded\n\t * content has access to the properties on the scope from which it was taken, even if the directive\n\t * has isolated scope.\n\t * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.\n\t *\n\t * This makes it possible for the widget to have private state for its template, while the transcluded\n\t * content has access to its originating scope.\n\t *\n\t *
\n\t * **Note:** When testing an element transclude directive you must not place the directive at the root of the\n\t * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives\n\t * Testing Transclusion Directives}.\n\t *
\n\t *\n\t * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the\n\t * directive's element, the entire element or multiple parts of the element contents:\n\t *\n\t * * `true` - transclude the content (i.e. the child nodes) of the directive's element.\n\t * * `'element'` - transclude the whole of the directive's element including any directives on this\n\t * element that defined at a lower priority than this directive. When used, the `template`\n\t * property is ignored.\n\t * * **`{...}` (an object hash):** - map elements of the content onto transclusion \"slots\" in the template.\n\t *\n\t * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.\n\t *\n\t * This object is a map where the keys are the name of the slot to fill and the value is an element selector\n\t * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)\n\t * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).\n\t *\n\t * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}\n\t *\n\t * If the element selector is prefixed with a `?` then that slot is optional.\n\t *\n\t * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `` elements to\n\t * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.\n\t *\n\t * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements\n\t * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call\n\t * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and\n\t * injectable into the directive's controller.\n\t *\n\t *\n\t * #### Transclusion Functions\n\t *\n\t * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion\n\t * function** to the directive's `link` function and `controller`. This transclusion function is a special\n\t * **linking function** that will return the compiled contents linked to a new transclusion scope.\n\t *\n\t *
\n\t * If you are just using {@link ngTransclude} then you don't need to worry about this function, since\n\t * ngTransclude will deal with it for us.\n\t *
\n\t *\n\t * If you want to manually control the insertion and removal of the transcluded content in your directive\n\t * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery\n\t * object that contains the compiled DOM, which is linked to the correct transclusion scope.\n\t *\n\t * When you call a transclusion function you can pass in a **clone attach function**. This function accepts\n\t * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded\n\t * content and the `scope` is the newly created transclusion scope, to which the clone is bound.\n\t *\n\t *
\n\t * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function\n\t * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.\n\t *
\n\t *\n\t * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone\n\t * attach function**:\n\t *\n\t * ```js\n\t * var transcludedContent, transclusionScope;\n\t *\n\t * $transclude(function(clone, scope) {\n\t * element.append(clone);\n\t * transcludedContent = clone;\n\t * transclusionScope = scope;\n\t * });\n\t * ```\n\t *\n\t * Later, if you want to remove the transcluded content from your DOM then you should also destroy the\n\t * associated transclusion scope:\n\t *\n\t * ```js\n\t * transcludedContent.remove();\n\t * transclusionScope.$destroy();\n\t * ```\n\t *\n\t *
\n\t * **Best Practice**: if you intend to add and remove transcluded content manually in your directive\n\t * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),\n\t * then you are also responsible for calling `$destroy` on the transclusion scope.\n\t *
\n\t *\n\t * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}\n\t * automatically destroy their transcluded clones as necessary so you do not need to worry about this if\n\t * you are simply using {@link ngTransclude} to inject the transclusion into your directive.\n\t *\n\t *\n\t * #### Transclusion Scopes\n\t *\n\t * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion\n\t * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed\n\t * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it\n\t * was taken.\n\t *\n\t * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look\n\t * like this:\n\t *\n\t * ```html\n\t *
\n\t *
\n\t *
\n\t *
\n\t *
\n\t *
\n\t * ```\n\t *\n\t * The `$parent` scope hierarchy will look like this:\n\t *\n\t ```\n\t - $rootScope\n\t - isolate\n\t - transclusion\n\t ```\n\t *\n\t * but the scopes will inherit prototypically from different scopes to their `$parent`.\n\t *\n\t ```\n\t - $rootScope\n\t - transclusion\n\t - isolate\n\t ```\n\t *\n\t *\n\t * ### Attributes\n\t *\n\t * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the\n\t * `link()` or `compile()` functions. It has a variety of uses.\n\t *\n\t * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:\n\t * 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access\n\t * to the attributes.\n\t *\n\t * * *Directive inter-communication:* All directives share the same instance of the attributes\n\t * object which allows the directives to use the attributes object as inter directive\n\t * communication.\n\t *\n\t * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object\n\t * allowing other directives to read the interpolated value.\n\t *\n\t * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes\n\t * that contain interpolation (e.g. `src=\"{{bar}}\"`). Not only is this very efficient but it's also\n\t * the only way to easily get the actual value because during the linking phase the interpolation\n\t * hasn't been evaluated yet and so the value is at this time set to `undefined`.\n\t *\n\t * ```js\n\t * function linkingFn(scope, elm, attrs, ctrl) {\n\t * // get the attribute value\n\t * console.log(attrs.ngModel);\n\t *\n\t * // change the attribute\n\t * attrs.$set('ngModel', 'new value');\n\t *\n\t * // observe changes to interpolated attribute\n\t * attrs.$observe('ngModel', function(value) {\n\t * console.log('ngModel has changed value to ' + value);\n\t * });\n\t * }\n\t * ```\n\t *\n\t * ## Example\n\t *\n\t *
\n\t * **Note**: Typically directives are registered with `module.directive`. The example below is\n\t * to illustrate how `$compile` works.\n\t *
\n\t *\n\t \n\t \n\t \n\t
\n\t
\n\t
\n\t
\n\t
\n\t
\n\t \n\t it('should auto compile', function() {\n\t var textarea = $('textarea');\n\t var output = $('div[compile]');\n\t // The initial state reads 'Hello Angular'.\n\t expect(output.getText()).toBe('Hello Angular');\n\t textarea.clear();\n\t textarea.sendKeys('{{name}}!');\n\t expect(output.getText()).toBe('Angular!');\n\t });\n\t \n\t
\n\t\n\t *\n\t *\n\t * @param {string|DOMElement} element Element or HTML string to compile into a template function.\n\t * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.\n\t *\n\t *
\n\t * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it\n\t * e.g. will not use the right outer scope. Please pass the transclude function as a\n\t * `parentBoundTranscludeFn` to the link function instead.\n\t *
\n\t *\n\t * @param {number} maxPriority only apply directives lower than given priority (Only effects the\n\t * root element(s), not their children)\n\t * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template\n\t * (a DOM element/tree) to a scope. Where:\n\t *\n\t * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.\n\t * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the\n\t * `template` and call the `cloneAttachFn` function allowing the caller to attach the\n\t * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is\n\t * called as:
`cloneAttachFn(clonedElement, scope)` where:\n\t *\n\t * * `clonedElement` - is a clone of the original `element` passed into the compiler.\n\t * * `scope` - is the current scope with which the linking function is working with.\n\t *\n\t * * `options` - An optional object hash with linking options. If `options` is provided, then the following\n\t * keys may be used to control linking behavior:\n\t *\n\t * * `parentBoundTranscludeFn` - the transclude function made available to\n\t * directives; if given, it will be passed through to the link functions of\n\t * directives found in `element` during compilation.\n\t * * `transcludeControllers` - an object hash with keys that map controller names\n\t * to a hash with the key `instance`, which maps to the controller instance;\n\t * if given, it will make the controllers available to directives on the compileNode:\n\t * ```\n\t * {\n\t * parent: {\n\t * instance: parentControllerInstance\n\t * }\n\t * }\n\t * ```\n\t * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add\n\t * the cloned elements; only needed for transcludes that are allowed to contain non html\n\t * elements (e.g. SVG elements). See also the directive.controller property.\n\t *\n\t * Calling the linking function returns the element of the template. It is either the original\n\t * element passed in, or the clone of the element if the `cloneAttachFn` is provided.\n\t *\n\t * After linking the view is not updated until after a call to $digest which typically is done by\n\t * Angular automatically.\n\t *\n\t * If you need access to the bound view, there are two ways to do it:\n\t *\n\t * - If you are not asking the linking function to clone the template, create the DOM element(s)\n\t * before you send them to the compiler and keep this reference around.\n\t * ```js\n\t * var element = $compile('

{{total}}

')(scope);\n\t * ```\n\t *\n\t * - if on the other hand, you need the element to be cloned, the view reference from the original\n\t * example would not point to the clone, but rather to the original template that was cloned. In\n\t * this case, you can access the clone via the cloneAttachFn:\n\t * ```js\n\t * var templateElement = angular.element('

{{total}}

'),\n\t * scope = ....;\n\t *\n\t * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {\n\t * //attach the clone to DOM document at the right place\n\t * });\n\t *\n\t * //now we have reference to the cloned DOM via `clonedElement`\n\t * ```\n\t *\n\t *\n\t * For information on how the compiler works, see the\n\t * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.\n\t */\n\t\n\tvar $compileMinErr = minErr('$compile');\n\t\n\tfunction UNINITIALIZED_VALUE() {}\n\tvar _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $compileProvider\n\t *\n\t * @description\n\t */\n\t$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];\n\tfunction $CompileProvider($provide, $$sanitizeUriProvider) {\n\t var hasDirectives = {},\n\t Suffix = 'Directive',\n\t COMMENT_DIRECTIVE_REGEXP = /^\\s*directive\\:\\s*([\\w\\-]+)\\s+(.*)$/,\n\t CLASS_DIRECTIVE_REGEXP = /(([\\w\\-]+)(?:\\:([^;]+))?;?)/,\n\t ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),\n\t REQUIRE_PREFIX_REGEXP = /^(?:(\\^\\^?)?(\\?)?(\\^\\^?)?)?/;\n\t\n\t // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes\n\t // The assumption is that future DOM event attribute names will begin with\n\t // 'on' and be composed of only English letters.\n\t var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;\n\t var bindingCache = createMap();\n\t\n\t function parseIsolateBindings(scope, directiveName, isController) {\n\t var LOCAL_REGEXP = /^\\s*([@&<]|=(\\*?))(\\??)\\s*(\\w*)\\s*$/;\n\t\n\t var bindings = createMap();\n\t\n\t forEach(scope, function(definition, scopeName) {\n\t if (definition in bindingCache) {\n\t bindings[scopeName] = bindingCache[definition];\n\t return;\n\t }\n\t var match = definition.match(LOCAL_REGEXP);\n\t\n\t if (!match) {\n\t throw $compileMinErr('iscp',\n\t \"Invalid {3} for directive '{0}'.\" +\n\t \" Definition: {... {1}: '{2}' ...}\",\n\t directiveName, scopeName, definition,\n\t (isController ? \"controller bindings definition\" :\n\t \"isolate scope definition\"));\n\t }\n\t\n\t bindings[scopeName] = {\n\t mode: match[1][0],\n\t collection: match[2] === '*',\n\t optional: match[3] === '?',\n\t attrName: match[4] || scopeName\n\t };\n\t if (match[4]) {\n\t bindingCache[definition] = bindings[scopeName];\n\t }\n\t });\n\t\n\t return bindings;\n\t }\n\t\n\t function parseDirectiveBindings(directive, directiveName) {\n\t var bindings = {\n\t isolateScope: null,\n\t bindToController: null\n\t };\n\t if (isObject(directive.scope)) {\n\t if (directive.bindToController === true) {\n\t bindings.bindToController = parseIsolateBindings(directive.scope,\n\t directiveName, true);\n\t bindings.isolateScope = {};\n\t } else {\n\t bindings.isolateScope = parseIsolateBindings(directive.scope,\n\t directiveName, false);\n\t }\n\t }\n\t if (isObject(directive.bindToController)) {\n\t bindings.bindToController =\n\t parseIsolateBindings(directive.bindToController, directiveName, true);\n\t }\n\t if (isObject(bindings.bindToController)) {\n\t var controller = directive.controller;\n\t var controllerAs = directive.controllerAs;\n\t if (!controller) {\n\t // There is no controller, there may or may not be a controllerAs property\n\t throw $compileMinErr('noctrl',\n\t \"Cannot bind to controller without directive '{0}'s controller.\",\n\t directiveName);\n\t } else if (!identifierForController(controller, controllerAs)) {\n\t // There is a controller, but no identifier or controllerAs property\n\t throw $compileMinErr('noident',\n\t \"Cannot bind to controller without identifier for directive '{0}'.\",\n\t directiveName);\n\t }\n\t }\n\t return bindings;\n\t }\n\t\n\t function assertValidDirectiveName(name) {\n\t var letter = name.charAt(0);\n\t if (!letter || letter !== lowercase(letter)) {\n\t throw $compileMinErr('baddir', \"Directive/Component name '{0}' is invalid. The first character must be a lowercase letter\", name);\n\t }\n\t if (name !== name.trim()) {\n\t throw $compileMinErr('baddir',\n\t \"Directive/Component name '{0}' is invalid. The name should not contain leading or trailing whitespaces\",\n\t name);\n\t }\n\t }\n\t\n\t function getDirectiveRequire(directive) {\n\t var require = directive.require || (directive.controller && directive.name);\n\t\n\t if (!isArray(require) && isObject(require)) {\n\t forEach(require, function(value, key) {\n\t var match = value.match(REQUIRE_PREFIX_REGEXP);\n\t var name = value.substring(match[0].length);\n\t if (!name) require[key] = match[0] + key;\n\t });\n\t }\n\t\n\t return require;\n\t }\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#directive\n\t * @kind function\n\t *\n\t * @description\n\t * Register a new directive with the compiler.\n\t *\n\t * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which\n\t * will match as ng-bind), or an object map of directives where the keys are the\n\t * names and the values are the factories.\n\t * @param {Function|Array} directiveFactory An injectable directive factory function. See the\n\t * {@link guide/directive directive guide} and the {@link $compile compile API} for more info.\n\t * @returns {ng.$compileProvider} Self for chaining.\n\t */\n\t this.directive = function registerDirective(name, directiveFactory) {\n\t assertNotHasOwnProperty(name, 'directive');\n\t if (isString(name)) {\n\t assertValidDirectiveName(name);\n\t assertArg(directiveFactory, 'directiveFactory');\n\t if (!hasDirectives.hasOwnProperty(name)) {\n\t hasDirectives[name] = [];\n\t $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',\n\t function($injector, $exceptionHandler) {\n\t var directives = [];\n\t forEach(hasDirectives[name], function(directiveFactory, index) {\n\t try {\n\t var directive = $injector.invoke(directiveFactory);\n\t if (isFunction(directive)) {\n\t directive = { compile: valueFn(directive) };\n\t } else if (!directive.compile && directive.link) {\n\t directive.compile = valueFn(directive.link);\n\t }\n\t directive.priority = directive.priority || 0;\n\t directive.index = index;\n\t directive.name = directive.name || name;\n\t directive.require = getDirectiveRequire(directive);\n\t directive.restrict = directive.restrict || 'EA';\n\t directive.$$moduleName = directiveFactory.$$moduleName;\n\t directives.push(directive);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t });\n\t return directives;\n\t }]);\n\t }\n\t hasDirectives[name].push(directiveFactory);\n\t } else {\n\t forEach(name, reverseParams(registerDirective));\n\t }\n\t return this;\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#component\n\t * @module ng\n\t * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match ``)\n\t * @param {Object} options Component definition object (a simplified\n\t * {@link ng.$compile#directive-definition-object directive definition object}),\n\t * with the following properties (all optional):\n\t *\n\t * - `controller` – `{(string|function()=}` – controller constructor function that should be\n\t * associated with newly created scope or the name of a {@link ng.$compile#-controller-\n\t * registered controller} if passed as a string. An empty `noop` function by default.\n\t * - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.\n\t * If present, the controller will be published to scope under the `controllerAs` name.\n\t * If not present, this will default to be `$ctrl`.\n\t * - `template` – `{string=|function()=}` – html template as a string or a function that\n\t * returns an html template as a string which should be used as the contents of this component.\n\t * Empty string by default.\n\t *\n\t * If `template` is a function, then it is {@link auto.$injector#invoke injected} with\n\t * the following locals:\n\t *\n\t * - `$element` - Current element\n\t * - `$attrs` - Current attributes object for the element\n\t *\n\t * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html\n\t * template that should be used as the contents of this component.\n\t *\n\t * If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with\n\t * the following locals:\n\t *\n\t * - `$element` - Current element\n\t * - `$attrs` - Current attributes object for the element\n\t *\n\t * - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.\n\t * Component properties are always bound to the component controller and not to the scope.\n\t * See {@link ng.$compile#-bindtocontroller- `bindToController`}.\n\t * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.\n\t * Disabled by default.\n\t * - `require` - `{Object=}` - requires the controllers of other directives and binds them to\n\t * this component's controller. The object keys specify the property names under which the required\n\t * controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.\n\t * - `$...` – additional properties to attach to the directive factory function and the controller\n\t * constructor function. (This is used by the component router to annotate)\n\t *\n\t * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.\n\t * @description\n\t * Register a **component definition** with the compiler. This is a shorthand for registering a special\n\t * type of directive, which represents a self-contained UI component in your application. Such components\n\t * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).\n\t *\n\t * Component definitions are very simple and do not require as much configuration as defining general\n\t * directives. Component definitions usually consist only of a template and a controller backing it.\n\t *\n\t * In order to make the definition easier, components enforce best practices like use of `controllerAs`,\n\t * `bindToController`. They always have **isolate scope** and are restricted to elements.\n\t *\n\t * Here are a few examples of how you would usually define components:\n\t *\n\t * ```js\n\t * var myMod = angular.module(...);\n\t * myMod.component('myComp', {\n\t * template: '
My name is {{$ctrl.name}}
',\n\t * controller: function() {\n\t * this.name = 'shahar';\n\t * }\n\t * });\n\t *\n\t * myMod.component('myComp', {\n\t * template: '
My name is {{$ctrl.name}}
',\n\t * bindings: {name: '@'}\n\t * });\n\t *\n\t * myMod.component('myComp', {\n\t * templateUrl: 'views/my-comp.html',\n\t * controller: 'MyCtrl',\n\t * controllerAs: 'ctrl',\n\t * bindings: {name: '@'}\n\t * });\n\t *\n\t * ```\n\t * For more examples, and an in-depth guide, see the {@link guide/component component guide}.\n\t *\n\t *
\n\t * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.\n\t */\n\t this.component = function registerComponent(name, options) {\n\t var controller = options.controller || function() {};\n\t\n\t function factory($injector) {\n\t function makeInjectable(fn) {\n\t if (isFunction(fn) || isArray(fn)) {\n\t return function(tElement, tAttrs) {\n\t return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});\n\t };\n\t } else {\n\t return fn;\n\t }\n\t }\n\t\n\t var template = (!options.template && !options.templateUrl ? '' : options.template);\n\t var ddo = {\n\t controller: controller,\n\t controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',\n\t template: makeInjectable(template),\n\t templateUrl: makeInjectable(options.templateUrl),\n\t transclude: options.transclude,\n\t scope: {},\n\t bindToController: options.bindings || {},\n\t restrict: 'E',\n\t require: options.require\n\t };\n\t\n\t // Copy annotations (starting with $) over to the DDO\n\t forEach(options, function(val, key) {\n\t if (key.charAt(0) === '$') ddo[key] = val;\n\t });\n\t\n\t return ddo;\n\t }\n\t\n\t // TODO(pete) remove the following `forEach` before we release 1.6.0\n\t // The component-router@0.2.0 looks for the annotations on the controller constructor\n\t // Nothing in Angular looks for annotations on the factory function but we can't remove\n\t // it from 1.5.x yet.\n\t\n\t // Copy any annotation properties (starting with $) over to the factory and controller constructor functions\n\t // These could be used by libraries such as the new component router\n\t forEach(options, function(val, key) {\n\t if (key.charAt(0) === '$') {\n\t factory[key] = val;\n\t // Don't try to copy over annotations to named controller\n\t if (isFunction(controller)) controller[key] = val;\n\t }\n\t });\n\t\n\t factory.$inject = ['$injector'];\n\t\n\t return this.directive(name, factory);\n\t };\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#aHrefSanitizationWhitelist\n\t * @kind function\n\t *\n\t * @description\n\t * Retrieves or overrides the default regular expression that is used for whitelisting of safe\n\t * urls during a[href] sanitization.\n\t *\n\t * The sanitization is a security measure aimed at preventing XSS attacks via html links.\n\t *\n\t * Any url about to be assigned to a[href] via data-binding is first normalized and turned into\n\t * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`\n\t * regular expression. If a match is found, the original url is written into the dom. Otherwise,\n\t * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.\n\t *\n\t * @param {RegExp=} regexp New regexp to whitelist urls with.\n\t * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for\n\t * chaining otherwise.\n\t */\n\t this.aHrefSanitizationWhitelist = function(regexp) {\n\t if (isDefined(regexp)) {\n\t $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);\n\t return this;\n\t } else {\n\t return $$sanitizeUriProvider.aHrefSanitizationWhitelist();\n\t }\n\t };\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#imgSrcSanitizationWhitelist\n\t * @kind function\n\t *\n\t * @description\n\t * Retrieves or overrides the default regular expression that is used for whitelisting of safe\n\t * urls during img[src] sanitization.\n\t *\n\t * The sanitization is a security measure aimed at prevent XSS attacks via html links.\n\t *\n\t * Any url about to be assigned to img[src] via data-binding is first normalized and turned into\n\t * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`\n\t * regular expression. If a match is found, the original url is written into the dom. Otherwise,\n\t * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.\n\t *\n\t * @param {RegExp=} regexp New regexp to whitelist urls with.\n\t * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for\n\t * chaining otherwise.\n\t */\n\t this.imgSrcSanitizationWhitelist = function(regexp) {\n\t if (isDefined(regexp)) {\n\t $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);\n\t return this;\n\t } else {\n\t return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#debugInfoEnabled\n\t *\n\t * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the\n\t * current debugInfoEnabled state\n\t * @returns {*} current value if used as getter or itself (chaining) if used as setter\n\t *\n\t * @kind function\n\t *\n\t * @description\n\t * Call this method to enable/disable various debug runtime information in the compiler such as adding\n\t * binding information and a reference to the current scope on to DOM elements.\n\t * If enabled, the compiler will add the following to DOM elements that have been bound to the scope\n\t * * `ng-binding` CSS class\n\t * * `$binding` data property containing an array of the binding expressions\n\t *\n\t * You may want to disable this in production for a significant performance boost. See\n\t * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.\n\t *\n\t * The default value is true.\n\t */\n\t var debugInfoEnabled = true;\n\t this.debugInfoEnabled = function(enabled) {\n\t if (isDefined(enabled)) {\n\t debugInfoEnabled = enabled;\n\t return this;\n\t }\n\t return debugInfoEnabled;\n\t };\n\t\n\t\n\t var TTL = 10;\n\t /**\n\t * @ngdoc method\n\t * @name $compileProvider#onChangesTtl\n\t * @description\n\t *\n\t * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and\n\t * assuming that the model is unstable.\n\t *\n\t * The current default is 10 iterations.\n\t *\n\t * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result\n\t * in several iterations of calls to these hooks. However if an application needs more than the default 10\n\t * iterations to stabilize then you should investigate what is causing the model to continuously change during\n\t * the `$onChanges` hook execution.\n\t *\n\t * Increasing the TTL could have performance implications, so you should not change it without proper justification.\n\t *\n\t * @param {number} limit The number of `$onChanges` hook iterations.\n\t * @returns {number|object} the current limit (or `this` if called as a setter for chaining)\n\t */\n\t this.onChangesTtl = function(value) {\n\t if (arguments.length) {\n\t TTL = value;\n\t return this;\n\t }\n\t return TTL;\n\t };\n\t\n\t this.$get = [\n\t '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',\n\t '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',\n\t function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,\n\t $controller, $rootScope, $sce, $animate, $$sanitizeUri) {\n\t\n\t var SIMPLE_ATTR_NAME = /^\\w/;\n\t var specialAttrHolder = window.document.createElement('div');\n\t\n\t\n\t\n\t var onChangesTtl = TTL;\n\t // The onChanges hooks should all be run together in a single digest\n\t // When changes occur, the call to trigger their hooks will be added to this queue\n\t var onChangesQueue;\n\t\n\t // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest\n\t function flushOnChangesQueue() {\n\t try {\n\t if (!(--onChangesTtl)) {\n\t // We have hit the TTL limit so reset everything\n\t onChangesQueue = undefined;\n\t throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\\n', TTL);\n\t }\n\t // We must run this hook in an apply since the $$postDigest runs outside apply\n\t $rootScope.$apply(function() {\n\t var errors = [];\n\t for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {\n\t try {\n\t onChangesQueue[i]();\n\t } catch (e) {\n\t errors.push(e);\n\t }\n\t }\n\t // Reset the queue to trigger a new schedule next time there is a change\n\t onChangesQueue = undefined;\n\t if (errors.length) {\n\t throw errors;\n\t }\n\t });\n\t } finally {\n\t onChangesTtl++;\n\t }\n\t }\n\t\n\t\n\t function Attributes(element, attributesToCopy) {\n\t if (attributesToCopy) {\n\t var keys = Object.keys(attributesToCopy);\n\t var i, l, key;\n\t\n\t for (i = 0, l = keys.length; i < l; i++) {\n\t key = keys[i];\n\t this[key] = attributesToCopy[key];\n\t }\n\t } else {\n\t this.$attr = {};\n\t }\n\t\n\t this.$$element = element;\n\t }\n\t\n\t Attributes.prototype = {\n\t /**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$normalize\n\t * @kind function\n\t *\n\t * @description\n\t * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or\n\t * `data-`) to its normalized, camelCase form.\n\t *\n\t * Also there is special case for Moz prefix starting with upper case letter.\n\t *\n\t * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}\n\t *\n\t * @param {string} name Name to normalize\n\t */\n\t $normalize: directiveNormalize,\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$addClass\n\t * @kind function\n\t *\n\t * @description\n\t * Adds the CSS class value specified by the classVal parameter to the element. If animations\n\t * are enabled then an animation will be triggered for the class addition.\n\t *\n\t * @param {string} classVal The className value that will be added to the element\n\t */\n\t $addClass: function(classVal) {\n\t if (classVal && classVal.length > 0) {\n\t $animate.addClass(this.$$element, classVal);\n\t }\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$removeClass\n\t * @kind function\n\t *\n\t * @description\n\t * Removes the CSS class value specified by the classVal parameter from the element. If\n\t * animations are enabled then an animation will be triggered for the class removal.\n\t *\n\t * @param {string} classVal The className value that will be removed from the element\n\t */\n\t $removeClass: function(classVal) {\n\t if (classVal && classVal.length > 0) {\n\t $animate.removeClass(this.$$element, classVal);\n\t }\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$updateClass\n\t * @kind function\n\t *\n\t * @description\n\t * Adds and removes the appropriate CSS class values to the element based on the difference\n\t * between the new and old CSS class values (specified as newClasses and oldClasses).\n\t *\n\t * @param {string} newClasses The current CSS className value\n\t * @param {string} oldClasses The former CSS className value\n\t */\n\t $updateClass: function(newClasses, oldClasses) {\n\t var toAdd = tokenDifference(newClasses, oldClasses);\n\t if (toAdd && toAdd.length) {\n\t $animate.addClass(this.$$element, toAdd);\n\t }\n\t\n\t var toRemove = tokenDifference(oldClasses, newClasses);\n\t if (toRemove && toRemove.length) {\n\t $animate.removeClass(this.$$element, toRemove);\n\t }\n\t },\n\t\n\t /**\n\t * Set a normalized attribute on the element in a way such that all directives\n\t * can share the attribute. This function properly handles boolean attributes.\n\t * @param {string} key Normalized key. (ie ngAttribute)\n\t * @param {string|boolean} value The value to set. If `null` attribute will be deleted.\n\t * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.\n\t * Defaults to true.\n\t * @param {string=} attrName Optional none normalized name. Defaults to key.\n\t */\n\t $set: function(key, value, writeAttr, attrName) {\n\t // TODO: decide whether or not to throw an error if \"class\"\n\t //is set through this function since it may cause $updateClass to\n\t //become unstable.\n\t\n\t var node = this.$$element[0],\n\t booleanKey = getBooleanAttrName(node, key),\n\t aliasedKey = getAliasedAttrName(key),\n\t observer = key,\n\t nodeName;\n\t\n\t if (booleanKey) {\n\t this.$$element.prop(key, value);\n\t attrName = booleanKey;\n\t } else if (aliasedKey) {\n\t this[aliasedKey] = value;\n\t observer = aliasedKey;\n\t }\n\t\n\t this[key] = value;\n\t\n\t // translate normalized key to actual key\n\t if (attrName) {\n\t this.$attr[key] = attrName;\n\t } else {\n\t attrName = this.$attr[key];\n\t if (!attrName) {\n\t this.$attr[key] = attrName = snake_case(key, '-');\n\t }\n\t }\n\t\n\t nodeName = nodeName_(this.$$element);\n\t\n\t if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||\n\t (nodeName === 'img' && key === 'src')) {\n\t // sanitize a[href] and img[src] values\n\t this[key] = value = $$sanitizeUri(value, key === 'src');\n\t } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) {\n\t // sanitize img[srcset] values\n\t var result = \"\";\n\t\n\t // first check if there are spaces because it's not the same pattern\n\t var trimmedSrcset = trim(value);\n\t // ( 999x ,| 999w ,| ,|, )\n\t var srcPattern = /(\\s+\\d+x\\s*,|\\s+\\d+w\\s*,|\\s+,|,\\s+)/;\n\t var pattern = /\\s/.test(trimmedSrcset) ? srcPattern : /(,)/;\n\t\n\t // split srcset into tuple of uri and descriptor except for the last item\n\t var rawUris = trimmedSrcset.split(pattern);\n\t\n\t // for each tuples\n\t var nbrUrisWith2parts = Math.floor(rawUris.length / 2);\n\t for (var i = 0; i < nbrUrisWith2parts; i++) {\n\t var innerIdx = i * 2;\n\t // sanitize the uri\n\t result += $$sanitizeUri(trim(rawUris[innerIdx]), true);\n\t // add the descriptor\n\t result += (\" \" + trim(rawUris[innerIdx + 1]));\n\t }\n\t\n\t // split the last item into uri and descriptor\n\t var lastTuple = trim(rawUris[i * 2]).split(/\\s/);\n\t\n\t // sanitize the last uri\n\t result += $$sanitizeUri(trim(lastTuple[0]), true);\n\t\n\t // and add the last descriptor if any\n\t if (lastTuple.length === 2) {\n\t result += (\" \" + trim(lastTuple[1]));\n\t }\n\t this[key] = value = result;\n\t }\n\t\n\t if (writeAttr !== false) {\n\t if (value === null || isUndefined(value)) {\n\t this.$$element.removeAttr(attrName);\n\t } else {\n\t if (SIMPLE_ATTR_NAME.test(attrName)) {\n\t this.$$element.attr(attrName, value);\n\t } else {\n\t setSpecialAttr(this.$$element[0], attrName, value);\n\t }\n\t }\n\t }\n\t\n\t // fire observers\n\t var $$observers = this.$$observers;\n\t $$observers && forEach($$observers[observer], function(fn) {\n\t try {\n\t fn(value);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t });\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$observe\n\t * @kind function\n\t *\n\t * @description\n\t * Observes an interpolated attribute.\n\t *\n\t * The observer function will be invoked once during the next `$digest` following\n\t * compilation. The observer is then invoked whenever the interpolated value\n\t * changes.\n\t *\n\t * @param {string} key Normalized key. (ie ngAttribute) .\n\t * @param {function(interpolatedValue)} fn Function that will be called whenever\n\t the interpolated value of the attribute changes.\n\t * See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation\n\t * guide} for more info.\n\t * @returns {function()} Returns a deregistration function for this observer.\n\t */\n\t $observe: function(key, fn) {\n\t var attrs = this,\n\t $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),\n\t listeners = ($$observers[key] || ($$observers[key] = []));\n\t\n\t listeners.push(fn);\n\t $rootScope.$evalAsync(function() {\n\t if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {\n\t // no one registered attribute interpolation function, so lets call it manually\n\t fn(attrs[key]);\n\t }\n\t });\n\t\n\t return function() {\n\t arrayRemove(listeners, fn);\n\t };\n\t }\n\t };\n\t\n\t function setSpecialAttr(element, attrName, value) {\n\t // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`\n\t // so we have to jump through some hoops to get such an attribute\n\t // https://github.com/angular/angular.js/pull/13318\n\t specialAttrHolder.innerHTML = \"\";\n\t var attributes = specialAttrHolder.firstChild.attributes;\n\t var attribute = attributes[0];\n\t // We have to remove the attribute from its container element before we can add it to the destination element\n\t attributes.removeNamedItem(attribute.name);\n\t attribute.value = value;\n\t element.attributes.setNamedItem(attribute);\n\t }\n\t\n\t function safeAddClass($element, className) {\n\t try {\n\t $element.addClass(className);\n\t } catch (e) {\n\t // ignore, since it means that we are trying to set class on\n\t // SVG element, where class name is read-only.\n\t }\n\t }\n\t\n\t\n\t var startSymbol = $interpolate.startSymbol(),\n\t endSymbol = $interpolate.endSymbol(),\n\t denormalizeTemplate = (startSymbol == '{{' && endSymbol == '}}')\n\t ? identity\n\t : function denormalizeTemplate(template) {\n\t return template.replace(/\\{\\{/g, startSymbol).replace(/}}/g, endSymbol);\n\t },\n\t NG_ATTR_BINDING = /^ngAttr[A-Z]/;\n\t var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;\n\t\n\t compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {\n\t var bindings = $element.data('$binding') || [];\n\t\n\t if (isArray(binding)) {\n\t bindings = bindings.concat(binding);\n\t } else {\n\t bindings.push(binding);\n\t }\n\t\n\t $element.data('$binding', bindings);\n\t } : noop;\n\t\n\t compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {\n\t safeAddClass($element, 'ng-binding');\n\t } : noop;\n\t\n\t compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {\n\t var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';\n\t $element.data(dataName, scope);\n\t } : noop;\n\t\n\t compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {\n\t safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');\n\t } : noop;\n\t\n\t compile.$$createComment = function(directiveName, comment) {\n\t var content = '';\n\t if (debugInfoEnabled) {\n\t content = ' ' + (directiveName || '') + ': ';\n\t if (comment) content += comment + ' ';\n\t }\n\t return window.document.createComment(content);\n\t };\n\t\n\t return compile;\n\t\n\t //================================\n\t\n\t function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,\n\t previousCompileContext) {\n\t if (!($compileNodes instanceof jqLite)) {\n\t // jquery always rewraps, whereas we need to preserve the original selector so that we can\n\t // modify it.\n\t $compileNodes = jqLite($compileNodes);\n\t }\n\t\n\t var NOT_EMPTY = /\\S+/;\n\t\n\t // We can not compile top level text elements since text nodes can be merged and we will\n\t // not be able to attach scope data to them, so we will wrap them in \n\t for (var i = 0, len = $compileNodes.length; i < len; i++) {\n\t var domNode = $compileNodes[i];\n\t\n\t if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {\n\t jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));\n\t }\n\t }\n\t\n\t var compositeLinkFn =\n\t compileNodes($compileNodes, transcludeFn, $compileNodes,\n\t maxPriority, ignoreDirective, previousCompileContext);\n\t compile.$$addScopeClass($compileNodes);\n\t var namespace = null;\n\t return function publicLinkFn(scope, cloneConnectFn, options) {\n\t assertArg(scope, 'scope');\n\t\n\t if (previousCompileContext && previousCompileContext.needsNewScope) {\n\t // A parent directive did a replace and a directive on this element asked\n\t // for transclusion, which caused us to lose a layer of element on which\n\t // we could hold the new transclusion scope, so we will create it manually\n\t // here.\n\t scope = scope.$parent.$new();\n\t }\n\t\n\t options = options || {};\n\t var parentBoundTranscludeFn = options.parentBoundTranscludeFn,\n\t transcludeControllers = options.transcludeControllers,\n\t futureParentElement = options.futureParentElement;\n\t\n\t // When `parentBoundTranscludeFn` is passed, it is a\n\t // `controllersBoundTransclude` function (it was previously passed\n\t // as `transclude` to directive.link) so we must unwrap it to get\n\t // its `boundTranscludeFn`\n\t if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {\n\t parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;\n\t }\n\t\n\t if (!namespace) {\n\t namespace = detectNamespaceForChildElements(futureParentElement);\n\t }\n\t var $linkNode;\n\t if (namespace !== 'html') {\n\t // When using a directive with replace:true and templateUrl the $compileNodes\n\t // (or a child element inside of them)\n\t // might change, so we need to recreate the namespace adapted compileNodes\n\t // for call to the link function.\n\t // Note: This will already clone the nodes...\n\t $linkNode = jqLite(\n\t wrapTemplate(namespace, jqLite('
').append($compileNodes).html())\n\t );\n\t } else if (cloneConnectFn) {\n\t // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart\n\t // and sometimes changes the structure of the DOM.\n\t $linkNode = JQLitePrototype.clone.call($compileNodes);\n\t } else {\n\t $linkNode = $compileNodes;\n\t }\n\t\n\t if (transcludeControllers) {\n\t for (var controllerName in transcludeControllers) {\n\t $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);\n\t }\n\t }\n\t\n\t compile.$$addScopeInfo($linkNode, scope);\n\t\n\t if (cloneConnectFn) cloneConnectFn($linkNode, scope);\n\t if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);\n\t return $linkNode;\n\t };\n\t }\n\t\n\t function detectNamespaceForChildElements(parentElement) {\n\t // TODO: Make this detect MathML as well...\n\t var node = parentElement && parentElement[0];\n\t if (!node) {\n\t return 'html';\n\t } else {\n\t return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';\n\t }\n\t }\n\t\n\t /**\n\t * Compile function matches each node in nodeList against the directives. Once all directives\n\t * for a particular node are collected their compile functions are executed. The compile\n\t * functions return values - the linking functions - are combined into a composite linking\n\t * function, which is the a linking function for the node.\n\t *\n\t * @param {NodeList} nodeList an array of nodes or NodeList to compile\n\t * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the\n\t * scope argument is auto-generated to the new child of the transcluded parent scope.\n\t * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then\n\t * the rootElement must be set the jqLite collection of the compile root. This is\n\t * needed so that the jqLite collection items can be replaced with widgets.\n\t * @param {number=} maxPriority Max directive priority.\n\t * @returns {Function} A composite linking function of all of the matched directives or null.\n\t */\n\t function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,\n\t previousCompileContext) {\n\t var linkFns = [],\n\t attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;\n\t\n\t for (var i = 0; i < nodeList.length; i++) {\n\t attrs = new Attributes();\n\t\n\t // we must always refer to nodeList[i] since the nodes can be replaced underneath us.\n\t directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,\n\t ignoreDirective);\n\t\n\t nodeLinkFn = (directives.length)\n\t ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,\n\t null, [], [], previousCompileContext)\n\t : null;\n\t\n\t if (nodeLinkFn && nodeLinkFn.scope) {\n\t compile.$$addScopeClass(attrs.$$element);\n\t }\n\t\n\t childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||\n\t !(childNodes = nodeList[i].childNodes) ||\n\t !childNodes.length)\n\t ? null\n\t : compileNodes(childNodes,\n\t nodeLinkFn ? (\n\t (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)\n\t && nodeLinkFn.transclude) : transcludeFn);\n\t\n\t if (nodeLinkFn || childLinkFn) {\n\t linkFns.push(i, nodeLinkFn, childLinkFn);\n\t linkFnFound = true;\n\t nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;\n\t }\n\t\n\t //use the previous context only for the first element in the virtual group\n\t previousCompileContext = null;\n\t }\n\t\n\t // return a linking function if we have found anything, null otherwise\n\t return linkFnFound ? compositeLinkFn : null;\n\t\n\t function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {\n\t var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;\n\t var stableNodeList;\n\t\n\t\n\t if (nodeLinkFnFound) {\n\t // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our\n\t // offsets don't get screwed up\n\t var nodeListLength = nodeList.length;\n\t stableNodeList = new Array(nodeListLength);\n\t\n\t // create a sparse array by only copying the elements which have a linkFn\n\t for (i = 0; i < linkFns.length; i+=3) {\n\t idx = linkFns[i];\n\t stableNodeList[idx] = nodeList[idx];\n\t }\n\t } else {\n\t stableNodeList = nodeList;\n\t }\n\t\n\t for (i = 0, ii = linkFns.length; i < ii;) {\n\t node = stableNodeList[linkFns[i++]];\n\t nodeLinkFn = linkFns[i++];\n\t childLinkFn = linkFns[i++];\n\t\n\t if (nodeLinkFn) {\n\t if (nodeLinkFn.scope) {\n\t childScope = scope.$new();\n\t compile.$$addScopeInfo(jqLite(node), childScope);\n\t } else {\n\t childScope = scope;\n\t }\n\t\n\t if (nodeLinkFn.transcludeOnThisElement) {\n\t childBoundTranscludeFn = createBoundTranscludeFn(\n\t scope, nodeLinkFn.transclude, parentBoundTranscludeFn);\n\t\n\t } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {\n\t childBoundTranscludeFn = parentBoundTranscludeFn;\n\t\n\t } else if (!parentBoundTranscludeFn && transcludeFn) {\n\t childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);\n\t\n\t } else {\n\t childBoundTranscludeFn = null;\n\t }\n\t\n\t nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);\n\t\n\t } else if (childLinkFn) {\n\t childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);\n\t }\n\t }\n\t }\n\t }\n\t\n\t function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {\n\t function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {\n\t\n\t if (!transcludedScope) {\n\t transcludedScope = scope.$new(false, containingScope);\n\t transcludedScope.$$transcluded = true;\n\t }\n\t\n\t return transcludeFn(transcludedScope, cloneFn, {\n\t parentBoundTranscludeFn: previousBoundTranscludeFn,\n\t transcludeControllers: controllers,\n\t futureParentElement: futureParentElement\n\t });\n\t }\n\t\n\t // We need to attach the transclusion slots onto the `boundTranscludeFn`\n\t // so that they are available inside the `controllersBoundTransclude` function\n\t var boundSlots = boundTranscludeFn.$$slots = createMap();\n\t for (var slotName in transcludeFn.$$slots) {\n\t if (transcludeFn.$$slots[slotName]) {\n\t boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);\n\t } else {\n\t boundSlots[slotName] = null;\n\t }\n\t }\n\t\n\t return boundTranscludeFn;\n\t }\n\t\n\t /**\n\t * Looks for directives on the given node and adds them to the directive collection which is\n\t * sorted.\n\t *\n\t * @param node Node to search.\n\t * @param directives An array to which the directives are added to. This array is sorted before\n\t * the function returns.\n\t * @param attrs The shared attrs object which is used to populate the normalized attributes.\n\t * @param {number=} maxPriority Max directive priority.\n\t */\n\t function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {\n\t var nodeType = node.nodeType,\n\t attrsMap = attrs.$attr,\n\t match,\n\t className;\n\t\n\t switch (nodeType) {\n\t case NODE_TYPE_ELEMENT: /* Element */\n\t // use the node name: \n\t addDirective(directives,\n\t directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);\n\t\n\t // iterate over the attributes\n\t for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,\n\t j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {\n\t var attrStartName = false;\n\t var attrEndName = false;\n\t\n\t attr = nAttrs[j];\n\t name = attr.name;\n\t value = trim(attr.value);\n\t\n\t // support ngAttr attribute binding\n\t ngAttrName = directiveNormalize(name);\n\t if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {\n\t name = name.replace(PREFIX_REGEXP, '')\n\t .substr(8).replace(/_(.)/g, function(match, letter) {\n\t return letter.toUpperCase();\n\t });\n\t }\n\t\n\t var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);\n\t if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {\n\t attrStartName = name;\n\t attrEndName = name.substr(0, name.length - 5) + 'end';\n\t name = name.substr(0, name.length - 6);\n\t }\n\t\n\t nName = directiveNormalize(name.toLowerCase());\n\t attrsMap[nName] = name;\n\t if (isNgAttr || !attrs.hasOwnProperty(nName)) {\n\t attrs[nName] = value;\n\t if (getBooleanAttrName(node, nName)) {\n\t attrs[nName] = true; // presence means true\n\t }\n\t }\n\t addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);\n\t addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,\n\t attrEndName);\n\t }\n\t\n\t // use class as directive\n\t className = node.className;\n\t if (isObject(className)) {\n\t // Maybe SVGAnimatedString\n\t className = className.animVal;\n\t }\n\t if (isString(className) && className !== '') {\n\t while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {\n\t nName = directiveNormalize(match[2]);\n\t if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {\n\t attrs[nName] = trim(match[3]);\n\t }\n\t className = className.substr(match.index + match[0].length);\n\t }\n\t }\n\t break;\n\t case NODE_TYPE_TEXT: /* Text Node */\n\t if (msie === 11) {\n\t // Workaround for #11781\n\t while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {\n\t node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;\n\t node.parentNode.removeChild(node.nextSibling);\n\t }\n\t }\n\t addTextInterpolateDirective(directives, node.nodeValue);\n\t break;\n\t case NODE_TYPE_COMMENT: /* Comment */\n\t collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);\n\t break;\n\t }\n\t\n\t directives.sort(byPriority);\n\t return directives;\n\t }\n\t\n\t function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {\n\t // function created because of performance, try/catch disables\n\t // the optimization of the whole function #14848\n\t try {\n\t var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);\n\t if (match) {\n\t var nName = directiveNormalize(match[1]);\n\t if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {\n\t attrs[nName] = trim(match[2]);\n\t }\n\t }\n\t } catch (e) {\n\t // turns out that under some circumstances IE9 throws errors when one attempts to read\n\t // comment's node value.\n\t // Just ignore it and continue. (Can't seem to reproduce in test case.)\n\t }\n\t }\n\t\n\t /**\n\t * Given a node with an directive-start it collects all of the siblings until it finds\n\t * directive-end.\n\t * @param node\n\t * @param attrStart\n\t * @param attrEnd\n\t * @returns {*}\n\t */\n\t function groupScan(node, attrStart, attrEnd) {\n\t var nodes = [];\n\t var depth = 0;\n\t if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {\n\t do {\n\t if (!node) {\n\t throw $compileMinErr('uterdir',\n\t \"Unterminated attribute, found '{0}' but no matching '{1}' found.\",\n\t attrStart, attrEnd);\n\t }\n\t if (node.nodeType == NODE_TYPE_ELEMENT) {\n\t if (node.hasAttribute(attrStart)) depth++;\n\t if (node.hasAttribute(attrEnd)) depth--;\n\t }\n\t nodes.push(node);\n\t node = node.nextSibling;\n\t } while (depth > 0);\n\t } else {\n\t nodes.push(node);\n\t }\n\t\n\t return jqLite(nodes);\n\t }\n\t\n\t /**\n\t * Wrapper for linking function which converts normal linking function into a grouped\n\t * linking function.\n\t * @param linkFn\n\t * @param attrStart\n\t * @param attrEnd\n\t * @returns {Function}\n\t */\n\t function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {\n\t return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {\n\t element = groupScan(element[0], attrStart, attrEnd);\n\t return linkFn(scope, element, attrs, controllers, transcludeFn);\n\t };\n\t }\n\t\n\t /**\n\t * A function generator that is used to support both eager and lazy compilation\n\t * linking function.\n\t * @param eager\n\t * @param $compileNodes\n\t * @param transcludeFn\n\t * @param maxPriority\n\t * @param ignoreDirective\n\t * @param previousCompileContext\n\t * @returns {Function}\n\t */\n\t function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {\n\t var compiled;\n\t\n\t if (eager) {\n\t return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);\n\t }\n\t return function lazyCompilation() {\n\t if (!compiled) {\n\t compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);\n\t\n\t // Null out all of these references in order to make them eligible for garbage collection\n\t // since this is a potentially long lived closure\n\t $compileNodes = transcludeFn = previousCompileContext = null;\n\t }\n\t return compiled.apply(this, arguments);\n\t };\n\t }\n\t\n\t /**\n\t * Once the directives have been collected, their compile functions are executed. This method\n\t * is responsible for inlining directive templates as well as terminating the application\n\t * of the directives if the terminal directive has been reached.\n\t *\n\t * @param {Array} directives Array of collected directives to execute their compile function.\n\t * this needs to be pre-sorted by priority order.\n\t * @param {Node} compileNode The raw DOM node to apply the compile functions to\n\t * @param {Object} templateAttrs The shared attribute function\n\t * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the\n\t * scope argument is auto-generated to the new\n\t * child of the transcluded parent scope.\n\t * @param {JQLite} jqCollection If we are working on the root of the compile tree then this\n\t * argument has the root jqLite array so that we can replace nodes\n\t * on it.\n\t * @param {Object=} originalReplaceDirective An optional directive that will be ignored when\n\t * compiling the transclusion.\n\t * @param {Array.} preLinkFns\n\t * @param {Array.} postLinkFns\n\t * @param {Object} previousCompileContext Context used for previous compilation of the current\n\t * node\n\t * @returns {Function} linkFn\n\t */\n\t function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,\n\t jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,\n\t previousCompileContext) {\n\t previousCompileContext = previousCompileContext || {};\n\t\n\t var terminalPriority = -Number.MAX_VALUE,\n\t newScopeDirective = previousCompileContext.newScopeDirective,\n\t controllerDirectives = previousCompileContext.controllerDirectives,\n\t newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,\n\t templateDirective = previousCompileContext.templateDirective,\n\t nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,\n\t hasTranscludeDirective = false,\n\t hasTemplate = false,\n\t hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,\n\t $compileNode = templateAttrs.$$element = jqLite(compileNode),\n\t directive,\n\t directiveName,\n\t $template,\n\t replaceDirective = originalReplaceDirective,\n\t childTranscludeFn = transcludeFn,\n\t linkFn,\n\t didScanForMultipleTransclusion = false,\n\t mightHaveMultipleTransclusionError = false,\n\t directiveValue;\n\t\n\t // executes all directives on the current element\n\t for (var i = 0, ii = directives.length; i < ii; i++) {\n\t directive = directives[i];\n\t var attrStart = directive.$$start;\n\t var attrEnd = directive.$$end;\n\t\n\t // collect multiblock sections\n\t if (attrStart) {\n\t $compileNode = groupScan(compileNode, attrStart, attrEnd);\n\t }\n\t $template = undefined;\n\t\n\t if (terminalPriority > directive.priority) {\n\t break; // prevent further processing of directives\n\t }\n\t\n\t if (directiveValue = directive.scope) {\n\t\n\t // skip the check for directives with async templates, we'll check the derived sync\n\t // directive when the template arrives\n\t if (!directive.templateUrl) {\n\t if (isObject(directiveValue)) {\n\t // This directive is trying to add an isolated scope.\n\t // Check that there is no scope of any kind already\n\t assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,\n\t directive, $compileNode);\n\t newIsolateScopeDirective = directive;\n\t } else {\n\t // This directive is trying to add a child scope.\n\t // Check that there is no isolated scope already\n\t assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,\n\t $compileNode);\n\t }\n\t }\n\t\n\t newScopeDirective = newScopeDirective || directive;\n\t }\n\t\n\t directiveName = directive.name;\n\t\n\t // If we encounter a condition that can result in transclusion on the directive,\n\t // then scan ahead in the remaining directives for others that may cause a multiple\n\t // transclusion error to be thrown during the compilation process. If a matching directive\n\t // is found, then we know that when we encounter a transcluded directive, we need to eagerly\n\t // compile the `transclude` function rather than doing it lazily in order to throw\n\t // exceptions at the correct time\n\t if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))\n\t || (directive.transclude && !directive.$$tlb))) {\n\t var candidateDirective;\n\t\n\t for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {\n\t if ((candidateDirective.transclude && !candidateDirective.$$tlb)\n\t || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {\n\t mightHaveMultipleTransclusionError = true;\n\t break;\n\t }\n\t }\n\t\n\t didScanForMultipleTransclusion = true;\n\t }\n\t\n\t if (!directive.templateUrl && directive.controller) {\n\t directiveValue = directive.controller;\n\t controllerDirectives = controllerDirectives || createMap();\n\t assertNoDuplicate(\"'\" + directiveName + \"' controller\",\n\t controllerDirectives[directiveName], directive, $compileNode);\n\t controllerDirectives[directiveName] = directive;\n\t }\n\t\n\t if (directiveValue = directive.transclude) {\n\t hasTranscludeDirective = true;\n\t\n\t // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.\n\t // This option should only be used by directives that know how to safely handle element transclusion,\n\t // where the transcluded nodes are added or replaced after linking.\n\t if (!directive.$$tlb) {\n\t assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);\n\t nonTlbTranscludeDirective = directive;\n\t }\n\t\n\t if (directiveValue == 'element') {\n\t hasElementTranscludeDirective = true;\n\t terminalPriority = directive.priority;\n\t $template = $compileNode;\n\t $compileNode = templateAttrs.$$element =\n\t jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));\n\t compileNode = $compileNode[0];\n\t replaceWith(jqCollection, sliceArgs($template), compileNode);\n\t\n\t // Support: Chrome < 50\n\t // https://github.com/angular/angular.js/issues/14041\n\t\n\t // In the versions of V8 prior to Chrome 50, the document fragment that is created\n\t // in the `replaceWith` function is improperly garbage collected despite still\n\t // being referenced by the `parentNode` property of all of the child nodes. By adding\n\t // a reference to the fragment via a different property, we can avoid that incorrect\n\t // behavior.\n\t // TODO: remove this line after Chrome 50 has been released\n\t $template[0].$$parentNode = $template[0].parentNode;\n\t\n\t childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,\n\t replaceDirective && replaceDirective.name, {\n\t // Don't pass in:\n\t // - controllerDirectives - otherwise we'll create duplicates controllers\n\t // - newIsolateScopeDirective or templateDirective - combining templates with\n\t // element transclusion doesn't make sense.\n\t //\n\t // We need only nonTlbTranscludeDirective so that we prevent putting transclusion\n\t // on the same element more than once.\n\t nonTlbTranscludeDirective: nonTlbTranscludeDirective\n\t });\n\t } else {\n\t\n\t var slots = createMap();\n\t\n\t $template = jqLite(jqLiteClone(compileNode)).contents();\n\t\n\t if (isObject(directiveValue)) {\n\t\n\t // We have transclusion slots,\n\t // collect them up, compile them and store their transclusion functions\n\t $template = [];\n\t\n\t var slotMap = createMap();\n\t var filledSlots = createMap();\n\t\n\t // Parse the element selectors\n\t forEach(directiveValue, function(elementSelector, slotName) {\n\t // If an element selector starts with a ? then it is optional\n\t var optional = (elementSelector.charAt(0) === '?');\n\t elementSelector = optional ? elementSelector.substring(1) : elementSelector;\n\t\n\t slotMap[elementSelector] = slotName;\n\t\n\t // We explicitly assign `null` since this implies that a slot was defined but not filled.\n\t // Later when calling boundTransclusion functions with a slot name we only error if the\n\t // slot is `undefined`\n\t slots[slotName] = null;\n\t\n\t // filledSlots contains `true` for all slots that are either optional or have been\n\t // filled. This is used to check that we have not missed any required slots\n\t filledSlots[slotName] = optional;\n\t });\n\t\n\t // Add the matching elements into their slot\n\t forEach($compileNode.contents(), function(node) {\n\t var slotName = slotMap[directiveNormalize(nodeName_(node))];\n\t if (slotName) {\n\t filledSlots[slotName] = true;\n\t slots[slotName] = slots[slotName] || [];\n\t slots[slotName].push(node);\n\t } else {\n\t $template.push(node);\n\t }\n\t });\n\t\n\t // Check for required slots that were not filled\n\t forEach(filledSlots, function(filled, slotName) {\n\t if (!filled) {\n\t throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);\n\t }\n\t });\n\t\n\t for (var slotName in slots) {\n\t if (slots[slotName]) {\n\t // Only define a transclusion function if the slot was filled\n\t slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);\n\t }\n\t }\n\t }\n\t\n\t $compileNode.empty(); // clear contents\n\t childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,\n\t undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});\n\t childTranscludeFn.$$slots = slots;\n\t }\n\t }\n\t\n\t if (directive.template) {\n\t hasTemplate = true;\n\t assertNoDuplicate('template', templateDirective, directive, $compileNode);\n\t templateDirective = directive;\n\t\n\t directiveValue = (isFunction(directive.template))\n\t ? directive.template($compileNode, templateAttrs)\n\t : directive.template;\n\t\n\t directiveValue = denormalizeTemplate(directiveValue);\n\t\n\t if (directive.replace) {\n\t replaceDirective = directive;\n\t if (jqLiteIsTextNode(directiveValue)) {\n\t $template = [];\n\t } else {\n\t $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));\n\t }\n\t compileNode = $template[0];\n\t\n\t if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {\n\t throw $compileMinErr('tplrt',\n\t \"Template for directive '{0}' must have exactly one root element. {1}\",\n\t directiveName, '');\n\t }\n\t\n\t replaceWith(jqCollection, $compileNode, compileNode);\n\t\n\t var newTemplateAttrs = {$attr: {}};\n\t\n\t // combine directives from the original node and from the template:\n\t // - take the array of directives for this element\n\t // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)\n\t // - collect directives from the template and sort them by priority\n\t // - combine directives as: processed + template + unprocessed\n\t var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);\n\t var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));\n\t\n\t if (newIsolateScopeDirective || newScopeDirective) {\n\t // The original directive caused the current element to be replaced but this element\n\t // also needs to have a new scope, so we need to tell the template directives\n\t // that they would need to get their scope from further up, if they require transclusion\n\t markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);\n\t }\n\t directives = directives.concat(templateDirectives).concat(unprocessedDirectives);\n\t mergeTemplateAttributes(templateAttrs, newTemplateAttrs);\n\t\n\t ii = directives.length;\n\t } else {\n\t $compileNode.html(directiveValue);\n\t }\n\t }\n\t\n\t if (directive.templateUrl) {\n\t hasTemplate = true;\n\t assertNoDuplicate('template', templateDirective, directive, $compileNode);\n\t templateDirective = directive;\n\t\n\t if (directive.replace) {\n\t replaceDirective = directive;\n\t }\n\t\n\t /* jshint -W021 */\n\t nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,\n\t /* jshint +W021 */\n\t templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {\n\t controllerDirectives: controllerDirectives,\n\t newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,\n\t newIsolateScopeDirective: newIsolateScopeDirective,\n\t templateDirective: templateDirective,\n\t nonTlbTranscludeDirective: nonTlbTranscludeDirective\n\t });\n\t ii = directives.length;\n\t } else if (directive.compile) {\n\t try {\n\t linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);\n\t var context = directive.$$originalDirective || directive;\n\t if (isFunction(linkFn)) {\n\t addLinkFns(null, bind(context, linkFn), attrStart, attrEnd);\n\t } else if (linkFn) {\n\t addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd);\n\t }\n\t } catch (e) {\n\t $exceptionHandler(e, startingTag($compileNode));\n\t }\n\t }\n\t\n\t if (directive.terminal) {\n\t nodeLinkFn.terminal = true;\n\t terminalPriority = Math.max(terminalPriority, directive.priority);\n\t }\n\t\n\t }\n\t\n\t nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;\n\t nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;\n\t nodeLinkFn.templateOnThisElement = hasTemplate;\n\t nodeLinkFn.transclude = childTranscludeFn;\n\t\n\t previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;\n\t\n\t // might be normal or delayed nodeLinkFn depending on if templateUrl is present\n\t return nodeLinkFn;\n\t\n\t ////////////////////\n\t\n\t function addLinkFns(pre, post, attrStart, attrEnd) {\n\t if (pre) {\n\t if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);\n\t pre.require = directive.require;\n\t pre.directiveName = directiveName;\n\t if (newIsolateScopeDirective === directive || directive.$$isolateScope) {\n\t pre = cloneAndAnnotateFn(pre, {isolateScope: true});\n\t }\n\t preLinkFns.push(pre);\n\t }\n\t if (post) {\n\t if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);\n\t post.require = directive.require;\n\t post.directiveName = directiveName;\n\t if (newIsolateScopeDirective === directive || directive.$$isolateScope) {\n\t post = cloneAndAnnotateFn(post, {isolateScope: true});\n\t }\n\t postLinkFns.push(post);\n\t }\n\t }\n\t\n\t function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {\n\t var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,\n\t attrs, scopeBindingInfo;\n\t\n\t if (compileNode === linkNode) {\n\t attrs = templateAttrs;\n\t $element = templateAttrs.$$element;\n\t } else {\n\t $element = jqLite(linkNode);\n\t attrs = new Attributes($element, templateAttrs);\n\t }\n\t\n\t controllerScope = scope;\n\t if (newIsolateScopeDirective) {\n\t isolateScope = scope.$new(true);\n\t } else if (newScopeDirective) {\n\t controllerScope = scope.$parent;\n\t }\n\t\n\t if (boundTranscludeFn) {\n\t // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`\n\t // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`\n\t transcludeFn = controllersBoundTransclude;\n\t transcludeFn.$$boundTransclude = boundTranscludeFn;\n\t // expose the slots on the `$transclude` function\n\t transcludeFn.isSlotFilled = function(slotName) {\n\t return !!boundTranscludeFn.$$slots[slotName];\n\t };\n\t }\n\t\n\t if (controllerDirectives) {\n\t elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);\n\t }\n\t\n\t if (newIsolateScopeDirective) {\n\t // Initialize isolate scope bindings for new isolate scope directive.\n\t compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||\n\t templateDirective === newIsolateScopeDirective.$$originalDirective)));\n\t compile.$$addScopeClass($element, true);\n\t isolateScope.$$isolateBindings =\n\t newIsolateScopeDirective.$$isolateBindings;\n\t scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,\n\t isolateScope.$$isolateBindings,\n\t newIsolateScopeDirective);\n\t if (scopeBindingInfo.removeWatches) {\n\t isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);\n\t }\n\t }\n\t\n\t // Initialize bindToController bindings\n\t for (var name in elementControllers) {\n\t var controllerDirective = controllerDirectives[name];\n\t var controller = elementControllers[name];\n\t var bindings = controllerDirective.$$bindings.bindToController;\n\t\n\t if (controller.identifier && bindings) {\n\t controller.bindingInfo =\n\t initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);\n\t } else {\n\t controller.bindingInfo = {};\n\t }\n\t\n\t var controllerResult = controller();\n\t if (controllerResult !== controller.instance) {\n\t // If the controller constructor has a return value, overwrite the instance\n\t // from setupControllers\n\t controller.instance = controllerResult;\n\t $element.data('$' + controllerDirective.name + 'Controller', controllerResult);\n\t controller.bindingInfo.removeWatches && controller.bindingInfo.removeWatches();\n\t controller.bindingInfo =\n\t initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);\n\t }\n\t }\n\t\n\t // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy\n\t forEach(controllerDirectives, function(controllerDirective, name) {\n\t var require = controllerDirective.require;\n\t if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {\n\t extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));\n\t }\n\t });\n\t\n\t // Handle the init and destroy lifecycle hooks on all controllers that have them\n\t forEach(elementControllers, function(controller) {\n\t var controllerInstance = controller.instance;\n\t if (isFunction(controllerInstance.$onChanges)) {\n\t try {\n\t controllerInstance.$onChanges(controller.bindingInfo.initialChanges);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t if (isFunction(controllerInstance.$onInit)) {\n\t try {\n\t controllerInstance.$onInit();\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t if (isFunction(controllerInstance.$doCheck)) {\n\t controllerScope.$watch(function() { controllerInstance.$doCheck(); });\n\t controllerInstance.$doCheck();\n\t }\n\t if (isFunction(controllerInstance.$onDestroy)) {\n\t controllerScope.$on('$destroy', function callOnDestroyHook() {\n\t controllerInstance.$onDestroy();\n\t });\n\t }\n\t });\n\t\n\t // PRELINKING\n\t for (i = 0, ii = preLinkFns.length; i < ii; i++) {\n\t linkFn = preLinkFns[i];\n\t invokeLinkFn(linkFn,\n\t linkFn.isolateScope ? isolateScope : scope,\n\t $element,\n\t attrs,\n\t linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),\n\t transcludeFn\n\t );\n\t }\n\t\n\t // RECURSION\n\t // We only pass the isolate scope, if the isolate directive has a template,\n\t // otherwise the child elements do not belong to the isolate directive.\n\t var scopeToChild = scope;\n\t if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {\n\t scopeToChild = isolateScope;\n\t }\n\t childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);\n\t\n\t // POSTLINKING\n\t for (i = postLinkFns.length - 1; i >= 0; i--) {\n\t linkFn = postLinkFns[i];\n\t invokeLinkFn(linkFn,\n\t linkFn.isolateScope ? isolateScope : scope,\n\t $element,\n\t attrs,\n\t linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),\n\t transcludeFn\n\t );\n\t }\n\t\n\t // Trigger $postLink lifecycle hooks\n\t forEach(elementControllers, function(controller) {\n\t var controllerInstance = controller.instance;\n\t if (isFunction(controllerInstance.$postLink)) {\n\t controllerInstance.$postLink();\n\t }\n\t });\n\t\n\t // This is the function that is injected as `$transclude`.\n\t // Note: all arguments are optional!\n\t function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {\n\t var transcludeControllers;\n\t // No scope passed in:\n\t if (!isScope(scope)) {\n\t slotName = futureParentElement;\n\t futureParentElement = cloneAttachFn;\n\t cloneAttachFn = scope;\n\t scope = undefined;\n\t }\n\t\n\t if (hasElementTranscludeDirective) {\n\t transcludeControllers = elementControllers;\n\t }\n\t if (!futureParentElement) {\n\t futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;\n\t }\n\t if (slotName) {\n\t // slotTranscludeFn can be one of three things:\n\t // * a transclude function - a filled slot\n\t // * `null` - an optional slot that was not filled\n\t // * `undefined` - a slot that was not declared (i.e. invalid)\n\t var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];\n\t if (slotTranscludeFn) {\n\t return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);\n\t } else if (isUndefined(slotTranscludeFn)) {\n\t throw $compileMinErr('noslot',\n\t 'No parent directive that requires a transclusion with slot name \"{0}\". ' +\n\t 'Element: {1}',\n\t slotName, startingTag($element));\n\t }\n\t } else {\n\t return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);\n\t }\n\t }\n\t }\n\t }\n\t\n\t function getControllers(directiveName, require, $element, elementControllers) {\n\t var value;\n\t\n\t if (isString(require)) {\n\t var match = require.match(REQUIRE_PREFIX_REGEXP);\n\t var name = require.substring(match[0].length);\n\t var inheritType = match[1] || match[3];\n\t var optional = match[2] === '?';\n\t\n\t //If only parents then start at the parent element\n\t if (inheritType === '^^') {\n\t $element = $element.parent();\n\t //Otherwise attempt getting the controller from elementControllers in case\n\t //the element is transcluded (and has no data) and to avoid .data if possible\n\t } else {\n\t value = elementControllers && elementControllers[name];\n\t value = value && value.instance;\n\t }\n\t\n\t if (!value) {\n\t var dataName = '$' + name + 'Controller';\n\t value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);\n\t }\n\t\n\t if (!value && !optional) {\n\t throw $compileMinErr('ctreq',\n\t \"Controller '{0}', required by directive '{1}', can't be found!\",\n\t name, directiveName);\n\t }\n\t } else if (isArray(require)) {\n\t value = [];\n\t for (var i = 0, ii = require.length; i < ii; i++) {\n\t value[i] = getControllers(directiveName, require[i], $element, elementControllers);\n\t }\n\t } else if (isObject(require)) {\n\t value = {};\n\t forEach(require, function(controller, property) {\n\t value[property] = getControllers(directiveName, controller, $element, elementControllers);\n\t });\n\t }\n\t\n\t return value || null;\n\t }\n\t\n\t function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {\n\t var elementControllers = createMap();\n\t for (var controllerKey in controllerDirectives) {\n\t var directive = controllerDirectives[controllerKey];\n\t var locals = {\n\t $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,\n\t $element: $element,\n\t $attrs: attrs,\n\t $transclude: transcludeFn\n\t };\n\t\n\t var controller = directive.controller;\n\t if (controller == '@') {\n\t controller = attrs[directive.name];\n\t }\n\t\n\t var controllerInstance = $controller(controller, locals, true, directive.controllerAs);\n\t\n\t // For directives with element transclusion the element is a comment.\n\t // In this case .data will not attach any data.\n\t // Instead, we save the controllers for the element in a local hash and attach to .data\n\t // later, once we have the actual element.\n\t elementControllers[directive.name] = controllerInstance;\n\t $element.data('$' + directive.name + 'Controller', controllerInstance.instance);\n\t }\n\t return elementControllers;\n\t }\n\t\n\t // Depending upon the context in which a directive finds itself it might need to have a new isolated\n\t // or child scope created. For instance:\n\t // * if the directive has been pulled into a template because another directive with a higher priority\n\t // asked for element transclusion\n\t // * if the directive itself asks for transclusion but it is at the root of a template and the original\n\t // element was replaced. See https://github.com/angular/angular.js/issues/12936\n\t function markDirectiveScope(directives, isolateScope, newScope) {\n\t for (var j = 0, jj = directives.length; j < jj; j++) {\n\t directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});\n\t }\n\t }\n\t\n\t /**\n\t * looks up the directive and decorates it with exception handling and proper parameters. We\n\t * call this the boundDirective.\n\t *\n\t * @param {string} name name of the directive to look up.\n\t * @param {string} location The directive must be found in specific format.\n\t * String containing any of theses characters:\n\t *\n\t * * `E`: element name\n\t * * `A': attribute\n\t * * `C`: class\n\t * * `M`: comment\n\t * @returns {boolean} true if directive was added.\n\t */\n\t function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,\n\t endAttrName) {\n\t if (name === ignoreDirective) return null;\n\t var match = null;\n\t if (hasDirectives.hasOwnProperty(name)) {\n\t for (var directive, directives = $injector.get(name + Suffix),\n\t i = 0, ii = directives.length; i < ii; i++) {\n\t try {\n\t directive = directives[i];\n\t if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&\n\t directive.restrict.indexOf(location) != -1) {\n\t if (startAttrName) {\n\t directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});\n\t }\n\t if (!directive.$$bindings) {\n\t var bindings = directive.$$bindings =\n\t parseDirectiveBindings(directive, directive.name);\n\t if (isObject(bindings.isolateScope)) {\n\t directive.$$isolateBindings = bindings.isolateScope;\n\t }\n\t }\n\t tDirectives.push(directive);\n\t match = directive;\n\t }\n\t } catch (e) { $exceptionHandler(e); }\n\t }\n\t }\n\t return match;\n\t }\n\t\n\t\n\t /**\n\t * looks up the directive and returns true if it is a multi-element directive,\n\t * and therefore requires DOM nodes between -start and -end markers to be grouped\n\t * together.\n\t *\n\t * @param {string} name name of the directive to look up.\n\t * @returns true if directive was registered as multi-element.\n\t */\n\t function directiveIsMultiElement(name) {\n\t if (hasDirectives.hasOwnProperty(name)) {\n\t for (var directive, directives = $injector.get(name + Suffix),\n\t i = 0, ii = directives.length; i < ii; i++) {\n\t directive = directives[i];\n\t if (directive.multiElement) {\n\t return true;\n\t }\n\t }\n\t }\n\t return false;\n\t }\n\t\n\t /**\n\t * When the element is replaced with HTML template then the new attributes\n\t * on the template need to be merged with the existing attributes in the DOM.\n\t * The desired effect is to have both of the attributes present.\n\t *\n\t * @param {object} dst destination attributes (original DOM)\n\t * @param {object} src source attributes (from the directive template)\n\t */\n\t function mergeTemplateAttributes(dst, src) {\n\t var srcAttr = src.$attr,\n\t dstAttr = dst.$attr,\n\t $element = dst.$$element;\n\t\n\t // reapply the old attributes to the new element\n\t forEach(dst, function(value, key) {\n\t if (key.charAt(0) != '$') {\n\t if (src[key] && src[key] !== value) {\n\t value += (key === 'style' ? ';' : ' ') + src[key];\n\t }\n\t dst.$set(key, value, true, srcAttr[key]);\n\t }\n\t });\n\t\n\t // copy the new attributes on the old attrs object\n\t forEach(src, function(value, key) {\n\t // Check if we already set this attribute in the loop above.\n\t // `dst` will never contain hasOwnProperty as DOM parser won't let it.\n\t // You will get an \"InvalidCharacterError: DOM Exception 5\" error if you\n\t // have an attribute like \"has-own-property\" or \"data-has-own-property\", etc.\n\t if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {\n\t dst[key] = value;\n\t\n\t if (key !== 'class' && key !== 'style') {\n\t dstAttr[key] = srcAttr[key];\n\t }\n\t }\n\t });\n\t }\n\t\n\t\n\t function compileTemplateUrl(directives, $compileNode, tAttrs,\n\t $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {\n\t var linkQueue = [],\n\t afterTemplateNodeLinkFn,\n\t afterTemplateChildLinkFn,\n\t beforeTemplateCompileNode = $compileNode[0],\n\t origAsyncDirective = directives.shift(),\n\t derivedSyncDirective = inherit(origAsyncDirective, {\n\t templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective\n\t }),\n\t templateUrl = (isFunction(origAsyncDirective.templateUrl))\n\t ? origAsyncDirective.templateUrl($compileNode, tAttrs)\n\t : origAsyncDirective.templateUrl,\n\t templateNamespace = origAsyncDirective.templateNamespace;\n\t\n\t $compileNode.empty();\n\t\n\t $templateRequest(templateUrl)\n\t .then(function(content) {\n\t var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;\n\t\n\t content = denormalizeTemplate(content);\n\t\n\t if (origAsyncDirective.replace) {\n\t if (jqLiteIsTextNode(content)) {\n\t $template = [];\n\t } else {\n\t $template = removeComments(wrapTemplate(templateNamespace, trim(content)));\n\t }\n\t compileNode = $template[0];\n\t\n\t if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {\n\t throw $compileMinErr('tplrt',\n\t \"Template for directive '{0}' must have exactly one root element. {1}\",\n\t origAsyncDirective.name, templateUrl);\n\t }\n\t\n\t tempTemplateAttrs = {$attr: {}};\n\t replaceWith($rootElement, $compileNode, compileNode);\n\t var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);\n\t\n\t if (isObject(origAsyncDirective.scope)) {\n\t // the original directive that caused the template to be loaded async required\n\t // an isolate scope\n\t markDirectiveScope(templateDirectives, true);\n\t }\n\t directives = templateDirectives.concat(directives);\n\t mergeTemplateAttributes(tAttrs, tempTemplateAttrs);\n\t } else {\n\t compileNode = beforeTemplateCompileNode;\n\t $compileNode.html(content);\n\t }\n\t\n\t directives.unshift(derivedSyncDirective);\n\t\n\t afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,\n\t childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,\n\t previousCompileContext);\n\t forEach($rootElement, function(node, i) {\n\t if (node == compileNode) {\n\t $rootElement[i] = $compileNode[0];\n\t }\n\t });\n\t afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);\n\t\n\t while (linkQueue.length) {\n\t var scope = linkQueue.shift(),\n\t beforeTemplateLinkNode = linkQueue.shift(),\n\t linkRootElement = linkQueue.shift(),\n\t boundTranscludeFn = linkQueue.shift(),\n\t linkNode = $compileNode[0];\n\t\n\t if (scope.$$destroyed) continue;\n\t\n\t if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {\n\t var oldClasses = beforeTemplateLinkNode.className;\n\t\n\t if (!(previousCompileContext.hasElementTranscludeDirective &&\n\t origAsyncDirective.replace)) {\n\t // it was cloned therefore we have to clone as well.\n\t linkNode = jqLiteClone(compileNode);\n\t }\n\t replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);\n\t\n\t // Copy in CSS classes from original node\n\t safeAddClass(jqLite(linkNode), oldClasses);\n\t }\n\t if (afterTemplateNodeLinkFn.transcludeOnThisElement) {\n\t childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);\n\t } else {\n\t childBoundTranscludeFn = boundTranscludeFn;\n\t }\n\t afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,\n\t childBoundTranscludeFn);\n\t }\n\t linkQueue = null;\n\t });\n\t\n\t return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {\n\t var childBoundTranscludeFn = boundTranscludeFn;\n\t if (scope.$$destroyed) return;\n\t if (linkQueue) {\n\t linkQueue.push(scope,\n\t node,\n\t rootElement,\n\t childBoundTranscludeFn);\n\t } else {\n\t if (afterTemplateNodeLinkFn.transcludeOnThisElement) {\n\t childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);\n\t }\n\t afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);\n\t }\n\t };\n\t }\n\t\n\t\n\t /**\n\t * Sorting function for bound directives.\n\t */\n\t function byPriority(a, b) {\n\t var diff = b.priority - a.priority;\n\t if (diff !== 0) return diff;\n\t if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;\n\t return a.index - b.index;\n\t }\n\t\n\t function assertNoDuplicate(what, previousDirective, directive, element) {\n\t\n\t function wrapModuleNameIfDefined(moduleName) {\n\t return moduleName ?\n\t (' (module: ' + moduleName + ')') :\n\t '';\n\t }\n\t\n\t if (previousDirective) {\n\t throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',\n\t previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),\n\t directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));\n\t }\n\t }\n\t\n\t\n\t function addTextInterpolateDirective(directives, text) {\n\t var interpolateFn = $interpolate(text, true);\n\t if (interpolateFn) {\n\t directives.push({\n\t priority: 0,\n\t compile: function textInterpolateCompileFn(templateNode) {\n\t var templateNodeParent = templateNode.parent(),\n\t hasCompileParent = !!templateNodeParent.length;\n\t\n\t // When transcluding a template that has bindings in the root\n\t // we don't have a parent and thus need to add the class during linking fn.\n\t if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);\n\t\n\t return function textInterpolateLinkFn(scope, node) {\n\t var parent = node.parent();\n\t if (!hasCompileParent) compile.$$addBindingClass(parent);\n\t compile.$$addBindingInfo(parent, interpolateFn.expressions);\n\t scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {\n\t node[0].nodeValue = value;\n\t });\n\t };\n\t }\n\t });\n\t }\n\t }\n\t\n\t\n\t function wrapTemplate(type, template) {\n\t type = lowercase(type || 'html');\n\t switch (type) {\n\t case 'svg':\n\t case 'math':\n\t var wrapper = window.document.createElement('div');\n\t wrapper.innerHTML = '<' + type + '>' + template + '';\n\t return wrapper.childNodes[0].childNodes;\n\t default:\n\t return template;\n\t }\n\t }\n\t\n\t\n\t function getTrustedContext(node, attrNormalizedName) {\n\t if (attrNormalizedName == \"srcdoc\") {\n\t return $sce.HTML;\n\t }\n\t var tag = nodeName_(node);\n\t // maction[xlink:href] can source SVG. It's not limited to .\n\t if (attrNormalizedName == \"xlinkHref\" ||\n\t (tag == \"form\" && attrNormalizedName == \"action\") ||\n\t (tag != \"img\" && (attrNormalizedName == \"src\" ||\n\t attrNormalizedName == \"ngSrc\"))) {\n\t return $sce.RESOURCE_URL;\n\t }\n\t }\n\t\n\t\n\t function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {\n\t var trustedContext = getTrustedContext(node, name);\n\t allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;\n\t\n\t var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);\n\t\n\t // no interpolation found -> ignore\n\t if (!interpolateFn) return;\n\t\n\t\n\t if (name === \"multiple\" && nodeName_(node) === \"select\") {\n\t throw $compileMinErr(\"selmulti\",\n\t \"Binding to the 'multiple' attribute is not supported. Element: {0}\",\n\t startingTag(node));\n\t }\n\t\n\t directives.push({\n\t priority: 100,\n\t compile: function() {\n\t return {\n\t pre: function attrInterpolatePreLinkFn(scope, element, attr) {\n\t var $$observers = (attr.$$observers || (attr.$$observers = createMap()));\n\t\n\t if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {\n\t throw $compileMinErr('nodomevents',\n\t \"Interpolations for HTML DOM event attributes are disallowed. Please use the \" +\n\t \"ng- versions (such as ng-click instead of onclick) instead.\");\n\t }\n\t\n\t // If the attribute has changed since last $interpolate()ed\n\t var newValue = attr[name];\n\t if (newValue !== value) {\n\t // we need to interpolate again since the attribute value has been updated\n\t // (e.g. by another directive's compile function)\n\t // ensure unset/empty values make interpolateFn falsy\n\t interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);\n\t value = newValue;\n\t }\n\t\n\t // if attribute was updated so that there is no interpolation going on we don't want to\n\t // register any observers\n\t if (!interpolateFn) return;\n\t\n\t // initialize attr object so that it's ready in case we need the value for isolate\n\t // scope initialization, otherwise the value would not be available from isolate\n\t // directive's linking fn during linking phase\n\t attr[name] = interpolateFn(scope);\n\t\n\t ($$observers[name] || ($$observers[name] = [])).$$inter = true;\n\t (attr.$$observers && attr.$$observers[name].$$scope || scope).\n\t $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {\n\t //special case for class attribute addition + removal\n\t //so that class changes can tap into the animation\n\t //hooks provided by the $animate service. Be sure to\n\t //skip animations when the first digest occurs (when\n\t //both the new and the old values are the same) since\n\t //the CSS classes are the non-interpolated values\n\t if (name === 'class' && newValue != oldValue) {\n\t attr.$updateClass(newValue, oldValue);\n\t } else {\n\t attr.$set(name, newValue);\n\t }\n\t });\n\t }\n\t };\n\t }\n\t });\n\t }\n\t\n\t\n\t /**\n\t * This is a special jqLite.replaceWith, which can replace items which\n\t * have no parents, provided that the containing jqLite collection is provided.\n\t *\n\t * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes\n\t * in the root of the tree.\n\t * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep\n\t * the shell, but replace its DOM node reference.\n\t * @param {Node} newNode The new DOM node.\n\t */\n\t function replaceWith($rootElement, elementsToRemove, newNode) {\n\t var firstElementToRemove = elementsToRemove[0],\n\t removeCount = elementsToRemove.length,\n\t parent = firstElementToRemove.parentNode,\n\t i, ii;\n\t\n\t if ($rootElement) {\n\t for (i = 0, ii = $rootElement.length; i < ii; i++) {\n\t if ($rootElement[i] == firstElementToRemove) {\n\t $rootElement[i++] = newNode;\n\t for (var j = i, j2 = j + removeCount - 1,\n\t jj = $rootElement.length;\n\t j < jj; j++, j2++) {\n\t if (j2 < jj) {\n\t $rootElement[j] = $rootElement[j2];\n\t } else {\n\t delete $rootElement[j];\n\t }\n\t }\n\t $rootElement.length -= removeCount - 1;\n\t\n\t // If the replaced element is also the jQuery .context then replace it\n\t // .context is a deprecated jQuery api, so we should set it only when jQuery set it\n\t // http://api.jquery.com/context/\n\t if ($rootElement.context === firstElementToRemove) {\n\t $rootElement.context = newNode;\n\t }\n\t break;\n\t }\n\t }\n\t }\n\t\n\t if (parent) {\n\t parent.replaceChild(newNode, firstElementToRemove);\n\t }\n\t\n\t // Append all the `elementsToRemove` to a fragment. This will...\n\t // - remove them from the DOM\n\t // - allow them to still be traversed with .nextSibling\n\t // - allow a single fragment.qSA to fetch all elements being removed\n\t var fragment = window.document.createDocumentFragment();\n\t for (i = 0; i < removeCount; i++) {\n\t fragment.appendChild(elementsToRemove[i]);\n\t }\n\t\n\t if (jqLite.hasData(firstElementToRemove)) {\n\t // Copy over user data (that includes Angular's $scope etc.). Don't copy private\n\t // data here because there's no public interface in jQuery to do that and copying over\n\t // event listeners (which is the main use of private data) wouldn't work anyway.\n\t jqLite.data(newNode, jqLite.data(firstElementToRemove));\n\t\n\t // Remove $destroy event listeners from `firstElementToRemove`\n\t jqLite(firstElementToRemove).off('$destroy');\n\t }\n\t\n\t // Cleanup any data/listeners on the elements and children.\n\t // This includes invoking the $destroy event on any elements with listeners.\n\t jqLite.cleanData(fragment.querySelectorAll('*'));\n\t\n\t // Update the jqLite collection to only contain the `newNode`\n\t for (i = 1; i < removeCount; i++) {\n\t delete elementsToRemove[i];\n\t }\n\t elementsToRemove[0] = newNode;\n\t elementsToRemove.length = 1;\n\t }\n\t\n\t\n\t function cloneAndAnnotateFn(fn, annotation) {\n\t return extend(function() { return fn.apply(null, arguments); }, fn, annotation);\n\t }\n\t\n\t\n\t function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {\n\t try {\n\t linkFn(scope, $element, attrs, controllers, transcludeFn);\n\t } catch (e) {\n\t $exceptionHandler(e, startingTag($element));\n\t }\n\t }\n\t\n\t\n\t // Set up $watches for isolate scope and controller bindings. This process\n\t // only occurs for isolate scopes and new scopes with controllerAs.\n\t function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {\n\t var removeWatchCollection = [];\n\t var initialChanges = {};\n\t var changes;\n\t forEach(bindings, function initializeBinding(definition, scopeName) {\n\t var attrName = definition.attrName,\n\t optional = definition.optional,\n\t mode = definition.mode, // @, =, <, or &\n\t lastValue,\n\t parentGet, parentSet, compare, removeWatch;\n\t\n\t switch (mode) {\n\t\n\t case '@':\n\t if (!optional && !hasOwnProperty.call(attrs, attrName)) {\n\t destination[scopeName] = attrs[attrName] = void 0;\n\t }\n\t attrs.$observe(attrName, function(value) {\n\t if (isString(value) || isBoolean(value)) {\n\t var oldValue = destination[scopeName];\n\t recordChanges(scopeName, value, oldValue);\n\t destination[scopeName] = value;\n\t }\n\t });\n\t attrs.$$observers[attrName].$$scope = scope;\n\t lastValue = attrs[attrName];\n\t if (isString(lastValue)) {\n\t // If the attribute has been provided then we trigger an interpolation to ensure\n\t // the value is there for use in the link fn\n\t destination[scopeName] = $interpolate(lastValue)(scope);\n\t } else if (isBoolean(lastValue)) {\n\t // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted\n\t // the value to boolean rather than a string, so we special case this situation\n\t destination[scopeName] = lastValue;\n\t }\n\t initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);\n\t break;\n\t\n\t case '=':\n\t if (!hasOwnProperty.call(attrs, attrName)) {\n\t if (optional) break;\n\t attrs[attrName] = void 0;\n\t }\n\t if (optional && !attrs[attrName]) break;\n\t\n\t parentGet = $parse(attrs[attrName]);\n\t if (parentGet.literal) {\n\t compare = equals;\n\t } else {\n\t compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };\n\t }\n\t parentSet = parentGet.assign || function() {\n\t // reset the change, or we will throw this exception on every $digest\n\t lastValue = destination[scopeName] = parentGet(scope);\n\t throw $compileMinErr('nonassign',\n\t \"Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!\",\n\t attrs[attrName], attrName, directive.name);\n\t };\n\t lastValue = destination[scopeName] = parentGet(scope);\n\t var parentValueWatch = function parentValueWatch(parentValue) {\n\t if (!compare(parentValue, destination[scopeName])) {\n\t // we are out of sync and need to copy\n\t if (!compare(parentValue, lastValue)) {\n\t // parent changed and it has precedence\n\t destination[scopeName] = parentValue;\n\t } else {\n\t // if the parent can be assigned then do so\n\t parentSet(scope, parentValue = destination[scopeName]);\n\t }\n\t }\n\t return lastValue = parentValue;\n\t };\n\t parentValueWatch.$stateful = true;\n\t if (definition.collection) {\n\t removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);\n\t } else {\n\t removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);\n\t }\n\t removeWatchCollection.push(removeWatch);\n\t break;\n\t\n\t case '<':\n\t if (!hasOwnProperty.call(attrs, attrName)) {\n\t if (optional) break;\n\t attrs[attrName] = void 0;\n\t }\n\t if (optional && !attrs[attrName]) break;\n\t\n\t parentGet = $parse(attrs[attrName]);\n\t\n\t var initialValue = destination[scopeName] = parentGet(scope);\n\t initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);\n\t\n\t removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {\n\t if (oldValue === newValue) {\n\t if (oldValue === initialValue) return;\n\t oldValue = initialValue;\n\t }\n\t recordChanges(scopeName, newValue, oldValue);\n\t destination[scopeName] = newValue;\n\t }, parentGet.literal);\n\t\n\t removeWatchCollection.push(removeWatch);\n\t break;\n\t\n\t case '&':\n\t // Don't assign Object.prototype method to scope\n\t parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;\n\t\n\t // Don't assign noop to destination if expression is not valid\n\t if (parentGet === noop && optional) break;\n\t\n\t destination[scopeName] = function(locals) {\n\t return parentGet(scope, locals);\n\t };\n\t break;\n\t }\n\t });\n\t\n\t function recordChanges(key, currentValue, previousValue) {\n\t if (isFunction(destination.$onChanges) && currentValue !== previousValue) {\n\t // If we have not already scheduled the top level onChangesQueue handler then do so now\n\t if (!onChangesQueue) {\n\t scope.$$postDigest(flushOnChangesQueue);\n\t onChangesQueue = [];\n\t }\n\t // If we have not already queued a trigger of onChanges for this controller then do so now\n\t if (!changes) {\n\t changes = {};\n\t onChangesQueue.push(triggerOnChangesHook);\n\t }\n\t // If the has been a change on this property already then we need to reuse the previous value\n\t if (changes[key]) {\n\t previousValue = changes[key].previousValue;\n\t }\n\t // Store this change\n\t changes[key] = new SimpleChange(previousValue, currentValue);\n\t }\n\t }\n\t\n\t function triggerOnChangesHook() {\n\t destination.$onChanges(changes);\n\t // Now clear the changes so that we schedule onChanges when more changes arrive\n\t changes = undefined;\n\t }\n\t\n\t return {\n\t initialChanges: initialChanges,\n\t removeWatches: removeWatchCollection.length && function removeWatches() {\n\t for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {\n\t removeWatchCollection[i]();\n\t }\n\t }\n\t };\n\t }\n\t }];\n\t}\n\t\n\tfunction SimpleChange(previous, current) {\n\t this.previousValue = previous;\n\t this.currentValue = current;\n\t}\n\tSimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };\n\t\n\t\n\tvar PREFIX_REGEXP = /^((?:x|data)[\\:\\-_])/i;\n\t/**\n\t * Converts all accepted directives format into proper directive name.\n\t * @param name Name to normalize\n\t */\n\tfunction directiveNormalize(name) {\n\t return camelCase(name.replace(PREFIX_REGEXP, ''));\n\t}\n\t\n\t/**\n\t * @ngdoc type\n\t * @name $compile.directive.Attributes\n\t *\n\t * @description\n\t * A shared object between directive compile / linking functions which contains normalized DOM\n\t * element attributes. The values reflect current binding state `{{ }}`. The normalization is\n\t * needed since all of these are treated as equivalent in Angular:\n\t *\n\t * ```\n\t * \n\t * ```\n\t */\n\t\n\t/**\n\t * @ngdoc property\n\t * @name $compile.directive.Attributes#$attr\n\t *\n\t * @description\n\t * A map of DOM element attribute names to the normalized name. This is\n\t * needed to do reverse lookup from normalized name back to actual name.\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $compile.directive.Attributes#$set\n\t * @kind function\n\t *\n\t * @description\n\t * Set DOM element attribute value.\n\t *\n\t *\n\t * @param {string} name Normalized element attribute name of the property to modify. The name is\n\t * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}\n\t * property to the original name.\n\t * @param {string} value Value to set the attribute to. The value can be an interpolated string.\n\t */\n\t\n\t\n\t\n\t/**\n\t * Closure compiler type information\n\t */\n\t\n\tfunction nodesetLinkingFn(\n\t /* angular.Scope */ scope,\n\t /* NodeList */ nodeList,\n\t /* Element */ rootElement,\n\t /* function(Function) */ boundTranscludeFn\n\t) {}\n\t\n\tfunction directiveLinkingFn(\n\t /* nodesetLinkingFn */ nodesetLinkingFn,\n\t /* angular.Scope */ scope,\n\t /* Node */ node,\n\t /* Element */ rootElement,\n\t /* function(Function) */ boundTranscludeFn\n\t) {}\n\t\n\tfunction tokenDifference(str1, str2) {\n\t var values = '',\n\t tokens1 = str1.split(/\\s+/),\n\t tokens2 = str2.split(/\\s+/);\n\t\n\t outer:\n\t for (var i = 0; i < tokens1.length; i++) {\n\t var token = tokens1[i];\n\t for (var j = 0; j < tokens2.length; j++) {\n\t if (token == tokens2[j]) continue outer;\n\t }\n\t values += (values.length > 0 ? ' ' : '') + token;\n\t }\n\t return values;\n\t}\n\t\n\tfunction removeComments(jqNodes) {\n\t jqNodes = jqLite(jqNodes);\n\t var i = jqNodes.length;\n\t\n\t if (i <= 1) {\n\t return jqNodes;\n\t }\n\t\n\t while (i--) {\n\t var node = jqNodes[i];\n\t if (node.nodeType === NODE_TYPE_COMMENT) {\n\t splice.call(jqNodes, i, 1);\n\t }\n\t }\n\t return jqNodes;\n\t}\n\t\n\tvar $controllerMinErr = minErr('$controller');\n\t\n\t\n\tvar CNTRL_REG = /^(\\S+)(\\s+as\\s+([\\w$]+))?$/;\n\tfunction identifierForController(controller, ident) {\n\t if (ident && isString(ident)) return ident;\n\t if (isString(controller)) {\n\t var match = CNTRL_REG.exec(controller);\n\t if (match) return match[3];\n\t }\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $controllerProvider\n\t * @description\n\t * The {@link ng.$controller $controller service} is used by Angular to create new\n\t * controllers.\n\t *\n\t * This provider allows controller registration via the\n\t * {@link ng.$controllerProvider#register register} method.\n\t */\n\tfunction $ControllerProvider() {\n\t var controllers = {},\n\t globals = false;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $controllerProvider#has\n\t * @param {string} name Controller name to check.\n\t */\n\t this.has = function(name) {\n\t return controllers.hasOwnProperty(name);\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $controllerProvider#register\n\t * @param {string|Object} name Controller name, or an object map of controllers where the keys are\n\t * the names and the values are the constructors.\n\t * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI\n\t * annotations in the array notation).\n\t */\n\t this.register = function(name, constructor) {\n\t assertNotHasOwnProperty(name, 'controller');\n\t if (isObject(name)) {\n\t extend(controllers, name);\n\t } else {\n\t controllers[name] = constructor;\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $controllerProvider#allowGlobals\n\t * @description If called, allows `$controller` to find controller constructors on `window`\n\t */\n\t this.allowGlobals = function() {\n\t globals = true;\n\t };\n\t\n\t\n\t this.$get = ['$injector', '$window', function($injector, $window) {\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $controller\n\t * @requires $injector\n\t *\n\t * @param {Function|string} constructor If called with a function then it's considered to be the\n\t * controller constructor function. Otherwise it's considered to be a string which is used\n\t * to retrieve the controller constructor using the following steps:\n\t *\n\t * * check if a controller with given name is registered via `$controllerProvider`\n\t * * check if evaluating the string on the current scope returns a constructor\n\t * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global\n\t * `window` object (not recommended)\n\t *\n\t * The string can use the `controller as property` syntax, where the controller instance is published\n\t * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this\n\t * to work correctly.\n\t *\n\t * @param {Object} locals Injection locals for Controller.\n\t * @return {Object} Instance of given controller.\n\t *\n\t * @description\n\t * `$controller` service is responsible for instantiating controllers.\n\t *\n\t * It's just a simple call to {@link auto.$injector $injector}, but extracted into\n\t * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).\n\t */\n\t return function $controller(expression, locals, later, ident) {\n\t // PRIVATE API:\n\t // param `later` --- indicates that the controller's constructor is invoked at a later time.\n\t // If true, $controller will allocate the object with the correct\n\t // prototype chain, but will not invoke the controller until a returned\n\t // callback is invoked.\n\t // param `ident` --- An optional label which overrides the label parsed from the controller\n\t // expression, if any.\n\t var instance, match, constructor, identifier;\n\t later = later === true;\n\t if (ident && isString(ident)) {\n\t identifier = ident;\n\t }\n\t\n\t if (isString(expression)) {\n\t match = expression.match(CNTRL_REG);\n\t if (!match) {\n\t throw $controllerMinErr('ctrlfmt',\n\t \"Badly formed controller string '{0}'. \" +\n\t \"Must match `__name__ as __id__` or `__name__`.\", expression);\n\t }\n\t constructor = match[1],\n\t identifier = identifier || match[3];\n\t expression = controllers.hasOwnProperty(constructor)\n\t ? controllers[constructor]\n\t : getter(locals.$scope, constructor, true) ||\n\t (globals ? getter($window, constructor, true) : undefined);\n\t\n\t assertArgFn(expression, constructor, true);\n\t }\n\t\n\t if (later) {\n\t // Instantiate controller later:\n\t // This machinery is used to create an instance of the object before calling the\n\t // controller's constructor itself.\n\t //\n\t // This allows properties to be added to the controller before the constructor is\n\t // invoked. Primarily, this is used for isolate scope bindings in $compile.\n\t //\n\t // This feature is not intended for use by applications, and is thus not documented\n\t // publicly.\n\t // Object creation: http://jsperf.com/create-constructor/2\n\t var controllerPrototype = (isArray(expression) ?\n\t expression[expression.length - 1] : expression).prototype;\n\t instance = Object.create(controllerPrototype || null);\n\t\n\t if (identifier) {\n\t addIdentifier(locals, identifier, instance, constructor || expression.name);\n\t }\n\t\n\t var instantiate;\n\t return instantiate = extend(function $controllerInit() {\n\t var result = $injector.invoke(expression, instance, locals, constructor);\n\t if (result !== instance && (isObject(result) || isFunction(result))) {\n\t instance = result;\n\t if (identifier) {\n\t // If result changed, re-assign controllerAs value to scope.\n\t addIdentifier(locals, identifier, instance, constructor || expression.name);\n\t }\n\t }\n\t return instance;\n\t }, {\n\t instance: instance,\n\t identifier: identifier\n\t });\n\t }\n\t\n\t instance = $injector.instantiate(expression, locals, constructor);\n\t\n\t if (identifier) {\n\t addIdentifier(locals, identifier, instance, constructor || expression.name);\n\t }\n\t\n\t return instance;\n\t };\n\t\n\t function addIdentifier(locals, identifier, instance, name) {\n\t if (!(locals && isObject(locals.$scope))) {\n\t throw minErr('$controller')('noscp',\n\t \"Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.\",\n\t name, identifier);\n\t }\n\t\n\t locals.$scope[identifier] = instance;\n\t }\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $document\n\t * @requires $window\n\t *\n\t * @description\n\t * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t

$document title:

\n\t

window.document title:

\n\t
\n\t
\n\t \n\t angular.module('documentExample', [])\n\t .controller('ExampleController', ['$scope', '$document', function($scope, $document) {\n\t $scope.title = $document[0].title;\n\t $scope.windowTitle = angular.element(window.document)[0].title;\n\t }]);\n\t \n\t
\n\t */\n\tfunction $DocumentProvider() {\n\t this.$get = ['$window', function(window) {\n\t return jqLite(window.document);\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $exceptionHandler\n\t * @requires ng.$log\n\t *\n\t * @description\n\t * Any uncaught exception in angular expressions is delegated to this service.\n\t * The default implementation simply delegates to `$log.error` which logs it into\n\t * the browser console.\n\t *\n\t * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by\n\t * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.\n\t *\n\t * ## Example:\n\t *\n\t * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught\n\t * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead\n\t * of `$log.error()`.\n\t *\n\t * ```js\n\t * angular.\n\t * module('exceptionOverwrite', []).\n\t * factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {\n\t * return function myExceptionHandler(exception, cause) {\n\t * logErrorsToBackend(exception, cause);\n\t * $log.warn(exception, cause);\n\t * };\n\t * }]);\n\t * ```\n\t *\n\t *
\n\t * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`\n\t * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}\n\t * (unless executed during a digest).\n\t *\n\t * If you wish, you can manually delegate exceptions, e.g.\n\t * `try { ... } catch(e) { $exceptionHandler(e); }`\n\t *\n\t * @param {Error} exception Exception associated with the error.\n\t * @param {string=} cause Optional information about the context in which\n\t * the error was thrown.\n\t *\n\t */\n\tfunction $ExceptionHandlerProvider() {\n\t this.$get = ['$log', function($log) {\n\t return function(exception, cause) {\n\t $log.error.apply($log, arguments);\n\t };\n\t }];\n\t}\n\t\n\tvar $$ForceReflowProvider = function() {\n\t this.$get = ['$document', function($document) {\n\t return function(domNode) {\n\t //the line below will force the browser to perform a repaint so\n\t //that all the animated elements within the animation frame will\n\t //be properly updated and drawn on screen. This is required to\n\t //ensure that the preparation animation is properly flushed so that\n\t //the active state picks up from there. DO NOT REMOVE THIS LINE.\n\t //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH\n\t //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND\n\t //WILL TAKE YEARS AWAY FROM YOUR LIFE.\n\t if (domNode) {\n\t if (!domNode.nodeType && domNode instanceof jqLite) {\n\t domNode = domNode[0];\n\t }\n\t } else {\n\t domNode = $document[0].body;\n\t }\n\t return domNode.offsetWidth + 1;\n\t };\n\t }];\n\t};\n\t\n\tvar APPLICATION_JSON = 'application/json';\n\tvar CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};\n\tvar JSON_START = /^\\[|^\\{(?!\\{)/;\n\tvar JSON_ENDS = {\n\t '[': /]$/,\n\t '{': /}$/\n\t};\n\tvar JSON_PROTECTION_PREFIX = /^\\)\\]\\}',?\\n/;\n\tvar $httpMinErr = minErr('$http');\n\tvar $httpMinErrLegacyFn = function(method) {\n\t return function() {\n\t throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);\n\t };\n\t};\n\t\n\tfunction serializeValue(v) {\n\t if (isObject(v)) {\n\t return isDate(v) ? v.toISOString() : toJson(v);\n\t }\n\t return v;\n\t}\n\t\n\t\n\tfunction $HttpParamSerializerProvider() {\n\t /**\n\t * @ngdoc service\n\t * @name $httpParamSerializer\n\t * @description\n\t *\n\t * Default {@link $http `$http`} params serializer that converts objects to strings\n\t * according to the following rules:\n\t *\n\t * * `{'foo': 'bar'}` results in `foo=bar`\n\t * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)\n\t * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)\n\t * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)\n\t *\n\t * Note that serializer will sort the request parameters alphabetically.\n\t * */\n\t\n\t this.$get = function() {\n\t return function ngParamSerializer(params) {\n\t if (!params) return '';\n\t var parts = [];\n\t forEachSorted(params, function(value, key) {\n\t if (value === null || isUndefined(value)) return;\n\t if (isArray(value)) {\n\t forEach(value, function(v) {\n\t parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v)));\n\t });\n\t } else {\n\t parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));\n\t }\n\t });\n\t\n\t return parts.join('&');\n\t };\n\t };\n\t}\n\t\n\tfunction $HttpParamSerializerJQLikeProvider() {\n\t /**\n\t * @ngdoc service\n\t * @name $httpParamSerializerJQLike\n\t * @description\n\t *\n\t * Alternative {@link $http `$http`} params serializer that follows\n\t * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.\n\t * The serializer will also sort the params alphabetically.\n\t *\n\t * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:\n\t *\n\t * ```js\n\t * $http({\n\t * url: myUrl,\n\t * method: 'GET',\n\t * params: myParams,\n\t * paramSerializer: '$httpParamSerializerJQLike'\n\t * });\n\t * ```\n\t *\n\t * It is also possible to set it as the default `paramSerializer` in the\n\t * {@link $httpProvider#defaults `$httpProvider`}.\n\t *\n\t * Additionally, you can inject the serializer and use it explicitly, for example to serialize\n\t * form data for submission:\n\t *\n\t * ```js\n\t * .controller(function($http, $httpParamSerializerJQLike) {\n\t * //...\n\t *\n\t * $http({\n\t * url: myUrl,\n\t * method: 'POST',\n\t * data: $httpParamSerializerJQLike(myData),\n\t * headers: {\n\t * 'Content-Type': 'application/x-www-form-urlencoded'\n\t * }\n\t * });\n\t *\n\t * });\n\t * ```\n\t *\n\t * */\n\t this.$get = function() {\n\t return function jQueryLikeParamSerializer(params) {\n\t if (!params) return '';\n\t var parts = [];\n\t serialize(params, '', true);\n\t return parts.join('&');\n\t\n\t function serialize(toSerialize, prefix, topLevel) {\n\t if (toSerialize === null || isUndefined(toSerialize)) return;\n\t if (isArray(toSerialize)) {\n\t forEach(toSerialize, function(value, index) {\n\t serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');\n\t });\n\t } else if (isObject(toSerialize) && !isDate(toSerialize)) {\n\t forEachSorted(toSerialize, function(value, key) {\n\t serialize(value, prefix +\n\t (topLevel ? '' : '[') +\n\t key +\n\t (topLevel ? '' : ']'));\n\t });\n\t } else {\n\t parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));\n\t }\n\t }\n\t };\n\t };\n\t}\n\t\n\tfunction defaultHttpResponseTransform(data, headers) {\n\t if (isString(data)) {\n\t // Strip json vulnerability protection prefix and trim whitespace\n\t var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();\n\t\n\t if (tempData) {\n\t var contentType = headers('Content-Type');\n\t if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {\n\t data = fromJson(tempData);\n\t }\n\t }\n\t }\n\t\n\t return data;\n\t}\n\t\n\tfunction isJsonLike(str) {\n\t var jsonStart = str.match(JSON_START);\n\t return jsonStart && JSON_ENDS[jsonStart[0]].test(str);\n\t}\n\t\n\t/**\n\t * Parse headers into key value object\n\t *\n\t * @param {string} headers Raw headers as a string\n\t * @returns {Object} Parsed headers as key value object\n\t */\n\tfunction parseHeaders(headers) {\n\t var parsed = createMap(), i;\n\t\n\t function fillInParsed(key, val) {\n\t if (key) {\n\t parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;\n\t }\n\t }\n\t\n\t if (isString(headers)) {\n\t forEach(headers.split('\\n'), function(line) {\n\t i = line.indexOf(':');\n\t fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));\n\t });\n\t } else if (isObject(headers)) {\n\t forEach(headers, function(headerVal, headerKey) {\n\t fillInParsed(lowercase(headerKey), trim(headerVal));\n\t });\n\t }\n\t\n\t return parsed;\n\t}\n\t\n\t\n\t/**\n\t * Returns a function that provides access to parsed headers.\n\t *\n\t * Headers are lazy parsed when first requested.\n\t * @see parseHeaders\n\t *\n\t * @param {(string|Object)} headers Headers to provide access to.\n\t * @returns {function(string=)} Returns a getter function which if called with:\n\t *\n\t * - if called with single an argument returns a single header value or null\n\t * - if called with no arguments returns an object containing all headers.\n\t */\n\tfunction headersGetter(headers) {\n\t var headersObj;\n\t\n\t return function(name) {\n\t if (!headersObj) headersObj = parseHeaders(headers);\n\t\n\t if (name) {\n\t var value = headersObj[lowercase(name)];\n\t if (value === void 0) {\n\t value = null;\n\t }\n\t return value;\n\t }\n\t\n\t return headersObj;\n\t };\n\t}\n\t\n\t\n\t/**\n\t * Chain all given functions\n\t *\n\t * This function is used for both request and response transforming\n\t *\n\t * @param {*} data Data to transform.\n\t * @param {function(string=)} headers HTTP headers getter fn.\n\t * @param {number} status HTTP status code of the response.\n\t * @param {(Function|Array.)} fns Function or an array of functions.\n\t * @returns {*} Transformed data.\n\t */\n\tfunction transformData(data, headers, status, fns) {\n\t if (isFunction(fns)) {\n\t return fns(data, headers, status);\n\t }\n\t\n\t forEach(fns, function(fn) {\n\t data = fn(data, headers, status);\n\t });\n\t\n\t return data;\n\t}\n\t\n\t\n\tfunction isSuccess(status) {\n\t return 200 <= status && status < 300;\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $httpProvider\n\t * @description\n\t * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.\n\t * */\n\tfunction $HttpProvider() {\n\t /**\n\t * @ngdoc property\n\t * @name $httpProvider#defaults\n\t * @description\n\t *\n\t * Object containing default values for all {@link ng.$http $http} requests.\n\t *\n\t * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with\n\t * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses\n\t * by default. See {@link $http#caching $http Caching} for more information.\n\t *\n\t * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.\n\t * Defaults value is `'XSRF-TOKEN'`.\n\t *\n\t * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the\n\t * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.\n\t *\n\t * - **`defaults.headers`** - {Object} - Default headers for all $http requests.\n\t * Refer to {@link ng.$http#setting-http-headers $http} for documentation on\n\t * setting default headers.\n\t * - **`defaults.headers.common`**\n\t * - **`defaults.headers.post`**\n\t * - **`defaults.headers.put`**\n\t * - **`defaults.headers.patch`**\n\t *\n\t *\n\t * - **`defaults.paramSerializer`** - `{string|function(Object):string}` - A function\n\t * used to the prepare string representation of request parameters (specified as an object).\n\t * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.\n\t * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.\n\t *\n\t **/\n\t var defaults = this.defaults = {\n\t // transform incoming response data\n\t transformResponse: [defaultHttpResponseTransform],\n\t\n\t // transform outgoing request data\n\t transformRequest: [function(d) {\n\t return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;\n\t }],\n\t\n\t // default headers\n\t headers: {\n\t common: {\n\t 'Accept': 'application/json, text/plain, */*'\n\t },\n\t post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON),\n\t put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON),\n\t patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON)\n\t },\n\t\n\t xsrfCookieName: 'XSRF-TOKEN',\n\t xsrfHeaderName: 'X-XSRF-TOKEN',\n\t\n\t paramSerializer: '$httpParamSerializer'\n\t };\n\t\n\t var useApplyAsync = false;\n\t /**\n\t * @ngdoc method\n\t * @name $httpProvider#useApplyAsync\n\t * @description\n\t *\n\t * Configure $http service to combine processing of multiple http responses received at around\n\t * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in\n\t * significant performance improvement for bigger applications that make many HTTP requests\n\t * concurrently (common during application bootstrap).\n\t *\n\t * Defaults to false. If no value is specified, returns the current configured value.\n\t *\n\t * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred\n\t * \"apply\" on the next tick, giving time for subsequent requests in a roughly ~10ms window\n\t * to load and share the same digest cycle.\n\t *\n\t * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.\n\t * otherwise, returns the current configured value.\n\t **/\n\t this.useApplyAsync = function(value) {\n\t if (isDefined(value)) {\n\t useApplyAsync = !!value;\n\t return this;\n\t }\n\t return useApplyAsync;\n\t };\n\t\n\t var useLegacyPromise = true;\n\t /**\n\t * @ngdoc method\n\t * @name $httpProvider#useLegacyPromiseExtensions\n\t * @description\n\t *\n\t * Configure `$http` service to return promises without the shorthand methods `success` and `error`.\n\t * This should be used to make sure that applications work without these methods.\n\t *\n\t * Defaults to true. If no value is specified, returns the current configured value.\n\t *\n\t * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.\n\t *\n\t * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.\n\t * otherwise, returns the current configured value.\n\t **/\n\t this.useLegacyPromiseExtensions = function(value) {\n\t if (isDefined(value)) {\n\t useLegacyPromise = !!value;\n\t return this;\n\t }\n\t return useLegacyPromise;\n\t };\n\t\n\t /**\n\t * @ngdoc property\n\t * @name $httpProvider#interceptors\n\t * @description\n\t *\n\t * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}\n\t * pre-processing of request or postprocessing of responses.\n\t *\n\t * These service factories are ordered by request, i.e. they are applied in the same order as the\n\t * array, on request, but reverse order, on response.\n\t *\n\t * {@link ng.$http#interceptors Interceptors detailed info}\n\t **/\n\t var interceptorFactories = this.interceptors = [];\n\t\n\t this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',\n\t function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {\n\t\n\t var defaultCache = $cacheFactory('$http');\n\t\n\t /**\n\t * Make sure that default param serializer is exposed as a function\n\t */\n\t defaults.paramSerializer = isString(defaults.paramSerializer) ?\n\t $injector.get(defaults.paramSerializer) : defaults.paramSerializer;\n\t\n\t /**\n\t * Interceptors stored in reverse order. Inner interceptors before outer interceptors.\n\t * The reversal is needed so that we can build up the interception chain around the\n\t * server request.\n\t */\n\t var reversedInterceptors = [];\n\t\n\t forEach(interceptorFactories, function(interceptorFactory) {\n\t reversedInterceptors.unshift(isString(interceptorFactory)\n\t ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));\n\t });\n\t\n\t /**\n\t * @ngdoc service\n\t * @kind function\n\t * @name $http\n\t * @requires ng.$httpBackend\n\t * @requires $cacheFactory\n\t * @requires $rootScope\n\t * @requires $q\n\t * @requires $injector\n\t *\n\t * @description\n\t * The `$http` service is a core Angular service that facilitates communication with the remote\n\t * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)\n\t * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).\n\t *\n\t * For unit testing applications that use `$http` service, see\n\t * {@link ngMock.$httpBackend $httpBackend mock}.\n\t *\n\t * For a higher level of abstraction, please check out the {@link ngResource.$resource\n\t * $resource} service.\n\t *\n\t * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by\n\t * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage\n\t * it is important to familiarize yourself with these APIs and the guarantees they provide.\n\t *\n\t *\n\t * ## General usage\n\t * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —\n\t * that is used to generate an HTTP request and returns a {@link ng.$q promise}.\n\t *\n\t * ```js\n\t * // Simple GET request example:\n\t * $http({\n\t * method: 'GET',\n\t * url: '/someUrl'\n\t * }).then(function successCallback(response) {\n\t * // this callback will be called asynchronously\n\t * // when the response is available\n\t * }, function errorCallback(response) {\n\t * // called asynchronously if an error occurs\n\t * // or server returns response with an error status.\n\t * });\n\t * ```\n\t *\n\t * The response object has these properties:\n\t *\n\t * - **data** – `{string|Object}` – The response body transformed with the transform\n\t * functions.\n\t * - **status** – `{number}` – HTTP status code of the response.\n\t * - **headers** – `{function([headerName])}` – Header getter function.\n\t * - **config** – `{Object}` – The configuration object that was used to generate the request.\n\t * - **statusText** – `{string}` – HTTP status text of the response.\n\t *\n\t * A response status code between 200 and 299 is considered a success status and will result in\n\t * the success callback being called. Any response status code outside of that range is\n\t * considered an error status and will result in the error callback being called.\n\t * Also, status codes less than -1 are normalized to zero. -1 usually means the request was\n\t * aborted, e.g. using a `config.timeout`.\n\t * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning\n\t * that the outcome (success or error) will be determined by the final response status code.\n\t *\n\t *\n\t * ## Shortcut methods\n\t *\n\t * Shortcut methods are also available. All shortcut methods require passing in the URL, and\n\t * request data must be passed in for POST/PUT requests. An optional config can be passed as the\n\t * last argument.\n\t *\n\t * ```js\n\t * $http.get('/someUrl', config).then(successCallback, errorCallback);\n\t * $http.post('/someUrl', data, config).then(successCallback, errorCallback);\n\t * ```\n\t *\n\t * Complete list of shortcut methods:\n\t *\n\t * - {@link ng.$http#get $http.get}\n\t * - {@link ng.$http#head $http.head}\n\t * - {@link ng.$http#post $http.post}\n\t * - {@link ng.$http#put $http.put}\n\t * - {@link ng.$http#delete $http.delete}\n\t * - {@link ng.$http#jsonp $http.jsonp}\n\t * - {@link ng.$http#patch $http.patch}\n\t *\n\t *\n\t * ## Writing Unit Tests that use $http\n\t * When unit testing (using {@link ngMock ngMock}), it is necessary to call\n\t * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending\n\t * request using trained responses.\n\t *\n\t * ```\n\t * $httpBackend.expectGET(...);\n\t * $http.get(...);\n\t * $httpBackend.flush();\n\t * ```\n\t *\n\t * ## Deprecation Notice\n\t *
\n\t * The `$http` legacy promise methods `success` and `error` have been deprecated.\n\t * Use the standard `then` method instead.\n\t * If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to\n\t * `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.\n\t *
\n\t *\n\t * ## Setting HTTP Headers\n\t *\n\t * The $http service will automatically add certain HTTP headers to all requests. These defaults\n\t * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration\n\t * object, which currently contains this default configuration:\n\t *\n\t * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):\n\t * - `Accept: application/json, text/plain, * / *`\n\t * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)\n\t * - `Content-Type: application/json`\n\t * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)\n\t * - `Content-Type: application/json`\n\t *\n\t * To add or overwrite these defaults, simply add or remove a property from these configuration\n\t * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object\n\t * with the lowercased HTTP method name as the key, e.g.\n\t * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.\n\t *\n\t * The defaults can also be set at runtime via the `$http.defaults` object in the same\n\t * fashion. For example:\n\t *\n\t * ```\n\t * module.run(function($http) {\n\t * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';\n\t * });\n\t * ```\n\t *\n\t * In addition, you can supply a `headers` property in the config object passed when\n\t * calling `$http(config)`, which overrides the defaults without changing them globally.\n\t *\n\t * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,\n\t * Use the `headers` property, setting the desired header to `undefined`. For example:\n\t *\n\t * ```js\n\t * var req = {\n\t * method: 'POST',\n\t * url: 'http://example.com',\n\t * headers: {\n\t * 'Content-Type': undefined\n\t * },\n\t * data: { test: 'test' }\n\t * }\n\t *\n\t * $http(req).then(function(){...}, function(){...});\n\t * ```\n\t *\n\t * ## Transforming Requests and Responses\n\t *\n\t * Both requests and responses can be transformed using transformation functions: `transformRequest`\n\t * and `transformResponse`. These properties can be a single function that returns\n\t * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,\n\t * which allows you to `push` or `unshift` a new transformation function into the transformation chain.\n\t *\n\t *
\n\t * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.\n\t * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).\n\t * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest\n\t * function will be reflected on the scope and in any templates where the object is data-bound.\n\t * To prevent this, transform functions should have no side-effects.\n\t * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.\n\t *
\n\t *\n\t * ### Default Transformations\n\t *\n\t * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and\n\t * `defaults.transformResponse` properties. If a request does not provide its own transformations\n\t * then these will be applied.\n\t *\n\t * You can augment or replace the default transformations by modifying these properties by adding to or\n\t * replacing the array.\n\t *\n\t * Angular provides the following default transformations:\n\t *\n\t * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):\n\t *\n\t * - If the `data` property of the request configuration object contains an object, serialize it\n\t * into JSON format.\n\t *\n\t * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):\n\t *\n\t * - If XSRF prefix is detected, strip it (see Security Considerations section below).\n\t * - If JSON response is detected, deserialize it using a JSON parser.\n\t *\n\t *\n\t * ### Overriding the Default Transformations Per Request\n\t *\n\t * If you wish to override the request/response transformations only for a single request then provide\n\t * `transformRequest` and/or `transformResponse` properties on the configuration object passed\n\t * into `$http`.\n\t *\n\t * Note that if you provide these properties on the config object the default transformations will be\n\t * overwritten. If you wish to augment the default transformations then you must include them in your\n\t * local transformation array.\n\t *\n\t * The following code demonstrates adding a new response transformation to be run after the default response\n\t * transformations have been run.\n\t *\n\t * ```js\n\t * function appendTransform(defaults, transform) {\n\t *\n\t * // We can't guarantee that the default transformation is an array\n\t * defaults = angular.isArray(defaults) ? defaults : [defaults];\n\t *\n\t * // Append the new transformation to the defaults\n\t * return defaults.concat(transform);\n\t * }\n\t *\n\t * $http({\n\t * url: '...',\n\t * method: 'GET',\n\t * transformResponse: appendTransform($http.defaults.transformResponse, function(value) {\n\t * return doTransform(value);\n\t * })\n\t * });\n\t * ```\n\t *\n\t *\n\t * ## Caching\n\t *\n\t * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must\n\t * set the config.cache value or the default cache value to TRUE or to a cache object (created\n\t * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes\n\t * precedence over the default cache value.\n\t *\n\t * In order to:\n\t * * cache all responses - set the default cache value to TRUE or to a cache object\n\t * * cache a specific response - set config.cache value to TRUE or to a cache object\n\t *\n\t * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,\n\t * then the default `$cacheFactory(\"$http\")` object is used.\n\t *\n\t * The default cache value can be set by updating the\n\t * {@link ng.$http#defaults `$http.defaults.cache`} property or the\n\t * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.\n\t *\n\t * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using\n\t * the relevant cache object. The next time the same request is made, the response is returned\n\t * from the cache without sending a request to the server.\n\t *\n\t * Take note that:\n\t *\n\t * * Only GET and JSONP requests are cached.\n\t * * The cache key is the request URL including search parameters; headers are not considered.\n\t * * Cached responses are returned asynchronously, in the same way as responses from the server.\n\t * * If multiple identical requests are made using the same cache, which is not yet populated,\n\t * one request will be made to the server and remaining requests will return the same response.\n\t * * A cache-control header on the response does not affect if or how responses are cached.\n\t *\n\t *\n\t * ## Interceptors\n\t *\n\t * Before you start creating interceptors, be sure to understand the\n\t * {@link ng.$q $q and deferred/promise APIs}.\n\t *\n\t * For purposes of global error handling, authentication, or any kind of synchronous or\n\t * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be\n\t * able to intercept requests before they are handed to the server and\n\t * responses before they are handed over to the application code that\n\t * initiated these requests. The interceptors leverage the {@link ng.$q\n\t * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.\n\t *\n\t * The interceptors are service factories that are registered with the `$httpProvider` by\n\t * adding them to the `$httpProvider.interceptors` array. The factory is called and\n\t * injected with dependencies (if specified) and returns the interceptor.\n\t *\n\t * There are two kinds of interceptors (and two kinds of rejection interceptors):\n\t *\n\t * * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to\n\t * modify the `config` object or create a new one. The function needs to return the `config`\n\t * object directly, or a promise containing the `config` or a new `config` object.\n\t * * `requestError`: interceptor gets called when a previous interceptor threw an error or\n\t * resolved with a rejection.\n\t * * `response`: interceptors get called with http `response` object. The function is free to\n\t * modify the `response` object or create a new one. The function needs to return the `response`\n\t * object directly, or as a promise containing the `response` or a new `response` object.\n\t * * `responseError`: interceptor gets called when a previous interceptor threw an error or\n\t * resolved with a rejection.\n\t *\n\t *\n\t * ```js\n\t * // register the interceptor as a service\n\t * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {\n\t * return {\n\t * // optional method\n\t * 'request': function(config) {\n\t * // do something on success\n\t * return config;\n\t * },\n\t *\n\t * // optional method\n\t * 'requestError': function(rejection) {\n\t * // do something on error\n\t * if (canRecover(rejection)) {\n\t * return responseOrNewPromise\n\t * }\n\t * return $q.reject(rejection);\n\t * },\n\t *\n\t *\n\t *\n\t * // optional method\n\t * 'response': function(response) {\n\t * // do something on success\n\t * return response;\n\t * },\n\t *\n\t * // optional method\n\t * 'responseError': function(rejection) {\n\t * // do something on error\n\t * if (canRecover(rejection)) {\n\t * return responseOrNewPromise\n\t * }\n\t * return $q.reject(rejection);\n\t * }\n\t * };\n\t * });\n\t *\n\t * $httpProvider.interceptors.push('myHttpInterceptor');\n\t *\n\t *\n\t * // alternatively, register the interceptor via an anonymous factory\n\t * $httpProvider.interceptors.push(function($q, dependency1, dependency2) {\n\t * return {\n\t * 'request': function(config) {\n\t * // same as above\n\t * },\n\t *\n\t * 'response': function(response) {\n\t * // same as above\n\t * }\n\t * };\n\t * });\n\t * ```\n\t *\n\t * ## Security Considerations\n\t *\n\t * When designing web applications, consider security threats from:\n\t *\n\t * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)\n\t * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)\n\t *\n\t * Both server and the client must cooperate in order to eliminate these threats. Angular comes\n\t * pre-configured with strategies that address these issues, but for this to work backend server\n\t * cooperation is required.\n\t *\n\t * ### JSON Vulnerability Protection\n\t *\n\t * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)\n\t * allows third party website to turn your JSON resource URL into\n\t * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To\n\t * counter this your server can prefix all JSON requests with following string `\")]}',\\n\"`.\n\t * Angular will automatically strip the prefix before processing it as JSON.\n\t *\n\t * For example if your server needs to return:\n\t * ```js\n\t * ['one','two']\n\t * ```\n\t *\n\t * which is vulnerable to attack, your server can return:\n\t * ```js\n\t * )]}',\n\t * ['one','two']\n\t * ```\n\t *\n\t * Angular will strip the prefix, before processing the JSON.\n\t *\n\t *\n\t * ### Cross Site Request Forgery (XSRF) Protection\n\t *\n\t * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by\n\t * which the attacker can trick an authenticated user into unknowingly executing actions on your\n\t * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the\n\t * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP\n\t * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the\n\t * cookie, your server can be assured that the XHR came from JavaScript running on your domain.\n\t * The header will not be set for cross-domain requests.\n\t *\n\t * To take advantage of this, your server needs to set a token in a JavaScript readable session\n\t * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the\n\t * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure\n\t * that only JavaScript running on your domain could have sent the request. The token must be\n\t * unique for each user and must be verifiable by the server (to prevent the JavaScript from\n\t * making up its own tokens). We recommend that the token is a digest of your site's\n\t * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))\n\t * for added security.\n\t *\n\t * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName\n\t * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,\n\t * or the per-request config object.\n\t *\n\t * In order to prevent collisions in environments where multiple Angular apps share the\n\t * same domain or subdomain, we recommend that each application uses unique cookie name.\n\t *\n\t * @param {object} config Object describing the request to be made and how it should be\n\t * processed. The object has following properties:\n\t *\n\t * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)\n\t * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.\n\t * - **params** – `{Object.}` – Map of strings or objects which will be serialized\n\t * with the `paramSerializer` and appended as GET parameters.\n\t * - **data** – `{string|Object}` – Data to be sent as the request message data.\n\t * - **headers** – `{Object}` – Map of strings or functions which return strings representing\n\t * HTTP headers to send to the server. If the return value of a function is null, the\n\t * header will not be sent. Functions accept a config object as an argument.\n\t * - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.\n\t * To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.\n\t * The handler will be called in the context of a `$apply` block.\n\t * - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload\n\t * object. To bind events to the XMLHttpRequest object, use `eventHandlers`.\n\t * The handler will be called in the context of a `$apply` block.\n\t * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.\n\t * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.\n\t * - **transformRequest** –\n\t * `{function(data, headersGetter)|Array.}` –\n\t * transform function or an array of such functions. The transform function takes the http\n\t * request body and headers and returns its transformed (typically serialized) version.\n\t * See {@link ng.$http#overriding-the-default-transformations-per-request\n\t * Overriding the Default Transformations}\n\t * - **transformResponse** –\n\t * `{function(data, headersGetter, status)|Array.}` –\n\t * transform function or an array of such functions. The transform function takes the http\n\t * response body, headers and status and returns its transformed (typically deserialized) version.\n\t * See {@link ng.$http#overriding-the-default-transformations-per-request\n\t * Overriding the Default Transformations}\n\t * - **paramSerializer** - `{string|function(Object):string}` - A function used to\n\t * prepare the string representation of request parameters (specified as an object).\n\t * If specified as string, it is interpreted as function registered with the\n\t * {@link $injector $injector}, which means you can create your own serializer\n\t * by registering it as a {@link auto.$provide#service service}.\n\t * The default serializer is the {@link $httpParamSerializer $httpParamSerializer};\n\t * alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}\n\t * - **cache** – `{boolean|Object}` – A boolean value or object created with\n\t * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.\n\t * See {@link $http#caching $http Caching} for more information.\n\t * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}\n\t * that should abort the request when resolved.\n\t * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the\n\t * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)\n\t * for more information.\n\t * - **responseType** - `{string}` - see\n\t * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).\n\t *\n\t * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object\n\t * when the request succeeds or fails.\n\t *\n\t *\n\t * @property {Array.} pendingRequests Array of config objects for currently pending\n\t * requests. This is primarily meant to be used for debugging purposes.\n\t *\n\t *\n\t * @example\n\t\n\t\n\t
\n\t \n\t \n\t
\n\t \n\t \n\t \n\t
http status code: {{status}}
\n\t
http response data: {{data}}
\n\t
\n\t
\n\t\n\t angular.module('httpExample', [])\n\t .controller('FetchController', ['$scope', '$http', '$templateCache',\n\t function($scope, $http, $templateCache) {\n\t $scope.method = 'GET';\n\t $scope.url = 'http-hello.html';\n\t\n\t $scope.fetch = function() {\n\t $scope.code = null;\n\t $scope.response = null;\n\t\n\t $http({method: $scope.method, url: $scope.url, cache: $templateCache}).\n\t then(function(response) {\n\t $scope.status = response.status;\n\t $scope.data = response.data;\n\t }, function(response) {\n\t $scope.data = response.data || \"Request failed\";\n\t $scope.status = response.status;\n\t });\n\t };\n\t\n\t $scope.updateModel = function(method, url) {\n\t $scope.method = method;\n\t $scope.url = url;\n\t };\n\t }]);\n\t\n\t\n\t Hello, $http!\n\t\n\t\n\t var status = element(by.binding('status'));\n\t var data = element(by.binding('data'));\n\t var fetchBtn = element(by.id('fetchbtn'));\n\t var sampleGetBtn = element(by.id('samplegetbtn'));\n\t var sampleJsonpBtn = element(by.id('samplejsonpbtn'));\n\t var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));\n\t\n\t it('should make an xhr GET request', function() {\n\t sampleGetBtn.click();\n\t fetchBtn.click();\n\t expect(status.getText()).toMatch('200');\n\t expect(data.getText()).toMatch(/Hello, \\$http!/);\n\t });\n\t\n\t// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185\n\t// it('should make a JSONP request to angularjs.org', function() {\n\t// sampleJsonpBtn.click();\n\t// fetchBtn.click();\n\t// expect(status.getText()).toMatch('200');\n\t// expect(data.getText()).toMatch(/Super Hero!/);\n\t// });\n\t\n\t it('should make JSONP request to invalid URL and invoke the error handler',\n\t function() {\n\t invalidJsonpBtn.click();\n\t fetchBtn.click();\n\t expect(status.getText()).toMatch('0');\n\t expect(data.getText()).toMatch('Request failed');\n\t });\n\t\n\t
\n\t */\n\t function $http(requestConfig) {\n\t\n\t if (!isObject(requestConfig)) {\n\t throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);\n\t }\n\t\n\t if (!isString(requestConfig.url)) {\n\t throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);\n\t }\n\t\n\t var config = extend({\n\t method: 'get',\n\t transformRequest: defaults.transformRequest,\n\t transformResponse: defaults.transformResponse,\n\t paramSerializer: defaults.paramSerializer\n\t }, requestConfig);\n\t\n\t config.headers = mergeHeaders(requestConfig);\n\t config.method = uppercase(config.method);\n\t config.paramSerializer = isString(config.paramSerializer) ?\n\t $injector.get(config.paramSerializer) : config.paramSerializer;\n\t\n\t var requestInterceptors = [];\n\t var responseInterceptors = [];\n\t var promise = $q.when(config);\n\t\n\t // apply interceptors\n\t forEach(reversedInterceptors, function(interceptor) {\n\t if (interceptor.request || interceptor.requestError) {\n\t requestInterceptors.unshift(interceptor.request, interceptor.requestError);\n\t }\n\t if (interceptor.response || interceptor.responseError) {\n\t responseInterceptors.push(interceptor.response, interceptor.responseError);\n\t }\n\t });\n\t\n\t promise = chainInterceptors(promise, requestInterceptors);\n\t promise = promise.then(serverRequest);\n\t promise = chainInterceptors(promise, responseInterceptors);\n\t\n\t if (useLegacyPromise) {\n\t promise.success = function(fn) {\n\t assertArgFn(fn, 'fn');\n\t\n\t promise.then(function(response) {\n\t fn(response.data, response.status, response.headers, config);\n\t });\n\t return promise;\n\t };\n\t\n\t promise.error = function(fn) {\n\t assertArgFn(fn, 'fn');\n\t\n\t promise.then(null, function(response) {\n\t fn(response.data, response.status, response.headers, config);\n\t });\n\t return promise;\n\t };\n\t } else {\n\t promise.success = $httpMinErrLegacyFn('success');\n\t promise.error = $httpMinErrLegacyFn('error');\n\t }\n\t\n\t return promise;\n\t\n\t\n\t function chainInterceptors(promise, interceptors) {\n\t for (var i = 0, ii = interceptors.length; i < ii;) {\n\t var thenFn = interceptors[i++];\n\t var rejectFn = interceptors[i++];\n\t\n\t promise = promise.then(thenFn, rejectFn);\n\t }\n\t\n\t interceptors.length = 0;\n\t\n\t return promise;\n\t }\n\t\n\t function executeHeaderFns(headers, config) {\n\t var headerContent, processedHeaders = {};\n\t\n\t forEach(headers, function(headerFn, header) {\n\t if (isFunction(headerFn)) {\n\t headerContent = headerFn(config);\n\t if (headerContent != null) {\n\t processedHeaders[header] = headerContent;\n\t }\n\t } else {\n\t processedHeaders[header] = headerFn;\n\t }\n\t });\n\t\n\t return processedHeaders;\n\t }\n\t\n\t function mergeHeaders(config) {\n\t var defHeaders = defaults.headers,\n\t reqHeaders = extend({}, config.headers),\n\t defHeaderName, lowercaseDefHeaderName, reqHeaderName;\n\t\n\t defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);\n\t\n\t // using for-in instead of forEach to avoid unnecessary iteration after header has been found\n\t defaultHeadersIteration:\n\t for (defHeaderName in defHeaders) {\n\t lowercaseDefHeaderName = lowercase(defHeaderName);\n\t\n\t for (reqHeaderName in reqHeaders) {\n\t if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {\n\t continue defaultHeadersIteration;\n\t }\n\t }\n\t\n\t reqHeaders[defHeaderName] = defHeaders[defHeaderName];\n\t }\n\t\n\t // execute if header value is a function for merged headers\n\t return executeHeaderFns(reqHeaders, shallowCopy(config));\n\t }\n\t\n\t function serverRequest(config) {\n\t var headers = config.headers;\n\t var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);\n\t\n\t // strip content-type if data is undefined\n\t if (isUndefined(reqData)) {\n\t forEach(headers, function(value, header) {\n\t if (lowercase(header) === 'content-type') {\n\t delete headers[header];\n\t }\n\t });\n\t }\n\t\n\t if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {\n\t config.withCredentials = defaults.withCredentials;\n\t }\n\t\n\t // send request\n\t return sendReq(config, reqData).then(transformResponse, transformResponse);\n\t }\n\t\n\t function transformResponse(response) {\n\t // make a copy since the response must be cacheable\n\t var resp = extend({}, response);\n\t resp.data = transformData(response.data, response.headers, response.status,\n\t config.transformResponse);\n\t return (isSuccess(response.status))\n\t ? resp\n\t : $q.reject(resp);\n\t }\n\t }\n\t\n\t $http.pendingRequests = [];\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#get\n\t *\n\t * @description\n\t * Shortcut method to perform `GET` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#delete\n\t *\n\t * @description\n\t * Shortcut method to perform `DELETE` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#head\n\t *\n\t * @description\n\t * Shortcut method to perform `HEAD` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#jsonp\n\t *\n\t * @description\n\t * Shortcut method to perform `JSONP` request.\n\t * If you would like to customise where and how the callbacks are stored then try overriding\n\t * or decorating the {@link $jsonpCallbacks} service.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request.\n\t * The name of the callback should be the string `JSON_CALLBACK`.\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t createShortMethods('get', 'delete', 'head', 'jsonp');\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#post\n\t *\n\t * @description\n\t * Shortcut method to perform `POST` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {*} data Request content\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#put\n\t *\n\t * @description\n\t * Shortcut method to perform `PUT` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {*} data Request content\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $http#patch\n\t *\n\t * @description\n\t * Shortcut method to perform `PATCH` request.\n\t *\n\t * @param {string} url Relative or absolute URL specifying the destination of the request\n\t * @param {*} data Request content\n\t * @param {Object=} config Optional configuration object\n\t * @returns {HttpPromise} Future object\n\t */\n\t createShortMethodsWithData('post', 'put', 'patch');\n\t\n\t /**\n\t * @ngdoc property\n\t * @name $http#defaults\n\t *\n\t * @description\n\t * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of\n\t * default headers, withCredentials as well as request and response transformations.\n\t *\n\t * See \"Setting HTTP Headers\" and \"Transforming Requests and Responses\" sections above.\n\t */\n\t $http.defaults = defaults;\n\t\n\t\n\t return $http;\n\t\n\t\n\t function createShortMethods(names) {\n\t forEach(arguments, function(name) {\n\t $http[name] = function(url, config) {\n\t return $http(extend({}, config || {}, {\n\t method: name,\n\t url: url\n\t }));\n\t };\n\t });\n\t }\n\t\n\t\n\t function createShortMethodsWithData(name) {\n\t forEach(arguments, function(name) {\n\t $http[name] = function(url, data, config) {\n\t return $http(extend({}, config || {}, {\n\t method: name,\n\t url: url,\n\t data: data\n\t }));\n\t };\n\t });\n\t }\n\t\n\t\n\t /**\n\t * Makes the request.\n\t *\n\t * !!! ACCESSES CLOSURE VARS:\n\t * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests\n\t */\n\t function sendReq(config, reqData) {\n\t var deferred = $q.defer(),\n\t promise = deferred.promise,\n\t cache,\n\t cachedResp,\n\t reqHeaders = config.headers,\n\t url = buildUrl(config.url, config.paramSerializer(config.params));\n\t\n\t $http.pendingRequests.push(config);\n\t promise.then(removePendingReq, removePendingReq);\n\t\n\t\n\t if ((config.cache || defaults.cache) && config.cache !== false &&\n\t (config.method === 'GET' || config.method === 'JSONP')) {\n\t cache = isObject(config.cache) ? config.cache\n\t : isObject(defaults.cache) ? defaults.cache\n\t : defaultCache;\n\t }\n\t\n\t if (cache) {\n\t cachedResp = cache.get(url);\n\t if (isDefined(cachedResp)) {\n\t if (isPromiseLike(cachedResp)) {\n\t // cached request has already been sent, but there is no response yet\n\t cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);\n\t } else {\n\t // serving from cache\n\t if (isArray(cachedResp)) {\n\t resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);\n\t } else {\n\t resolvePromise(cachedResp, 200, {}, 'OK');\n\t }\n\t }\n\t } else {\n\t // put the promise for the non-transformed response into cache as a placeholder\n\t cache.put(url, promise);\n\t }\n\t }\n\t\n\t\n\t // if we won't have the response in cache, set the xsrf headers and\n\t // send the request to the backend\n\t if (isUndefined(cachedResp)) {\n\t var xsrfValue = urlIsSameOrigin(config.url)\n\t ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]\n\t : undefined;\n\t if (xsrfValue) {\n\t reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;\n\t }\n\t\n\t $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,\n\t config.withCredentials, config.responseType,\n\t createApplyHandlers(config.eventHandlers),\n\t createApplyHandlers(config.uploadEventHandlers));\n\t }\n\t\n\t return promise;\n\t\n\t function createApplyHandlers(eventHandlers) {\n\t if (eventHandlers) {\n\t var applyHandlers = {};\n\t forEach(eventHandlers, function(eventHandler, key) {\n\t applyHandlers[key] = function(event) {\n\t if (useApplyAsync) {\n\t $rootScope.$applyAsync(callEventHandler);\n\t } else if ($rootScope.$$phase) {\n\t callEventHandler();\n\t } else {\n\t $rootScope.$apply(callEventHandler);\n\t }\n\t\n\t function callEventHandler() {\n\t eventHandler(event);\n\t }\n\t };\n\t });\n\t return applyHandlers;\n\t }\n\t }\n\t\n\t\n\t /**\n\t * Callback registered to $httpBackend():\n\t * - caches the response if desired\n\t * - resolves the raw $http promise\n\t * - calls $apply\n\t */\n\t function done(status, response, headersString, statusText) {\n\t if (cache) {\n\t if (isSuccess(status)) {\n\t cache.put(url, [status, response, parseHeaders(headersString), statusText]);\n\t } else {\n\t // remove promise from the cache\n\t cache.remove(url);\n\t }\n\t }\n\t\n\t function resolveHttpPromise() {\n\t resolvePromise(response, status, headersString, statusText);\n\t }\n\t\n\t if (useApplyAsync) {\n\t $rootScope.$applyAsync(resolveHttpPromise);\n\t } else {\n\t resolveHttpPromise();\n\t if (!$rootScope.$$phase) $rootScope.$apply();\n\t }\n\t }\n\t\n\t\n\t /**\n\t * Resolves the raw $http promise.\n\t */\n\t function resolvePromise(response, status, headers, statusText) {\n\t //status: HTTP response status code, 0, -1 (aborted by timeout / promise)\n\t status = status >= -1 ? status : 0;\n\t\n\t (isSuccess(status) ? deferred.resolve : deferred.reject)({\n\t data: response,\n\t status: status,\n\t headers: headersGetter(headers),\n\t config: config,\n\t statusText: statusText\n\t });\n\t }\n\t\n\t function resolvePromiseWithResult(result) {\n\t resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);\n\t }\n\t\n\t function removePendingReq() {\n\t var idx = $http.pendingRequests.indexOf(config);\n\t if (idx !== -1) $http.pendingRequests.splice(idx, 1);\n\t }\n\t }\n\t\n\t\n\t function buildUrl(url, serializedParams) {\n\t if (serializedParams.length > 0) {\n\t url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;\n\t }\n\t return url;\n\t }\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $xhrFactory\n\t *\n\t * @description\n\t * Factory function used to create XMLHttpRequest objects.\n\t *\n\t * Replace or decorate this service to create your own custom XMLHttpRequest objects.\n\t *\n\t * ```\n\t * angular.module('myApp', [])\n\t * .factory('$xhrFactory', function() {\n\t * return function createXhr(method, url) {\n\t * return new window.XMLHttpRequest({mozSystem: true});\n\t * };\n\t * });\n\t * ```\n\t *\n\t * @param {string} method HTTP method of the request (GET, POST, PUT, ..)\n\t * @param {string} url URL of the request.\n\t */\n\tfunction $xhrFactoryProvider() {\n\t this.$get = function() {\n\t return function createXhr() {\n\t return new window.XMLHttpRequest();\n\t };\n\t };\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $httpBackend\n\t * @requires $jsonpCallbacks\n\t * @requires $document\n\t * @requires $xhrFactory\n\t *\n\t * @description\n\t * HTTP backend used by the {@link ng.$http service} that delegates to\n\t * XMLHttpRequest object or JSONP and deals with browser incompatibilities.\n\t *\n\t * You should never need to use this service directly, instead use the higher-level abstractions:\n\t * {@link ng.$http $http} or {@link ngResource.$resource $resource}.\n\t *\n\t * During testing this implementation is swapped with {@link ngMock.$httpBackend mock\n\t * $httpBackend} which can be trained with responses.\n\t */\n\tfunction $HttpBackendProvider() {\n\t this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {\n\t return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);\n\t }];\n\t}\n\t\n\tfunction createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {\n\t // TODO(vojta): fix the signature\n\t return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {\n\t $browser.$$incOutstandingRequestCount();\n\t url = url || $browser.url();\n\t\n\t if (lowercase(method) === 'jsonp') {\n\t var callbackPath = callbacks.createCallback(url);\n\t var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {\n\t // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)\n\t var response = (status === 200) && callbacks.getResponse(callbackPath);\n\t completeRequest(callback, status, response, \"\", text);\n\t callbacks.removeCallback(callbackPath);\n\t });\n\t } else {\n\t\n\t var xhr = createXhr(method, url);\n\t\n\t xhr.open(method, url, true);\n\t forEach(headers, function(value, key) {\n\t if (isDefined(value)) {\n\t xhr.setRequestHeader(key, value);\n\t }\n\t });\n\t\n\t xhr.onload = function requestLoaded() {\n\t var statusText = xhr.statusText || '';\n\t\n\t // responseText is the old-school way of retrieving response (supported by IE9)\n\t // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)\n\t var response = ('response' in xhr) ? xhr.response : xhr.responseText;\n\t\n\t // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)\n\t var status = xhr.status === 1223 ? 204 : xhr.status;\n\t\n\t // fix status code when it is 0 (0 status is undocumented).\n\t // Occurs when accessing file resources or on Android 4.1 stock browser\n\t // while retrieving files from application cache.\n\t if (status === 0) {\n\t status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;\n\t }\n\t\n\t completeRequest(callback,\n\t status,\n\t response,\n\t xhr.getAllResponseHeaders(),\n\t statusText);\n\t };\n\t\n\t var requestError = function() {\n\t // The response is always empty\n\t // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error\n\t completeRequest(callback, -1, null, null, '');\n\t };\n\t\n\t xhr.onerror = requestError;\n\t xhr.onabort = requestError;\n\t\n\t forEach(eventHandlers, function(value, key) {\n\t xhr.addEventListener(key, value);\n\t });\n\t\n\t forEach(uploadEventHandlers, function(value, key) {\n\t xhr.upload.addEventListener(key, value);\n\t });\n\t\n\t if (withCredentials) {\n\t xhr.withCredentials = true;\n\t }\n\t\n\t if (responseType) {\n\t try {\n\t xhr.responseType = responseType;\n\t } catch (e) {\n\t // WebKit added support for the json responseType value on 09/03/2013\n\t // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are\n\t // known to throw when setting the value \"json\" as the response type. Other older\n\t // browsers implementing the responseType\n\t //\n\t // The json response type can be ignored if not supported, because JSON payloads are\n\t // parsed on the client-side regardless.\n\t if (responseType !== 'json') {\n\t throw e;\n\t }\n\t }\n\t }\n\t\n\t xhr.send(isUndefined(post) ? null : post);\n\t }\n\t\n\t if (timeout > 0) {\n\t var timeoutId = $browserDefer(timeoutRequest, timeout);\n\t } else if (isPromiseLike(timeout)) {\n\t timeout.then(timeoutRequest);\n\t }\n\t\n\t\n\t function timeoutRequest() {\n\t jsonpDone && jsonpDone();\n\t xhr && xhr.abort();\n\t }\n\t\n\t function completeRequest(callback, status, response, headersString, statusText) {\n\t // cancel timeout and subsequent timeout promise resolution\n\t if (isDefined(timeoutId)) {\n\t $browserDefer.cancel(timeoutId);\n\t }\n\t jsonpDone = xhr = null;\n\t\n\t callback(status, response, headersString, statusText);\n\t $browser.$$completeOutstandingRequest(noop);\n\t }\n\t };\n\t\n\t function jsonpReq(url, callbackPath, done) {\n\t url = url.replace('JSON_CALLBACK', callbackPath);\n\t // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:\n\t // - fetches local scripts via XHR and evals them\n\t // - adds and immediately removes script elements from the document\n\t var script = rawDocument.createElement('script'), callback = null;\n\t script.type = \"text/javascript\";\n\t script.src = url;\n\t script.async = true;\n\t\n\t callback = function(event) {\n\t removeEventListenerFn(script, \"load\", callback);\n\t removeEventListenerFn(script, \"error\", callback);\n\t rawDocument.body.removeChild(script);\n\t script = null;\n\t var status = -1;\n\t var text = \"unknown\";\n\t\n\t if (event) {\n\t if (event.type === \"load\" && !callbacks.wasCalled(callbackPath)) {\n\t event = { type: \"error\" };\n\t }\n\t text = event.type;\n\t status = event.type === \"error\" ? 404 : 200;\n\t }\n\t\n\t if (done) {\n\t done(status, text);\n\t }\n\t };\n\t\n\t addEventListenerFn(script, \"load\", callback);\n\t addEventListenerFn(script, \"error\", callback);\n\t rawDocument.body.appendChild(script);\n\t return callback;\n\t }\n\t}\n\t\n\tvar $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');\n\t$interpolateMinErr.throwNoconcat = function(text) {\n\t throw $interpolateMinErr('noconcat',\n\t \"Error while interpolating: {0}\\nStrict Contextual Escaping disallows \" +\n\t \"interpolations that concatenate multiple expressions when a trusted value is \" +\n\t \"required. See http://docs.angularjs.org/api/ng.$sce\", text);\n\t};\n\t\n\t$interpolateMinErr.interr = function(text, err) {\n\t return $interpolateMinErr('interr', \"Can't interpolate: {0}\\n{1}\", text, err.toString());\n\t};\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $interpolateProvider\n\t *\n\t * @description\n\t *\n\t * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.\n\t *\n\t *
\n\t * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular\n\t * template within a Python Jinja template (or any other template language). Mixing templating\n\t * languages is **very dangerous**. The embedding template language will not safely escape Angular\n\t * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)\n\t * security bugs!\n\t *
\n\t *\n\t * @example\n\t\n\t\n\t\n\t
\n\t //demo.label//\n\t
\n\t
\n\t\n\t it('should interpolate binding with custom symbols', function() {\n\t expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');\n\t });\n\t\n\t
\n\t */\n\tfunction $InterpolateProvider() {\n\t var startSymbol = '{{';\n\t var endSymbol = '}}';\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $interpolateProvider#startSymbol\n\t * @description\n\t * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.\n\t *\n\t * @param {string=} value new value to set the starting symbol to.\n\t * @returns {string|self} Returns the symbol when used as getter and self if used as setter.\n\t */\n\t this.startSymbol = function(value) {\n\t if (value) {\n\t startSymbol = value;\n\t return this;\n\t } else {\n\t return startSymbol;\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $interpolateProvider#endSymbol\n\t * @description\n\t * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.\n\t *\n\t * @param {string=} value new value to set the ending symbol to.\n\t * @returns {string|self} Returns the symbol when used as getter and self if used as setter.\n\t */\n\t this.endSymbol = function(value) {\n\t if (value) {\n\t endSymbol = value;\n\t return this;\n\t } else {\n\t return endSymbol;\n\t }\n\t };\n\t\n\t\n\t this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {\n\t var startSymbolLength = startSymbol.length,\n\t endSymbolLength = endSymbol.length,\n\t escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),\n\t escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');\n\t\n\t function escape(ch) {\n\t return '\\\\\\\\\\\\' + ch;\n\t }\n\t\n\t function unescapeText(text) {\n\t return text.replace(escapedStartRegexp, startSymbol).\n\t replace(escapedEndRegexp, endSymbol);\n\t }\n\t\n\t function stringify(value) {\n\t if (value == null) { // null || undefined\n\t return '';\n\t }\n\t switch (typeof value) {\n\t case 'string':\n\t break;\n\t case 'number':\n\t value = '' + value;\n\t break;\n\t default:\n\t value = toJson(value);\n\t }\n\t\n\t return value;\n\t }\n\t\n\t //TODO: this is the same as the constantWatchDelegate in parse.js\n\t function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {\n\t var unwatch;\n\t return unwatch = scope.$watch(function constantInterpolateWatch(scope) {\n\t unwatch();\n\t return constantInterp(scope);\n\t }, listener, objectEquality);\n\t }\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $interpolate\n\t * @kind function\n\t *\n\t * @requires $parse\n\t * @requires $sce\n\t *\n\t * @description\n\t *\n\t * Compiles a string with markup into an interpolation function. This service is used by the\n\t * HTML {@link ng.$compile $compile} service for data binding. See\n\t * {@link ng.$interpolateProvider $interpolateProvider} for configuring the\n\t * interpolation markup.\n\t *\n\t *\n\t * ```js\n\t * var $interpolate = ...; // injected\n\t * var exp = $interpolate('Hello {{name | uppercase}}!');\n\t * expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');\n\t * ```\n\t *\n\t * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is\n\t * `true`, the interpolation function will return `undefined` unless all embedded expressions\n\t * evaluate to a value other than `undefined`.\n\t *\n\t * ```js\n\t * var $interpolate = ...; // injected\n\t * var context = {greeting: 'Hello', name: undefined };\n\t *\n\t * // default \"forgiving\" mode\n\t * var exp = $interpolate('{{greeting}} {{name}}!');\n\t * expect(exp(context)).toEqual('Hello !');\n\t *\n\t * // \"allOrNothing\" mode\n\t * exp = $interpolate('{{greeting}} {{name}}!', false, null, true);\n\t * expect(exp(context)).toBeUndefined();\n\t * context.name = 'Angular';\n\t * expect(exp(context)).toEqual('Hello Angular!');\n\t * ```\n\t *\n\t * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.\n\t *\n\t * #### Escaped Interpolation\n\t * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers\n\t * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).\n\t * It will be rendered as a regular start/end marker, and will not be interpreted as an expression\n\t * or binding.\n\t *\n\t * This enables web-servers to prevent script injection attacks and defacing attacks, to some\n\t * degree, while also enabling code examples to work without relying on the\n\t * {@link ng.directive:ngNonBindable ngNonBindable} directive.\n\t *\n\t * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,\n\t * replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all\n\t * interpolation start/end markers with their escaped counterparts.**\n\t *\n\t * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered\n\t * output when the $interpolate service processes the text. So, for HTML elements interpolated\n\t * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter\n\t * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,\n\t * this is typically useful only when user-data is used in rendering a template from the server, or\n\t * when otherwise untrusted data is used by a directive.\n\t *\n\t * \n\t * \n\t *
\n\t *

{{apptitle}}: \\{\\{ username = \"defaced value\"; \\}\\}\n\t *

\n\t *

{{username}} attempts to inject code which will deface the\n\t * application, but fails to accomplish their task, because the server has correctly\n\t * escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)\n\t * characters.

\n\t *

Instead, the result of the attempted script injection is visible, and can be removed\n\t * from the database by an administrator.

\n\t *
\n\t *
\n\t *
\n\t *\n\t * @knownIssue\n\t * It is currently not possible for an interpolated expression to contain the interpolation end\n\t * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.\n\t * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.\n\t *\n\t * @knownIssue\n\t * All directives and components must use the standard `{{` `}}` interpolation symbols\n\t * in their templates. If you change the application interpolation symbols the {@link $compile}\n\t * service will attempt to denormalize the standard symbols to the custom symbols.\n\t * The denormalization process is not clever enough to know not to replace instances of the standard\n\t * symbols where they would not normally be treated as interpolation symbols. For example in the following\n\t * code snippet the closing braces of the literal object will get incorrectly denormalized:\n\t *\n\t * ```\n\t *
\n\t * ```\n\t *\n\t * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.\n\t *\n\t * @param {string} text The text with markup to interpolate.\n\t * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have\n\t * embedded expression in order to return an interpolation function. Strings with no\n\t * embedded expression will return null for the interpolation function.\n\t * @param {string=} trustedContext when provided, the returned function passes the interpolated\n\t * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,\n\t * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that\n\t * provides Strict Contextual Escaping for details.\n\t * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined\n\t * unless all embedded expressions evaluate to a value other than `undefined`.\n\t * @returns {function(context)} an interpolation function which is used to compute the\n\t * interpolated string. The function has these parameters:\n\t *\n\t * - `context`: evaluation context for all expressions embedded in the interpolated text\n\t */\n\t function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {\n\t // Provide a quick exit and simplified result function for text with no interpolation\n\t if (!text.length || text.indexOf(startSymbol) === -1) {\n\t var constantInterp;\n\t if (!mustHaveExpression) {\n\t var unescapedText = unescapeText(text);\n\t constantInterp = valueFn(unescapedText);\n\t constantInterp.exp = text;\n\t constantInterp.expressions = [];\n\t constantInterp.$$watchDelegate = constantWatchDelegate;\n\t }\n\t return constantInterp;\n\t }\n\t\n\t allOrNothing = !!allOrNothing;\n\t var startIndex,\n\t endIndex,\n\t index = 0,\n\t expressions = [],\n\t parseFns = [],\n\t textLength = text.length,\n\t exp,\n\t concat = [],\n\t expressionPositions = [];\n\t\n\t while (index < textLength) {\n\t if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&\n\t ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {\n\t if (index !== startIndex) {\n\t concat.push(unescapeText(text.substring(index, startIndex)));\n\t }\n\t exp = text.substring(startIndex + startSymbolLength, endIndex);\n\t expressions.push(exp);\n\t parseFns.push($parse(exp, parseStringifyInterceptor));\n\t index = endIndex + endSymbolLength;\n\t expressionPositions.push(concat.length);\n\t concat.push('');\n\t } else {\n\t // we did not find an interpolation, so we have to add the remainder to the separators array\n\t if (index !== textLength) {\n\t concat.push(unescapeText(text.substring(index)));\n\t }\n\t break;\n\t }\n\t }\n\t\n\t // Concatenating expressions makes it hard to reason about whether some combination of\n\t // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a\n\t // single expression be used for iframe[src], object[src], etc., we ensure that the value\n\t // that's used is assigned or constructed by some JS code somewhere that is more testable or\n\t // make it obvious that you bound the value to some user controlled value. This helps reduce\n\t // the load when auditing for XSS issues.\n\t if (trustedContext && concat.length > 1) {\n\t $interpolateMinErr.throwNoconcat(text);\n\t }\n\t\n\t if (!mustHaveExpression || expressions.length) {\n\t var compute = function(values) {\n\t for (var i = 0, ii = expressions.length; i < ii; i++) {\n\t if (allOrNothing && isUndefined(values[i])) return;\n\t concat[expressionPositions[i]] = values[i];\n\t }\n\t return concat.join('');\n\t };\n\t\n\t var getValue = function(value) {\n\t return trustedContext ?\n\t $sce.getTrusted(trustedContext, value) :\n\t $sce.valueOf(value);\n\t };\n\t\n\t return extend(function interpolationFn(context) {\n\t var i = 0;\n\t var ii = expressions.length;\n\t var values = new Array(ii);\n\t\n\t try {\n\t for (; i < ii; i++) {\n\t values[i] = parseFns[i](context);\n\t }\n\t\n\t return compute(values);\n\t } catch (err) {\n\t $exceptionHandler($interpolateMinErr.interr(text, err));\n\t }\n\t\n\t }, {\n\t // all of these properties are undocumented for now\n\t exp: text, //just for compatibility with regular watchers created via $watch\n\t expressions: expressions,\n\t $$watchDelegate: function(scope, listener) {\n\t var lastValue;\n\t return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {\n\t var currValue = compute(values);\n\t if (isFunction(listener)) {\n\t listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);\n\t }\n\t lastValue = currValue;\n\t });\n\t }\n\t });\n\t }\n\t\n\t function parseStringifyInterceptor(value) {\n\t try {\n\t value = getValue(value);\n\t return allOrNothing && !isDefined(value) ? value : stringify(value);\n\t } catch (err) {\n\t $exceptionHandler($interpolateMinErr.interr(text, err));\n\t }\n\t }\n\t }\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $interpolate#startSymbol\n\t * @description\n\t * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.\n\t *\n\t * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change\n\t * the symbol.\n\t *\n\t * @returns {string} start symbol.\n\t */\n\t $interpolate.startSymbol = function() {\n\t return startSymbol;\n\t };\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $interpolate#endSymbol\n\t * @description\n\t * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.\n\t *\n\t * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change\n\t * the symbol.\n\t *\n\t * @returns {string} end symbol.\n\t */\n\t $interpolate.endSymbol = function() {\n\t return endSymbol;\n\t };\n\t\n\t return $interpolate;\n\t }];\n\t}\n\t\n\tfunction $IntervalProvider() {\n\t this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',\n\t function($rootScope, $window, $q, $$q, $browser) {\n\t var intervals = {};\n\t\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $interval\n\t *\n\t * @description\n\t * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`\n\t * milliseconds.\n\t *\n\t * The return value of registering an interval function is a promise. This promise will be\n\t * notified upon each tick of the interval, and will be resolved after `count` iterations, or\n\t * run indefinitely if `count` is not defined. The value of the notification will be the\n\t * number of iterations that have run.\n\t * To cancel an interval, call `$interval.cancel(promise)`.\n\t *\n\t * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to\n\t * move forward by `millis` milliseconds and trigger any functions scheduled to run in that\n\t * time.\n\t *\n\t *
\n\t * **Note**: Intervals created by this service must be explicitly destroyed when you are finished\n\t * with them. In particular they are not automatically destroyed when a controller's scope or a\n\t * directive's element are destroyed.\n\t * You should take this into consideration and make sure to always cancel the interval at the\n\t * appropriate moment. See the example below for more details on how and when to do this.\n\t *
\n\t *\n\t * @param {function()} fn A function that should be called repeatedly.\n\t * @param {number} delay Number of milliseconds between each function call.\n\t * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat\n\t * indefinitely.\n\t * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise\n\t * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.\n\t * @param {...*=} Pass additional parameters to the executed function.\n\t * @returns {promise} A promise which will be notified on each iteration.\n\t *\n\t * @example\n\t * \n\t * \n\t * \n\t *\n\t *
\n\t *
\n\t *
\n\t * Current time is: \n\t *
\n\t * Blood 1 : {{blood_1}}\n\t * Blood 2 : {{blood_2}}\n\t * \n\t * \n\t * \n\t *
\n\t *
\n\t *\n\t *
\n\t *
\n\t */\n\t function interval(fn, delay, count, invokeApply) {\n\t var hasParams = arguments.length > 4,\n\t args = hasParams ? sliceArgs(arguments, 4) : [],\n\t setInterval = $window.setInterval,\n\t clearInterval = $window.clearInterval,\n\t iteration = 0,\n\t skipApply = (isDefined(invokeApply) && !invokeApply),\n\t deferred = (skipApply ? $$q : $q).defer(),\n\t promise = deferred.promise;\n\t\n\t count = isDefined(count) ? count : 0;\n\t\n\t promise.$$intervalId = setInterval(function tick() {\n\t if (skipApply) {\n\t $browser.defer(callback);\n\t } else {\n\t $rootScope.$evalAsync(callback);\n\t }\n\t deferred.notify(iteration++);\n\t\n\t if (count > 0 && iteration >= count) {\n\t deferred.resolve(iteration);\n\t clearInterval(promise.$$intervalId);\n\t delete intervals[promise.$$intervalId];\n\t }\n\t\n\t if (!skipApply) $rootScope.$apply();\n\t\n\t }, delay);\n\t\n\t intervals[promise.$$intervalId] = deferred;\n\t\n\t return promise;\n\t\n\t function callback() {\n\t if (!hasParams) {\n\t fn(iteration);\n\t } else {\n\t fn.apply(null, args);\n\t }\n\t }\n\t }\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $interval#cancel\n\t *\n\t * @description\n\t * Cancels a task associated with the `promise`.\n\t *\n\t * @param {Promise=} promise returned by the `$interval` function.\n\t * @returns {boolean} Returns `true` if the task was successfully canceled.\n\t */\n\t interval.cancel = function(promise) {\n\t if (promise && promise.$$intervalId in intervals) {\n\t intervals[promise.$$intervalId].reject('canceled');\n\t $window.clearInterval(promise.$$intervalId);\n\t delete intervals[promise.$$intervalId];\n\t return true;\n\t }\n\t return false;\n\t };\n\t\n\t return interval;\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $jsonpCallbacks\n\t * @requires $window\n\t * @description\n\t * This service handles the lifecycle of callbacks to handle JSONP requests.\n\t * Override this service if you wish to customise where the callbacks are stored and\n\t * how they vary compared to the requested url.\n\t */\n\tvar $jsonpCallbacksProvider = function() {\n\t this.$get = ['$window', function($window) {\n\t var callbacks = $window.angular.callbacks;\n\t var callbackMap = {};\n\t\n\t function createCallback(callbackId) {\n\t var callback = function(data) {\n\t callback.data = data;\n\t callback.called = true;\n\t };\n\t callback.id = callbackId;\n\t return callback;\n\t }\n\t\n\t return {\n\t /**\n\t * @ngdoc method\n\t * @name $jsonpCallbacks#createCallback\n\t * @param {string} url the url of the JSONP request\n\t * @returns {string} the callback path to send to the server as part of the JSONP request\n\t * @description\n\t * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback\n\t * to pass to the server, which will be used to call the callback with its payload in the JSONP response.\n\t */\n\t createCallback: function(url) {\n\t var callbackId = '_' + (callbacks.$$counter++).toString(36);\n\t var callbackPath = 'angular.callbacks.' + callbackId;\n\t var callback = createCallback(callbackId);\n\t callbackMap[callbackPath] = callbacks[callbackId] = callback;\n\t return callbackPath;\n\t },\n\t /**\n\t * @ngdoc method\n\t * @name $jsonpCallbacks#wasCalled\n\t * @param {string} callbackPath the path to the callback that was sent in the JSONP request\n\t * @returns {boolean} whether the callback has been called, as a result of the JSONP response\n\t * @description\n\t * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the\n\t * callback that was passed in the request.\n\t */\n\t wasCalled: function(callbackPath) {\n\t return callbackMap[callbackPath].called;\n\t },\n\t /**\n\t * @ngdoc method\n\t * @name $jsonpCallbacks#getResponse\n\t * @param {string} callbackPath the path to the callback that was sent in the JSONP request\n\t * @returns {*} the data received from the response via the registered callback\n\t * @description\n\t * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback\n\t * in the JSONP response.\n\t */\n\t getResponse: function(callbackPath) {\n\t return callbackMap[callbackPath].data;\n\t },\n\t /**\n\t * @ngdoc method\n\t * @name $jsonpCallbacks#removeCallback\n\t * @param {string} callbackPath the path to the callback that was sent in the JSONP request\n\t * @description\n\t * {@link $httpBackend} calls this method to remove the callback after the JSONP request has\n\t * completed or timed-out.\n\t */\n\t removeCallback: function(callbackPath) {\n\t var callback = callbackMap[callbackPath];\n\t delete callbacks[callback.id];\n\t delete callbackMap[callbackPath];\n\t }\n\t };\n\t }];\n\t};\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $locale\n\t *\n\t * @description\n\t * $locale service provides localization rules for various Angular components. As of right now the\n\t * only public api is:\n\t *\n\t * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)\n\t */\n\t\n\tvar PATH_MATCH = /^([^\\?#]*)(\\?([^#]*))?(#(.*))?$/,\n\t DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};\n\tvar $locationMinErr = minErr('$location');\n\t\n\t\n\t/**\n\t * Encode path using encodeUriSegment, ignoring forward slashes\n\t *\n\t * @param {string} path Path to encode\n\t * @returns {string}\n\t */\n\tfunction encodePath(path) {\n\t var segments = path.split('/'),\n\t i = segments.length;\n\t\n\t while (i--) {\n\t segments[i] = encodeUriSegment(segments[i]);\n\t }\n\t\n\t return segments.join('/');\n\t}\n\t\n\tfunction parseAbsoluteUrl(absoluteUrl, locationObj) {\n\t var parsedUrl = urlResolve(absoluteUrl);\n\t\n\t locationObj.$$protocol = parsedUrl.protocol;\n\t locationObj.$$host = parsedUrl.hostname;\n\t locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;\n\t}\n\t\n\t\n\tfunction parseAppUrl(relativeUrl, locationObj) {\n\t var prefixed = (relativeUrl.charAt(0) !== '/');\n\t if (prefixed) {\n\t relativeUrl = '/' + relativeUrl;\n\t }\n\t var match = urlResolve(relativeUrl);\n\t locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?\n\t match.pathname.substring(1) : match.pathname);\n\t locationObj.$$search = parseKeyValue(match.search);\n\t locationObj.$$hash = decodeURIComponent(match.hash);\n\t\n\t // make sure path starts with '/';\n\t if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {\n\t locationObj.$$path = '/' + locationObj.$$path;\n\t }\n\t}\n\t\n\tfunction startsWith(haystack, needle) {\n\t return haystack.lastIndexOf(needle, 0) === 0;\n\t}\n\t\n\t/**\n\t *\n\t * @param {string} base\n\t * @param {string} url\n\t * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with\n\t * the expected string.\n\t */\n\tfunction stripBaseUrl(base, url) {\n\t if (startsWith(url, base)) {\n\t return url.substr(base.length);\n\t }\n\t}\n\t\n\t\n\tfunction stripHash(url) {\n\t var index = url.indexOf('#');\n\t return index == -1 ? url : url.substr(0, index);\n\t}\n\t\n\tfunction trimEmptyHash(url) {\n\t return url.replace(/(#.+)|#$/, '$1');\n\t}\n\t\n\t\n\tfunction stripFile(url) {\n\t return url.substr(0, stripHash(url).lastIndexOf('/') + 1);\n\t}\n\t\n\t/* return the server only (scheme://host:port) */\n\tfunction serverBase(url) {\n\t return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));\n\t}\n\t\n\t\n\t/**\n\t * LocationHtml5Url represents an url\n\t * This object is exposed as $location service when HTML5 mode is enabled and supported\n\t *\n\t * @constructor\n\t * @param {string} appBase application base URL\n\t * @param {string} appBaseNoFile application base URL stripped of any filename\n\t * @param {string} basePrefix url path prefix\n\t */\n\tfunction LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {\n\t this.$$html5 = true;\n\t basePrefix = basePrefix || '';\n\t parseAbsoluteUrl(appBase, this);\n\t\n\t\n\t /**\n\t * Parse given html5 (regular) url string into properties\n\t * @param {string} url HTML5 url\n\t * @private\n\t */\n\t this.$$parse = function(url) {\n\t var pathUrl = stripBaseUrl(appBaseNoFile, url);\n\t if (!isString(pathUrl)) {\n\t throw $locationMinErr('ipthprfx', 'Invalid url \"{0}\", missing path prefix \"{1}\".', url,\n\t appBaseNoFile);\n\t }\n\t\n\t parseAppUrl(pathUrl, this);\n\t\n\t if (!this.$$path) {\n\t this.$$path = '/';\n\t }\n\t\n\t this.$$compose();\n\t };\n\t\n\t /**\n\t * Compose url and update `absUrl` property\n\t * @private\n\t */\n\t this.$$compose = function() {\n\t var search = toKeyValue(this.$$search),\n\t hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';\n\t\n\t this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;\n\t this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'\n\t };\n\t\n\t this.$$parseLinkUrl = function(url, relHref) {\n\t if (relHref && relHref[0] === '#') {\n\t // special case for links to hash fragments:\n\t // keep the old url and only replace the hash fragment\n\t this.hash(relHref.slice(1));\n\t return true;\n\t }\n\t var appUrl, prevAppUrl;\n\t var rewrittenUrl;\n\t\n\t if (isDefined(appUrl = stripBaseUrl(appBase, url))) {\n\t prevAppUrl = appUrl;\n\t if (isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) {\n\t rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl);\n\t } else {\n\t rewrittenUrl = appBase + prevAppUrl;\n\t }\n\t } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) {\n\t rewrittenUrl = appBaseNoFile + appUrl;\n\t } else if (appBaseNoFile == url + '/') {\n\t rewrittenUrl = appBaseNoFile;\n\t }\n\t if (rewrittenUrl) {\n\t this.$$parse(rewrittenUrl);\n\t }\n\t return !!rewrittenUrl;\n\t };\n\t}\n\t\n\t\n\t/**\n\t * LocationHashbangUrl represents url\n\t * This object is exposed as $location service when developer doesn't opt into html5 mode.\n\t * It also serves as the base class for html5 mode fallback on legacy browsers.\n\t *\n\t * @constructor\n\t * @param {string} appBase application base URL\n\t * @param {string} appBaseNoFile application base URL stripped of any filename\n\t * @param {string} hashPrefix hashbang prefix\n\t */\n\tfunction LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {\n\t\n\t parseAbsoluteUrl(appBase, this);\n\t\n\t\n\t /**\n\t * Parse given hashbang url into properties\n\t * @param {string} url Hashbang url\n\t * @private\n\t */\n\t this.$$parse = function(url) {\n\t var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url);\n\t var withoutHashUrl;\n\t\n\t if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {\n\t\n\t // The rest of the url starts with a hash so we have\n\t // got either a hashbang path or a plain hash fragment\n\t withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);\n\t if (isUndefined(withoutHashUrl)) {\n\t // There was no hashbang prefix so we just have a hash fragment\n\t withoutHashUrl = withoutBaseUrl;\n\t }\n\t\n\t } else {\n\t // There was no hashbang path nor hash fragment:\n\t // If we are in HTML5 mode we use what is left as the path;\n\t // Otherwise we ignore what is left\n\t if (this.$$html5) {\n\t withoutHashUrl = withoutBaseUrl;\n\t } else {\n\t withoutHashUrl = '';\n\t if (isUndefined(withoutBaseUrl)) {\n\t appBase = url;\n\t this.replace();\n\t }\n\t }\n\t }\n\t\n\t parseAppUrl(withoutHashUrl, this);\n\t\n\t this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);\n\t\n\t this.$$compose();\n\t\n\t /*\n\t * In Windows, on an anchor node on documents loaded from\n\t * the filesystem, the browser will return a pathname\n\t * prefixed with the drive name ('/C:/path') when a\n\t * pathname without a drive is set:\n\t * * a.setAttribute('href', '/foo')\n\t * * a.pathname === '/C:/foo' //true\n\t *\n\t * Inside of Angular, we're always using pathnames that\n\t * do not include drive names for routing.\n\t */\n\t function removeWindowsDriveName(path, url, base) {\n\t /*\n\t Matches paths for file protocol on windows,\n\t such as /C:/foo/bar, and captures only /foo/bar.\n\t */\n\t var windowsFilePathExp = /^\\/[A-Z]:(\\/.*)/;\n\t\n\t var firstPathSegmentMatch;\n\t\n\t //Get the relative path from the input URL.\n\t if (startsWith(url, base)) {\n\t url = url.replace(base, '');\n\t }\n\t\n\t // The input URL intentionally contains a first path segment that ends with a colon.\n\t if (windowsFilePathExp.exec(url)) {\n\t return path;\n\t }\n\t\n\t firstPathSegmentMatch = windowsFilePathExp.exec(path);\n\t return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;\n\t }\n\t };\n\t\n\t /**\n\t * Compose hashbang url and update `absUrl` property\n\t * @private\n\t */\n\t this.$$compose = function() {\n\t var search = toKeyValue(this.$$search),\n\t hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';\n\t\n\t this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;\n\t this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');\n\t };\n\t\n\t this.$$parseLinkUrl = function(url, relHref) {\n\t if (stripHash(appBase) == stripHash(url)) {\n\t this.$$parse(url);\n\t return true;\n\t }\n\t return false;\n\t };\n\t}\n\t\n\t\n\t/**\n\t * LocationHashbangUrl represents url\n\t * This object is exposed as $location service when html5 history api is enabled but the browser\n\t * does not support it.\n\t *\n\t * @constructor\n\t * @param {string} appBase application base URL\n\t * @param {string} appBaseNoFile application base URL stripped of any filename\n\t * @param {string} hashPrefix hashbang prefix\n\t */\n\tfunction LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {\n\t this.$$html5 = true;\n\t LocationHashbangUrl.apply(this, arguments);\n\t\n\t this.$$parseLinkUrl = function(url, relHref) {\n\t if (relHref && relHref[0] === '#') {\n\t // special case for links to hash fragments:\n\t // keep the old url and only replace the hash fragment\n\t this.hash(relHref.slice(1));\n\t return true;\n\t }\n\t\n\t var rewrittenUrl;\n\t var appUrl;\n\t\n\t if (appBase == stripHash(url)) {\n\t rewrittenUrl = url;\n\t } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {\n\t rewrittenUrl = appBase + hashPrefix + appUrl;\n\t } else if (appBaseNoFile === url + '/') {\n\t rewrittenUrl = appBaseNoFile;\n\t }\n\t if (rewrittenUrl) {\n\t this.$$parse(rewrittenUrl);\n\t }\n\t return !!rewrittenUrl;\n\t };\n\t\n\t this.$$compose = function() {\n\t var search = toKeyValue(this.$$search),\n\t hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';\n\t\n\t this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;\n\t // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'\n\t this.$$absUrl = appBase + hashPrefix + this.$$url;\n\t };\n\t\n\t}\n\t\n\t\n\tvar locationPrototype = {\n\t\n\t /**\n\t * Ensure absolute url is initialized.\n\t * @private\n\t */\n\t $$absUrl:'',\n\t\n\t /**\n\t * Are we in html5 mode?\n\t * @private\n\t */\n\t $$html5: false,\n\t\n\t /**\n\t * Has any change been replacing?\n\t * @private\n\t */\n\t $$replace: false,\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#absUrl\n\t *\n\t * @description\n\t * This method is getter only.\n\t *\n\t * Return full url representation with all segments encoded according to rules specified in\n\t * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var absUrl = $location.absUrl();\n\t * // => \"http://example.com/#/some/path?foo=bar&baz=xoxo\"\n\t * ```\n\t *\n\t * @return {string} full url\n\t */\n\t absUrl: locationGetter('$$absUrl'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#url\n\t *\n\t * @description\n\t * This method is getter / setter.\n\t *\n\t * Return url (e.g. `/path?a=b#hash`) when called without any parameter.\n\t *\n\t * Change path, search and hash, when called with parameter and return `$location`.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var url = $location.url();\n\t * // => \"/some/path?foo=bar&baz=xoxo\"\n\t * ```\n\t *\n\t * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)\n\t * @return {string} url\n\t */\n\t url: function(url) {\n\t if (isUndefined(url)) {\n\t return this.$$url;\n\t }\n\t\n\t var match = PATH_MATCH.exec(url);\n\t if (match[1] || url === '') this.path(decodeURIComponent(match[1]));\n\t if (match[2] || match[1] || url === '') this.search(match[3] || '');\n\t this.hash(match[5] || '');\n\t\n\t return this;\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#protocol\n\t *\n\t * @description\n\t * This method is getter only.\n\t *\n\t * Return protocol of current url.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var protocol = $location.protocol();\n\t * // => \"http\"\n\t * ```\n\t *\n\t * @return {string} protocol of current url\n\t */\n\t protocol: locationGetter('$$protocol'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#host\n\t *\n\t * @description\n\t * This method is getter only.\n\t *\n\t * Return host of current url.\n\t *\n\t * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var host = $location.host();\n\t * // => \"example.com\"\n\t *\n\t * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo\n\t * host = $location.host();\n\t * // => \"example.com\"\n\t * host = location.host;\n\t * // => \"example.com:8080\"\n\t * ```\n\t *\n\t * @return {string} host of current url.\n\t */\n\t host: locationGetter('$$host'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#port\n\t *\n\t * @description\n\t * This method is getter only.\n\t *\n\t * Return port of current url.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var port = $location.port();\n\t * // => 80\n\t * ```\n\t *\n\t * @return {Number} port\n\t */\n\t port: locationGetter('$$port'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#path\n\t *\n\t * @description\n\t * This method is getter / setter.\n\t *\n\t * Return path of current url when called without any parameter.\n\t *\n\t * Change path when called with parameter and return `$location`.\n\t *\n\t * Note: Path should always begin with forward slash (/), this method will add the forward slash\n\t * if it is missing.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var path = $location.path();\n\t * // => \"/some/path\"\n\t * ```\n\t *\n\t * @param {(string|number)=} path New path\n\t * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter\n\t */\n\t path: locationGetterSetter('$$path', function(path) {\n\t path = path !== null ? path.toString() : '';\n\t return path.charAt(0) == '/' ? path : '/' + path;\n\t }),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#search\n\t *\n\t * @description\n\t * This method is getter / setter.\n\t *\n\t * Return search part (as object) of current url when called without any parameter.\n\t *\n\t * Change search part when called with parameter and return `$location`.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo\n\t * var searchObject = $location.search();\n\t * // => {foo: 'bar', baz: 'xoxo'}\n\t *\n\t * // set foo to 'yipee'\n\t * $location.search('foo', 'yipee');\n\t * // $location.search() => {foo: 'yipee', baz: 'xoxo'}\n\t * ```\n\t *\n\t * @param {string|Object.|Object.>} search New search params - string or\n\t * hash object.\n\t *\n\t * When called with a single argument the method acts as a setter, setting the `search` component\n\t * of `$location` to the specified value.\n\t *\n\t * If the argument is a hash object containing an array of values, these values will be encoded\n\t * as duplicate search parameters in the url.\n\t *\n\t * @param {(string|Number|Array|boolean)=} paramValue If `search` is a string or number, then `paramValue`\n\t * will override only a single search property.\n\t *\n\t * If `paramValue` is an array, it will override the property of the `search` component of\n\t * `$location` specified via the first argument.\n\t *\n\t * If `paramValue` is `null`, the property specified via the first argument will be deleted.\n\t *\n\t * If `paramValue` is `true`, the property specified via the first argument will be added with no\n\t * value nor trailing equal sign.\n\t *\n\t * @return {Object} If called with no arguments returns the parsed `search` object. If called with\n\t * one or more arguments returns `$location` object itself.\n\t */\n\t search: function(search, paramValue) {\n\t switch (arguments.length) {\n\t case 0:\n\t return this.$$search;\n\t case 1:\n\t if (isString(search) || isNumber(search)) {\n\t search = search.toString();\n\t this.$$search = parseKeyValue(search);\n\t } else if (isObject(search)) {\n\t search = copy(search, {});\n\t // remove object undefined or null properties\n\t forEach(search, function(value, key) {\n\t if (value == null) delete search[key];\n\t });\n\t\n\t this.$$search = search;\n\t } else {\n\t throw $locationMinErr('isrcharg',\n\t 'The first argument of the `$location#search()` call must be a string or an object.');\n\t }\n\t break;\n\t default:\n\t if (isUndefined(paramValue) || paramValue === null) {\n\t delete this.$$search[search];\n\t } else {\n\t this.$$search[search] = paramValue;\n\t }\n\t }\n\t\n\t this.$$compose();\n\t return this;\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#hash\n\t *\n\t * @description\n\t * This method is getter / setter.\n\t *\n\t * Returns the hash fragment when called without any parameters.\n\t *\n\t * Changes the hash fragment when called with a parameter and returns `$location`.\n\t *\n\t *\n\t * ```js\n\t * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue\n\t * var hash = $location.hash();\n\t * // => \"hashValue\"\n\t * ```\n\t *\n\t * @param {(string|number)=} hash New hash fragment\n\t * @return {string} hash\n\t */\n\t hash: locationGetterSetter('$$hash', function(hash) {\n\t return hash !== null ? hash.toString() : '';\n\t }),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#replace\n\t *\n\t * @description\n\t * If called, all changes to $location during the current `$digest` will replace the current history\n\t * record, instead of adding a new one.\n\t */\n\t replace: function() {\n\t this.$$replace = true;\n\t return this;\n\t }\n\t};\n\t\n\tforEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {\n\t Location.prototype = Object.create(locationPrototype);\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $location#state\n\t *\n\t * @description\n\t * This method is getter / setter.\n\t *\n\t * Return the history state object when called without any parameter.\n\t *\n\t * Change the history state object when called with one parameter and return `$location`.\n\t * The state object is later passed to `pushState` or `replaceState`.\n\t *\n\t * NOTE: This method is supported only in HTML5 mode and only in browsers supporting\n\t * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support\n\t * older browsers (like IE9 or Android < 4.0), don't use this method.\n\t *\n\t * @param {object=} state State object for pushState or replaceState\n\t * @return {object} state\n\t */\n\t Location.prototype.state = function(state) {\n\t if (!arguments.length) {\n\t return this.$$state;\n\t }\n\t\n\t if (Location !== LocationHtml5Url || !this.$$html5) {\n\t throw $locationMinErr('nostate', 'History API state support is available only ' +\n\t 'in HTML5 mode and only in browsers supporting HTML5 History API');\n\t }\n\t // The user might modify `stateObject` after invoking `$location.state(stateObject)`\n\t // but we're changing the $$state reference to $browser.state() during the $digest\n\t // so the modification window is narrow.\n\t this.$$state = isUndefined(state) ? null : state;\n\t\n\t return this;\n\t };\n\t});\n\t\n\t\n\tfunction locationGetter(property) {\n\t return function() {\n\t return this[property];\n\t };\n\t}\n\t\n\t\n\tfunction locationGetterSetter(property, preprocess) {\n\t return function(value) {\n\t if (isUndefined(value)) {\n\t return this[property];\n\t }\n\t\n\t this[property] = preprocess(value);\n\t this.$$compose();\n\t\n\t return this;\n\t };\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $location\n\t *\n\t * @requires $rootElement\n\t *\n\t * @description\n\t * The $location service parses the URL in the browser address bar (based on the\n\t * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL\n\t * available to your application. Changes to the URL in the address bar are reflected into\n\t * $location service and changes to $location are reflected into the browser address bar.\n\t *\n\t * **The $location service:**\n\t *\n\t * - Exposes the current URL in the browser address bar, so you can\n\t * - Watch and observe the URL.\n\t * - Change the URL.\n\t * - Synchronizes the URL with the browser when the user\n\t * - Changes the address bar.\n\t * - Clicks the back or forward button (or clicks a History link).\n\t * - Clicks on a link.\n\t * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).\n\t *\n\t * For more information see {@link guide/$location Developer Guide: Using $location}\n\t */\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $locationProvider\n\t * @description\n\t * Use the `$locationProvider` to configure how the application deep linking paths are stored.\n\t */\n\tfunction $LocationProvider() {\n\t var hashPrefix = '',\n\t html5Mode = {\n\t enabled: false,\n\t requireBase: true,\n\t rewriteLinks: true\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $locationProvider#hashPrefix\n\t * @description\n\t * @param {string=} prefix Prefix for hash part (containing path and search)\n\t * @returns {*} current value if used as getter or itself (chaining) if used as setter\n\t */\n\t this.hashPrefix = function(prefix) {\n\t if (isDefined(prefix)) {\n\t hashPrefix = prefix;\n\t return this;\n\t } else {\n\t return hashPrefix;\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $locationProvider#html5Mode\n\t * @description\n\t * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.\n\t * If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported\n\t * properties:\n\t * - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to\n\t * change urls where supported. Will fall back to hash-prefixed paths in browsers that do not\n\t * support `pushState`.\n\t * - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies\n\t * whether or not a tag is required to be present. If `enabled` and `requireBase` are\n\t * true, and a base tag is not present, an error will be thrown when `$location` is injected.\n\t * See the {@link guide/$location $location guide for more information}\n\t * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,\n\t * enables/disables url rewriting for relative links.\n\t *\n\t * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter\n\t */\n\t this.html5Mode = function(mode) {\n\t if (isBoolean(mode)) {\n\t html5Mode.enabled = mode;\n\t return this;\n\t } else if (isObject(mode)) {\n\t\n\t if (isBoolean(mode.enabled)) {\n\t html5Mode.enabled = mode.enabled;\n\t }\n\t\n\t if (isBoolean(mode.requireBase)) {\n\t html5Mode.requireBase = mode.requireBase;\n\t }\n\t\n\t if (isBoolean(mode.rewriteLinks)) {\n\t html5Mode.rewriteLinks = mode.rewriteLinks;\n\t }\n\t\n\t return this;\n\t } else {\n\t return html5Mode;\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc event\n\t * @name $location#$locationChangeStart\n\t * @eventType broadcast on root scope\n\t * @description\n\t * Broadcasted before a URL will change.\n\t *\n\t * This change can be prevented by calling\n\t * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more\n\t * details about event object. Upon successful change\n\t * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.\n\t *\n\t * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when\n\t * the browser supports the HTML5 History API.\n\t *\n\t * @param {Object} angularEvent Synthetic event object.\n\t * @param {string} newUrl New URL\n\t * @param {string=} oldUrl URL that was before it was changed.\n\t * @param {string=} newState New history state object\n\t * @param {string=} oldState History state object that was before it was changed.\n\t */\n\t\n\t /**\n\t * @ngdoc event\n\t * @name $location#$locationChangeSuccess\n\t * @eventType broadcast on root scope\n\t * @description\n\t * Broadcasted after a URL was changed.\n\t *\n\t * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when\n\t * the browser supports the HTML5 History API.\n\t *\n\t * @param {Object} angularEvent Synthetic event object.\n\t * @param {string} newUrl New URL\n\t * @param {string=} oldUrl URL that was before it was changed.\n\t * @param {string=} newState New history state object\n\t * @param {string=} oldState History state object that was before it was changed.\n\t */\n\t\n\t this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',\n\t function($rootScope, $browser, $sniffer, $rootElement, $window) {\n\t var $location,\n\t LocationMode,\n\t baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''\n\t initialUrl = $browser.url(),\n\t appBase;\n\t\n\t if (html5Mode.enabled) {\n\t if (!baseHref && html5Mode.requireBase) {\n\t throw $locationMinErr('nobase',\n\t \"$location in HTML5 mode requires a tag to be present!\");\n\t }\n\t appBase = serverBase(initialUrl) + (baseHref || '/');\n\t LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;\n\t } else {\n\t appBase = stripHash(initialUrl);\n\t LocationMode = LocationHashbangUrl;\n\t }\n\t var appBaseNoFile = stripFile(appBase);\n\t\n\t $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);\n\t $location.$$parseLinkUrl(initialUrl, initialUrl);\n\t\n\t $location.$$state = $browser.state();\n\t\n\t var IGNORE_URI_REGEXP = /^\\s*(javascript|mailto):/i;\n\t\n\t function setBrowserUrlWithFallback(url, replace, state) {\n\t var oldUrl = $location.url();\n\t var oldState = $location.$$state;\n\t try {\n\t $browser.url(url, replace, state);\n\t\n\t // Make sure $location.state() returns referentially identical (not just deeply equal)\n\t // state object; this makes possible quick checking if the state changed in the digest\n\t // loop. Checking deep equality would be too expensive.\n\t $location.$$state = $browser.state();\n\t } catch (e) {\n\t // Restore old values if pushState fails\n\t $location.url(oldUrl);\n\t $location.$$state = oldState;\n\t\n\t throw e;\n\t }\n\t }\n\t\n\t $rootElement.on('click', function(event) {\n\t // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)\n\t // currently we open nice url link and redirect then\n\t\n\t if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;\n\t\n\t var elm = jqLite(event.target);\n\t\n\t // traverse the DOM up to find first A tag\n\t while (nodeName_(elm[0]) !== 'a') {\n\t // ignore rewriting if no A tag (reached root element, or no parent - removed from document)\n\t if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;\n\t }\n\t\n\t var absHref = elm.prop('href');\n\t // get the actual href attribute - see\n\t // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx\n\t var relHref = elm.attr('href') || elm.attr('xlink:href');\n\t\n\t if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {\n\t // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during\n\t // an animation.\n\t absHref = urlResolve(absHref.animVal).href;\n\t }\n\t\n\t // Ignore when url is started with javascript: or mailto:\n\t if (IGNORE_URI_REGEXP.test(absHref)) return;\n\t\n\t if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {\n\t if ($location.$$parseLinkUrl(absHref, relHref)) {\n\t // We do a preventDefault for all urls that are part of the angular application,\n\t // in html5mode and also without, so that we are able to abort navigation without\n\t // getting double entries in the location history.\n\t event.preventDefault();\n\t // update location manually\n\t if ($location.absUrl() != $browser.url()) {\n\t $rootScope.$apply();\n\t // hack to work around FF6 bug 684208 when scenario runner clicks on links\n\t $window.angular['ff-684208-preventDefault'] = true;\n\t }\n\t }\n\t }\n\t });\n\t\n\t\n\t // rewrite hashbang url <> html5 url\n\t if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {\n\t $browser.url($location.absUrl(), true);\n\t }\n\t\n\t var initializing = true;\n\t\n\t // update $location when $browser url changes\n\t $browser.onUrlChange(function(newUrl, newState) {\n\t\n\t if (isUndefined(stripBaseUrl(appBaseNoFile, newUrl))) {\n\t // If we are navigating outside of the app then force a reload\n\t $window.location.href = newUrl;\n\t return;\n\t }\n\t\n\t $rootScope.$evalAsync(function() {\n\t var oldUrl = $location.absUrl();\n\t var oldState = $location.$$state;\n\t var defaultPrevented;\n\t newUrl = trimEmptyHash(newUrl);\n\t $location.$$parse(newUrl);\n\t $location.$$state = newState;\n\t\n\t defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,\n\t newState, oldState).defaultPrevented;\n\t\n\t // if the location was changed by a `$locationChangeStart` handler then stop\n\t // processing this location change\n\t if ($location.absUrl() !== newUrl) return;\n\t\n\t if (defaultPrevented) {\n\t $location.$$parse(oldUrl);\n\t $location.$$state = oldState;\n\t setBrowserUrlWithFallback(oldUrl, false, oldState);\n\t } else {\n\t initializing = false;\n\t afterLocationChange(oldUrl, oldState);\n\t }\n\t });\n\t if (!$rootScope.$$phase) $rootScope.$digest();\n\t });\n\t\n\t // update browser\n\t $rootScope.$watch(function $locationWatch() {\n\t var oldUrl = trimEmptyHash($browser.url());\n\t var newUrl = trimEmptyHash($location.absUrl());\n\t var oldState = $browser.state();\n\t var currentReplace = $location.$$replace;\n\t var urlOrStateChanged = oldUrl !== newUrl ||\n\t ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);\n\t\n\t if (initializing || urlOrStateChanged) {\n\t initializing = false;\n\t\n\t $rootScope.$evalAsync(function() {\n\t var newUrl = $location.absUrl();\n\t var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,\n\t $location.$$state, oldState).defaultPrevented;\n\t\n\t // if the location was changed by a `$locationChangeStart` handler then stop\n\t // processing this location change\n\t if ($location.absUrl() !== newUrl) return;\n\t\n\t if (defaultPrevented) {\n\t $location.$$parse(oldUrl);\n\t $location.$$state = oldState;\n\t } else {\n\t if (urlOrStateChanged) {\n\t setBrowserUrlWithFallback(newUrl, currentReplace,\n\t oldState === $location.$$state ? null : $location.$$state);\n\t }\n\t afterLocationChange(oldUrl, oldState);\n\t }\n\t });\n\t }\n\t\n\t $location.$$replace = false;\n\t\n\t // we don't need to return anything because $evalAsync will make the digest loop dirty when\n\t // there is a change\n\t });\n\t\n\t return $location;\n\t\n\t function afterLocationChange(oldUrl, oldState) {\n\t $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,\n\t $location.$$state, oldState);\n\t }\n\t}];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $log\n\t * @requires $window\n\t *\n\t * @description\n\t * Simple service for logging. Default implementation safely writes the message\n\t * into the browser's console (if present).\n\t *\n\t * The main purpose of this service is to simplify debugging and troubleshooting.\n\t *\n\t * The default is to log `debug` messages. You can use\n\t * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.\n\t *\n\t * @example\n\t \n\t \n\t angular.module('logExample', [])\n\t .controller('LogController', ['$scope', '$log', function($scope, $log) {\n\t $scope.$log = $log;\n\t $scope.message = 'Hello World!';\n\t }]);\n\t \n\t \n\t
\n\t

Reload this page with open console, enter text and hit the log button...

\n\t \n\t \n\t \n\t \n\t \n\t \n\t
\n\t
\n\t
\n\t */\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $logProvider\n\t * @description\n\t * Use the `$logProvider` to configure how the application logs messages\n\t */\n\tfunction $LogProvider() {\n\t var debug = true,\n\t self = this;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $logProvider#debugEnabled\n\t * @description\n\t * @param {boolean=} flag enable or disable debug level messages\n\t * @returns {*} current value if used as getter or itself (chaining) if used as setter\n\t */\n\t this.debugEnabled = function(flag) {\n\t if (isDefined(flag)) {\n\t debug = flag;\n\t return this;\n\t } else {\n\t return debug;\n\t }\n\t };\n\t\n\t this.$get = ['$window', function($window) {\n\t return {\n\t /**\n\t * @ngdoc method\n\t * @name $log#log\n\t *\n\t * @description\n\t * Write a log message\n\t */\n\t log: consoleLog('log'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $log#info\n\t *\n\t * @description\n\t * Write an information message\n\t */\n\t info: consoleLog('info'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $log#warn\n\t *\n\t * @description\n\t * Write a warning message\n\t */\n\t warn: consoleLog('warn'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $log#error\n\t *\n\t * @description\n\t * Write an error message\n\t */\n\t error: consoleLog('error'),\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $log#debug\n\t *\n\t * @description\n\t * Write a debug message\n\t */\n\t debug: (function() {\n\t var fn = consoleLog('debug');\n\t\n\t return function() {\n\t if (debug) {\n\t fn.apply(self, arguments);\n\t }\n\t };\n\t }())\n\t };\n\t\n\t function formatError(arg) {\n\t if (arg instanceof Error) {\n\t if (arg.stack) {\n\t arg = (arg.message && arg.stack.indexOf(arg.message) === -1)\n\t ? 'Error: ' + arg.message + '\\n' + arg.stack\n\t : arg.stack;\n\t } else if (arg.sourceURL) {\n\t arg = arg.message + '\\n' + arg.sourceURL + ':' + arg.line;\n\t }\n\t }\n\t return arg;\n\t }\n\t\n\t function consoleLog(type) {\n\t var console = $window.console || {},\n\t logFn = console[type] || console.log || noop,\n\t hasApply = false;\n\t\n\t // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.\n\t // The reason behind this is that console.log has type \"object\" in IE8...\n\t try {\n\t hasApply = !!logFn.apply;\n\t } catch (e) {}\n\t\n\t if (hasApply) {\n\t return function() {\n\t var args = [];\n\t forEach(arguments, function(arg) {\n\t args.push(formatError(arg));\n\t });\n\t return logFn.apply(console, args);\n\t };\n\t }\n\t\n\t // we are IE which either doesn't have window.console => this is noop and we do nothing,\n\t // or we are IE where console.log doesn't have apply so we log at least first 2 args\n\t return function(arg1, arg2) {\n\t logFn(arg1, arg2 == null ? '' : arg2);\n\t };\n\t }\n\t }];\n\t}\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Any commits to this file should be reviewed with security in mind. *\n\t * Changes to this file can potentially create security vulnerabilities. *\n\t * An approval from 2 Core members with history of modifying *\n\t * this file is required. *\n\t * *\n\t * Does the change somehow allow for arbitrary javascript to be executed? *\n\t * Or allows for someone to change the prototype of built-in objects? *\n\t * Or gives undesired access to variables likes document or window? *\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\tvar $parseMinErr = minErr('$parse');\n\t\n\t// Sandboxing Angular Expressions\n\t// ------------------------------\n\t// Angular expressions are generally considered safe because these expressions only have direct\n\t// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by\n\t// obtaining a reference to native JS functions such as the Function constructor.\n\t//\n\t// As an example, consider the following Angular expression:\n\t//\n\t// {}.toString.constructor('alert(\"evil JS code\")')\n\t//\n\t// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits\n\t// against the expression language, but not to prevent exploits that were enabled by exposing\n\t// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good\n\t// practice and therefore we are not even trying to protect against interaction with an object\n\t// explicitly exposed in this way.\n\t//\n\t// In general, it is not possible to access a Window object from an angular expression unless a\n\t// window or some DOM object that has a reference to window is published onto a Scope.\n\t// Similarly we prevent invocations of function known to be dangerous, as well as assignments to\n\t// native objects.\n\t//\n\t// See https://docs.angularjs.org/guide/security\n\t\n\t\n\tfunction ensureSafeMemberName(name, fullExpression) {\n\t if (name === \"__defineGetter__\" || name === \"__defineSetter__\"\n\t || name === \"__lookupGetter__\" || name === \"__lookupSetter__\"\n\t || name === \"__proto__\") {\n\t throw $parseMinErr('isecfld',\n\t 'Attempting to access a disallowed field in Angular expressions! '\n\t + 'Expression: {0}', fullExpression);\n\t }\n\t return name;\n\t}\n\t\n\tfunction getStringValue(name) {\n\t // Property names must be strings. This means that non-string objects cannot be used\n\t // as keys in an object. Any non-string object, including a number, is typecasted\n\t // into a string via the toString method.\n\t // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names\n\t //\n\t // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it\n\t // to a string. It's not always possible. If `name` is an object and its `toString` method is\n\t // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:\n\t //\n\t // TypeError: Cannot convert object to primitive value\n\t //\n\t // For performance reasons, we don't catch this error here and allow it to propagate up the call\n\t // stack. Note that you'll get the same error in JavaScript if you try to access a property using\n\t // such a 'broken' object as a key.\n\t return name + '';\n\t}\n\t\n\tfunction ensureSafeObject(obj, fullExpression) {\n\t // nifty check if obj is Function that is fast and works across iframes and other contexts\n\t if (obj) {\n\t if (obj.constructor === obj) {\n\t throw $parseMinErr('isecfn',\n\t 'Referencing Function in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t } else if (// isWindow(obj)\n\t obj.window === obj) {\n\t throw $parseMinErr('isecwindow',\n\t 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t } else if (// isElement(obj)\n\t obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {\n\t throw $parseMinErr('isecdom',\n\t 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t } else if (// block Object so that we can't get hold of dangerous Object.* methods\n\t obj === Object) {\n\t throw $parseMinErr('isecobj',\n\t 'Referencing Object in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t }\n\t }\n\t return obj;\n\t}\n\t\n\tvar CALL = Function.prototype.call;\n\tvar APPLY = Function.prototype.apply;\n\tvar BIND = Function.prototype.bind;\n\t\n\tfunction ensureSafeFunction(obj, fullExpression) {\n\t if (obj) {\n\t if (obj.constructor === obj) {\n\t throw $parseMinErr('isecfn',\n\t 'Referencing Function in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t } else if (obj === CALL || obj === APPLY || obj === BIND) {\n\t throw $parseMinErr('isecff',\n\t 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',\n\t fullExpression);\n\t }\n\t }\n\t}\n\t\n\tfunction ensureSafeAssignContext(obj, fullExpression) {\n\t if (obj) {\n\t if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||\n\t obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {\n\t throw $parseMinErr('isecaf',\n\t 'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);\n\t }\n\t }\n\t}\n\t\n\tvar OPERATORS = createMap();\n\tforEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });\n\tvar ESCAPE = {\"n\":\"\\n\", \"f\":\"\\f\", \"r\":\"\\r\", \"t\":\"\\t\", \"v\":\"\\v\", \"'\":\"'\", '\"':'\"'};\n\t\n\t\n\t/////////////////////////////////////////\n\t\n\t\n\t/**\n\t * @constructor\n\t */\n\tvar Lexer = function(options) {\n\t this.options = options;\n\t};\n\t\n\tLexer.prototype = {\n\t constructor: Lexer,\n\t\n\t lex: function(text) {\n\t this.text = text;\n\t this.index = 0;\n\t this.tokens = [];\n\t\n\t while (this.index < this.text.length) {\n\t var ch = this.text.charAt(this.index);\n\t if (ch === '\"' || ch === \"'\") {\n\t this.readString(ch);\n\t } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {\n\t this.readNumber();\n\t } else if (this.isIdentifierStart(this.peekMultichar())) {\n\t this.readIdent();\n\t } else if (this.is(ch, '(){}[].,;:?')) {\n\t this.tokens.push({index: this.index, text: ch});\n\t this.index++;\n\t } else if (this.isWhitespace(ch)) {\n\t this.index++;\n\t } else {\n\t var ch2 = ch + this.peek();\n\t var ch3 = ch2 + this.peek(2);\n\t var op1 = OPERATORS[ch];\n\t var op2 = OPERATORS[ch2];\n\t var op3 = OPERATORS[ch3];\n\t if (op1 || op2 || op3) {\n\t var token = op3 ? ch3 : (op2 ? ch2 : ch);\n\t this.tokens.push({index: this.index, text: token, operator: true});\n\t this.index += token.length;\n\t } else {\n\t this.throwError('Unexpected next character ', this.index, this.index + 1);\n\t }\n\t }\n\t }\n\t return this.tokens;\n\t },\n\t\n\t is: function(ch, chars) {\n\t return chars.indexOf(ch) !== -1;\n\t },\n\t\n\t peek: function(i) {\n\t var num = i || 1;\n\t return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;\n\t },\n\t\n\t isNumber: function(ch) {\n\t return ('0' <= ch && ch <= '9') && typeof ch === \"string\";\n\t },\n\t\n\t isWhitespace: function(ch) {\n\t // IE treats non-breaking space as \\u00A0\n\t return (ch === ' ' || ch === '\\r' || ch === '\\t' ||\n\t ch === '\\n' || ch === '\\v' || ch === '\\u00A0');\n\t },\n\t\n\t isIdentifierStart: function(ch) {\n\t return this.options.isIdentifierStart ?\n\t this.options.isIdentifierStart(ch, this.codePointAt(ch)) :\n\t this.isValidIdentifierStart(ch);\n\t },\n\t\n\t isValidIdentifierStart: function(ch) {\n\t return ('a' <= ch && ch <= 'z' ||\n\t 'A' <= ch && ch <= 'Z' ||\n\t '_' === ch || ch === '$');\n\t },\n\t\n\t isIdentifierContinue: function(ch) {\n\t return this.options.isIdentifierContinue ?\n\t this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :\n\t this.isValidIdentifierContinue(ch);\n\t },\n\t\n\t isValidIdentifierContinue: function(ch, cp) {\n\t return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);\n\t },\n\t\n\t codePointAt: function(ch) {\n\t if (ch.length === 1) return ch.charCodeAt(0);\n\t /*jshint bitwise: false*/\n\t return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;\n\t /*jshint bitwise: true*/\n\t },\n\t\n\t peekMultichar: function() {\n\t var ch = this.text.charAt(this.index);\n\t var peek = this.peek();\n\t if (!peek) {\n\t return ch;\n\t }\n\t var cp1 = ch.charCodeAt(0);\n\t var cp2 = peek.charCodeAt(0);\n\t if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {\n\t return ch + peek;\n\t }\n\t return ch;\n\t },\n\t\n\t isExpOperator: function(ch) {\n\t return (ch === '-' || ch === '+' || this.isNumber(ch));\n\t },\n\t\n\t throwError: function(error, start, end) {\n\t end = end || this.index;\n\t var colStr = (isDefined(start)\n\t ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']'\n\t : ' ' + end);\n\t throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',\n\t error, colStr, this.text);\n\t },\n\t\n\t readNumber: function() {\n\t var number = '';\n\t var start = this.index;\n\t while (this.index < this.text.length) {\n\t var ch = lowercase(this.text.charAt(this.index));\n\t if (ch == '.' || this.isNumber(ch)) {\n\t number += ch;\n\t } else {\n\t var peekCh = this.peek();\n\t if (ch == 'e' && this.isExpOperator(peekCh)) {\n\t number += ch;\n\t } else if (this.isExpOperator(ch) &&\n\t peekCh && this.isNumber(peekCh) &&\n\t number.charAt(number.length - 1) == 'e') {\n\t number += ch;\n\t } else if (this.isExpOperator(ch) &&\n\t (!peekCh || !this.isNumber(peekCh)) &&\n\t number.charAt(number.length - 1) == 'e') {\n\t this.throwError('Invalid exponent');\n\t } else {\n\t break;\n\t }\n\t }\n\t this.index++;\n\t }\n\t this.tokens.push({\n\t index: start,\n\t text: number,\n\t constant: true,\n\t value: Number(number)\n\t });\n\t },\n\t\n\t readIdent: function() {\n\t var start = this.index;\n\t this.index += this.peekMultichar().length;\n\t while (this.index < this.text.length) {\n\t var ch = this.peekMultichar();\n\t if (!this.isIdentifierContinue(ch)) {\n\t break;\n\t }\n\t this.index += ch.length;\n\t }\n\t this.tokens.push({\n\t index: start,\n\t text: this.text.slice(start, this.index),\n\t identifier: true\n\t });\n\t },\n\t\n\t readString: function(quote) {\n\t var start = this.index;\n\t this.index++;\n\t var string = '';\n\t var rawString = quote;\n\t var escape = false;\n\t while (this.index < this.text.length) {\n\t var ch = this.text.charAt(this.index);\n\t rawString += ch;\n\t if (escape) {\n\t if (ch === 'u') {\n\t var hex = this.text.substring(this.index + 1, this.index + 5);\n\t if (!hex.match(/[\\da-f]{4}/i)) {\n\t this.throwError('Invalid unicode escape [\\\\u' + hex + ']');\n\t }\n\t this.index += 4;\n\t string += String.fromCharCode(parseInt(hex, 16));\n\t } else {\n\t var rep = ESCAPE[ch];\n\t string = string + (rep || ch);\n\t }\n\t escape = false;\n\t } else if (ch === '\\\\') {\n\t escape = true;\n\t } else if (ch === quote) {\n\t this.index++;\n\t this.tokens.push({\n\t index: start,\n\t text: rawString,\n\t constant: true,\n\t value: string\n\t });\n\t return;\n\t } else {\n\t string += ch;\n\t }\n\t this.index++;\n\t }\n\t this.throwError('Unterminated quote', start);\n\t }\n\t};\n\t\n\tvar AST = function(lexer, options) {\n\t this.lexer = lexer;\n\t this.options = options;\n\t};\n\t\n\tAST.Program = 'Program';\n\tAST.ExpressionStatement = 'ExpressionStatement';\n\tAST.AssignmentExpression = 'AssignmentExpression';\n\tAST.ConditionalExpression = 'ConditionalExpression';\n\tAST.LogicalExpression = 'LogicalExpression';\n\tAST.BinaryExpression = 'BinaryExpression';\n\tAST.UnaryExpression = 'UnaryExpression';\n\tAST.CallExpression = 'CallExpression';\n\tAST.MemberExpression = 'MemberExpression';\n\tAST.Identifier = 'Identifier';\n\tAST.Literal = 'Literal';\n\tAST.ArrayExpression = 'ArrayExpression';\n\tAST.Property = 'Property';\n\tAST.ObjectExpression = 'ObjectExpression';\n\tAST.ThisExpression = 'ThisExpression';\n\tAST.LocalsExpression = 'LocalsExpression';\n\t\n\t// Internal use only\n\tAST.NGValueParameter = 'NGValueParameter';\n\t\n\tAST.prototype = {\n\t ast: function(text) {\n\t this.text = text;\n\t this.tokens = this.lexer.lex(text);\n\t\n\t var value = this.program();\n\t\n\t if (this.tokens.length !== 0) {\n\t this.throwError('is an unexpected token', this.tokens[0]);\n\t }\n\t\n\t return value;\n\t },\n\t\n\t program: function() {\n\t var body = [];\n\t while (true) {\n\t if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))\n\t body.push(this.expressionStatement());\n\t if (!this.expect(';')) {\n\t return { type: AST.Program, body: body};\n\t }\n\t }\n\t },\n\t\n\t expressionStatement: function() {\n\t return { type: AST.ExpressionStatement, expression: this.filterChain() };\n\t },\n\t\n\t filterChain: function() {\n\t var left = this.expression();\n\t var token;\n\t while ((token = this.expect('|'))) {\n\t left = this.filter(left);\n\t }\n\t return left;\n\t },\n\t\n\t expression: function() {\n\t return this.assignment();\n\t },\n\t\n\t assignment: function() {\n\t var result = this.ternary();\n\t if (this.expect('=')) {\n\t result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};\n\t }\n\t return result;\n\t },\n\t\n\t ternary: function() {\n\t var test = this.logicalOR();\n\t var alternate;\n\t var consequent;\n\t if (this.expect('?')) {\n\t alternate = this.expression();\n\t if (this.consume(':')) {\n\t consequent = this.expression();\n\t return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};\n\t }\n\t }\n\t return test;\n\t },\n\t\n\t logicalOR: function() {\n\t var left = this.logicalAND();\n\t while (this.expect('||')) {\n\t left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };\n\t }\n\t return left;\n\t },\n\t\n\t logicalAND: function() {\n\t var left = this.equality();\n\t while (this.expect('&&')) {\n\t left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};\n\t }\n\t return left;\n\t },\n\t\n\t equality: function() {\n\t var left = this.relational();\n\t var token;\n\t while ((token = this.expect('==','!=','===','!=='))) {\n\t left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };\n\t }\n\t return left;\n\t },\n\t\n\t relational: function() {\n\t var left = this.additive();\n\t var token;\n\t while ((token = this.expect('<', '>', '<=', '>='))) {\n\t left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };\n\t }\n\t return left;\n\t },\n\t\n\t additive: function() {\n\t var left = this.multiplicative();\n\t var token;\n\t while ((token = this.expect('+','-'))) {\n\t left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };\n\t }\n\t return left;\n\t },\n\t\n\t multiplicative: function() {\n\t var left = this.unary();\n\t var token;\n\t while ((token = this.expect('*','/','%'))) {\n\t left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };\n\t }\n\t return left;\n\t },\n\t\n\t unary: function() {\n\t var token;\n\t if ((token = this.expect('+', '-', '!'))) {\n\t return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };\n\t } else {\n\t return this.primary();\n\t }\n\t },\n\t\n\t primary: function() {\n\t var primary;\n\t if (this.expect('(')) {\n\t primary = this.filterChain();\n\t this.consume(')');\n\t } else if (this.expect('[')) {\n\t primary = this.arrayDeclaration();\n\t } else if (this.expect('{')) {\n\t primary = this.object();\n\t } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {\n\t primary = copy(this.selfReferential[this.consume().text]);\n\t } else if (this.options.literals.hasOwnProperty(this.peek().text)) {\n\t primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};\n\t } else if (this.peek().identifier) {\n\t primary = this.identifier();\n\t } else if (this.peek().constant) {\n\t primary = this.constant();\n\t } else {\n\t this.throwError('not a primary expression', this.peek());\n\t }\n\t\n\t var next;\n\t while ((next = this.expect('(', '[', '.'))) {\n\t if (next.text === '(') {\n\t primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };\n\t this.consume(')');\n\t } else if (next.text === '[') {\n\t primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };\n\t this.consume(']');\n\t } else if (next.text === '.') {\n\t primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };\n\t } else {\n\t this.throwError('IMPOSSIBLE');\n\t }\n\t }\n\t return primary;\n\t },\n\t\n\t filter: function(baseExpression) {\n\t var args = [baseExpression];\n\t var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};\n\t\n\t while (this.expect(':')) {\n\t args.push(this.expression());\n\t }\n\t\n\t return result;\n\t },\n\t\n\t parseArguments: function() {\n\t var args = [];\n\t if (this.peekToken().text !== ')') {\n\t do {\n\t args.push(this.filterChain());\n\t } while (this.expect(','));\n\t }\n\t return args;\n\t },\n\t\n\t identifier: function() {\n\t var token = this.consume();\n\t if (!token.identifier) {\n\t this.throwError('is not a valid identifier', token);\n\t }\n\t return { type: AST.Identifier, name: token.text };\n\t },\n\t\n\t constant: function() {\n\t // TODO check that it is a constant\n\t return { type: AST.Literal, value: this.consume().value };\n\t },\n\t\n\t arrayDeclaration: function() {\n\t var elements = [];\n\t if (this.peekToken().text !== ']') {\n\t do {\n\t if (this.peek(']')) {\n\t // Support trailing commas per ES5.1.\n\t break;\n\t }\n\t elements.push(this.expression());\n\t } while (this.expect(','));\n\t }\n\t this.consume(']');\n\t\n\t return { type: AST.ArrayExpression, elements: elements };\n\t },\n\t\n\t object: function() {\n\t var properties = [], property;\n\t if (this.peekToken().text !== '}') {\n\t do {\n\t if (this.peek('}')) {\n\t // Support trailing commas per ES5.1.\n\t break;\n\t }\n\t property = {type: AST.Property, kind: 'init'};\n\t if (this.peek().constant) {\n\t property.key = this.constant();\n\t property.computed = false;\n\t this.consume(':');\n\t property.value = this.expression();\n\t } else if (this.peek().identifier) {\n\t property.key = this.identifier();\n\t property.computed = false;\n\t if (this.peek(':')) {\n\t this.consume(':');\n\t property.value = this.expression();\n\t } else {\n\t property.value = property.key;\n\t }\n\t } else if (this.peek('[')) {\n\t this.consume('[');\n\t property.key = this.expression();\n\t this.consume(']');\n\t property.computed = true;\n\t this.consume(':');\n\t property.value = this.expression();\n\t } else {\n\t this.throwError(\"invalid key\", this.peek());\n\t }\n\t properties.push(property);\n\t } while (this.expect(','));\n\t }\n\t this.consume('}');\n\t\n\t return {type: AST.ObjectExpression, properties: properties };\n\t },\n\t\n\t throwError: function(msg, token) {\n\t throw $parseMinErr('syntax',\n\t 'Syntax Error: Token \\'{0}\\' {1} at column {2} of the expression [{3}] starting at [{4}].',\n\t token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));\n\t },\n\t\n\t consume: function(e1) {\n\t if (this.tokens.length === 0) {\n\t throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);\n\t }\n\t\n\t var token = this.expect(e1);\n\t if (!token) {\n\t this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());\n\t }\n\t return token;\n\t },\n\t\n\t peekToken: function() {\n\t if (this.tokens.length === 0) {\n\t throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);\n\t }\n\t return this.tokens[0];\n\t },\n\t\n\t peek: function(e1, e2, e3, e4) {\n\t return this.peekAhead(0, e1, e2, e3, e4);\n\t },\n\t\n\t peekAhead: function(i, e1, e2, e3, e4) {\n\t if (this.tokens.length > i) {\n\t var token = this.tokens[i];\n\t var t = token.text;\n\t if (t === e1 || t === e2 || t === e3 || t === e4 ||\n\t (!e1 && !e2 && !e3 && !e4)) {\n\t return token;\n\t }\n\t }\n\t return false;\n\t },\n\t\n\t expect: function(e1, e2, e3, e4) {\n\t var token = this.peek(e1, e2, e3, e4);\n\t if (token) {\n\t this.tokens.shift();\n\t return token;\n\t }\n\t return false;\n\t },\n\t\n\t selfReferential: {\n\t 'this': {type: AST.ThisExpression },\n\t '$locals': {type: AST.LocalsExpression }\n\t }\n\t};\n\t\n\tfunction ifDefined(v, d) {\n\t return typeof v !== 'undefined' ? v : d;\n\t}\n\t\n\tfunction plusFn(l, r) {\n\t if (typeof l === 'undefined') return r;\n\t if (typeof r === 'undefined') return l;\n\t return l + r;\n\t}\n\t\n\tfunction isStateless($filter, filterName) {\n\t var fn = $filter(filterName);\n\t return !fn.$stateful;\n\t}\n\t\n\tfunction findConstantAndWatchExpressions(ast, $filter) {\n\t var allConstants;\n\t var argsToWatch;\n\t switch (ast.type) {\n\t case AST.Program:\n\t allConstants = true;\n\t forEach(ast.body, function(expr) {\n\t findConstantAndWatchExpressions(expr.expression, $filter);\n\t allConstants = allConstants && expr.expression.constant;\n\t });\n\t ast.constant = allConstants;\n\t break;\n\t case AST.Literal:\n\t ast.constant = true;\n\t ast.toWatch = [];\n\t break;\n\t case AST.UnaryExpression:\n\t findConstantAndWatchExpressions(ast.argument, $filter);\n\t ast.constant = ast.argument.constant;\n\t ast.toWatch = ast.argument.toWatch;\n\t break;\n\t case AST.BinaryExpression:\n\t findConstantAndWatchExpressions(ast.left, $filter);\n\t findConstantAndWatchExpressions(ast.right, $filter);\n\t ast.constant = ast.left.constant && ast.right.constant;\n\t ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);\n\t break;\n\t case AST.LogicalExpression:\n\t findConstantAndWatchExpressions(ast.left, $filter);\n\t findConstantAndWatchExpressions(ast.right, $filter);\n\t ast.constant = ast.left.constant && ast.right.constant;\n\t ast.toWatch = ast.constant ? [] : [ast];\n\t break;\n\t case AST.ConditionalExpression:\n\t findConstantAndWatchExpressions(ast.test, $filter);\n\t findConstantAndWatchExpressions(ast.alternate, $filter);\n\t findConstantAndWatchExpressions(ast.consequent, $filter);\n\t ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;\n\t ast.toWatch = ast.constant ? [] : [ast];\n\t break;\n\t case AST.Identifier:\n\t ast.constant = false;\n\t ast.toWatch = [ast];\n\t break;\n\t case AST.MemberExpression:\n\t findConstantAndWatchExpressions(ast.object, $filter);\n\t if (ast.computed) {\n\t findConstantAndWatchExpressions(ast.property, $filter);\n\t }\n\t ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);\n\t ast.toWatch = [ast];\n\t break;\n\t case AST.CallExpression:\n\t allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;\n\t argsToWatch = [];\n\t forEach(ast.arguments, function(expr) {\n\t findConstantAndWatchExpressions(expr, $filter);\n\t allConstants = allConstants && expr.constant;\n\t if (!expr.constant) {\n\t argsToWatch.push.apply(argsToWatch, expr.toWatch);\n\t }\n\t });\n\t ast.constant = allConstants;\n\t ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];\n\t break;\n\t case AST.AssignmentExpression:\n\t findConstantAndWatchExpressions(ast.left, $filter);\n\t findConstantAndWatchExpressions(ast.right, $filter);\n\t ast.constant = ast.left.constant && ast.right.constant;\n\t ast.toWatch = [ast];\n\t break;\n\t case AST.ArrayExpression:\n\t allConstants = true;\n\t argsToWatch = [];\n\t forEach(ast.elements, function(expr) {\n\t findConstantAndWatchExpressions(expr, $filter);\n\t allConstants = allConstants && expr.constant;\n\t if (!expr.constant) {\n\t argsToWatch.push.apply(argsToWatch, expr.toWatch);\n\t }\n\t });\n\t ast.constant = allConstants;\n\t ast.toWatch = argsToWatch;\n\t break;\n\t case AST.ObjectExpression:\n\t allConstants = true;\n\t argsToWatch = [];\n\t forEach(ast.properties, function(property) {\n\t findConstantAndWatchExpressions(property.value, $filter);\n\t allConstants = allConstants && property.value.constant && !property.computed;\n\t if (!property.value.constant) {\n\t argsToWatch.push.apply(argsToWatch, property.value.toWatch);\n\t }\n\t });\n\t ast.constant = allConstants;\n\t ast.toWatch = argsToWatch;\n\t break;\n\t case AST.ThisExpression:\n\t ast.constant = false;\n\t ast.toWatch = [];\n\t break;\n\t case AST.LocalsExpression:\n\t ast.constant = false;\n\t ast.toWatch = [];\n\t break;\n\t }\n\t}\n\t\n\tfunction getInputs(body) {\n\t if (body.length != 1) return;\n\t var lastExpression = body[0].expression;\n\t var candidate = lastExpression.toWatch;\n\t if (candidate.length !== 1) return candidate;\n\t return candidate[0] !== lastExpression ? candidate : undefined;\n\t}\n\t\n\tfunction isAssignable(ast) {\n\t return ast.type === AST.Identifier || ast.type === AST.MemberExpression;\n\t}\n\t\n\tfunction assignableAST(ast) {\n\t if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {\n\t return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};\n\t }\n\t}\n\t\n\tfunction isLiteral(ast) {\n\t return ast.body.length === 0 ||\n\t ast.body.length === 1 && (\n\t ast.body[0].expression.type === AST.Literal ||\n\t ast.body[0].expression.type === AST.ArrayExpression ||\n\t ast.body[0].expression.type === AST.ObjectExpression);\n\t}\n\t\n\tfunction isConstant(ast) {\n\t return ast.constant;\n\t}\n\t\n\tfunction ASTCompiler(astBuilder, $filter) {\n\t this.astBuilder = astBuilder;\n\t this.$filter = $filter;\n\t}\n\t\n\tASTCompiler.prototype = {\n\t compile: function(expression, expensiveChecks) {\n\t var self = this;\n\t var ast = this.astBuilder.ast(expression);\n\t this.state = {\n\t nextId: 0,\n\t filters: {},\n\t expensiveChecks: expensiveChecks,\n\t fn: {vars: [], body: [], own: {}},\n\t assign: {vars: [], body: [], own: {}},\n\t inputs: []\n\t };\n\t findConstantAndWatchExpressions(ast, self.$filter);\n\t var extra = '';\n\t var assignable;\n\t this.stage = 'assign';\n\t if ((assignable = assignableAST(ast))) {\n\t this.state.computing = 'assign';\n\t var result = this.nextId();\n\t this.recurse(assignable, result);\n\t this.return_(result);\n\t extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');\n\t }\n\t var toWatch = getInputs(ast.body);\n\t self.stage = 'inputs';\n\t forEach(toWatch, function(watch, key) {\n\t var fnKey = 'fn' + key;\n\t self.state[fnKey] = {vars: [], body: [], own: {}};\n\t self.state.computing = fnKey;\n\t var intoId = self.nextId();\n\t self.recurse(watch, intoId);\n\t self.return_(intoId);\n\t self.state.inputs.push(fnKey);\n\t watch.watchId = key;\n\t });\n\t this.state.computing = 'fn';\n\t this.stage = 'main';\n\t this.recurse(ast);\n\t var fnString =\n\t // The build and minification steps remove the string \"use strict\" from the code, but this is done using a regex.\n\t // This is a workaround for this until we do a better job at only removing the prefix only when we should.\n\t '\"' + this.USE + ' ' + this.STRICT + '\";\\n' +\n\t this.filterPrefix() +\n\t 'var fn=' + this.generateFunction('fn', 's,l,a,i') +\n\t extra +\n\t this.watchFns() +\n\t 'return fn;';\n\t\n\t /* jshint -W054 */\n\t var fn = (new Function('$filter',\n\t 'ensureSafeMemberName',\n\t 'ensureSafeObject',\n\t 'ensureSafeFunction',\n\t 'getStringValue',\n\t 'ensureSafeAssignContext',\n\t 'ifDefined',\n\t 'plus',\n\t 'text',\n\t fnString))(\n\t this.$filter,\n\t ensureSafeMemberName,\n\t ensureSafeObject,\n\t ensureSafeFunction,\n\t getStringValue,\n\t ensureSafeAssignContext,\n\t ifDefined,\n\t plusFn,\n\t expression);\n\t /* jshint +W054 */\n\t this.state = this.stage = undefined;\n\t fn.literal = isLiteral(ast);\n\t fn.constant = isConstant(ast);\n\t return fn;\n\t },\n\t\n\t USE: 'use',\n\t\n\t STRICT: 'strict',\n\t\n\t watchFns: function() {\n\t var result = [];\n\t var fns = this.state.inputs;\n\t var self = this;\n\t forEach(fns, function(name) {\n\t result.push('var ' + name + '=' + self.generateFunction(name, 's'));\n\t });\n\t if (fns.length) {\n\t result.push('fn.inputs=[' + fns.join(',') + '];');\n\t }\n\t return result.join('');\n\t },\n\t\n\t generateFunction: function(name, params) {\n\t return 'function(' + params + '){' +\n\t this.varsPrefix(name) +\n\t this.body(name) +\n\t '};';\n\t },\n\t\n\t filterPrefix: function() {\n\t var parts = [];\n\t var self = this;\n\t forEach(this.state.filters, function(id, filter) {\n\t parts.push(id + '=$filter(' + self.escape(filter) + ')');\n\t });\n\t if (parts.length) return 'var ' + parts.join(',') + ';';\n\t return '';\n\t },\n\t\n\t varsPrefix: function(section) {\n\t return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';\n\t },\n\t\n\t body: function(section) {\n\t return this.state[section].body.join('');\n\t },\n\t\n\t recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {\n\t var left, right, self = this, args, expression, computed;\n\t recursionFn = recursionFn || noop;\n\t if (!skipWatchIdCheck && isDefined(ast.watchId)) {\n\t intoId = intoId || this.nextId();\n\t this.if_('i',\n\t this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),\n\t this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)\n\t );\n\t return;\n\t }\n\t switch (ast.type) {\n\t case AST.Program:\n\t forEach(ast.body, function(expression, pos) {\n\t self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });\n\t if (pos !== ast.body.length - 1) {\n\t self.current().body.push(right, ';');\n\t } else {\n\t self.return_(right);\n\t }\n\t });\n\t break;\n\t case AST.Literal:\n\t expression = this.escape(ast.value);\n\t this.assign(intoId, expression);\n\t recursionFn(expression);\n\t break;\n\t case AST.UnaryExpression:\n\t this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });\n\t expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';\n\t this.assign(intoId, expression);\n\t recursionFn(expression);\n\t break;\n\t case AST.BinaryExpression:\n\t this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });\n\t this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });\n\t if (ast.operator === '+') {\n\t expression = this.plus(left, right);\n\t } else if (ast.operator === '-') {\n\t expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);\n\t } else {\n\t expression = '(' + left + ')' + ast.operator + '(' + right + ')';\n\t }\n\t this.assign(intoId, expression);\n\t recursionFn(expression);\n\t break;\n\t case AST.LogicalExpression:\n\t intoId = intoId || this.nextId();\n\t self.recurse(ast.left, intoId);\n\t self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));\n\t recursionFn(intoId);\n\t break;\n\t case AST.ConditionalExpression:\n\t intoId = intoId || this.nextId();\n\t self.recurse(ast.test, intoId);\n\t self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));\n\t recursionFn(intoId);\n\t break;\n\t case AST.Identifier:\n\t intoId = intoId || this.nextId();\n\t if (nameId) {\n\t nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');\n\t nameId.computed = false;\n\t nameId.name = ast.name;\n\t }\n\t ensureSafeMemberName(ast.name);\n\t self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),\n\t function() {\n\t self.if_(self.stage === 'inputs' || 's', function() {\n\t if (create && create !== 1) {\n\t self.if_(\n\t self.not(self.nonComputedMember('s', ast.name)),\n\t self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));\n\t }\n\t self.assign(intoId, self.nonComputedMember('s', ast.name));\n\t });\n\t }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))\n\t );\n\t if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {\n\t self.addEnsureSafeObject(intoId);\n\t }\n\t recursionFn(intoId);\n\t break;\n\t case AST.MemberExpression:\n\t left = nameId && (nameId.context = this.nextId()) || this.nextId();\n\t intoId = intoId || this.nextId();\n\t self.recurse(ast.object, left, undefined, function() {\n\t self.if_(self.notNull(left), function() {\n\t if (create && create !== 1) {\n\t self.addEnsureSafeAssignContext(left);\n\t }\n\t if (ast.computed) {\n\t right = self.nextId();\n\t self.recurse(ast.property, right);\n\t self.getStringValue(right);\n\t self.addEnsureSafeMemberName(right);\n\t if (create && create !== 1) {\n\t self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));\n\t }\n\t expression = self.ensureSafeObject(self.computedMember(left, right));\n\t self.assign(intoId, expression);\n\t if (nameId) {\n\t nameId.computed = true;\n\t nameId.name = right;\n\t }\n\t } else {\n\t ensureSafeMemberName(ast.property.name);\n\t if (create && create !== 1) {\n\t self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));\n\t }\n\t expression = self.nonComputedMember(left, ast.property.name);\n\t if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {\n\t expression = self.ensureSafeObject(expression);\n\t }\n\t self.assign(intoId, expression);\n\t if (nameId) {\n\t nameId.computed = false;\n\t nameId.name = ast.property.name;\n\t }\n\t }\n\t }, function() {\n\t self.assign(intoId, 'undefined');\n\t });\n\t recursionFn(intoId);\n\t }, !!create);\n\t break;\n\t case AST.CallExpression:\n\t intoId = intoId || this.nextId();\n\t if (ast.filter) {\n\t right = self.filter(ast.callee.name);\n\t args = [];\n\t forEach(ast.arguments, function(expr) {\n\t var argument = self.nextId();\n\t self.recurse(expr, argument);\n\t args.push(argument);\n\t });\n\t expression = right + '(' + args.join(',') + ')';\n\t self.assign(intoId, expression);\n\t recursionFn(intoId);\n\t } else {\n\t right = self.nextId();\n\t left = {};\n\t args = [];\n\t self.recurse(ast.callee, right, left, function() {\n\t self.if_(self.notNull(right), function() {\n\t self.addEnsureSafeFunction(right);\n\t forEach(ast.arguments, function(expr) {\n\t self.recurse(expr, self.nextId(), undefined, function(argument) {\n\t args.push(self.ensureSafeObject(argument));\n\t });\n\t });\n\t if (left.name) {\n\t if (!self.state.expensiveChecks) {\n\t self.addEnsureSafeObject(left.context);\n\t }\n\t expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';\n\t } else {\n\t expression = right + '(' + args.join(',') + ')';\n\t }\n\t expression = self.ensureSafeObject(expression);\n\t self.assign(intoId, expression);\n\t }, function() {\n\t self.assign(intoId, 'undefined');\n\t });\n\t recursionFn(intoId);\n\t });\n\t }\n\t break;\n\t case AST.AssignmentExpression:\n\t right = this.nextId();\n\t left = {};\n\t if (!isAssignable(ast.left)) {\n\t throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');\n\t }\n\t this.recurse(ast.left, undefined, left, function() {\n\t self.if_(self.notNull(left.context), function() {\n\t self.recurse(ast.right, right);\n\t self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));\n\t self.addEnsureSafeAssignContext(left.context);\n\t expression = self.member(left.context, left.name, left.computed) + ast.operator + right;\n\t self.assign(intoId, expression);\n\t recursionFn(intoId || expression);\n\t });\n\t }, 1);\n\t break;\n\t case AST.ArrayExpression:\n\t args = [];\n\t forEach(ast.elements, function(expr) {\n\t self.recurse(expr, self.nextId(), undefined, function(argument) {\n\t args.push(argument);\n\t });\n\t });\n\t expression = '[' + args.join(',') + ']';\n\t this.assign(intoId, expression);\n\t recursionFn(expression);\n\t break;\n\t case AST.ObjectExpression:\n\t args = [];\n\t computed = false;\n\t forEach(ast.properties, function(property) {\n\t if (property.computed) {\n\t computed = true;\n\t }\n\t });\n\t if (computed) {\n\t intoId = intoId || this.nextId();\n\t this.assign(intoId, '{}');\n\t forEach(ast.properties, function(property) {\n\t if (property.computed) {\n\t left = self.nextId();\n\t self.recurse(property.key, left);\n\t } else {\n\t left = property.key.type === AST.Identifier ?\n\t property.key.name :\n\t ('' + property.key.value);\n\t }\n\t right = self.nextId();\n\t self.recurse(property.value, right);\n\t self.assign(self.member(intoId, left, property.computed), right);\n\t });\n\t } else {\n\t forEach(ast.properties, function(property) {\n\t self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) {\n\t args.push(self.escape(\n\t property.key.type === AST.Identifier ? property.key.name :\n\t ('' + property.key.value)) +\n\t ':' + expr);\n\t });\n\t });\n\t expression = '{' + args.join(',') + '}';\n\t this.assign(intoId, expression);\n\t }\n\t recursionFn(intoId || expression);\n\t break;\n\t case AST.ThisExpression:\n\t this.assign(intoId, 's');\n\t recursionFn('s');\n\t break;\n\t case AST.LocalsExpression:\n\t this.assign(intoId, 'l');\n\t recursionFn('l');\n\t break;\n\t case AST.NGValueParameter:\n\t this.assign(intoId, 'v');\n\t recursionFn('v');\n\t break;\n\t }\n\t },\n\t\n\t getHasOwnProperty: function(element, property) {\n\t var key = element + '.' + property;\n\t var own = this.current().own;\n\t if (!own.hasOwnProperty(key)) {\n\t own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');\n\t }\n\t return own[key];\n\t },\n\t\n\t assign: function(id, value) {\n\t if (!id) return;\n\t this.current().body.push(id, '=', value, ';');\n\t return id;\n\t },\n\t\n\t filter: function(filterName) {\n\t if (!this.state.filters.hasOwnProperty(filterName)) {\n\t this.state.filters[filterName] = this.nextId(true);\n\t }\n\t return this.state.filters[filterName];\n\t },\n\t\n\t ifDefined: function(id, defaultValue) {\n\t return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';\n\t },\n\t\n\t plus: function(left, right) {\n\t return 'plus(' + left + ',' + right + ')';\n\t },\n\t\n\t return_: function(id) {\n\t this.current().body.push('return ', id, ';');\n\t },\n\t\n\t if_: function(test, alternate, consequent) {\n\t if (test === true) {\n\t alternate();\n\t } else {\n\t var body = this.current().body;\n\t body.push('if(', test, '){');\n\t alternate();\n\t body.push('}');\n\t if (consequent) {\n\t body.push('else{');\n\t consequent();\n\t body.push('}');\n\t }\n\t }\n\t },\n\t\n\t not: function(expression) {\n\t return '!(' + expression + ')';\n\t },\n\t\n\t notNull: function(expression) {\n\t return expression + '!=null';\n\t },\n\t\n\t nonComputedMember: function(left, right) {\n\t var SAFE_IDENTIFIER = /[$_a-zA-Z][$_a-zA-Z0-9]*/;\n\t var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;\n\t if (SAFE_IDENTIFIER.test(right)) {\n\t return left + '.' + right;\n\t } else {\n\t return left + '[\"' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '\"]';\n\t }\n\t },\n\t\n\t computedMember: function(left, right) {\n\t return left + '[' + right + ']';\n\t },\n\t\n\t member: function(left, right, computed) {\n\t if (computed) return this.computedMember(left, right);\n\t return this.nonComputedMember(left, right);\n\t },\n\t\n\t addEnsureSafeObject: function(item) {\n\t this.current().body.push(this.ensureSafeObject(item), ';');\n\t },\n\t\n\t addEnsureSafeMemberName: function(item) {\n\t this.current().body.push(this.ensureSafeMemberName(item), ';');\n\t },\n\t\n\t addEnsureSafeFunction: function(item) {\n\t this.current().body.push(this.ensureSafeFunction(item), ';');\n\t },\n\t\n\t addEnsureSafeAssignContext: function(item) {\n\t this.current().body.push(this.ensureSafeAssignContext(item), ';');\n\t },\n\t\n\t ensureSafeObject: function(item) {\n\t return 'ensureSafeObject(' + item + ',text)';\n\t },\n\t\n\t ensureSafeMemberName: function(item) {\n\t return 'ensureSafeMemberName(' + item + ',text)';\n\t },\n\t\n\t ensureSafeFunction: function(item) {\n\t return 'ensureSafeFunction(' + item + ',text)';\n\t },\n\t\n\t getStringValue: function(item) {\n\t this.assign(item, 'getStringValue(' + item + ')');\n\t },\n\t\n\t ensureSafeAssignContext: function(item) {\n\t return 'ensureSafeAssignContext(' + item + ',text)';\n\t },\n\t\n\t lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {\n\t var self = this;\n\t return function() {\n\t self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);\n\t };\n\t },\n\t\n\t lazyAssign: function(id, value) {\n\t var self = this;\n\t return function() {\n\t self.assign(id, value);\n\t };\n\t },\n\t\n\t stringEscapeRegex: /[^ a-zA-Z0-9]/g,\n\t\n\t stringEscapeFn: function(c) {\n\t return '\\\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);\n\t },\n\t\n\t escape: function(value) {\n\t if (isString(value)) return \"'\" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + \"'\";\n\t if (isNumber(value)) return value.toString();\n\t if (value === true) return 'true';\n\t if (value === false) return 'false';\n\t if (value === null) return 'null';\n\t if (typeof value === 'undefined') return 'undefined';\n\t\n\t throw $parseMinErr('esc', 'IMPOSSIBLE');\n\t },\n\t\n\t nextId: function(skip, init) {\n\t var id = 'v' + (this.state.nextId++);\n\t if (!skip) {\n\t this.current().vars.push(id + (init ? '=' + init : ''));\n\t }\n\t return id;\n\t },\n\t\n\t current: function() {\n\t return this.state[this.state.computing];\n\t }\n\t};\n\t\n\t\n\tfunction ASTInterpreter(astBuilder, $filter) {\n\t this.astBuilder = astBuilder;\n\t this.$filter = $filter;\n\t}\n\t\n\tASTInterpreter.prototype = {\n\t compile: function(expression, expensiveChecks) {\n\t var self = this;\n\t var ast = this.astBuilder.ast(expression);\n\t this.expression = expression;\n\t this.expensiveChecks = expensiveChecks;\n\t findConstantAndWatchExpressions(ast, self.$filter);\n\t var assignable;\n\t var assign;\n\t if ((assignable = assignableAST(ast))) {\n\t assign = this.recurse(assignable);\n\t }\n\t var toWatch = getInputs(ast.body);\n\t var inputs;\n\t if (toWatch) {\n\t inputs = [];\n\t forEach(toWatch, function(watch, key) {\n\t var input = self.recurse(watch);\n\t watch.input = input;\n\t inputs.push(input);\n\t watch.watchId = key;\n\t });\n\t }\n\t var expressions = [];\n\t forEach(ast.body, function(expression) {\n\t expressions.push(self.recurse(expression.expression));\n\t });\n\t var fn = ast.body.length === 0 ? noop :\n\t ast.body.length === 1 ? expressions[0] :\n\t function(scope, locals) {\n\t var lastValue;\n\t forEach(expressions, function(exp) {\n\t lastValue = exp(scope, locals);\n\t });\n\t return lastValue;\n\t };\n\t if (assign) {\n\t fn.assign = function(scope, value, locals) {\n\t return assign(scope, locals, value);\n\t };\n\t }\n\t if (inputs) {\n\t fn.inputs = inputs;\n\t }\n\t fn.literal = isLiteral(ast);\n\t fn.constant = isConstant(ast);\n\t return fn;\n\t },\n\t\n\t recurse: function(ast, context, create) {\n\t var left, right, self = this, args, expression;\n\t if (ast.input) {\n\t return this.inputs(ast.input, ast.watchId);\n\t }\n\t switch (ast.type) {\n\t case AST.Literal:\n\t return this.value(ast.value, context);\n\t case AST.UnaryExpression:\n\t right = this.recurse(ast.argument);\n\t return this['unary' + ast.operator](right, context);\n\t case AST.BinaryExpression:\n\t left = this.recurse(ast.left);\n\t right = this.recurse(ast.right);\n\t return this['binary' + ast.operator](left, right, context);\n\t case AST.LogicalExpression:\n\t left = this.recurse(ast.left);\n\t right = this.recurse(ast.right);\n\t return this['binary' + ast.operator](left, right, context);\n\t case AST.ConditionalExpression:\n\t return this['ternary?:'](\n\t this.recurse(ast.test),\n\t this.recurse(ast.alternate),\n\t this.recurse(ast.consequent),\n\t context\n\t );\n\t case AST.Identifier:\n\t ensureSafeMemberName(ast.name, self.expression);\n\t return self.identifier(ast.name,\n\t self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),\n\t context, create, self.expression);\n\t case AST.MemberExpression:\n\t left = this.recurse(ast.object, false, !!create);\n\t if (!ast.computed) {\n\t ensureSafeMemberName(ast.property.name, self.expression);\n\t right = ast.property.name;\n\t }\n\t if (ast.computed) right = this.recurse(ast.property);\n\t return ast.computed ?\n\t this.computedMember(left, right, context, create, self.expression) :\n\t this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);\n\t case AST.CallExpression:\n\t args = [];\n\t forEach(ast.arguments, function(expr) {\n\t args.push(self.recurse(expr));\n\t });\n\t if (ast.filter) right = this.$filter(ast.callee.name);\n\t if (!ast.filter) right = this.recurse(ast.callee, true);\n\t return ast.filter ?\n\t function(scope, locals, assign, inputs) {\n\t var values = [];\n\t for (var i = 0; i < args.length; ++i) {\n\t values.push(args[i](scope, locals, assign, inputs));\n\t }\n\t var value = right.apply(undefined, values, inputs);\n\t return context ? {context: undefined, name: undefined, value: value} : value;\n\t } :\n\t function(scope, locals, assign, inputs) {\n\t var rhs = right(scope, locals, assign, inputs);\n\t var value;\n\t if (rhs.value != null) {\n\t ensureSafeObject(rhs.context, self.expression);\n\t ensureSafeFunction(rhs.value, self.expression);\n\t var values = [];\n\t for (var i = 0; i < args.length; ++i) {\n\t values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));\n\t }\n\t value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);\n\t }\n\t return context ? {value: value} : value;\n\t };\n\t case AST.AssignmentExpression:\n\t left = this.recurse(ast.left, true, 1);\n\t right = this.recurse(ast.right);\n\t return function(scope, locals, assign, inputs) {\n\t var lhs = left(scope, locals, assign, inputs);\n\t var rhs = right(scope, locals, assign, inputs);\n\t ensureSafeObject(lhs.value, self.expression);\n\t ensureSafeAssignContext(lhs.context);\n\t lhs.context[lhs.name] = rhs;\n\t return context ? {value: rhs} : rhs;\n\t };\n\t case AST.ArrayExpression:\n\t args = [];\n\t forEach(ast.elements, function(expr) {\n\t args.push(self.recurse(expr));\n\t });\n\t return function(scope, locals, assign, inputs) {\n\t var value = [];\n\t for (var i = 0; i < args.length; ++i) {\n\t value.push(args[i](scope, locals, assign, inputs));\n\t }\n\t return context ? {value: value} : value;\n\t };\n\t case AST.ObjectExpression:\n\t args = [];\n\t forEach(ast.properties, function(property) {\n\t if (property.computed) {\n\t args.push({key: self.recurse(property.key),\n\t computed: true,\n\t value: self.recurse(property.value)\n\t });\n\t } else {\n\t args.push({key: property.key.type === AST.Identifier ?\n\t property.key.name :\n\t ('' + property.key.value),\n\t computed: false,\n\t value: self.recurse(property.value)\n\t });\n\t }\n\t });\n\t return function(scope, locals, assign, inputs) {\n\t var value = {};\n\t for (var i = 0; i < args.length; ++i) {\n\t if (args[i].computed) {\n\t value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs);\n\t } else {\n\t value[args[i].key] = args[i].value(scope, locals, assign, inputs);\n\t }\n\t }\n\t return context ? {value: value} : value;\n\t };\n\t case AST.ThisExpression:\n\t return function(scope) {\n\t return context ? {value: scope} : scope;\n\t };\n\t case AST.LocalsExpression:\n\t return function(scope, locals) {\n\t return context ? {value: locals} : locals;\n\t };\n\t case AST.NGValueParameter:\n\t return function(scope, locals, assign) {\n\t return context ? {value: assign} : assign;\n\t };\n\t }\n\t },\n\t\n\t 'unary+': function(argument, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = argument(scope, locals, assign, inputs);\n\t if (isDefined(arg)) {\n\t arg = +arg;\n\t } else {\n\t arg = 0;\n\t }\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'unary-': function(argument, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = argument(scope, locals, assign, inputs);\n\t if (isDefined(arg)) {\n\t arg = -arg;\n\t } else {\n\t arg = 0;\n\t }\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'unary!': function(argument, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = !argument(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary+': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var lhs = left(scope, locals, assign, inputs);\n\t var rhs = right(scope, locals, assign, inputs);\n\t var arg = plusFn(lhs, rhs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary-': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var lhs = left(scope, locals, assign, inputs);\n\t var rhs = right(scope, locals, assign, inputs);\n\t var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary*': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary/': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary%': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary===': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary!==': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary==': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary!=': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary<': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary>': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary<=': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary>=': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary&&': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'binary||': function(left, right, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t 'ternary?:': function(test, alternate, consequent, context) {\n\t return function(scope, locals, assign, inputs) {\n\t var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);\n\t return context ? {value: arg} : arg;\n\t };\n\t },\n\t value: function(value, context) {\n\t return function() { return context ? {context: undefined, name: undefined, value: value} : value; };\n\t },\n\t identifier: function(name, expensiveChecks, context, create, expression) {\n\t return function(scope, locals, assign, inputs) {\n\t var base = locals && (name in locals) ? locals : scope;\n\t if (create && create !== 1 && base && !(base[name])) {\n\t base[name] = {};\n\t }\n\t var value = base ? base[name] : undefined;\n\t if (expensiveChecks) {\n\t ensureSafeObject(value, expression);\n\t }\n\t if (context) {\n\t return {context: base, name: name, value: value};\n\t } else {\n\t return value;\n\t }\n\t };\n\t },\n\t computedMember: function(left, right, context, create, expression) {\n\t return function(scope, locals, assign, inputs) {\n\t var lhs = left(scope, locals, assign, inputs);\n\t var rhs;\n\t var value;\n\t if (lhs != null) {\n\t rhs = right(scope, locals, assign, inputs);\n\t rhs = getStringValue(rhs);\n\t ensureSafeMemberName(rhs, expression);\n\t if (create && create !== 1) {\n\t ensureSafeAssignContext(lhs);\n\t if (lhs && !(lhs[rhs])) {\n\t lhs[rhs] = {};\n\t }\n\t }\n\t value = lhs[rhs];\n\t ensureSafeObject(value, expression);\n\t }\n\t if (context) {\n\t return {context: lhs, name: rhs, value: value};\n\t } else {\n\t return value;\n\t }\n\t };\n\t },\n\t nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {\n\t return function(scope, locals, assign, inputs) {\n\t var lhs = left(scope, locals, assign, inputs);\n\t if (create && create !== 1) {\n\t ensureSafeAssignContext(lhs);\n\t if (lhs && !(lhs[right])) {\n\t lhs[right] = {};\n\t }\n\t }\n\t var value = lhs != null ? lhs[right] : undefined;\n\t if (expensiveChecks || isPossiblyDangerousMemberName(right)) {\n\t ensureSafeObject(value, expression);\n\t }\n\t if (context) {\n\t return {context: lhs, name: right, value: value};\n\t } else {\n\t return value;\n\t }\n\t };\n\t },\n\t inputs: function(input, watchId) {\n\t return function(scope, value, locals, inputs) {\n\t if (inputs) return inputs[watchId];\n\t return input(scope, value, locals);\n\t };\n\t }\n\t};\n\t\n\t/**\n\t * @constructor\n\t */\n\tvar Parser = function(lexer, $filter, options) {\n\t this.lexer = lexer;\n\t this.$filter = $filter;\n\t this.options = options;\n\t this.ast = new AST(lexer, options);\n\t this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :\n\t new ASTCompiler(this.ast, $filter);\n\t};\n\t\n\tParser.prototype = {\n\t constructor: Parser,\n\t\n\t parse: function(text) {\n\t return this.astCompiler.compile(text, this.options.expensiveChecks);\n\t }\n\t};\n\t\n\tfunction isPossiblyDangerousMemberName(name) {\n\t return name == 'constructor';\n\t}\n\t\n\tvar objectValueOf = Object.prototype.valueOf;\n\t\n\tfunction getValueOf(value) {\n\t return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);\n\t}\n\t\n\t///////////////////////////////////\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $parse\n\t * @kind function\n\t *\n\t * @description\n\t *\n\t * Converts Angular {@link guide/expression expression} into a function.\n\t *\n\t * ```js\n\t * var getter = $parse('user.name');\n\t * var setter = getter.assign;\n\t * var context = {user:{name:'angular'}};\n\t * var locals = {user:{name:'local'}};\n\t *\n\t * expect(getter(context)).toEqual('angular');\n\t * setter(context, 'newValue');\n\t * expect(context.user.name).toEqual('newValue');\n\t * expect(getter(context, locals)).toEqual('local');\n\t * ```\n\t *\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t *\n\t * The returned function also has the following properties:\n\t * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript\n\t * literal.\n\t * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript\n\t * constant literals.\n\t * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be\n\t * set to a function to change its value on the given context.\n\t *\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $parseProvider\n\t *\n\t * @description\n\t * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}\n\t * service.\n\t */\n\tfunction $ParseProvider() {\n\t var cacheDefault = createMap();\n\t var cacheExpensive = createMap();\n\t var literals = {\n\t 'true': true,\n\t 'false': false,\n\t 'null': null,\n\t 'undefined': undefined\n\t };\n\t var identStart, identContinue;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $parseProvider#addLiteral\n\t * @description\n\t *\n\t * Configure $parse service to add literal values that will be present as literal at expressions.\n\t *\n\t * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.\n\t * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.\n\t *\n\t **/\n\t this.addLiteral = function(literalName, literalValue) {\n\t literals[literalName] = literalValue;\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $parseProvider#setIdentifierFns\n\t * @description\n\t *\n\t * Allows defining the set of characters that are allowed in Angular expressions. The function\n\t * `identifierStart` will get called to know if a given character is a valid character to be the\n\t * first character for an identifier. The function `identifierContinue` will get called to know if\n\t * a given character is a valid character to be a follow-up identifier character. The functions\n\t * `identifierStart` and `identifierContinue` will receive as arguments the single character to be\n\t * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in\n\t * mind that the `string` parameter can be two characters long depending on the character\n\t * representation. It is expected for the function to return `true` or `false`, whether that\n\t * character is allowed or not.\n\t *\n\t * Since this function will be called extensivelly, keep the implementation of these functions fast,\n\t * as the performance of these functions have a direct impact on the expressions parsing speed.\n\t *\n\t * @param {function=} identifierStart The function that will decide whether the given character is\n\t * a valid identifier start character.\n\t * @param {function=} identifierContinue The function that will decide whether the given character is\n\t * a valid identifier continue character.\n\t */\n\t this.setIdentifierFns = function(identifierStart, identifierContinue) {\n\t identStart = identifierStart;\n\t identContinue = identifierContinue;\n\t return this;\n\t };\n\t\n\t this.$get = ['$filter', function($filter) {\n\t var noUnsafeEval = csp().noUnsafeEval;\n\t var $parseOptions = {\n\t csp: noUnsafeEval,\n\t expensiveChecks: false,\n\t literals: copy(literals),\n\t isIdentifierStart: isFunction(identStart) && identStart,\n\t isIdentifierContinue: isFunction(identContinue) && identContinue\n\t },\n\t $parseOptionsExpensive = {\n\t csp: noUnsafeEval,\n\t expensiveChecks: true,\n\t literals: copy(literals),\n\t isIdentifierStart: isFunction(identStart) && identStart,\n\t isIdentifierContinue: isFunction(identContinue) && identContinue\n\t };\n\t var runningChecksEnabled = false;\n\t\n\t $parse.$$runningExpensiveChecks = function() {\n\t return runningChecksEnabled;\n\t };\n\t\n\t return $parse;\n\t\n\t function $parse(exp, interceptorFn, expensiveChecks) {\n\t var parsedExpression, oneTime, cacheKey;\n\t\n\t expensiveChecks = expensiveChecks || runningChecksEnabled;\n\t\n\t switch (typeof exp) {\n\t case 'string':\n\t exp = exp.trim();\n\t cacheKey = exp;\n\t\n\t var cache = (expensiveChecks ? cacheExpensive : cacheDefault);\n\t parsedExpression = cache[cacheKey];\n\t\n\t if (!parsedExpression) {\n\t if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {\n\t oneTime = true;\n\t exp = exp.substring(2);\n\t }\n\t var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;\n\t var lexer = new Lexer(parseOptions);\n\t var parser = new Parser(lexer, $filter, parseOptions);\n\t parsedExpression = parser.parse(exp);\n\t if (parsedExpression.constant) {\n\t parsedExpression.$$watchDelegate = constantWatchDelegate;\n\t } else if (oneTime) {\n\t parsedExpression.$$watchDelegate = parsedExpression.literal ?\n\t oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;\n\t } else if (parsedExpression.inputs) {\n\t parsedExpression.$$watchDelegate = inputsWatchDelegate;\n\t }\n\t if (expensiveChecks) {\n\t parsedExpression = expensiveChecksInterceptor(parsedExpression);\n\t }\n\t cache[cacheKey] = parsedExpression;\n\t }\n\t return addInterceptor(parsedExpression, interceptorFn);\n\t\n\t case 'function':\n\t return addInterceptor(exp, interceptorFn);\n\t\n\t default:\n\t return addInterceptor(noop, interceptorFn);\n\t }\n\t }\n\t\n\t function expensiveChecksInterceptor(fn) {\n\t if (!fn) return fn;\n\t expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;\n\t expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);\n\t expensiveCheckFn.constant = fn.constant;\n\t expensiveCheckFn.literal = fn.literal;\n\t for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {\n\t fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);\n\t }\n\t expensiveCheckFn.inputs = fn.inputs;\n\t\n\t return expensiveCheckFn;\n\t\n\t function expensiveCheckFn(scope, locals, assign, inputs) {\n\t var expensiveCheckOldValue = runningChecksEnabled;\n\t runningChecksEnabled = true;\n\t try {\n\t return fn(scope, locals, assign, inputs);\n\t } finally {\n\t runningChecksEnabled = expensiveCheckOldValue;\n\t }\n\t }\n\t }\n\t\n\t function expressionInputDirtyCheck(newValue, oldValueOfValue) {\n\t\n\t if (newValue == null || oldValueOfValue == null) { // null/undefined\n\t return newValue === oldValueOfValue;\n\t }\n\t\n\t if (typeof newValue === 'object') {\n\t\n\t // attempt to convert the value to a primitive type\n\t // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can\n\t // be cheaply dirty-checked\n\t newValue = getValueOf(newValue);\n\t\n\t if (typeof newValue === 'object') {\n\t // objects/arrays are not supported - deep-watching them would be too expensive\n\t return false;\n\t }\n\t\n\t // fall-through to the primitive equality check\n\t }\n\t\n\t //Primitive or NaN\n\t return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);\n\t }\n\t\n\t function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {\n\t var inputExpressions = parsedExpression.inputs;\n\t var lastResult;\n\t\n\t if (inputExpressions.length === 1) {\n\t var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails\n\t inputExpressions = inputExpressions[0];\n\t return scope.$watch(function expressionInputWatch(scope) {\n\t var newInputValue = inputExpressions(scope);\n\t if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {\n\t lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);\n\t oldInputValueOf = newInputValue && getValueOf(newInputValue);\n\t }\n\t return lastResult;\n\t }, listener, objectEquality, prettyPrintExpression);\n\t }\n\t\n\t var oldInputValueOfValues = [];\n\t var oldInputValues = [];\n\t for (var i = 0, ii = inputExpressions.length; i < ii; i++) {\n\t oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails\n\t oldInputValues[i] = null;\n\t }\n\t\n\t return scope.$watch(function expressionInputsWatch(scope) {\n\t var changed = false;\n\t\n\t for (var i = 0, ii = inputExpressions.length; i < ii; i++) {\n\t var newInputValue = inputExpressions[i](scope);\n\t if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {\n\t oldInputValues[i] = newInputValue;\n\t oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);\n\t }\n\t }\n\t\n\t if (changed) {\n\t lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);\n\t }\n\t\n\t return lastResult;\n\t }, listener, objectEquality, prettyPrintExpression);\n\t }\n\t\n\t function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {\n\t var unwatch, lastValue;\n\t return unwatch = scope.$watch(function oneTimeWatch(scope) {\n\t return parsedExpression(scope);\n\t }, function oneTimeListener(value, old, scope) {\n\t lastValue = value;\n\t if (isFunction(listener)) {\n\t listener.apply(this, arguments);\n\t }\n\t if (isDefined(value)) {\n\t scope.$$postDigest(function() {\n\t if (isDefined(lastValue)) {\n\t unwatch();\n\t }\n\t });\n\t }\n\t }, objectEquality);\n\t }\n\t\n\t function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {\n\t var unwatch, lastValue;\n\t return unwatch = scope.$watch(function oneTimeWatch(scope) {\n\t return parsedExpression(scope);\n\t }, function oneTimeListener(value, old, scope) {\n\t lastValue = value;\n\t if (isFunction(listener)) {\n\t listener.call(this, value, old, scope);\n\t }\n\t if (isAllDefined(value)) {\n\t scope.$$postDigest(function() {\n\t if (isAllDefined(lastValue)) unwatch();\n\t });\n\t }\n\t }, objectEquality);\n\t\n\t function isAllDefined(value) {\n\t var allDefined = true;\n\t forEach(value, function(val) {\n\t if (!isDefined(val)) allDefined = false;\n\t });\n\t return allDefined;\n\t }\n\t }\n\t\n\t function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {\n\t var unwatch;\n\t return unwatch = scope.$watch(function constantWatch(scope) {\n\t unwatch();\n\t return parsedExpression(scope);\n\t }, listener, objectEquality);\n\t }\n\t\n\t function addInterceptor(parsedExpression, interceptorFn) {\n\t if (!interceptorFn) return parsedExpression;\n\t var watchDelegate = parsedExpression.$$watchDelegate;\n\t var useInputs = false;\n\t\n\t var regularWatch =\n\t watchDelegate !== oneTimeLiteralWatchDelegate &&\n\t watchDelegate !== oneTimeWatchDelegate;\n\t\n\t var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {\n\t var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);\n\t return interceptorFn(value, scope, locals);\n\t } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {\n\t var value = parsedExpression(scope, locals, assign, inputs);\n\t var result = interceptorFn(value, scope, locals);\n\t // we only return the interceptor's result if the\n\t // initial value is defined (for bind-once)\n\t return isDefined(value) ? result : value;\n\t };\n\t\n\t // Propagate $$watchDelegates other then inputsWatchDelegate\n\t if (parsedExpression.$$watchDelegate &&\n\t parsedExpression.$$watchDelegate !== inputsWatchDelegate) {\n\t fn.$$watchDelegate = parsedExpression.$$watchDelegate;\n\t } else if (!interceptorFn.$stateful) {\n\t // If there is an interceptor, but no watchDelegate then treat the interceptor like\n\t // we treat filters - it is assumed to be a pure function unless flagged with $stateful\n\t fn.$$watchDelegate = inputsWatchDelegate;\n\t useInputs = !parsedExpression.inputs;\n\t fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];\n\t }\n\t\n\t return fn;\n\t }\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $q\n\t * @requires $rootScope\n\t *\n\t * @description\n\t * A service that helps you run functions asynchronously, and use their return values (or exceptions)\n\t * when they are done processing.\n\t *\n\t * This is an implementation of promises/deferred objects inspired by\n\t * [Kris Kowal's Q](https://github.com/kriskowal/q).\n\t *\n\t * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred\n\t * implementations, and the other which resembles ES6 (ES2015) promises to some degree.\n\t *\n\t * # $q constructor\n\t *\n\t * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`\n\t * function as the first argument. This is similar to the native Promise implementation from ES6,\n\t * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).\n\t *\n\t * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are\n\t * available yet.\n\t *\n\t * It can be used like so:\n\t *\n\t * ```js\n\t * // for the purpose of this example let's assume that variables `$q` and `okToGreet`\n\t * // are available in the current lexical scope (they could have been injected or passed in).\n\t *\n\t * function asyncGreet(name) {\n\t * // perform some asynchronous operation, resolve or reject the promise when appropriate.\n\t * return $q(function(resolve, reject) {\n\t * setTimeout(function() {\n\t * if (okToGreet(name)) {\n\t * resolve('Hello, ' + name + '!');\n\t * } else {\n\t * reject('Greeting ' + name + ' is not allowed.');\n\t * }\n\t * }, 1000);\n\t * });\n\t * }\n\t *\n\t * var promise = asyncGreet('Robin Hood');\n\t * promise.then(function(greeting) {\n\t * alert('Success: ' + greeting);\n\t * }, function(reason) {\n\t * alert('Failed: ' + reason);\n\t * });\n\t * ```\n\t *\n\t * Note: progress/notify callbacks are not currently supported via the ES6-style interface.\n\t *\n\t * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.\n\t *\n\t * However, the more traditional CommonJS-style usage is still available, and documented below.\n\t *\n\t * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an\n\t * interface for interacting with an object that represents the result of an action that is\n\t * performed asynchronously, and may or may not be finished at any given point in time.\n\t *\n\t * From the perspective of dealing with error handling, deferred and promise APIs are to\n\t * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.\n\t *\n\t * ```js\n\t * // for the purpose of this example let's assume that variables `$q` and `okToGreet`\n\t * // are available in the current lexical scope (they could have been injected or passed in).\n\t *\n\t * function asyncGreet(name) {\n\t * var deferred = $q.defer();\n\t *\n\t * setTimeout(function() {\n\t * deferred.notify('About to greet ' + name + '.');\n\t *\n\t * if (okToGreet(name)) {\n\t * deferred.resolve('Hello, ' + name + '!');\n\t * } else {\n\t * deferred.reject('Greeting ' + name + ' is not allowed.');\n\t * }\n\t * }, 1000);\n\t *\n\t * return deferred.promise;\n\t * }\n\t *\n\t * var promise = asyncGreet('Robin Hood');\n\t * promise.then(function(greeting) {\n\t * alert('Success: ' + greeting);\n\t * }, function(reason) {\n\t * alert('Failed: ' + reason);\n\t * }, function(update) {\n\t * alert('Got notification: ' + update);\n\t * });\n\t * ```\n\t *\n\t * At first it might not be obvious why this extra complexity is worth the trouble. The payoff\n\t * comes in the way of guarantees that promise and deferred APIs make, see\n\t * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.\n\t *\n\t * Additionally the promise api allows for composition that is very hard to do with the\n\t * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.\n\t * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the\n\t * section on serial or parallel joining of promises.\n\t *\n\t * # The Deferred API\n\t *\n\t * A new instance of deferred is constructed by calling `$q.defer()`.\n\t *\n\t * The purpose of the deferred object is to expose the associated Promise instance as well as APIs\n\t * that can be used for signaling the successful or unsuccessful completion, as well as the status\n\t * of the task.\n\t *\n\t * **Methods**\n\t *\n\t * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection\n\t * constructed via `$q.reject`, the promise will be rejected instead.\n\t * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to\n\t * resolving it with a rejection constructed via `$q.reject`.\n\t * - `notify(value)` - provides updates on the status of the promise's execution. This may be called\n\t * multiple times before the promise is either resolved or rejected.\n\t *\n\t * **Properties**\n\t *\n\t * - promise – `{Promise}` – promise object associated with this deferred.\n\t *\n\t *\n\t * # The Promise API\n\t *\n\t * A new promise instance is created when a deferred instance is created and can be retrieved by\n\t * calling `deferred.promise`.\n\t *\n\t * The purpose of the promise object is to allow for interested parties to get access to the result\n\t * of the deferred task when it completes.\n\t *\n\t * **Methods**\n\t *\n\t * - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or\n\t * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously\n\t * as soon as the result is available. The callbacks are called with a single argument: the result\n\t * or rejection reason. Additionally, the notify callback may be called zero or more times to\n\t * provide a progress indication, before the promise is resolved or rejected.\n\t *\n\t * This method *returns a new promise* which is resolved or rejected via the return value of the\n\t * `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved\n\t * with the value which is resolved in that promise using\n\t * [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).\n\t * It also notifies via the return value of the `notifyCallback` method. The promise cannot be\n\t * resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback\n\t * arguments are optional.\n\t *\n\t * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`\n\t *\n\t * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,\n\t * but to do so without modifying the final value. This is useful to release resources or do some\n\t * clean-up that needs to be done whether the promise was rejected or resolved. See the [full\n\t * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for\n\t * more information.\n\t *\n\t * # Chaining promises\n\t *\n\t * Because calling the `then` method of a promise returns a new derived promise, it is easily\n\t * possible to create a chain of promises:\n\t *\n\t * ```js\n\t * promiseB = promiseA.then(function(result) {\n\t * return result + 1;\n\t * });\n\t *\n\t * // promiseB will be resolved immediately after promiseA is resolved and its value\n\t * // will be the result of promiseA incremented by 1\n\t * ```\n\t *\n\t * It is possible to create chains of any length and since a promise can be resolved with another\n\t * promise (which will defer its resolution further), it is possible to pause/defer resolution of\n\t * the promises at any point in the chain. This makes it possible to implement powerful APIs like\n\t * $http's response interceptors.\n\t *\n\t *\n\t * # Differences between Kris Kowal's Q and $q\n\t *\n\t * There are two main differences:\n\t *\n\t * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation\n\t * mechanism in angular, which means faster propagation of resolution or rejection into your\n\t * models and avoiding unnecessary browser repaints, which would result in flickering UI.\n\t * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains\n\t * all the important functionality needed for common async tasks.\n\t *\n\t * # Testing\n\t *\n\t * ```js\n\t * it('should simulate promise', inject(function($q, $rootScope) {\n\t * var deferred = $q.defer();\n\t * var promise = deferred.promise;\n\t * var resolvedValue;\n\t *\n\t * promise.then(function(value) { resolvedValue = value; });\n\t * expect(resolvedValue).toBeUndefined();\n\t *\n\t * // Simulate resolving of promise\n\t * deferred.resolve(123);\n\t * // Note that the 'then' function does not get called synchronously.\n\t * // This is because we want the promise API to always be async, whether or not\n\t * // it got called synchronously or asynchronously.\n\t * expect(resolvedValue).toBeUndefined();\n\t *\n\t * // Propagate promise resolution to 'then' functions using $apply().\n\t * $rootScope.$apply();\n\t * expect(resolvedValue).toEqual(123);\n\t * }));\n\t * ```\n\t *\n\t * @param {function(function, function)} resolver Function which is responsible for resolving or\n\t * rejecting the newly created promise. The first parameter is a function which resolves the\n\t * promise, the second parameter is a function which rejects the promise.\n\t *\n\t * @returns {Promise} The newly created promise.\n\t */\n\tfunction $QProvider() {\n\t\n\t this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {\n\t return qFactory(function(callback) {\n\t $rootScope.$evalAsync(callback);\n\t }, $exceptionHandler);\n\t }];\n\t}\n\t\n\tfunction $$QProvider() {\n\t this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {\n\t return qFactory(function(callback) {\n\t $browser.defer(callback);\n\t }, $exceptionHandler);\n\t }];\n\t}\n\t\n\t/**\n\t * Constructs a promise manager.\n\t *\n\t * @param {function(function)} nextTick Function for executing functions in the next turn.\n\t * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for\n\t * debugging purposes.\n\t * @returns {object} Promise manager.\n\t */\n\tfunction qFactory(nextTick, exceptionHandler) {\n\t var $qMinErr = minErr('$q', TypeError);\n\t\n\t /**\n\t * @ngdoc method\n\t * @name ng.$q#defer\n\t * @kind function\n\t *\n\t * @description\n\t * Creates a `Deferred` object which represents a task which will finish in the future.\n\t *\n\t * @returns {Deferred} Returns a new instance of deferred.\n\t */\n\t var defer = function() {\n\t var d = new Deferred();\n\t //Necessary to support unbound execution :/\n\t d.resolve = simpleBind(d, d.resolve);\n\t d.reject = simpleBind(d, d.reject);\n\t d.notify = simpleBind(d, d.notify);\n\t return d;\n\t };\n\t\n\t function Promise() {\n\t this.$$state = { status: 0 };\n\t }\n\t\n\t extend(Promise.prototype, {\n\t then: function(onFulfilled, onRejected, progressBack) {\n\t if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {\n\t return this;\n\t }\n\t var result = new Deferred();\n\t\n\t this.$$state.pending = this.$$state.pending || [];\n\t this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);\n\t if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);\n\t\n\t return result.promise;\n\t },\n\t\n\t \"catch\": function(callback) {\n\t return this.then(null, callback);\n\t },\n\t\n\t \"finally\": function(callback, progressBack) {\n\t return this.then(function(value) {\n\t return handleCallback(value, true, callback);\n\t }, function(error) {\n\t return handleCallback(error, false, callback);\n\t }, progressBack);\n\t }\n\t });\n\t\n\t //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native\n\t function simpleBind(context, fn) {\n\t return function(value) {\n\t fn.call(context, value);\n\t };\n\t }\n\t\n\t function processQueue(state) {\n\t var fn, deferred, pending;\n\t\n\t pending = state.pending;\n\t state.processScheduled = false;\n\t state.pending = undefined;\n\t for (var i = 0, ii = pending.length; i < ii; ++i) {\n\t deferred = pending[i][0];\n\t fn = pending[i][state.status];\n\t try {\n\t if (isFunction(fn)) {\n\t deferred.resolve(fn(state.value));\n\t } else if (state.status === 1) {\n\t deferred.resolve(state.value);\n\t } else {\n\t deferred.reject(state.value);\n\t }\n\t } catch (e) {\n\t deferred.reject(e);\n\t exceptionHandler(e);\n\t }\n\t }\n\t }\n\t\n\t function scheduleProcessQueue(state) {\n\t if (state.processScheduled || !state.pending) return;\n\t state.processScheduled = true;\n\t nextTick(function() { processQueue(state); });\n\t }\n\t\n\t function Deferred() {\n\t this.promise = new Promise();\n\t }\n\t\n\t extend(Deferred.prototype, {\n\t resolve: function(val) {\n\t if (this.promise.$$state.status) return;\n\t if (val === this.promise) {\n\t this.$$reject($qMinErr(\n\t 'qcycle',\n\t \"Expected promise to be resolved with value other than itself '{0}'\",\n\t val));\n\t } else {\n\t this.$$resolve(val);\n\t }\n\t\n\t },\n\t\n\t $$resolve: function(val) {\n\t var then;\n\t var that = this;\n\t var done = false;\n\t try {\n\t if ((isObject(val) || isFunction(val))) then = val && val.then;\n\t if (isFunction(then)) {\n\t this.promise.$$state.status = -1;\n\t then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));\n\t } else {\n\t this.promise.$$state.value = val;\n\t this.promise.$$state.status = 1;\n\t scheduleProcessQueue(this.promise.$$state);\n\t }\n\t } catch (e) {\n\t rejectPromise(e);\n\t exceptionHandler(e);\n\t }\n\t\n\t function resolvePromise(val) {\n\t if (done) return;\n\t done = true;\n\t that.$$resolve(val);\n\t }\n\t function rejectPromise(val) {\n\t if (done) return;\n\t done = true;\n\t that.$$reject(val);\n\t }\n\t },\n\t\n\t reject: function(reason) {\n\t if (this.promise.$$state.status) return;\n\t this.$$reject(reason);\n\t },\n\t\n\t $$reject: function(reason) {\n\t this.promise.$$state.value = reason;\n\t this.promise.$$state.status = 2;\n\t scheduleProcessQueue(this.promise.$$state);\n\t },\n\t\n\t notify: function(progress) {\n\t var callbacks = this.promise.$$state.pending;\n\t\n\t if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {\n\t nextTick(function() {\n\t var callback, result;\n\t for (var i = 0, ii = callbacks.length; i < ii; i++) {\n\t result = callbacks[i][0];\n\t callback = callbacks[i][3];\n\t try {\n\t result.notify(isFunction(callback) ? callback(progress) : progress);\n\t } catch (e) {\n\t exceptionHandler(e);\n\t }\n\t }\n\t });\n\t }\n\t }\n\t });\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $q#reject\n\t * @kind function\n\t *\n\t * @description\n\t * Creates a promise that is resolved as rejected with the specified `reason`. This api should be\n\t * used to forward rejection in a chain of promises. If you are dealing with the last promise in\n\t * a promise chain, you don't need to worry about it.\n\t *\n\t * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of\n\t * `reject` as the `throw` keyword in JavaScript. This also means that if you \"catch\" an error via\n\t * a promise error callback and you want to forward the error to the promise derived from the\n\t * current promise, you have to \"rethrow\" the error by returning a rejection constructed via\n\t * `reject`.\n\t *\n\t * ```js\n\t * promiseB = promiseA.then(function(result) {\n\t * // success: do something and resolve promiseB\n\t * // with the old or a new result\n\t * return result;\n\t * }, function(reason) {\n\t * // error: handle the error if possible and\n\t * // resolve promiseB with newPromiseOrValue,\n\t * // otherwise forward the rejection to promiseB\n\t * if (canHandle(reason)) {\n\t * // handle the error and recover\n\t * return newPromiseOrValue;\n\t * }\n\t * return $q.reject(reason);\n\t * });\n\t * ```\n\t *\n\t * @param {*} reason Constant, message, exception or an object representing the rejection reason.\n\t * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.\n\t */\n\t var reject = function(reason) {\n\t var result = new Deferred();\n\t result.reject(reason);\n\t return result.promise;\n\t };\n\t\n\t var makePromise = function makePromise(value, resolved) {\n\t var result = new Deferred();\n\t if (resolved) {\n\t result.resolve(value);\n\t } else {\n\t result.reject(value);\n\t }\n\t return result.promise;\n\t };\n\t\n\t var handleCallback = function handleCallback(value, isResolved, callback) {\n\t var callbackOutput = null;\n\t try {\n\t if (isFunction(callback)) callbackOutput = callback();\n\t } catch (e) {\n\t return makePromise(e, false);\n\t }\n\t if (isPromiseLike(callbackOutput)) {\n\t return callbackOutput.then(function() {\n\t return makePromise(value, isResolved);\n\t }, function(error) {\n\t return makePromise(error, false);\n\t });\n\t } else {\n\t return makePromise(value, isResolved);\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $q#when\n\t * @kind function\n\t *\n\t * @description\n\t * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.\n\t * This is useful when you are dealing with an object that might or might not be a promise, or if\n\t * the promise comes from a source that can't be trusted.\n\t *\n\t * @param {*} value Value or a promise\n\t * @param {Function=} successCallback\n\t * @param {Function=} errorCallback\n\t * @param {Function=} progressCallback\n\t * @returns {Promise} Returns a promise of the passed value or promise\n\t */\n\t\n\t\n\t var when = function(value, callback, errback, progressBack) {\n\t var result = new Deferred();\n\t result.resolve(value);\n\t return result.promise.then(callback, errback, progressBack);\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $q#resolve\n\t * @kind function\n\t *\n\t * @description\n\t * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.\n\t *\n\t * @param {*} value Value or a promise\n\t * @param {Function=} successCallback\n\t * @param {Function=} errorCallback\n\t * @param {Function=} progressCallback\n\t * @returns {Promise} Returns a promise of the passed value or promise\n\t */\n\t var resolve = when;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $q#all\n\t * @kind function\n\t *\n\t * @description\n\t * Combines multiple promises into a single promise that is resolved when all of the input\n\t * promises are resolved.\n\t *\n\t * @param {Array.|Object.} promises An array or hash of promises.\n\t * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,\n\t * each value corresponding to the promise at the same index/key in the `promises` array/hash.\n\t * If any of the promises is resolved with a rejection, this resulting promise will be rejected\n\t * with the same rejection value.\n\t */\n\t\n\t function all(promises) {\n\t var deferred = new Deferred(),\n\t counter = 0,\n\t results = isArray(promises) ? [] : {};\n\t\n\t forEach(promises, function(promise, key) {\n\t counter++;\n\t when(promise).then(function(value) {\n\t if (results.hasOwnProperty(key)) return;\n\t results[key] = value;\n\t if (!(--counter)) deferred.resolve(results);\n\t }, function(reason) {\n\t if (results.hasOwnProperty(key)) return;\n\t deferred.reject(reason);\n\t });\n\t });\n\t\n\t if (counter === 0) {\n\t deferred.resolve(results);\n\t }\n\t\n\t return deferred.promise;\n\t }\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $q#race\n\t * @kind function\n\t *\n\t * @description\n\t * Returns a promise that resolves or rejects as soon as one of those promises\n\t * resolves or rejects, with the value or reason from that promise.\n\t *\n\t * @param {Array.|Object.} promises An array or hash of promises.\n\t * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`\n\t * resolves or rejects, with the value or reason from that promise.\n\t */\n\t\n\t function race(promises) {\n\t var deferred = defer();\n\t\n\t forEach(promises, function(promise) {\n\t when(promise).then(deferred.resolve, deferred.reject);\n\t });\n\t\n\t return deferred.promise;\n\t }\n\t\n\t var $Q = function Q(resolver) {\n\t if (!isFunction(resolver)) {\n\t throw $qMinErr('norslvr', \"Expected resolverFn, got '{0}'\", resolver);\n\t }\n\t\n\t var deferred = new Deferred();\n\t\n\t function resolveFn(value) {\n\t deferred.resolve(value);\n\t }\n\t\n\t function rejectFn(reason) {\n\t deferred.reject(reason);\n\t }\n\t\n\t resolver(resolveFn, rejectFn);\n\t\n\t return deferred.promise;\n\t };\n\t\n\t // Let's make the instanceof operator work for promises, so that\n\t // `new $q(fn) instanceof $q` would evaluate to true.\n\t $Q.prototype = Promise.prototype;\n\t\n\t $Q.defer = defer;\n\t $Q.reject = reject;\n\t $Q.when = when;\n\t $Q.resolve = resolve;\n\t $Q.all = all;\n\t $Q.race = race;\n\t\n\t return $Q;\n\t}\n\t\n\tfunction $$RAFProvider() { //rAF\n\t this.$get = ['$window', '$timeout', function($window, $timeout) {\n\t var requestAnimationFrame = $window.requestAnimationFrame ||\n\t $window.webkitRequestAnimationFrame;\n\t\n\t var cancelAnimationFrame = $window.cancelAnimationFrame ||\n\t $window.webkitCancelAnimationFrame ||\n\t $window.webkitCancelRequestAnimationFrame;\n\t\n\t var rafSupported = !!requestAnimationFrame;\n\t var raf = rafSupported\n\t ? function(fn) {\n\t var id = requestAnimationFrame(fn);\n\t return function() {\n\t cancelAnimationFrame(id);\n\t };\n\t }\n\t : function(fn) {\n\t var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n\t return function() {\n\t $timeout.cancel(timer);\n\t };\n\t };\n\t\n\t raf.supported = rafSupported;\n\t\n\t return raf;\n\t }];\n\t}\n\t\n\t/**\n\t * DESIGN NOTES\n\t *\n\t * The design decisions behind the scope are heavily favored for speed and memory consumption.\n\t *\n\t * The typical use of scope is to watch the expressions, which most of the time return the same\n\t * value as last time so we optimize the operation.\n\t *\n\t * Closures construction is expensive in terms of speed as well as memory:\n\t * - No closures, instead use prototypical inheritance for API\n\t * - Internal state needs to be stored on scope directly, which means that private state is\n\t * exposed as $$____ properties\n\t *\n\t * Loop operations are optimized by using while(count--) { ... }\n\t * - This means that in order to keep the same order of execution as addition we have to add\n\t * items to the array at the beginning (unshift) instead of at the end (push)\n\t *\n\t * Child scopes are created and removed often\n\t * - Using an array would be slow since inserts in the middle are expensive; so we use linked lists\n\t *\n\t * There are fewer watches than observers. This is why you don't want the observer to be implemented\n\t * in the same way as watch. Watch requires return of the initialization function which is expensive\n\t * to construct.\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $rootScopeProvider\n\t * @description\n\t *\n\t * Provider for the $rootScope service.\n\t */\n\t\n\t/**\n\t * @ngdoc method\n\t * @name $rootScopeProvider#digestTtl\n\t * @description\n\t *\n\t * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and\n\t * assuming that the model is unstable.\n\t *\n\t * The current default is 10 iterations.\n\t *\n\t * In complex applications it's possible that the dependencies between `$watch`s will result in\n\t * several digest iterations. However if an application needs more than the default 10 digest\n\t * iterations for its model to stabilize then you should investigate what is causing the model to\n\t * continuously change during the digest.\n\t *\n\t * Increasing the TTL could have performance implications, so you should not change it without\n\t * proper justification.\n\t *\n\t * @param {number} limit The number of digest iterations.\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $rootScope\n\t * @description\n\t *\n\t * Every application has a single root {@link ng.$rootScope.Scope scope}.\n\t * All other scopes are descendant scopes of the root scope. Scopes provide separation\n\t * between the model and the view, via a mechanism for watching the model for changes.\n\t * They also provide event emission/broadcast and subscription facility. See the\n\t * {@link guide/scope developer guide on scopes}.\n\t */\n\tfunction $RootScopeProvider() {\n\t var TTL = 10;\n\t var $rootScopeMinErr = minErr('$rootScope');\n\t var lastDirtyWatch = null;\n\t var applyAsyncId = null;\n\t\n\t this.digestTtl = function(value) {\n\t if (arguments.length) {\n\t TTL = value;\n\t }\n\t return TTL;\n\t };\n\t\n\t function createChildScopeClass(parent) {\n\t function ChildScope() {\n\t this.$$watchers = this.$$nextSibling =\n\t this.$$childHead = this.$$childTail = null;\n\t this.$$listeners = {};\n\t this.$$listenerCount = {};\n\t this.$$watchersCount = 0;\n\t this.$id = nextUid();\n\t this.$$ChildScope = null;\n\t }\n\t ChildScope.prototype = parent;\n\t return ChildScope;\n\t }\n\t\n\t this.$get = ['$exceptionHandler', '$parse', '$browser',\n\t function($exceptionHandler, $parse, $browser) {\n\t\n\t function destroyChildScope($event) {\n\t $event.currentScope.$$destroyed = true;\n\t }\n\t\n\t function cleanUpScope($scope) {\n\t\n\t if (msie === 9) {\n\t // There is a memory leak in IE9 if all child scopes are not disconnected\n\t // completely when a scope is destroyed. So this code will recurse up through\n\t // all this scopes children\n\t //\n\t // See issue https://github.com/angular/angular.js/issues/10706\n\t $scope.$$childHead && cleanUpScope($scope.$$childHead);\n\t $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);\n\t }\n\t\n\t // The code below works around IE9 and V8's memory leaks\n\t //\n\t // See:\n\t // - https://code.google.com/p/v8/issues/detail?id=2073#c26\n\t // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909\n\t // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451\n\t\n\t $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =\n\t $scope.$$childTail = $scope.$root = $scope.$$watchers = null;\n\t }\n\t\n\t /**\n\t * @ngdoc type\n\t * @name $rootScope.Scope\n\t *\n\t * @description\n\t * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the\n\t * {@link auto.$injector $injector}. Child scopes are created using the\n\t * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when\n\t * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for\n\t * an in-depth introduction and usage examples.\n\t *\n\t *\n\t * # Inheritance\n\t * A scope can inherit from a parent scope, as in this example:\n\t * ```js\n\t var parent = $rootScope;\n\t var child = parent.$new();\n\t\n\t parent.salutation = \"Hello\";\n\t expect(child.salutation).toEqual('Hello');\n\t\n\t child.salutation = \"Welcome\";\n\t expect(child.salutation).toEqual('Welcome');\n\t expect(parent.salutation).toEqual('Hello');\n\t * ```\n\t *\n\t * When interacting with `Scope` in tests, additional helper methods are available on the\n\t * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional\n\t * details.\n\t *\n\t *\n\t * @param {Object.=} providers Map of service factory which need to be\n\t * provided for the current scope. Defaults to {@link ng}.\n\t * @param {Object.=} instanceCache Provides pre-instantiated services which should\n\t * append/override services provided by `providers`. This is handy\n\t * when unit-testing and having the need to override a default\n\t * service.\n\t * @returns {Object} Newly created scope.\n\t *\n\t */\n\t function Scope() {\n\t this.$id = nextUid();\n\t this.$$phase = this.$parent = this.$$watchers =\n\t this.$$nextSibling = this.$$prevSibling =\n\t this.$$childHead = this.$$childTail = null;\n\t this.$root = this;\n\t this.$$destroyed = false;\n\t this.$$listeners = {};\n\t this.$$listenerCount = {};\n\t this.$$watchersCount = 0;\n\t this.$$isolateBindings = null;\n\t }\n\t\n\t /**\n\t * @ngdoc property\n\t * @name $rootScope.Scope#$id\n\t *\n\t * @description\n\t * Unique scope ID (monotonically increasing) useful for debugging.\n\t */\n\t\n\t /**\n\t * @ngdoc property\n\t * @name $rootScope.Scope#$parent\n\t *\n\t * @description\n\t * Reference to the parent scope.\n\t */\n\t\n\t /**\n\t * @ngdoc property\n\t * @name $rootScope.Scope#$root\n\t *\n\t * @description\n\t * Reference to the root scope.\n\t */\n\t\n\t Scope.prototype = {\n\t constructor: Scope,\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$new\n\t * @kind function\n\t *\n\t * @description\n\t * Creates a new child {@link ng.$rootScope.Scope scope}.\n\t *\n\t * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.\n\t * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.\n\t *\n\t * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is\n\t * desired for the scope and its child scopes to be permanently detached from the parent and\n\t * thus stop participating in model change detection and listener notification by invoking.\n\t *\n\t * @param {boolean} isolate If true, then the scope does not prototypically inherit from the\n\t * parent scope. The scope is isolated, as it can not see parent scope properties.\n\t * When creating widgets, it is useful for the widget to not accidentally read parent\n\t * state.\n\t *\n\t * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`\n\t * of the newly created scope. Defaults to `this` scope if not provided.\n\t * This is used when creating a transclude scope to correctly place it\n\t * in the scope hierarchy while maintaining the correct prototypical\n\t * inheritance.\n\t *\n\t * @returns {Object} The newly created child scope.\n\t *\n\t */\n\t $new: function(isolate, parent) {\n\t var child;\n\t\n\t parent = parent || this;\n\t\n\t if (isolate) {\n\t child = new Scope();\n\t child.$root = this.$root;\n\t } else {\n\t // Only create a child scope class if somebody asks for one,\n\t // but cache it to allow the VM to optimize lookups.\n\t if (!this.$$ChildScope) {\n\t this.$$ChildScope = createChildScopeClass(this);\n\t }\n\t child = new this.$$ChildScope();\n\t }\n\t child.$parent = parent;\n\t child.$$prevSibling = parent.$$childTail;\n\t if (parent.$$childHead) {\n\t parent.$$childTail.$$nextSibling = child;\n\t parent.$$childTail = child;\n\t } else {\n\t parent.$$childHead = parent.$$childTail = child;\n\t }\n\t\n\t // When the new scope is not isolated or we inherit from `this`, and\n\t // the parent scope is destroyed, the property `$$destroyed` is inherited\n\t // prototypically. In all other cases, this property needs to be set\n\t // when the parent scope is destroyed.\n\t // The listener needs to be added after the parent is set\n\t if (isolate || parent != this) child.$on('$destroy', destroyChildScope);\n\t\n\t return child;\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$watch\n\t * @kind function\n\t *\n\t * @description\n\t * Registers a `listener` callback to be executed whenever the `watchExpression` changes.\n\t *\n\t * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest\n\t * $digest()} and should return the value that will be watched. (`watchExpression` should not change\n\t * its value when executed multiple times with the same input because it may be executed multiple\n\t * times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be\n\t * [idempotent](http://en.wikipedia.org/wiki/Idempotence).\n\t * - The `listener` is called only when the value from the current `watchExpression` and the\n\t * previous call to `watchExpression` are not equal (with the exception of the initial run,\n\t * see below). Inequality is determined according to reference inequality,\n\t * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)\n\t * via the `!==` Javascript operator, unless `objectEquality == true`\n\t * (see next point)\n\t * - When `objectEquality == true`, inequality of the `watchExpression` is determined\n\t * according to the {@link angular.equals} function. To save the value of the object for\n\t * later comparison, the {@link angular.copy} function is used. This therefore means that\n\t * watching complex objects will have adverse memory and performance implications.\n\t * - The watch `listener` may change the model, which may trigger other `listener`s to fire.\n\t * This is achieved by rerunning the watchers until no changes are detected. The rerun\n\t * iteration limit is 10 to prevent an infinite loop deadlock.\n\t *\n\t *\n\t * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,\n\t * you can register a `watchExpression` function with no `listener`. (Be prepared for\n\t * multiple calls to your `watchExpression` because it will execute multiple times in a\n\t * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)\n\t *\n\t * After a watcher is registered with the scope, the `listener` fn is called asynchronously\n\t * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the\n\t * watcher. In rare cases, this is undesirable because the listener is called when the result\n\t * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you\n\t * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the\n\t * listener was called due to initialization.\n\t *\n\t *\n\t *\n\t * # Example\n\t * ```js\n\t // let's assume that scope was dependency injected as the $rootScope\n\t var scope = $rootScope;\n\t scope.name = 'misko';\n\t scope.counter = 0;\n\t\n\t expect(scope.counter).toEqual(0);\n\t scope.$watch('name', function(newValue, oldValue) {\n\t scope.counter = scope.counter + 1;\n\t });\n\t expect(scope.counter).toEqual(0);\n\t\n\t scope.$digest();\n\t // the listener is always called during the first $digest loop after it was registered\n\t expect(scope.counter).toEqual(1);\n\t\n\t scope.$digest();\n\t // but now it will not be called unless the value changes\n\t expect(scope.counter).toEqual(1);\n\t\n\t scope.name = 'adam';\n\t scope.$digest();\n\t expect(scope.counter).toEqual(2);\n\t\n\t\n\t\n\t // Using a function as a watchExpression\n\t var food;\n\t scope.foodCounter = 0;\n\t expect(scope.foodCounter).toEqual(0);\n\t scope.$watch(\n\t // This function returns the value being watched. It is called for each turn of the $digest loop\n\t function() { return food; },\n\t // This is the change listener, called when the value returned from the above function changes\n\t function(newValue, oldValue) {\n\t if ( newValue !== oldValue ) {\n\t // Only increment the counter if the value changed\n\t scope.foodCounter = scope.foodCounter + 1;\n\t }\n\t }\n\t );\n\t // No digest has been run so the counter will be zero\n\t expect(scope.foodCounter).toEqual(0);\n\t\n\t // Run the digest but since food has not changed count will still be zero\n\t scope.$digest();\n\t expect(scope.foodCounter).toEqual(0);\n\t\n\t // Update food and run digest. Now the counter will increment\n\t food = 'cheeseburger';\n\t scope.$digest();\n\t expect(scope.foodCounter).toEqual(1);\n\t\n\t * ```\n\t *\n\t *\n\t *\n\t * @param {(function()|string)} watchExpression Expression that is evaluated on each\n\t * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers\n\t * a call to the `listener`.\n\t *\n\t * - `string`: Evaluated as {@link guide/expression expression}\n\t * - `function(scope)`: called with current `scope` as a parameter.\n\t * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value\n\t * of `watchExpression` changes.\n\t *\n\t * - `newVal` contains the current value of the `watchExpression`\n\t * - `oldVal` contains the previous value of the `watchExpression`\n\t * - `scope` refers to the current scope\n\t * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of\n\t * comparing for reference equality.\n\t * @returns {function()} Returns a deregistration function for this listener.\n\t */\n\t $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {\n\t var get = $parse(watchExp);\n\t\n\t if (get.$$watchDelegate) {\n\t return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);\n\t }\n\t var scope = this,\n\t array = scope.$$watchers,\n\t watcher = {\n\t fn: listener,\n\t last: initWatchVal,\n\t get: get,\n\t exp: prettyPrintExpression || watchExp,\n\t eq: !!objectEquality\n\t };\n\t\n\t lastDirtyWatch = null;\n\t\n\t if (!isFunction(listener)) {\n\t watcher.fn = noop;\n\t }\n\t\n\t if (!array) {\n\t array = scope.$$watchers = [];\n\t }\n\t // we use unshift since we use a while loop in $digest for speed.\n\t // the while loop reads in reverse order.\n\t array.unshift(watcher);\n\t incrementWatchersCount(this, 1);\n\t\n\t return function deregisterWatch() {\n\t if (arrayRemove(array, watcher) >= 0) {\n\t incrementWatchersCount(scope, -1);\n\t }\n\t lastDirtyWatch = null;\n\t };\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$watchGroup\n\t * @kind function\n\t *\n\t * @description\n\t * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.\n\t * If any one expression in the collection changes the `listener` is executed.\n\t *\n\t * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every\n\t * call to $digest() to see if any items changes.\n\t * - The `listener` is called whenever any expression in the `watchExpressions` array changes.\n\t *\n\t * @param {Array.} watchExpressions Array of expressions that will be individually\n\t * watched using {@link ng.$rootScope.Scope#$watch $watch()}\n\t *\n\t * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any\n\t * expression in `watchExpressions` changes\n\t * The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching\n\t * those of `watchExpression`\n\t * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching\n\t * those of `watchExpression`\n\t * The `scope` refers to the current scope.\n\t * @returns {function()} Returns a de-registration function for all listeners.\n\t */\n\t $watchGroup: function(watchExpressions, listener) {\n\t var oldValues = new Array(watchExpressions.length);\n\t var newValues = new Array(watchExpressions.length);\n\t var deregisterFns = [];\n\t var self = this;\n\t var changeReactionScheduled = false;\n\t var firstRun = true;\n\t\n\t if (!watchExpressions.length) {\n\t // No expressions means we call the listener ASAP\n\t var shouldCall = true;\n\t self.$evalAsync(function() {\n\t if (shouldCall) listener(newValues, newValues, self);\n\t });\n\t return function deregisterWatchGroup() {\n\t shouldCall = false;\n\t };\n\t }\n\t\n\t if (watchExpressions.length === 1) {\n\t // Special case size of one\n\t return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {\n\t newValues[0] = value;\n\t oldValues[0] = oldValue;\n\t listener(newValues, (value === oldValue) ? newValues : oldValues, scope);\n\t });\n\t }\n\t\n\t forEach(watchExpressions, function(expr, i) {\n\t var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {\n\t newValues[i] = value;\n\t oldValues[i] = oldValue;\n\t if (!changeReactionScheduled) {\n\t changeReactionScheduled = true;\n\t self.$evalAsync(watchGroupAction);\n\t }\n\t });\n\t deregisterFns.push(unwatchFn);\n\t });\n\t\n\t function watchGroupAction() {\n\t changeReactionScheduled = false;\n\t\n\t if (firstRun) {\n\t firstRun = false;\n\t listener(newValues, newValues, self);\n\t } else {\n\t listener(newValues, oldValues, self);\n\t }\n\t }\n\t\n\t return function deregisterWatchGroup() {\n\t while (deregisterFns.length) {\n\t deregisterFns.shift()();\n\t }\n\t };\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$watchCollection\n\t * @kind function\n\t *\n\t * @description\n\t * Shallow watches the properties of an object and fires whenever any of the properties change\n\t * (for arrays, this implies watching the array items; for object maps, this implies watching\n\t * the properties). If a change is detected, the `listener` callback is fired.\n\t *\n\t * - The `obj` collection is observed via standard $watch operation and is examined on every\n\t * call to $digest() to see if any items have been added, removed, or moved.\n\t * - The `listener` is called whenever anything within the `obj` has changed. Examples include\n\t * adding, removing, and moving items belonging to an object or array.\n\t *\n\t *\n\t * # Example\n\t * ```js\n\t $scope.names = ['igor', 'matias', 'misko', 'james'];\n\t $scope.dataCount = 4;\n\t\n\t $scope.$watchCollection('names', function(newNames, oldNames) {\n\t $scope.dataCount = newNames.length;\n\t });\n\t\n\t expect($scope.dataCount).toEqual(4);\n\t $scope.$digest();\n\t\n\t //still at 4 ... no changes\n\t expect($scope.dataCount).toEqual(4);\n\t\n\t $scope.names.pop();\n\t $scope.$digest();\n\t\n\t //now there's been a change\n\t expect($scope.dataCount).toEqual(3);\n\t * ```\n\t *\n\t *\n\t * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The\n\t * expression value should evaluate to an object or an array which is observed on each\n\t * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the\n\t * collection will trigger a call to the `listener`.\n\t *\n\t * @param {function(newCollection, oldCollection, scope)} listener a callback function called\n\t * when a change is detected.\n\t * - The `newCollection` object is the newly modified data obtained from the `obj` expression\n\t * - The `oldCollection` object is a copy of the former collection data.\n\t * Due to performance considerations, the`oldCollection` value is computed only if the\n\t * `listener` function declares two or more arguments.\n\t * - The `scope` argument refers to the current scope.\n\t *\n\t * @returns {function()} Returns a de-registration function for this listener. When the\n\t * de-registration function is executed, the internal watch operation is terminated.\n\t */\n\t $watchCollection: function(obj, listener) {\n\t $watchCollectionInterceptor.$stateful = true;\n\t\n\t var self = this;\n\t // the current value, updated on each dirty-check run\n\t var newValue;\n\t // a shallow copy of the newValue from the last dirty-check run,\n\t // updated to match newValue during dirty-check run\n\t var oldValue;\n\t // a shallow copy of the newValue from when the last change happened\n\t var veryOldValue;\n\t // only track veryOldValue if the listener is asking for it\n\t var trackVeryOldValue = (listener.length > 1);\n\t var changeDetected = 0;\n\t var changeDetector = $parse(obj, $watchCollectionInterceptor);\n\t var internalArray = [];\n\t var internalObject = {};\n\t var initRun = true;\n\t var oldLength = 0;\n\t\n\t function $watchCollectionInterceptor(_value) {\n\t newValue = _value;\n\t var newLength, key, bothNaN, newItem, oldItem;\n\t\n\t // If the new value is undefined, then return undefined as the watch may be a one-time watch\n\t if (isUndefined(newValue)) return;\n\t\n\t if (!isObject(newValue)) { // if primitive\n\t if (oldValue !== newValue) {\n\t oldValue = newValue;\n\t changeDetected++;\n\t }\n\t } else if (isArrayLike(newValue)) {\n\t if (oldValue !== internalArray) {\n\t // we are transitioning from something which was not an array into array.\n\t oldValue = internalArray;\n\t oldLength = oldValue.length = 0;\n\t changeDetected++;\n\t }\n\t\n\t newLength = newValue.length;\n\t\n\t if (oldLength !== newLength) {\n\t // if lengths do not match we need to trigger change notification\n\t changeDetected++;\n\t oldValue.length = oldLength = newLength;\n\t }\n\t // copy the items to oldValue and look for changes.\n\t for (var i = 0; i < newLength; i++) {\n\t oldItem = oldValue[i];\n\t newItem = newValue[i];\n\t\n\t bothNaN = (oldItem !== oldItem) && (newItem !== newItem);\n\t if (!bothNaN && (oldItem !== newItem)) {\n\t changeDetected++;\n\t oldValue[i] = newItem;\n\t }\n\t }\n\t } else {\n\t if (oldValue !== internalObject) {\n\t // we are transitioning from something which was not an object into object.\n\t oldValue = internalObject = {};\n\t oldLength = 0;\n\t changeDetected++;\n\t }\n\t // copy the items to oldValue and look for changes.\n\t newLength = 0;\n\t for (key in newValue) {\n\t if (hasOwnProperty.call(newValue, key)) {\n\t newLength++;\n\t newItem = newValue[key];\n\t oldItem = oldValue[key];\n\t\n\t if (key in oldValue) {\n\t bothNaN = (oldItem !== oldItem) && (newItem !== newItem);\n\t if (!bothNaN && (oldItem !== newItem)) {\n\t changeDetected++;\n\t oldValue[key] = newItem;\n\t }\n\t } else {\n\t oldLength++;\n\t oldValue[key] = newItem;\n\t changeDetected++;\n\t }\n\t }\n\t }\n\t if (oldLength > newLength) {\n\t // we used to have more keys, need to find them and destroy them.\n\t changeDetected++;\n\t for (key in oldValue) {\n\t if (!hasOwnProperty.call(newValue, key)) {\n\t oldLength--;\n\t delete oldValue[key];\n\t }\n\t }\n\t }\n\t }\n\t return changeDetected;\n\t }\n\t\n\t function $watchCollectionAction() {\n\t if (initRun) {\n\t initRun = false;\n\t listener(newValue, newValue, self);\n\t } else {\n\t listener(newValue, veryOldValue, self);\n\t }\n\t\n\t // make a copy for the next time a collection is changed\n\t if (trackVeryOldValue) {\n\t if (!isObject(newValue)) {\n\t //primitive\n\t veryOldValue = newValue;\n\t } else if (isArrayLike(newValue)) {\n\t veryOldValue = new Array(newValue.length);\n\t for (var i = 0; i < newValue.length; i++) {\n\t veryOldValue[i] = newValue[i];\n\t }\n\t } else { // if object\n\t veryOldValue = {};\n\t for (var key in newValue) {\n\t if (hasOwnProperty.call(newValue, key)) {\n\t veryOldValue[key] = newValue[key];\n\t }\n\t }\n\t }\n\t }\n\t }\n\t\n\t return this.$watch(changeDetector, $watchCollectionAction);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$digest\n\t * @kind function\n\t *\n\t * @description\n\t * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and\n\t * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change\n\t * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}\n\t * until no more listeners are firing. This means that it is possible to get into an infinite\n\t * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of\n\t * iterations exceeds 10.\n\t *\n\t * Usually, you don't call `$digest()` directly in\n\t * {@link ng.directive:ngController controllers} or in\n\t * {@link ng.$compileProvider#directive directives}.\n\t * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within\n\t * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.\n\t *\n\t * If you want to be notified whenever `$digest()` is called,\n\t * you can register a `watchExpression` function with\n\t * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.\n\t *\n\t * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.\n\t *\n\t * # Example\n\t * ```js\n\t var scope = ...;\n\t scope.name = 'misko';\n\t scope.counter = 0;\n\t\n\t expect(scope.counter).toEqual(0);\n\t scope.$watch('name', function(newValue, oldValue) {\n\t scope.counter = scope.counter + 1;\n\t });\n\t expect(scope.counter).toEqual(0);\n\t\n\t scope.$digest();\n\t // the listener is always called during the first $digest loop after it was registered\n\t expect(scope.counter).toEqual(1);\n\t\n\t scope.$digest();\n\t // but now it will not be called unless the value changes\n\t expect(scope.counter).toEqual(1);\n\t\n\t scope.name = 'adam';\n\t scope.$digest();\n\t expect(scope.counter).toEqual(2);\n\t * ```\n\t *\n\t */\n\t $digest: function() {\n\t var watch, value, last, fn, get,\n\t watchers,\n\t length,\n\t dirty, ttl = TTL,\n\t next, current, target = this,\n\t watchLog = [],\n\t logIdx, asyncTask;\n\t\n\t beginPhase('$digest');\n\t // Check for changes to browser url that happened in sync before the call to $digest\n\t $browser.$$checkUrlChange();\n\t\n\t if (this === $rootScope && applyAsyncId !== null) {\n\t // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then\n\t // cancel the scheduled $apply and flush the queue of expressions to be evaluated.\n\t $browser.defer.cancel(applyAsyncId);\n\t flushApplyAsync();\n\t }\n\t\n\t lastDirtyWatch = null;\n\t\n\t do { // \"while dirty\" loop\n\t dirty = false;\n\t current = target;\n\t\n\t // It's safe for asyncQueuePosition to be a local variable here because this loop can't\n\t // be reentered recursively. Calling $digest from a function passed to $applyAsync would\n\t // lead to a '$digest already in progress' error.\n\t for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {\n\t try {\n\t asyncTask = asyncQueue[asyncQueuePosition];\n\t asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t lastDirtyWatch = null;\n\t }\n\t asyncQueue.length = 0;\n\t\n\t traverseScopesLoop:\n\t do { // \"traverse the scopes\" loop\n\t if ((watchers = current.$$watchers)) {\n\t // process our watches\n\t length = watchers.length;\n\t while (length--) {\n\t try {\n\t watch = watchers[length];\n\t // Most common watches are on primitives, in which case we can short\n\t // circuit it with === operator, only when === fails do we use .equals\n\t if (watch) {\n\t get = watch.get;\n\t if ((value = get(current)) !== (last = watch.last) &&\n\t !(watch.eq\n\t ? equals(value, last)\n\t : (typeof value === 'number' && typeof last === 'number'\n\t && isNaN(value) && isNaN(last)))) {\n\t dirty = true;\n\t lastDirtyWatch = watch;\n\t watch.last = watch.eq ? copy(value, null) : value;\n\t fn = watch.fn;\n\t fn(value, ((last === initWatchVal) ? value : last), current);\n\t if (ttl < 5) {\n\t logIdx = 4 - ttl;\n\t if (!watchLog[logIdx]) watchLog[logIdx] = [];\n\t watchLog[logIdx].push({\n\t msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,\n\t newVal: value,\n\t oldVal: last\n\t });\n\t }\n\t } else if (watch === lastDirtyWatch) {\n\t // If the most recently dirty watcher is now clean, short circuit since the remaining watchers\n\t // have already been tested.\n\t dirty = false;\n\t break traverseScopesLoop;\n\t }\n\t }\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t }\n\t\n\t // Insanity Warning: scope depth-first traversal\n\t // yes, this code is a bit crazy, but it works and we have tests to prove it!\n\t // this piece should be kept in sync with the traversal in $broadcast\n\t if (!(next = ((current.$$watchersCount && current.$$childHead) ||\n\t (current !== target && current.$$nextSibling)))) {\n\t while (current !== target && !(next = current.$$nextSibling)) {\n\t current = current.$parent;\n\t }\n\t }\n\t } while ((current = next));\n\t\n\t // `break traverseScopesLoop;` takes us to here\n\t\n\t if ((dirty || asyncQueue.length) && !(ttl--)) {\n\t clearPhase();\n\t throw $rootScopeMinErr('infdig',\n\t '{0} $digest() iterations reached. Aborting!\\n' +\n\t 'Watchers fired in the last 5 iterations: {1}',\n\t TTL, watchLog);\n\t }\n\t\n\t } while (dirty || asyncQueue.length);\n\t\n\t clearPhase();\n\t\n\t // postDigestQueuePosition isn't local here because this loop can be reentered recursively.\n\t while (postDigestQueuePosition < postDigestQueue.length) {\n\t try {\n\t postDigestQueue[postDigestQueuePosition++]();\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t postDigestQueue.length = postDigestQueuePosition = 0;\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc event\n\t * @name $rootScope.Scope#$destroy\n\t * @eventType broadcast on scope being destroyed\n\t *\n\t * @description\n\t * Broadcasted when a scope and its children are being destroyed.\n\t *\n\t * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to\n\t * clean up DOM bindings before an element is removed from the DOM.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$destroy\n\t * @kind function\n\t *\n\t * @description\n\t * Removes the current scope (and all of its children) from the parent scope. Removal implies\n\t * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer\n\t * propagate to the current scope and its children. Removal also implies that the current\n\t * scope is eligible for garbage collection.\n\t *\n\t * The `$destroy()` is usually used by directives such as\n\t * {@link ng.directive:ngRepeat ngRepeat} for managing the\n\t * unrolling of the loop.\n\t *\n\t * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.\n\t * Application code can register a `$destroy` event handler that will give it a chance to\n\t * perform any necessary cleanup.\n\t *\n\t * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to\n\t * clean up DOM bindings before an element is removed from the DOM.\n\t */\n\t $destroy: function() {\n\t // We can't destroy a scope that has been already destroyed.\n\t if (this.$$destroyed) return;\n\t var parent = this.$parent;\n\t\n\t this.$broadcast('$destroy');\n\t this.$$destroyed = true;\n\t\n\t if (this === $rootScope) {\n\t //Remove handlers attached to window when $rootScope is removed\n\t $browser.$$applicationDestroyed();\n\t }\n\t\n\t incrementWatchersCount(this, -this.$$watchersCount);\n\t for (var eventName in this.$$listenerCount) {\n\t decrementListenerCount(this, this.$$listenerCount[eventName], eventName);\n\t }\n\t\n\t // sever all the references to parent scopes (after this cleanup, the current scope should\n\t // not be retained by any of our references and should be eligible for garbage collection)\n\t if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;\n\t if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;\n\t if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;\n\t if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;\n\t\n\t // Disable listeners, watchers and apply/digest methods\n\t this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;\n\t this.$on = this.$watch = this.$watchGroup = function() { return noop; };\n\t this.$$listeners = {};\n\t\n\t // Disconnect the next sibling to prevent `cleanUpScope` destroying those too\n\t this.$$nextSibling = null;\n\t cleanUpScope(this);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$eval\n\t * @kind function\n\t *\n\t * @description\n\t * Executes the `expression` on the current scope and returns the result. Any exceptions in\n\t * the expression are propagated (uncaught). This is useful when evaluating Angular\n\t * expressions.\n\t *\n\t * # Example\n\t * ```js\n\t var scope = ng.$rootScope.Scope();\n\t scope.a = 1;\n\t scope.b = 2;\n\t\n\t expect(scope.$eval('a+b')).toEqual(3);\n\t expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);\n\t * ```\n\t *\n\t * @param {(string|function())=} expression An angular expression to be executed.\n\t *\n\t * - `string`: execute using the rules as defined in {@link guide/expression expression}.\n\t * - `function(scope)`: execute the function with the current `scope` parameter.\n\t *\n\t * @param {(object)=} locals Local variables object, useful for overriding values in scope.\n\t * @returns {*} The result of evaluating the expression.\n\t */\n\t $eval: function(expr, locals) {\n\t return $parse(expr)(this, locals);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$evalAsync\n\t * @kind function\n\t *\n\t * @description\n\t * Executes the expression on the current scope at a later point in time.\n\t *\n\t * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only\n\t * that:\n\t *\n\t * - it will execute after the function that scheduled the evaluation (preferably before DOM\n\t * rendering).\n\t * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after\n\t * `expression` execution.\n\t *\n\t * Any exceptions from the execution of the expression are forwarded to the\n\t * {@link ng.$exceptionHandler $exceptionHandler} service.\n\t *\n\t * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle\n\t * will be scheduled. However, it is encouraged to always call code that changes the model\n\t * from within an `$apply` call. That includes code evaluated via `$evalAsync`.\n\t *\n\t * @param {(string|function())=} expression An angular expression to be executed.\n\t *\n\t * - `string`: execute using the rules as defined in {@link guide/expression expression}.\n\t * - `function(scope)`: execute the function with the current `scope` parameter.\n\t *\n\t * @param {(object)=} locals Local variables object, useful for overriding values in scope.\n\t */\n\t $evalAsync: function(expr, locals) {\n\t // if we are outside of an $digest loop and this is the first time we are scheduling async\n\t // task also schedule async auto-flush\n\t if (!$rootScope.$$phase && !asyncQueue.length) {\n\t $browser.defer(function() {\n\t if (asyncQueue.length) {\n\t $rootScope.$digest();\n\t }\n\t });\n\t }\n\t\n\t asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});\n\t },\n\t\n\t $$postDigest: function(fn) {\n\t postDigestQueue.push(fn);\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$apply\n\t * @kind function\n\t *\n\t * @description\n\t * `$apply()` is used to execute an expression in angular from outside of the angular\n\t * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).\n\t * Because we are calling into the angular framework we need to perform proper scope life\n\t * cycle of {@link ng.$exceptionHandler exception handling},\n\t * {@link ng.$rootScope.Scope#$digest executing watches}.\n\t *\n\t * ## Life cycle\n\t *\n\t * # Pseudo-Code of `$apply()`\n\t * ```js\n\t function $apply(expr) {\n\t try {\n\t return $eval(expr);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t } finally {\n\t $root.$digest();\n\t }\n\t }\n\t * ```\n\t *\n\t *\n\t * Scope's `$apply()` method transitions through the following stages:\n\t *\n\t * 1. The {@link guide/expression expression} is executed using the\n\t * {@link ng.$rootScope.Scope#$eval $eval()} method.\n\t * 2. Any exceptions from the execution of the expression are forwarded to the\n\t * {@link ng.$exceptionHandler $exceptionHandler} service.\n\t * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the\n\t * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.\n\t *\n\t *\n\t * @param {(string|function())=} exp An angular expression to be executed.\n\t *\n\t * - `string`: execute using the rules as defined in {@link guide/expression expression}.\n\t * - `function(scope)`: execute the function with current `scope` parameter.\n\t *\n\t * @returns {*} The result of evaluating the expression.\n\t */\n\t $apply: function(expr) {\n\t try {\n\t beginPhase('$apply');\n\t try {\n\t return this.$eval(expr);\n\t } finally {\n\t clearPhase();\n\t }\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t } finally {\n\t try {\n\t $rootScope.$digest();\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t throw e;\n\t }\n\t }\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$applyAsync\n\t * @kind function\n\t *\n\t * @description\n\t * Schedule the invocation of $apply to occur at a later time. The actual time difference\n\t * varies across browsers, but is typically around ~10 milliseconds.\n\t *\n\t * This can be used to queue up multiple expressions which need to be evaluated in the same\n\t * digest.\n\t *\n\t * @param {(string|function())=} exp An angular expression to be executed.\n\t *\n\t * - `string`: execute using the rules as defined in {@link guide/expression expression}.\n\t * - `function(scope)`: execute the function with current `scope` parameter.\n\t */\n\t $applyAsync: function(expr) {\n\t var scope = this;\n\t expr && applyAsyncQueue.push($applyAsyncExpression);\n\t expr = $parse(expr);\n\t scheduleApplyAsync();\n\t\n\t function $applyAsyncExpression() {\n\t scope.$eval(expr);\n\t }\n\t },\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$on\n\t * @kind function\n\t *\n\t * @description\n\t * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for\n\t * discussion of event life cycle.\n\t *\n\t * The event listener function format is: `function(event, args...)`. The `event` object\n\t * passed into the listener has the following attributes:\n\t *\n\t * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or\n\t * `$broadcast`-ed.\n\t * - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the\n\t * event propagates through the scope hierarchy, this property is set to null.\n\t * - `name` - `{string}`: name of the event.\n\t * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel\n\t * further event propagation (available only for events that were `$emit`-ed).\n\t * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag\n\t * to true.\n\t * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.\n\t *\n\t * @param {string} name Event name to listen on.\n\t * @param {function(event, ...args)} listener Function to call when the event is emitted.\n\t * @returns {function()} Returns a deregistration function for this listener.\n\t */\n\t $on: function(name, listener) {\n\t var namedListeners = this.$$listeners[name];\n\t if (!namedListeners) {\n\t this.$$listeners[name] = namedListeners = [];\n\t }\n\t namedListeners.push(listener);\n\t\n\t var current = this;\n\t do {\n\t if (!current.$$listenerCount[name]) {\n\t current.$$listenerCount[name] = 0;\n\t }\n\t current.$$listenerCount[name]++;\n\t } while ((current = current.$parent));\n\t\n\t var self = this;\n\t return function() {\n\t var indexOfListener = namedListeners.indexOf(listener);\n\t if (indexOfListener !== -1) {\n\t namedListeners[indexOfListener] = null;\n\t decrementListenerCount(self, 1, name);\n\t }\n\t };\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$emit\n\t * @kind function\n\t *\n\t * @description\n\t * Dispatches an event `name` upwards through the scope hierarchy notifying the\n\t * registered {@link ng.$rootScope.Scope#$on} listeners.\n\t *\n\t * The event life cycle starts at the scope on which `$emit` was called. All\n\t * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get\n\t * notified. Afterwards, the event traverses upwards toward the root scope and calls all\n\t * registered listeners along the way. The event will stop propagating if one of the listeners\n\t * cancels it.\n\t *\n\t * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed\n\t * onto the {@link ng.$exceptionHandler $exceptionHandler} service.\n\t *\n\t * @param {string} name Event name to emit.\n\t * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.\n\t * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).\n\t */\n\t $emit: function(name, args) {\n\t var empty = [],\n\t namedListeners,\n\t scope = this,\n\t stopPropagation = false,\n\t event = {\n\t name: name,\n\t targetScope: scope,\n\t stopPropagation: function() {stopPropagation = true;},\n\t preventDefault: function() {\n\t event.defaultPrevented = true;\n\t },\n\t defaultPrevented: false\n\t },\n\t listenerArgs = concat([event], arguments, 1),\n\t i, length;\n\t\n\t do {\n\t namedListeners = scope.$$listeners[name] || empty;\n\t event.currentScope = scope;\n\t for (i = 0, length = namedListeners.length; i < length; i++) {\n\t\n\t // if listeners were deregistered, defragment the array\n\t if (!namedListeners[i]) {\n\t namedListeners.splice(i, 1);\n\t i--;\n\t length--;\n\t continue;\n\t }\n\t try {\n\t //allow all listeners attached to the current scope to run\n\t namedListeners[i].apply(null, listenerArgs);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t //if any listener on the current scope stops propagation, prevent bubbling\n\t if (stopPropagation) {\n\t event.currentScope = null;\n\t return event;\n\t }\n\t //traverse upwards\n\t scope = scope.$parent;\n\t } while (scope);\n\t\n\t event.currentScope = null;\n\t\n\t return event;\n\t },\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $rootScope.Scope#$broadcast\n\t * @kind function\n\t *\n\t * @description\n\t * Dispatches an event `name` downwards to all child scopes (and their children) notifying the\n\t * registered {@link ng.$rootScope.Scope#$on} listeners.\n\t *\n\t * The event life cycle starts at the scope on which `$broadcast` was called. All\n\t * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get\n\t * notified. Afterwards, the event propagates to all direct and indirect scopes of the current\n\t * scope and calls all registered listeners along the way. The event cannot be canceled.\n\t *\n\t * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed\n\t * onto the {@link ng.$exceptionHandler $exceptionHandler} service.\n\t *\n\t * @param {string} name Event name to broadcast.\n\t * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.\n\t * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}\n\t */\n\t $broadcast: function(name, args) {\n\t var target = this,\n\t current = target,\n\t next = target,\n\t event = {\n\t name: name,\n\t targetScope: target,\n\t preventDefault: function() {\n\t event.defaultPrevented = true;\n\t },\n\t defaultPrevented: false\n\t };\n\t\n\t if (!target.$$listenerCount[name]) return event;\n\t\n\t var listenerArgs = concat([event], arguments, 1),\n\t listeners, i, length;\n\t\n\t //down while you can, then up and next sibling or up and next sibling until back at root\n\t while ((current = next)) {\n\t event.currentScope = current;\n\t listeners = current.$$listeners[name] || [];\n\t for (i = 0, length = listeners.length; i < length; i++) {\n\t // if listeners were deregistered, defragment the array\n\t if (!listeners[i]) {\n\t listeners.splice(i, 1);\n\t i--;\n\t length--;\n\t continue;\n\t }\n\t\n\t try {\n\t listeners[i].apply(null, listenerArgs);\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t\n\t // Insanity Warning: scope depth-first traversal\n\t // yes, this code is a bit crazy, but it works and we have tests to prove it!\n\t // this piece should be kept in sync with the traversal in $digest\n\t // (though it differs due to having the extra check for $$listenerCount)\n\t if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||\n\t (current !== target && current.$$nextSibling)))) {\n\t while (current !== target && !(next = current.$$nextSibling)) {\n\t current = current.$parent;\n\t }\n\t }\n\t }\n\t\n\t event.currentScope = null;\n\t return event;\n\t }\n\t };\n\t\n\t var $rootScope = new Scope();\n\t\n\t //The internal queues. Expose them on the $rootScope for debugging/testing purposes.\n\t var asyncQueue = $rootScope.$$asyncQueue = [];\n\t var postDigestQueue = $rootScope.$$postDigestQueue = [];\n\t var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];\n\t\n\t var postDigestQueuePosition = 0;\n\t\n\t return $rootScope;\n\t\n\t\n\t function beginPhase(phase) {\n\t if ($rootScope.$$phase) {\n\t throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);\n\t }\n\t\n\t $rootScope.$$phase = phase;\n\t }\n\t\n\t function clearPhase() {\n\t $rootScope.$$phase = null;\n\t }\n\t\n\t function incrementWatchersCount(current, count) {\n\t do {\n\t current.$$watchersCount += count;\n\t } while ((current = current.$parent));\n\t }\n\t\n\t function decrementListenerCount(current, count, name) {\n\t do {\n\t current.$$listenerCount[name] -= count;\n\t\n\t if (current.$$listenerCount[name] === 0) {\n\t delete current.$$listenerCount[name];\n\t }\n\t } while ((current = current.$parent));\n\t }\n\t\n\t /**\n\t * function used as an initial value for watchers.\n\t * because it's unique we can easily tell it apart from other values\n\t */\n\t function initWatchVal() {}\n\t\n\t function flushApplyAsync() {\n\t while (applyAsyncQueue.length) {\n\t try {\n\t applyAsyncQueue.shift()();\n\t } catch (e) {\n\t $exceptionHandler(e);\n\t }\n\t }\n\t applyAsyncId = null;\n\t }\n\t\n\t function scheduleApplyAsync() {\n\t if (applyAsyncId === null) {\n\t applyAsyncId = $browser.defer(function() {\n\t $rootScope.$apply(flushApplyAsync);\n\t });\n\t }\n\t }\n\t }];\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $rootElement\n\t *\n\t * @description\n\t * The root element of Angular application. This is either the element where {@link\n\t * ng.directive:ngApp ngApp} was declared or the element passed into\n\t * {@link angular.bootstrap}. The element represents the root element of application. It is also the\n\t * location where the application's {@link auto.$injector $injector} service gets\n\t * published, and can be retrieved using `$rootElement.injector()`.\n\t */\n\t\n\t\n\t// the implementation is in angular.bootstrap\n\t\n\t/**\n\t * @description\n\t * Private service to sanitize uris for links and images. Used by $compile and $sanitize.\n\t */\n\tfunction $$SanitizeUriProvider() {\n\t var aHrefSanitizationWhitelist = /^\\s*(https?|ftp|mailto|tel|file):/,\n\t imgSrcSanitizationWhitelist = /^\\s*((https?|ftp|file|blob):|data:image\\/)/;\n\t\n\t /**\n\t * @description\n\t * Retrieves or overrides the default regular expression that is used for whitelisting of safe\n\t * urls during a[href] sanitization.\n\t *\n\t * The sanitization is a security measure aimed at prevent XSS attacks via html links.\n\t *\n\t * Any url about to be assigned to a[href] via data-binding is first normalized and turned into\n\t * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`\n\t * regular expression. If a match is found, the original url is written into the dom. Otherwise,\n\t * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.\n\t *\n\t * @param {RegExp=} regexp New regexp to whitelist urls with.\n\t * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for\n\t * chaining otherwise.\n\t */\n\t this.aHrefSanitizationWhitelist = function(regexp) {\n\t if (isDefined(regexp)) {\n\t aHrefSanitizationWhitelist = regexp;\n\t return this;\n\t }\n\t return aHrefSanitizationWhitelist;\n\t };\n\t\n\t\n\t /**\n\t * @description\n\t * Retrieves or overrides the default regular expression that is used for whitelisting of safe\n\t * urls during img[src] sanitization.\n\t *\n\t * The sanitization is a security measure aimed at prevent XSS attacks via html links.\n\t *\n\t * Any url about to be assigned to img[src] via data-binding is first normalized and turned into\n\t * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`\n\t * regular expression. If a match is found, the original url is written into the dom. Otherwise,\n\t * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.\n\t *\n\t * @param {RegExp=} regexp New regexp to whitelist urls with.\n\t * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for\n\t * chaining otherwise.\n\t */\n\t this.imgSrcSanitizationWhitelist = function(regexp) {\n\t if (isDefined(regexp)) {\n\t imgSrcSanitizationWhitelist = regexp;\n\t return this;\n\t }\n\t return imgSrcSanitizationWhitelist;\n\t };\n\t\n\t this.$get = function() {\n\t return function sanitizeUri(uri, isImage) {\n\t var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;\n\t var normalizedVal;\n\t normalizedVal = urlResolve(uri).href;\n\t if (normalizedVal !== '' && !normalizedVal.match(regex)) {\n\t return 'unsafe:' + normalizedVal;\n\t }\n\t return uri;\n\t };\n\t };\n\t}\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Any commits to this file should be reviewed with security in mind. *\n\t * Changes to this file can potentially create security vulnerabilities. *\n\t * An approval from 2 Core members with history of modifying *\n\t * this file is required. *\n\t * *\n\t * Does the change somehow allow for arbitrary javascript to be executed? *\n\t * Or allows for someone to change the prototype of built-in objects? *\n\t * Or gives undesired access to variables likes document or window? *\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\tvar $sceMinErr = minErr('$sce');\n\t\n\tvar SCE_CONTEXTS = {\n\t HTML: 'html',\n\t CSS: 'css',\n\t URL: 'url',\n\t // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a\n\t // url. (e.g. ng-include, script src, templateUrl)\n\t RESOURCE_URL: 'resourceUrl',\n\t JS: 'js'\n\t};\n\t\n\t// Helper functions follow.\n\t\n\tfunction adjustMatcher(matcher) {\n\t if (matcher === 'self') {\n\t return matcher;\n\t } else if (isString(matcher)) {\n\t // Strings match exactly except for 2 wildcards - '*' and '**'.\n\t // '*' matches any character except those from the set ':/.?&'.\n\t // '**' matches any character (like .* in a RegExp).\n\t // More than 2 *'s raises an error as it's ill defined.\n\t if (matcher.indexOf('***') > -1) {\n\t throw $sceMinErr('iwcard',\n\t 'Illegal sequence *** in string matcher. String: {0}', matcher);\n\t }\n\t matcher = escapeForRegexp(matcher).\n\t replace('\\\\*\\\\*', '.*').\n\t replace('\\\\*', '[^:/.?&;]*');\n\t return new RegExp('^' + matcher + '$');\n\t } else if (isRegExp(matcher)) {\n\t // The only other type of matcher allowed is a Regexp.\n\t // Match entire URL / disallow partial matches.\n\t // Flags are reset (i.e. no global, ignoreCase or multiline)\n\t return new RegExp('^' + matcher.source + '$');\n\t } else {\n\t throw $sceMinErr('imatcher',\n\t 'Matchers may only be \"self\", string patterns or RegExp objects');\n\t }\n\t}\n\t\n\t\n\tfunction adjustMatchers(matchers) {\n\t var adjustedMatchers = [];\n\t if (isDefined(matchers)) {\n\t forEach(matchers, function(matcher) {\n\t adjustedMatchers.push(adjustMatcher(matcher));\n\t });\n\t }\n\t return adjustedMatchers;\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $sceDelegate\n\t * @kind function\n\t *\n\t * @description\n\t *\n\t * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict\n\t * Contextual Escaping (SCE)} services to AngularJS.\n\t *\n\t * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of\n\t * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is\n\t * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to\n\t * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things\n\t * work because `$sce` delegates to `$sceDelegate` for these operations.\n\t *\n\t * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.\n\t *\n\t * The default instance of `$sceDelegate` should work out of the box with little pain. While you\n\t * can override it completely to change the behavior of `$sce`, the common case would\n\t * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting\n\t * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as\n\t * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist\n\t * $sceDelegateProvider.resourceUrlWhitelist} and {@link\n\t * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}\n\t */\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $sceDelegateProvider\n\t * @description\n\t *\n\t * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate\n\t * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure\n\t * that the URLs used for sourcing Angular templates are safe. Refer {@link\n\t * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and\n\t * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}\n\t *\n\t * For the general details about this service in Angular, read the main page for {@link ng.$sce\n\t * Strict Contextual Escaping (SCE)}.\n\t *\n\t * **Example**: Consider the following case. \n\t *\n\t * - your app is hosted at url `http://myapp.example.com/`\n\t * - but some of your templates are hosted on other domains you control such as\n\t * `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.\n\t * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.\n\t *\n\t * Here is what a secure configuration for this scenario might look like:\n\t *\n\t * ```\n\t * angular.module('myApp', []).config(function($sceDelegateProvider) {\n\t * $sceDelegateProvider.resourceUrlWhitelist([\n\t * // Allow same origin resource loads.\n\t * 'self',\n\t * // Allow loading from our assets domain. Notice the difference between * and **.\n\t * 'http://srv*.assets.example.com/**'\n\t * ]);\n\t *\n\t * // The blacklist overrides the whitelist so the open redirect here is blocked.\n\t * $sceDelegateProvider.resourceUrlBlacklist([\n\t * 'http://myapp.example.com/clickThru**'\n\t * ]);\n\t * });\n\t * ```\n\t */\n\t\n\tfunction $SceDelegateProvider() {\n\t this.SCE_CONTEXTS = SCE_CONTEXTS;\n\t\n\t // Resource URLs can also be trusted by policy.\n\t var resourceUrlWhitelist = ['self'],\n\t resourceUrlBlacklist = [];\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceDelegateProvider#resourceUrlWhitelist\n\t * @kind function\n\t *\n\t * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value\n\t * provided. This must be an array or null. A snapshot of this array is used so further\n\t * changes to the array are ignored.\n\t *\n\t * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items\n\t * allowed in this array.\n\t *\n\t *
\n\t * **Note:** an empty whitelist array will block all URLs!\n\t *
\n\t *\n\t * @return {Array} the currently set whitelist array.\n\t *\n\t * The **default value** when no whitelist has been explicitly set is `['self']` allowing only\n\t * same origin resource requests.\n\t *\n\t * @description\n\t * Sets/Gets the whitelist of trusted resource URLs.\n\t */\n\t this.resourceUrlWhitelist = function(value) {\n\t if (arguments.length) {\n\t resourceUrlWhitelist = adjustMatchers(value);\n\t }\n\t return resourceUrlWhitelist;\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceDelegateProvider#resourceUrlBlacklist\n\t * @kind function\n\t *\n\t * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value\n\t * provided. This must be an array or null. A snapshot of this array is used so further\n\t * changes to the array are ignored.\n\t *\n\t * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items\n\t * allowed in this array.\n\t *\n\t * The typical usage for the blacklist is to **block\n\t * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as\n\t * these would otherwise be trusted but actually return content from the redirected domain.\n\t *\n\t * Finally, **the blacklist overrides the whitelist** and has the final say.\n\t *\n\t * @return {Array} the currently set blacklist array.\n\t *\n\t * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there\n\t * is no blacklist.)\n\t *\n\t * @description\n\t * Sets/Gets the blacklist of trusted resource URLs.\n\t */\n\t\n\t this.resourceUrlBlacklist = function(value) {\n\t if (arguments.length) {\n\t resourceUrlBlacklist = adjustMatchers(value);\n\t }\n\t return resourceUrlBlacklist;\n\t };\n\t\n\t this.$get = ['$injector', function($injector) {\n\t\n\t var htmlSanitizer = function htmlSanitizer(html) {\n\t throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');\n\t };\n\t\n\t if ($injector.has('$sanitize')) {\n\t htmlSanitizer = $injector.get('$sanitize');\n\t }\n\t\n\t\n\t function matchUrl(matcher, parsedUrl) {\n\t if (matcher === 'self') {\n\t return urlIsSameOrigin(parsedUrl);\n\t } else {\n\t // definitely a regex. See adjustMatchers()\n\t return !!matcher.exec(parsedUrl.href);\n\t }\n\t }\n\t\n\t function isResourceUrlAllowedByPolicy(url) {\n\t var parsedUrl = urlResolve(url.toString());\n\t var i, n, allowed = false;\n\t // Ensure that at least one item from the whitelist allows this url.\n\t for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {\n\t if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {\n\t allowed = true;\n\t break;\n\t }\n\t }\n\t if (allowed) {\n\t // Ensure that no item from the blacklist blocked this url.\n\t for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {\n\t if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {\n\t allowed = false;\n\t break;\n\t }\n\t }\n\t }\n\t return allowed;\n\t }\n\t\n\t function generateHolderType(Base) {\n\t var holderType = function TrustedValueHolderType(trustedValue) {\n\t this.$$unwrapTrustedValue = function() {\n\t return trustedValue;\n\t };\n\t };\n\t if (Base) {\n\t holderType.prototype = new Base();\n\t }\n\t holderType.prototype.valueOf = function sceValueOf() {\n\t return this.$$unwrapTrustedValue();\n\t };\n\t holderType.prototype.toString = function sceToString() {\n\t return this.$$unwrapTrustedValue().toString();\n\t };\n\t return holderType;\n\t }\n\t\n\t var trustedValueHolderBase = generateHolderType(),\n\t byType = {};\n\t\n\t byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);\n\t byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);\n\t byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);\n\t byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);\n\t byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceDelegate#trustAs\n\t *\n\t * @description\n\t * Returns an object that is trusted by angular for use in specified strict\n\t * contextual escaping contexts (such as ng-bind-html, ng-include, any src\n\t * attribute interpolation, any dom event binding attribute interpolation\n\t * such as for onclick, etc.) that uses the provided value.\n\t * See {@link ng.$sce $sce} for enabling strict contextual escaping.\n\t *\n\t * @param {string} type The kind of context in which this value is safe for use. e.g. url,\n\t * resourceUrl, html, js and css.\n\t * @param {*} value The value that that should be considered trusted/safe.\n\t * @returns {*} A value that can be used to stand in for the provided `value` in places\n\t * where Angular expects a $sce.trustAs() return value.\n\t */\n\t function trustAs(type, trustedValue) {\n\t var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);\n\t if (!Constructor) {\n\t throw $sceMinErr('icontext',\n\t 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',\n\t type, trustedValue);\n\t }\n\t if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {\n\t return trustedValue;\n\t }\n\t // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting\n\t // mutable objects, we ensure here that the value passed in is actually a string.\n\t if (typeof trustedValue !== 'string') {\n\t throw $sceMinErr('itype',\n\t 'Attempted to trust a non-string value in a content requiring a string: Context: {0}',\n\t type);\n\t }\n\t return new Constructor(trustedValue);\n\t }\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceDelegate#valueOf\n\t *\n\t * @description\n\t * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs\n\t * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link\n\t * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.\n\t *\n\t * If the passed parameter is not a value that had been returned by {@link\n\t * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.\n\t *\n\t * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}\n\t * call or anything else.\n\t * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs\n\t * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns\n\t * `value` unchanged.\n\t */\n\t function valueOf(maybeTrusted) {\n\t if (maybeTrusted instanceof trustedValueHolderBase) {\n\t return maybeTrusted.$$unwrapTrustedValue();\n\t } else {\n\t return maybeTrusted;\n\t }\n\t }\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceDelegate#getTrusted\n\t *\n\t * @description\n\t * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and\n\t * returns the originally supplied value if the queried context type is a supertype of the\n\t * created type. If this condition isn't satisfied, throws an exception.\n\t *\n\t *
\n\t * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting\n\t * (XSS) vulnerability in your application.\n\t *
\n\t *\n\t * @param {string} type The kind of context in which this value is to be used.\n\t * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs\n\t * `$sceDelegate.trustAs`} call.\n\t * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs\n\t * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception.\n\t */\n\t function getTrusted(type, maybeTrusted) {\n\t if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {\n\t return maybeTrusted;\n\t }\n\t var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);\n\t if (constructor && maybeTrusted instanceof constructor) {\n\t return maybeTrusted.$$unwrapTrustedValue();\n\t }\n\t // If we get here, then we may only take one of two actions.\n\t // 1. sanitize the value for the requested type, or\n\t // 2. throw an exception.\n\t if (type === SCE_CONTEXTS.RESOURCE_URL) {\n\t if (isResourceUrlAllowedByPolicy(maybeTrusted)) {\n\t return maybeTrusted;\n\t } else {\n\t throw $sceMinErr('insecurl',\n\t 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}',\n\t maybeTrusted.toString());\n\t }\n\t } else if (type === SCE_CONTEXTS.HTML) {\n\t return htmlSanitizer(maybeTrusted);\n\t }\n\t throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');\n\t }\n\t\n\t return { trustAs: trustAs,\n\t getTrusted: getTrusted,\n\t valueOf: valueOf };\n\t }];\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $sceProvider\n\t * @description\n\t *\n\t * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.\n\t * - enable/disable Strict Contextual Escaping (SCE) in a module\n\t * - override the default implementation with a custom delegate\n\t *\n\t * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.\n\t */\n\t\n\t/* jshint maxlen: false*/\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $sce\n\t * @kind function\n\t *\n\t * @description\n\t *\n\t * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.\n\t *\n\t * # Strict Contextual Escaping\n\t *\n\t * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain\n\t * contexts to result in a value that is marked as safe to use for that context. One example of\n\t * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer\n\t * to these contexts as privileged or SCE contexts.\n\t *\n\t * As of version 1.2, Angular ships with SCE enabled by default.\n\t *\n\t * Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow\n\t * one to execute arbitrary javascript by the use of the expression() syntax. Refer\n\t * to learn more about them.\n\t * You can ensure your document is in standards mode and not quirks mode by adding ``\n\t * to the top of your HTML document.\n\t *\n\t * SCE assists in writing code in a way that (a) is secure by default and (b) makes auditing for\n\t * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.\n\t *\n\t * Here's an example of a binding in a privileged context:\n\t *\n\t * ```\n\t * \n\t *
\n\t * ```\n\t *\n\t * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE\n\t * disabled, this application allows the user to render arbitrary HTML into the DIV.\n\t * In a more realistic example, one may be rendering user comments, blog articles, etc. via\n\t * bindings. (HTML is just one example of a context where rendering user controlled input creates\n\t * security vulnerabilities.)\n\t *\n\t * For the case of HTML, you might use a library, either on the client side, or on the server side,\n\t * to sanitize unsafe HTML before binding to the value and rendering it in the document.\n\t *\n\t * How would you ensure that every place that used these types of bindings was bound to a value that\n\t * was sanitized by your library (or returned as safe for rendering by your server?) How can you\n\t * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some\n\t * properties/fields and forgot to update the binding to the sanitized value?\n\t *\n\t * To be secure by default, you want to ensure that any such bindings are disallowed unless you can\n\t * determine that something explicitly says it's safe to use a value for binding in that\n\t * context. You can then audit your code (a simple grep would do) to ensure that this is only done\n\t * for those values that you can easily tell are safe - because they were received from your server,\n\t * sanitized by your library, etc. You can organize your codebase to help with this - perhaps\n\t * allowing only the files in a specific directory to do this. Ensuring that the internal API\n\t * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.\n\t *\n\t * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}\n\t * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to\n\t * obtain values that will be accepted by SCE / privileged contexts.\n\t *\n\t *\n\t * ## How does it work?\n\t *\n\t * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted\n\t * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link\n\t * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the\n\t * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.\n\t *\n\t * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link\n\t * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly\n\t * simplified):\n\t *\n\t * ```\n\t * var ngBindHtmlDirective = ['$sce', function($sce) {\n\t * return function(scope, element, attr) {\n\t * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {\n\t * element.html(value || '');\n\t * });\n\t * };\n\t * }];\n\t * ```\n\t *\n\t * ## Impact on loading templates\n\t *\n\t * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as\n\t * `templateUrl`'s specified by {@link guide/directive directives}.\n\t *\n\t * By default, Angular only loads templates from the same domain and protocol as the application\n\t * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl\n\t * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or\n\t * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist\n\t * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.\n\t *\n\t * *Please note*:\n\t * The browser's\n\t * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)\n\t * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)\n\t * policy apply in addition to this and may further restrict whether the template is successfully\n\t * loaded. This means that without the right CORS policy, loading templates from a different domain\n\t * won't work on all browsers. Also, loading templates from `file://` URL does not work on some\n\t * browsers.\n\t *\n\t * ## This feels like too much overhead\n\t *\n\t * It's important to remember that SCE only applies to interpolation expressions.\n\t *\n\t * If your expressions are constant literals, they're automatically trusted and you don't need to\n\t * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.\n\t * `
implicitly trusted'\">
`) just works.\n\t *\n\t * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them\n\t * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here.\n\t *\n\t * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load\n\t * templates in `ng-include` from your application's domain without having to even know about SCE.\n\t * It blocks loading templates from other domains or loading templates over http from an https\n\t * served document. You can change these by setting your own custom {@link\n\t * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link\n\t * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.\n\t *\n\t * This significantly reduces the overhead. It is far easier to pay the small overhead and have an\n\t * application that's secure and can be audited to verify that with much more ease than bolting\n\t * security onto an application later.\n\t *\n\t * \n\t * ## What trusted context types are supported?\n\t *\n\t * | Context | Notes |\n\t * |---------------------|----------------|\n\t * | `$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. |\n\t * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |\n\t * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |\n\t * | `$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. |\n\t *\n\t * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist}
\n\t *\n\t * Each element in these arrays must be one of the following:\n\t *\n\t * - **'self'**\n\t * - The special **string**, `'self'`, can be used to match against all URLs of the **same\n\t * domain** as the application document using the **same protocol**.\n\t * - **String** (except the special value `'self'`)\n\t * - The string is matched against the full *normalized / absolute URL* of the resource\n\t * being tested (substring matches are not good enough.)\n\t * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters\n\t * match themselves.\n\t * - `*`: matches zero or more occurrences of any character other than one of the following 6\n\t * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'. It's a useful wildcard for use\n\t * in a whitelist.\n\t * - `**`: matches zero or more occurrences of *any* character. As such, it's not\n\t * appropriate for use in a scheme, domain, etc. as it would match too much. (e.g.\n\t * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might\n\t * not have been the intention.) Its usage at the very end of the path is ok. (e.g.\n\t * http://foo.example.com/templates/**).\n\t * - **RegExp** (*see caveat below*)\n\t * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax\n\t * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to\n\t * accidentally introduce a bug when one updates a complex expression (imho, all regexes should\n\t * have good test coverage). For instance, the use of `.` in the regex is correct only in a\n\t * small number of cases. A `.` character in the regex used when matching the scheme or a\n\t * subdomain could be matched against a `:` or literal `.` that was likely not intended. It\n\t * is highly recommended to use the string patterns and only fall back to regular expressions\n\t * as a last resort.\n\t * - The regular expression must be an instance of RegExp (i.e. not a string.) It is\n\t * matched against the **entire** *normalized / absolute URL* of the resource being tested\n\t * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags\n\t * present on the RegExp (such as multiline, global, ignoreCase) are ignored.\n\t * - If you are generating your JavaScript from some other templating engine (not\n\t * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),\n\t * remember to escape your regular expression (and be aware that you might need more than\n\t * one level of escaping depending on your templating engine and the way you interpolated\n\t * the value.) Do make use of your platform's escaping mechanism as it might be good\n\t * enough before coding your own. E.g. Ruby has\n\t * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)\n\t * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).\n\t * Javascript lacks a similar built in function for escaping. Take a look at Google\n\t * Closure library's [goog.string.regExpEscape(s)](\n\t * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).\n\t *\n\t * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.\n\t *\n\t * ## Show me an example using SCE.\n\t *\n\t * \n\t * \n\t *
\n\t *

\n\t * User comments
\n\t * By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when\n\t * $sanitize is available. If $sanitize isn't available, this results in an error instead of an\n\t * exploit.\n\t *
\n\t *
\n\t * {{userComment.name}}:\n\t * \n\t *
\n\t *
\n\t *
\n\t *
\n\t *
\n\t *\n\t * \n\t * angular.module('mySceApp', ['ngSanitize'])\n\t * .controller('AppController', ['$http', '$templateCache', '$sce',\n\t * function($http, $templateCache, $sce) {\n\t * var self = this;\n\t * $http.get(\"test_data.json\", {cache: $templateCache}).success(function(userComments) {\n\t * self.userComments = userComments;\n\t * });\n\t * self.explicitlyTrustedHtml = $sce.trustAsHtml(\n\t * 'Hover over this text.');\n\t * }]);\n\t * \n\t *\n\t * \n\t * [\n\t * { \"name\": \"Alice\",\n\t * \"htmlComment\":\n\t * \"Is anyone reading this?\"\n\t * },\n\t * { \"name\": \"Bob\",\n\t * \"htmlComment\": \"Yes! Am I the only other one?\"\n\t * }\n\t * ]\n\t * \n\t *\n\t * \n\t * describe('SCE doc demo', function() {\n\t * it('should sanitize untrusted values', function() {\n\t * expect(element.all(by.css('.htmlComment')).first().getInnerHtml())\n\t * .toBe('Is anyone reading this?');\n\t * });\n\t *\n\t * it('should NOT sanitize explicitly trusted values', function() {\n\t * expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(\n\t * 'Hover over this text.');\n\t * });\n\t * });\n\t * \n\t *
\n\t *\n\t *\n\t *\n\t * ## Can I disable SCE completely?\n\t *\n\t * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits\n\t * for little coding overhead. It will be much harder to take an SCE disabled application and\n\t * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE\n\t * for cases where you have a lot of existing code that was written before SCE was introduced and\n\t * you're migrating them a module at a time.\n\t *\n\t * That said, here's how you can completely disable SCE:\n\t *\n\t * ```\n\t * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {\n\t * // Completely disable SCE. For demonstration purposes only!\n\t * // Do not use in new projects.\n\t * $sceProvider.enabled(false);\n\t * });\n\t * ```\n\t *\n\t */\n\t/* jshint maxlen: 100 */\n\t\n\tfunction $SceProvider() {\n\t var enabled = true;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sceProvider#enabled\n\t * @kind function\n\t *\n\t * @param {boolean=} value If provided, then enables/disables SCE.\n\t * @return {boolean} true if SCE is enabled, false otherwise.\n\t *\n\t * @description\n\t * Enables/disables SCE and returns the current value.\n\t */\n\t this.enabled = function(value) {\n\t if (arguments.length) {\n\t enabled = !!value;\n\t }\n\t return enabled;\n\t };\n\t\n\t\n\t /* Design notes on the default implementation for SCE.\n\t *\n\t * The API contract for the SCE delegate\n\t * -------------------------------------\n\t * The SCE delegate object must provide the following 3 methods:\n\t *\n\t * - trustAs(contextEnum, value)\n\t * This method is used to tell the SCE service that the provided value is OK to use in the\n\t * contexts specified by contextEnum. It must return an object that will be accepted by\n\t * getTrusted() for a compatible contextEnum and return this value.\n\t *\n\t * - valueOf(value)\n\t * For values that were not produced by trustAs(), return them as is. For values that were\n\t * produced by trustAs(), return the corresponding input value to trustAs. Basically, if\n\t * trustAs is wrapping the given values into some type, this operation unwraps it when given\n\t * such a value.\n\t *\n\t * - getTrusted(contextEnum, value)\n\t * This function should return the a value that is safe to use in the context specified by\n\t * contextEnum or throw and exception otherwise.\n\t *\n\t * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be\n\t * opaque or wrapped in some holder object. That happens to be an implementation detail. For\n\t * instance, an implementation could maintain a registry of all trusted objects by context. In\n\t * such a case, trustAs() would return the same object that was passed in. getTrusted() would\n\t * return the same object passed in if it was found in the registry under a compatible context or\n\t * throw an exception otherwise. An implementation might only wrap values some of the time based\n\t * on some criteria. getTrusted() might return a value and not throw an exception for special\n\t * constants or objects even if not wrapped. All such implementations fulfill this contract.\n\t *\n\t *\n\t * A note on the inheritance model for SCE contexts\n\t * ------------------------------------------------\n\t * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This\n\t * is purely an implementation details.\n\t *\n\t * The contract is simply this:\n\t *\n\t * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)\n\t * will also succeed.\n\t *\n\t * Inheritance happens to capture this in a natural way. In some future, we\n\t * may not use inheritance anymore. That is OK because no code outside of\n\t * sce.js and sceSpecs.js would need to be aware of this detail.\n\t */\n\t\n\t this.$get = ['$parse', '$sceDelegate', function(\n\t $parse, $sceDelegate) {\n\t // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow\n\t // the \"expression(javascript expression)\" syntax which is insecure.\n\t if (enabled && msie < 8) {\n\t throw $sceMinErr('iequirks',\n\t 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +\n\t 'mode. You can fix this by adding the text to the top of your HTML ' +\n\t 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');\n\t }\n\t\n\t var sce = shallowCopy(SCE_CONTEXTS);\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#isEnabled\n\t * @kind function\n\t *\n\t * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you\n\t * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.\n\t *\n\t * @description\n\t * Returns a boolean indicating if SCE is enabled.\n\t */\n\t sce.isEnabled = function() {\n\t return enabled;\n\t };\n\t sce.trustAs = $sceDelegate.trustAs;\n\t sce.getTrusted = $sceDelegate.getTrusted;\n\t sce.valueOf = $sceDelegate.valueOf;\n\t\n\t if (!enabled) {\n\t sce.trustAs = sce.getTrusted = function(type, value) { return value; };\n\t sce.valueOf = identity;\n\t }\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAs\n\t *\n\t * @description\n\t * Converts Angular {@link guide/expression expression} into a function. This is like {@link\n\t * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it\n\t * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,\n\t * *result*)}\n\t *\n\t * @param {string} type The kind of SCE context in which this result will be used.\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t sce.parseAs = function sceParseAs(type, expr) {\n\t var parsed = $parse(expr);\n\t if (parsed.literal && parsed.constant) {\n\t return parsed;\n\t } else {\n\t return $parse(expr, function(value) {\n\t return sce.getTrusted(type, value);\n\t });\n\t }\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#trustAs\n\t *\n\t * @description\n\t * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such,\n\t * returns an object that is trusted by angular for use in specified strict contextual\n\t * escaping contexts (such as ng-bind-html, ng-include, any src attribute\n\t * interpolation, any dom event binding attribute interpolation such as for onclick, etc.)\n\t * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual\n\t * escaping.\n\t *\n\t * @param {string} type The kind of context in which this value is safe for use. e.g. url,\n\t * resourceUrl, html, js and css.\n\t * @param {*} value The value that that should be considered trusted/safe.\n\t * @returns {*} A value that can be used to stand in for the provided `value` in places\n\t * where Angular expects a $sce.trustAs() return value.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#trustAsHtml\n\t *\n\t * @description\n\t * Shorthand method. `$sce.trustAsHtml(value)` →\n\t * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}\n\t *\n\t * @param {*} value The value to trustAs.\n\t * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml\n\t * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives\n\t * only accept expressions that are either literal constants or are the\n\t * return value of {@link ng.$sce#trustAs $sce.trustAs}.)\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#trustAsUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.trustAsUrl(value)` →\n\t * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}\n\t *\n\t * @param {*} value The value to trustAs.\n\t * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl\n\t * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives\n\t * only accept expressions that are either literal constants or are the\n\t * return value of {@link ng.$sce#trustAs $sce.trustAs}.)\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#trustAsResourceUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.trustAsResourceUrl(value)` →\n\t * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}\n\t *\n\t * @param {*} value The value to trustAs.\n\t * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl\n\t * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives\n\t * only accept expressions that are either literal constants or are the return\n\t * value of {@link ng.$sce#trustAs $sce.trustAs}.)\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#trustAsJs\n\t *\n\t * @description\n\t * Shorthand method. `$sce.trustAsJs(value)` →\n\t * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}\n\t *\n\t * @param {*} value The value to trustAs.\n\t * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs\n\t * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives\n\t * only accept expressions that are either literal constants or are the\n\t * return value of {@link ng.$sce#trustAs $sce.trustAs}.)\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrusted\n\t *\n\t * @description\n\t * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such,\n\t * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the\n\t * originally supplied value if the queried context type is a supertype of the created type.\n\t * If this condition isn't satisfied, throws an exception.\n\t *\n\t * @param {string} type The kind of context in which this value is to be used.\n\t * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}\n\t * call.\n\t * @returns {*} The value the was originally provided to\n\t * {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.\n\t * Otherwise, throws an exception.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrustedHtml\n\t *\n\t * @description\n\t * Shorthand method. `$sce.getTrustedHtml(value)` →\n\t * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}\n\t *\n\t * @param {*} value The value to pass to `$sce.getTrusted`.\n\t * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrustedCss\n\t *\n\t * @description\n\t * Shorthand method. `$sce.getTrustedCss(value)` →\n\t * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}\n\t *\n\t * @param {*} value The value to pass to `$sce.getTrusted`.\n\t * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrustedUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.getTrustedUrl(value)` →\n\t * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}\n\t *\n\t * @param {*} value The value to pass to `$sce.getTrusted`.\n\t * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrustedResourceUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.getTrustedResourceUrl(value)` →\n\t * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}\n\t *\n\t * @param {*} value The value to pass to `$sceDelegate.getTrusted`.\n\t * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#getTrustedJs\n\t *\n\t * @description\n\t * Shorthand method. `$sce.getTrustedJs(value)` →\n\t * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}\n\t *\n\t * @param {*} value The value to pass to `$sce.getTrusted`.\n\t * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAsHtml\n\t *\n\t * @description\n\t * Shorthand method. `$sce.parseAsHtml(expression string)` →\n\t * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAsCss\n\t *\n\t * @description\n\t * Shorthand method. `$sce.parseAsCss(value)` →\n\t * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAsUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.parseAsUrl(value)` →\n\t * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAsResourceUrl\n\t *\n\t * @description\n\t * Shorthand method. `$sce.parseAsResourceUrl(value)` →\n\t * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $sce#parseAsJs\n\t *\n\t * @description\n\t * Shorthand method. `$sce.parseAsJs(value)` →\n\t * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}\n\t *\n\t * @param {string} expression String expression to compile.\n\t * @returns {function(context, locals)} a function which represents the compiled expression:\n\t *\n\t * * `context` – `{object}` – an object against which any expressions embedded in the strings\n\t * are evaluated against (typically a scope object).\n\t * * `locals` – `{object=}` – local variables context object, useful for overriding values in\n\t * `context`.\n\t */\n\t\n\t // Shorthand delegations.\n\t var parse = sce.parseAs,\n\t getTrusted = sce.getTrusted,\n\t trustAs = sce.trustAs;\n\t\n\t forEach(SCE_CONTEXTS, function(enumValue, name) {\n\t var lName = lowercase(name);\n\t sce[camelCase(\"parse_as_\" + lName)] = function(expr) {\n\t return parse(enumValue, expr);\n\t };\n\t sce[camelCase(\"get_trusted_\" + lName)] = function(value) {\n\t return getTrusted(enumValue, value);\n\t };\n\t sce[camelCase(\"trust_as_\" + lName)] = function(value) {\n\t return trustAs(enumValue, value);\n\t };\n\t });\n\t\n\t return sce;\n\t }];\n\t}\n\t\n\t/**\n\t * !!! This is an undocumented \"private\" service !!!\n\t *\n\t * @name $sniffer\n\t * @requires $window\n\t * @requires $document\n\t *\n\t * @property {boolean} history Does the browser support html5 history api ?\n\t * @property {boolean} transitions Does the browser support CSS transition events ?\n\t * @property {boolean} animations Does the browser support CSS animation events ?\n\t *\n\t * @description\n\t * This is very simple implementation of testing browser's features.\n\t */\n\tfunction $SnifferProvider() {\n\t this.$get = ['$window', '$document', function($window, $document) {\n\t var eventSupport = {},\n\t // Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by\n\t // the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index)\n\t isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,\n\t hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,\n\t android =\n\t toInt((/android (\\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),\n\t boxee = /Boxee/i.test(($window.navigator || {}).userAgent),\n\t document = $document[0] || {},\n\t vendorPrefix,\n\t vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,\n\t bodyStyle = document.body && document.body.style,\n\t transitions = false,\n\t animations = false,\n\t match;\n\t\n\t if (bodyStyle) {\n\t for (var prop in bodyStyle) {\n\t if (match = vendorRegex.exec(prop)) {\n\t vendorPrefix = match[0];\n\t vendorPrefix = vendorPrefix[0].toUpperCase() + vendorPrefix.substr(1);\n\t break;\n\t }\n\t }\n\t\n\t if (!vendorPrefix) {\n\t vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';\n\t }\n\t\n\t transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));\n\t animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));\n\t\n\t if (android && (!transitions || !animations)) {\n\t transitions = isString(bodyStyle.webkitTransition);\n\t animations = isString(bodyStyle.webkitAnimation);\n\t }\n\t }\n\t\n\t\n\t return {\n\t // Android has history.pushState, but it does not update location correctly\n\t // so let's not use the history API at all.\n\t // http://code.google.com/p/android/issues/detail?id=17471\n\t // https://github.com/angular/angular.js/issues/904\n\t\n\t // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has\n\t // so let's not use the history API also\n\t // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined\n\t // jshint -W018\n\t history: !!(hasHistoryPushState && !(android < 4) && !boxee),\n\t // jshint +W018\n\t hasEvent: function(event) {\n\t // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have\n\t // it. In particular the event is not fired when backspace or delete key are pressed or\n\t // when cut operation is performed.\n\t // IE10+ implements 'input' event but it erroneously fires under various situations,\n\t // e.g. when placeholder changes, or a form is focused.\n\t if (event === 'input' && msie <= 11) return false;\n\t\n\t if (isUndefined(eventSupport[event])) {\n\t var divElm = document.createElement('div');\n\t eventSupport[event] = 'on' + event in divElm;\n\t }\n\t\n\t return eventSupport[event];\n\t },\n\t csp: csp(),\n\t vendorPrefix: vendorPrefix,\n\t transitions: transitions,\n\t animations: animations,\n\t android: android\n\t };\n\t }];\n\t}\n\t\n\tvar $templateRequestMinErr = minErr('$compile');\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $templateRequestProvider\n\t * @description\n\t * Used to configure the options passed to the {@link $http} service when making a template request.\n\t *\n\t * For example, it can be used for specifying the \"Accept\" header that is sent to the server, when\n\t * requesting a template.\n\t */\n\tfunction $TemplateRequestProvider() {\n\t\n\t var httpOptions;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $templateRequestProvider#httpOptions\n\t * @description\n\t * The options to be passed to the {@link $http} service when making the request.\n\t * You can use this to override options such as the \"Accept\" header for template requests.\n\t *\n\t * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the\n\t * options if not overridden here.\n\t *\n\t * @param {string=} value new value for the {@link $http} options.\n\t * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.\n\t */\n\t this.httpOptions = function(val) {\n\t if (val) {\n\t httpOptions = val;\n\t return this;\n\t }\n\t return httpOptions;\n\t };\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $templateRequest\n\t *\n\t * @description\n\t * The `$templateRequest` service runs security checks then downloads the provided template using\n\t * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request\n\t * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the\n\t * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the\n\t * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted\n\t * when `tpl` is of type string and `$templateCache` has the matching entry.\n\t *\n\t * If you want to pass custom options to the `$http` service, such as setting the Accept header you\n\t * can configure this via {@link $templateRequestProvider#httpOptions}.\n\t *\n\t * @param {string|TrustedResourceUrl} tpl The HTTP request template URL\n\t * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty\n\t *\n\t * @return {Promise} a promise for the HTTP response data of the given URL.\n\t *\n\t * @property {number} totalPendingRequests total amount of pending template requests being downloaded.\n\t */\n\t this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {\n\t\n\t function handleRequestFn(tpl, ignoreRequestError) {\n\t handleRequestFn.totalPendingRequests++;\n\t\n\t // We consider the template cache holds only trusted templates, so\n\t // there's no need to go through whitelisting again for keys that already\n\t // are included in there. This also makes Angular accept any script\n\t // directive, no matter its name. However, we still need to unwrap trusted\n\t // types.\n\t if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {\n\t tpl = $sce.getTrustedResourceUrl(tpl);\n\t }\n\t\n\t var transformResponse = $http.defaults && $http.defaults.transformResponse;\n\t\n\t if (isArray(transformResponse)) {\n\t transformResponse = transformResponse.filter(function(transformer) {\n\t return transformer !== defaultHttpResponseTransform;\n\t });\n\t } else if (transformResponse === defaultHttpResponseTransform) {\n\t transformResponse = null;\n\t }\n\t\n\t return $http.get(tpl, extend({\n\t cache: $templateCache,\n\t transformResponse: transformResponse\n\t }, httpOptions))\n\t ['finally'](function() {\n\t handleRequestFn.totalPendingRequests--;\n\t })\n\t .then(function(response) {\n\t $templateCache.put(tpl, response.data);\n\t return response.data;\n\t }, handleError);\n\t\n\t function handleError(resp) {\n\t if (!ignoreRequestError) {\n\t throw $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',\n\t tpl, resp.status, resp.statusText);\n\t }\n\t return $q.reject(resp);\n\t }\n\t }\n\t\n\t handleRequestFn.totalPendingRequests = 0;\n\t\n\t return handleRequestFn;\n\t }];\n\t}\n\t\n\tfunction $$TestabilityProvider() {\n\t this.$get = ['$rootScope', '$browser', '$location',\n\t function($rootScope, $browser, $location) {\n\t\n\t /**\n\t * @name $testability\n\t *\n\t * @description\n\t * The private $$testability service provides a collection of methods for use when debugging\n\t * or by automated test and debugging tools.\n\t */\n\t var testability = {};\n\t\n\t /**\n\t * @name $$testability#findBindings\n\t *\n\t * @description\n\t * Returns an array of elements that are bound (via ng-bind or {{}})\n\t * to expressions matching the input.\n\t *\n\t * @param {Element} element The element root to search from.\n\t * @param {string} expression The binding expression to match.\n\t * @param {boolean} opt_exactMatch If true, only returns exact matches\n\t * for the expression. Filters and whitespace are ignored.\n\t */\n\t testability.findBindings = function(element, expression, opt_exactMatch) {\n\t var bindings = element.getElementsByClassName('ng-binding');\n\t var matches = [];\n\t forEach(bindings, function(binding) {\n\t var dataBinding = angular.element(binding).data('$binding');\n\t if (dataBinding) {\n\t forEach(dataBinding, function(bindingName) {\n\t if (opt_exactMatch) {\n\t var matcher = new RegExp('(^|\\\\s)' + escapeForRegexp(expression) + '(\\\\s|\\\\||$)');\n\t if (matcher.test(bindingName)) {\n\t matches.push(binding);\n\t }\n\t } else {\n\t if (bindingName.indexOf(expression) != -1) {\n\t matches.push(binding);\n\t }\n\t }\n\t });\n\t }\n\t });\n\t return matches;\n\t };\n\t\n\t /**\n\t * @name $$testability#findModels\n\t *\n\t * @description\n\t * Returns an array of elements that are two-way found via ng-model to\n\t * expressions matching the input.\n\t *\n\t * @param {Element} element The element root to search from.\n\t * @param {string} expression The model expression to match.\n\t * @param {boolean} opt_exactMatch If true, only returns exact matches\n\t * for the expression.\n\t */\n\t testability.findModels = function(element, expression, opt_exactMatch) {\n\t var prefixes = ['ng-', 'data-ng-', 'ng\\\\:'];\n\t for (var p = 0; p < prefixes.length; ++p) {\n\t var attributeEquals = opt_exactMatch ? '=' : '*=';\n\t var selector = '[' + prefixes[p] + 'model' + attributeEquals + '\"' + expression + '\"]';\n\t var elements = element.querySelectorAll(selector);\n\t if (elements.length) {\n\t return elements;\n\t }\n\t }\n\t };\n\t\n\t /**\n\t * @name $$testability#getLocation\n\t *\n\t * @description\n\t * Shortcut for getting the location in a browser agnostic way. Returns\n\t * the path, search, and hash. (e.g. /path?a=b#hash)\n\t */\n\t testability.getLocation = function() {\n\t return $location.url();\n\t };\n\t\n\t /**\n\t * @name $$testability#setLocation\n\t *\n\t * @description\n\t * Shortcut for navigating to a location without doing a full page reload.\n\t *\n\t * @param {string} url The location url (path, search and hash,\n\t * e.g. /path?a=b#hash) to go to.\n\t */\n\t testability.setLocation = function(url) {\n\t if (url !== $location.url()) {\n\t $location.url(url);\n\t $rootScope.$digest();\n\t }\n\t };\n\t\n\t /**\n\t * @name $$testability#whenStable\n\t *\n\t * @description\n\t * Calls the callback when $timeout and $http requests are completed.\n\t *\n\t * @param {function} callback\n\t */\n\t testability.whenStable = function(callback) {\n\t $browser.notifyWhenNoOutstandingRequests(callback);\n\t };\n\t\n\t return testability;\n\t }];\n\t}\n\t\n\tfunction $TimeoutProvider() {\n\t this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',\n\t function($rootScope, $browser, $q, $$q, $exceptionHandler) {\n\t\n\t var deferreds = {};\n\t\n\t\n\t /**\n\t * @ngdoc service\n\t * @name $timeout\n\t *\n\t * @description\n\t * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch\n\t * block and delegates any exceptions to\n\t * {@link ng.$exceptionHandler $exceptionHandler} service.\n\t *\n\t * The return value of calling `$timeout` is a promise, which will be resolved when\n\t * the delay has passed and the timeout function, if provided, is executed.\n\t *\n\t * To cancel a timeout request, call `$timeout.cancel(promise)`.\n\t *\n\t * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to\n\t * synchronously flush the queue of deferred functions.\n\t *\n\t * If you only want a promise that will be resolved after some specified delay\n\t * then you can call `$timeout` without the `fn` function.\n\t *\n\t * @param {function()=} fn A function, whose execution should be delayed.\n\t * @param {number=} [delay=0] Delay in milliseconds.\n\t * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise\n\t * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.\n\t * @param {...*=} Pass additional parameters to the executed function.\n\t * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise\n\t * will be resolved with the return value of the `fn` function.\n\t *\n\t */\n\t function timeout(fn, delay, invokeApply) {\n\t if (!isFunction(fn)) {\n\t invokeApply = delay;\n\t delay = fn;\n\t fn = noop;\n\t }\n\t\n\t var args = sliceArgs(arguments, 3),\n\t skipApply = (isDefined(invokeApply) && !invokeApply),\n\t deferred = (skipApply ? $$q : $q).defer(),\n\t promise = deferred.promise,\n\t timeoutId;\n\t\n\t timeoutId = $browser.defer(function() {\n\t try {\n\t deferred.resolve(fn.apply(null, args));\n\t } catch (e) {\n\t deferred.reject(e);\n\t $exceptionHandler(e);\n\t }\n\t finally {\n\t delete deferreds[promise.$$timeoutId];\n\t }\n\t\n\t if (!skipApply) $rootScope.$apply();\n\t }, delay);\n\t\n\t promise.$$timeoutId = timeoutId;\n\t deferreds[timeoutId] = deferred;\n\t\n\t return promise;\n\t }\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $timeout#cancel\n\t *\n\t * @description\n\t * Cancels a task associated with the `promise`. As a result of this, the promise will be\n\t * resolved with a rejection.\n\t *\n\t * @param {Promise=} promise Promise returned by the `$timeout` function.\n\t * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully\n\t * canceled.\n\t */\n\t timeout.cancel = function(promise) {\n\t if (promise && promise.$$timeoutId in deferreds) {\n\t deferreds[promise.$$timeoutId].reject('canceled');\n\t delete deferreds[promise.$$timeoutId];\n\t return $browser.defer.cancel(promise.$$timeoutId);\n\t }\n\t return false;\n\t };\n\t\n\t return timeout;\n\t }];\n\t}\n\t\n\t// NOTE: The usage of window and document instead of $window and $document here is\n\t// deliberate. This service depends on the specific behavior of anchor nodes created by the\n\t// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and\n\t// cause us to break tests. In addition, when the browser resolves a URL for XHR, it\n\t// doesn't know about mocked locations and resolves URLs to the real document - which is\n\t// exactly the behavior needed here. There is little value is mocking these out for this\n\t// service.\n\tvar urlParsingNode = window.document.createElement(\"a\");\n\tvar originUrl = urlResolve(window.location.href);\n\t\n\t\n\t/**\n\t *\n\t * Implementation Notes for non-IE browsers\n\t * ----------------------------------------\n\t * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,\n\t * results both in the normalizing and parsing of the URL. Normalizing means that a relative\n\t * URL will be resolved into an absolute URL in the context of the application document.\n\t * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related\n\t * properties are all populated to reflect the normalized URL. This approach has wide\n\t * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See\n\t * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html\n\t *\n\t * Implementation Notes for IE\n\t * ---------------------------\n\t * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other\n\t * browsers. However, the parsed components will not be set if the URL assigned did not specify\n\t * them. (e.g. if you assign a.href = \"foo\", then a.protocol, a.host, etc. will be empty.) We\n\t * work around that by performing the parsing in a 2nd step by taking a previously normalized\n\t * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the\n\t * properties such as protocol, hostname, port, etc.\n\t *\n\t * References:\n\t * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement\n\t * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html\n\t * http://url.spec.whatwg.org/#urlutils\n\t * https://github.com/angular/angular.js/pull/2902\n\t * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/\n\t *\n\t * @kind function\n\t * @param {string} url The URL to be parsed.\n\t * @description Normalizes and parses a URL.\n\t * @returns {object} Returns the normalized URL as a dictionary.\n\t *\n\t * | member name | Description |\n\t * |---------------|----------------|\n\t * | href | A normalized version of the provided URL if it was not an absolute URL |\n\t * | protocol | The protocol including the trailing colon |\n\t * | host | The host and port (if the port is non-default) of the normalizedUrl |\n\t * | search | The search params, minus the question mark |\n\t * | hash | The hash string, minus the hash symbol\n\t * | hostname | The hostname\n\t * | port | The port, without \":\"\n\t * | pathname | The pathname, beginning with \"/\"\n\t *\n\t */\n\tfunction urlResolve(url) {\n\t var href = url;\n\t\n\t if (msie) {\n\t // Normalize before parse. Refer Implementation Notes on why this is\n\t // done in two steps on IE.\n\t urlParsingNode.setAttribute(\"href\", href);\n\t href = urlParsingNode.href;\n\t }\n\t\n\t urlParsingNode.setAttribute('href', href);\n\t\n\t // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils\n\t return {\n\t href: urlParsingNode.href,\n\t protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',\n\t host: urlParsingNode.host,\n\t search: urlParsingNode.search ? urlParsingNode.search.replace(/^\\?/, '') : '',\n\t hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',\n\t hostname: urlParsingNode.hostname,\n\t port: urlParsingNode.port,\n\t pathname: (urlParsingNode.pathname.charAt(0) === '/')\n\t ? urlParsingNode.pathname\n\t : '/' + urlParsingNode.pathname\n\t };\n\t}\n\t\n\t/**\n\t * Parse a request URL and determine whether this is a same-origin request as the application document.\n\t *\n\t * @param {string|object} requestUrl The url of the request as a string that will be resolved\n\t * or a parsed URL object.\n\t * @returns {boolean} Whether the request is for the same origin as the application document.\n\t */\n\tfunction urlIsSameOrigin(requestUrl) {\n\t var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;\n\t return (parsed.protocol === originUrl.protocol &&\n\t parsed.host === originUrl.host);\n\t}\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $window\n\t *\n\t * @description\n\t * A reference to the browser's `window` object. While `window`\n\t * is globally available in JavaScript, it causes testability problems, because\n\t * it is a global variable. In angular we always refer to it through the\n\t * `$window` service, so it may be overridden, removed or mocked for testing.\n\t *\n\t * Expressions, like the one defined for the `ngClick` directive in the example\n\t * below, are evaluated with respect to the current scope. Therefore, there is\n\t * no risk of inadvertently coding in a dependency on a global value in such an\n\t * expression.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t \n\t
\n\t
\n\t \n\t it('should display the greeting in the input box', function() {\n\t element(by.model('greeting')).sendKeys('Hello, E2E Tests');\n\t // If we click the button it will block the test runner\n\t // element(':button').click();\n\t });\n\t \n\t
\n\t */\n\tfunction $WindowProvider() {\n\t this.$get = valueFn(window);\n\t}\n\t\n\t/**\n\t * @name $$cookieReader\n\t * @requires $document\n\t *\n\t * @description\n\t * This is a private service for reading cookies used by $http and ngCookies\n\t *\n\t * @return {Object} a key/value map of the current cookies\n\t */\n\tfunction $$CookieReader($document) {\n\t var rawDocument = $document[0] || {};\n\t var lastCookies = {};\n\t var lastCookieString = '';\n\t\n\t function safeDecodeURIComponent(str) {\n\t try {\n\t return decodeURIComponent(str);\n\t } catch (e) {\n\t return str;\n\t }\n\t }\n\t\n\t return function() {\n\t var cookieArray, cookie, i, index, name;\n\t var currentCookieString = rawDocument.cookie || '';\n\t\n\t if (currentCookieString !== lastCookieString) {\n\t lastCookieString = currentCookieString;\n\t cookieArray = lastCookieString.split('; ');\n\t lastCookies = {};\n\t\n\t for (i = 0; i < cookieArray.length; i++) {\n\t cookie = cookieArray[i];\n\t index = cookie.indexOf('=');\n\t if (index > 0) { //ignore nameless cookies\n\t name = safeDecodeURIComponent(cookie.substring(0, index));\n\t // the first value that is seen for a cookie is the most\n\t // specific one. values for the same cookie name that\n\t // follow are for less specific paths.\n\t if (isUndefined(lastCookies[name])) {\n\t lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));\n\t }\n\t }\n\t }\n\t }\n\t return lastCookies;\n\t };\n\t}\n\t\n\t$$CookieReader.$inject = ['$document'];\n\t\n\tfunction $$CookieReaderProvider() {\n\t this.$get = $$CookieReader;\n\t}\n\t\n\t/* global currencyFilter: true,\n\t dateFilter: true,\n\t filterFilter: true,\n\t jsonFilter: true,\n\t limitToFilter: true,\n\t lowercaseFilter: true,\n\t numberFilter: true,\n\t orderByFilter: true,\n\t uppercaseFilter: true,\n\t */\n\t\n\t/**\n\t * @ngdoc provider\n\t * @name $filterProvider\n\t * @description\n\t *\n\t * Filters are just functions which transform input to an output. However filters need to be\n\t * Dependency Injected. To achieve this a filter definition consists of a factory function which is\n\t * annotated with dependencies and is responsible for creating a filter function.\n\t *\n\t *
\n\t * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.\n\t * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace\n\t * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores\n\t * (`myapp_subsection_filterx`).\n\t *
\n\t *\n\t * ```js\n\t * // Filter registration\n\t * function MyModule($provide, $filterProvider) {\n\t * // create a service to demonstrate injection (not always needed)\n\t * $provide.value('greet', function(name){\n\t * return 'Hello ' + name + '!';\n\t * });\n\t *\n\t * // register a filter factory which uses the\n\t * // greet service to demonstrate DI.\n\t * $filterProvider.register('greet', function(greet){\n\t * // return the filter function which uses the greet service\n\t * // to generate salutation\n\t * return function(text) {\n\t * // filters need to be forgiving so check input validity\n\t * return text && greet(text) || text;\n\t * };\n\t * });\n\t * }\n\t * ```\n\t *\n\t * The filter function is registered with the `$injector` under the filter name suffix with\n\t * `Filter`.\n\t *\n\t * ```js\n\t * it('should be the same instance', inject(\n\t * function($filterProvider) {\n\t * $filterProvider.register('reverse', function(){\n\t * return ...;\n\t * });\n\t * },\n\t * function($filter, reverseFilter) {\n\t * expect($filter('reverse')).toBe(reverseFilter);\n\t * });\n\t * ```\n\t *\n\t *\n\t * For more information about how angular filters work, and how to create your own filters, see\n\t * {@link guide/filter Filters} in the Angular Developer Guide.\n\t */\n\t\n\t/**\n\t * @ngdoc service\n\t * @name $filter\n\t * @kind function\n\t * @description\n\t * Filters are used for formatting data displayed to the user.\n\t *\n\t * The general syntax in templates is as follows:\n\t *\n\t * {{ expression [| filter_name[:parameter_value] ... ] }}\n\t *\n\t * @param {String} name Name of the filter function to retrieve\n\t * @return {Function} the filter function\n\t * @example\n\t \n\t \n\t
\n\t

{{ originalText }}

\n\t

{{ filteredText }}

\n\t
\n\t
\n\t\n\t \n\t angular.module('filterExample', [])\n\t .controller('MainCtrl', function($scope, $filter) {\n\t $scope.originalText = 'hello';\n\t $scope.filteredText = $filter('uppercase')($scope.originalText);\n\t });\n\t \n\t
\n\t */\n\t$FilterProvider.$inject = ['$provide'];\n\tfunction $FilterProvider($provide) {\n\t var suffix = 'Filter';\n\t\n\t /**\n\t * @ngdoc method\n\t * @name $filterProvider#register\n\t * @param {string|Object} name Name of the filter function, or an object map of filters where\n\t * the keys are the filter names and the values are the filter factories.\n\t *\n\t *
\n\t * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.\n\t * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace\n\t * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores\n\t * (`myapp_subsection_filterx`).\n\t *
\n\t * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.\n\t * @returns {Object} Registered filter instance, or if a map of filters was provided then a map\n\t * of the registered filter instances.\n\t */\n\t function register(name, factory) {\n\t if (isObject(name)) {\n\t var filters = {};\n\t forEach(name, function(filter, key) {\n\t filters[key] = register(key, filter);\n\t });\n\t return filters;\n\t } else {\n\t return $provide.factory(name + suffix, factory);\n\t }\n\t }\n\t this.register = register;\n\t\n\t this.$get = ['$injector', function($injector) {\n\t return function(name) {\n\t return $injector.get(name + suffix);\n\t };\n\t }];\n\t\n\t ////////////////////////////////////////\n\t\n\t /* global\n\t currencyFilter: false,\n\t dateFilter: false,\n\t filterFilter: false,\n\t jsonFilter: false,\n\t limitToFilter: false,\n\t lowercaseFilter: false,\n\t numberFilter: false,\n\t orderByFilter: false,\n\t uppercaseFilter: false,\n\t */\n\t\n\t register('currency', currencyFilter);\n\t register('date', dateFilter);\n\t register('filter', filterFilter);\n\t register('json', jsonFilter);\n\t register('limitTo', limitToFilter);\n\t register('lowercase', lowercaseFilter);\n\t register('number', numberFilter);\n\t register('orderBy', orderByFilter);\n\t register('uppercase', uppercaseFilter);\n\t}\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name filter\n\t * @kind function\n\t *\n\t * @description\n\t * Selects a subset of items from `array` and returns it as a new array.\n\t *\n\t * @param {Array} array The source array.\n\t * @param {string|Object|function()} expression The predicate to be used for selecting items from\n\t * `array`.\n\t *\n\t * Can be one of:\n\t *\n\t * - `string`: The string is used for matching against the contents of the `array`. All strings or\n\t * objects with string properties in `array` that match this string will be returned. This also\n\t * applies to nested object properties.\n\t * The predicate can be negated by prefixing the string with `!`.\n\t *\n\t * - `Object`: A pattern object can be used to filter specific properties on objects contained\n\t * by `array`. For example `{name:\"M\", phone:\"1\"}` predicate will return an array of items\n\t * which have property `name` containing \"M\" and property `phone` containing \"1\". A special\n\t * property name (`$` by default) can be used (e.g. as in `{$: \"text\"}`) to accept a match\n\t * against any property of the object or its nested object properties. That's equivalent to the\n\t * simple substring match with a `string` as described above. The special property name can be\n\t * overwritten, using the `anyPropertyKey` parameter.\n\t * The predicate can be negated by prefixing the string with `!`.\n\t * For example `{name: \"!M\"}` predicate will return an array of items which have property `name`\n\t * not containing \"M\".\n\t *\n\t * Note that a named property will match properties on the same level only, while the special\n\t * `$` property will match properties on the same level or deeper. E.g. an array item like\n\t * `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but\n\t * **will** be matched by `{$: 'John'}`.\n\t *\n\t * - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.\n\t * The function is called for each element of the array, with the element, its index, and\n\t * the entire array itself as arguments.\n\t *\n\t * The final result is an array of those elements that the predicate returned true for.\n\t *\n\t * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in\n\t * determining if the expected value (from the filter expression) and actual value (from\n\t * the object in the array) should be considered a match.\n\t *\n\t * Can be one of:\n\t *\n\t * - `function(actual, expected)`:\n\t * The function will be given the object value and the predicate value to compare and\n\t * should return true if both values should be considered equal.\n\t *\n\t * - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.\n\t * This is essentially strict comparison of expected and actual.\n\t *\n\t * - `false|undefined`: A short hand for a function which will look for a substring match in case\n\t * insensitive way.\n\t *\n\t * Primitive values are converted to strings. Objects are not compared against primitives,\n\t * unless they have a custom `toString` method (e.g. `Date` objects).\n\t *\n\t * @param {string=} anyPropertyKey The special property name that matches against any property.\n\t * By default `$`.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
NamePhone
{{friend.name}}{{friend.phone}}
\n\t
\n\t
\n\t
\n\t
\n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t
NamePhone
{{friendObj.name}}{{friendObj.phone}}
\n\t
\n\t \n\t var expectFriendNames = function(expectedNames, key) {\n\t element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {\n\t arr.forEach(function(wd, i) {\n\t expect(wd.getText()).toMatch(expectedNames[i]);\n\t });\n\t });\n\t };\n\t\n\t it('should search across all fields when filtering with a string', function() {\n\t var searchText = element(by.model('searchText'));\n\t searchText.clear();\n\t searchText.sendKeys('m');\n\t expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');\n\t\n\t searchText.clear();\n\t searchText.sendKeys('76');\n\t expectFriendNames(['John', 'Julie'], 'friend');\n\t });\n\t\n\t it('should search in specific fields when filtering with a predicate object', function() {\n\t var searchAny = element(by.model('search.$'));\n\t searchAny.clear();\n\t searchAny.sendKeys('i');\n\t expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');\n\t });\n\t it('should use a equal comparison when comparator is true', function() {\n\t var searchName = element(by.model('search.name'));\n\t var strict = element(by.model('strict'));\n\t searchName.clear();\n\t searchName.sendKeys('Julie');\n\t strict.click();\n\t expectFriendNames(['Julie'], 'friendObj');\n\t });\n\t \n\t
\n\t */\n\t\n\tfunction filterFilter() {\n\t return function(array, expression, comparator, anyPropertyKey) {\n\t if (!isArrayLike(array)) {\n\t if (array == null) {\n\t return array;\n\t } else {\n\t throw minErr('filter')('notarray', 'Expected array but received: {0}', array);\n\t }\n\t }\n\t\n\t anyPropertyKey = anyPropertyKey || '$';\n\t var expressionType = getTypeForFilter(expression);\n\t var predicateFn;\n\t var matchAgainstAnyProp;\n\t\n\t switch (expressionType) {\n\t case 'function':\n\t predicateFn = expression;\n\t break;\n\t case 'boolean':\n\t case 'null':\n\t case 'number':\n\t case 'string':\n\t matchAgainstAnyProp = true;\n\t //jshint -W086\n\t case 'object':\n\t //jshint +W086\n\t predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);\n\t break;\n\t default:\n\t return array;\n\t }\n\t\n\t return Array.prototype.filter.call(array, predicateFn);\n\t };\n\t}\n\t\n\t// Helper functions for `filterFilter`\n\tfunction createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {\n\t var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);\n\t var predicateFn;\n\t\n\t if (comparator === true) {\n\t comparator = equals;\n\t } else if (!isFunction(comparator)) {\n\t comparator = function(actual, expected) {\n\t if (isUndefined(actual)) {\n\t // No substring matching against `undefined`\n\t return false;\n\t }\n\t if ((actual === null) || (expected === null)) {\n\t // No substring matching against `null`; only match against `null`\n\t return actual === expected;\n\t }\n\t if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {\n\t // Should not compare primitives against objects, unless they have custom `toString` method\n\t return false;\n\t }\n\t\n\t actual = lowercase('' + actual);\n\t expected = lowercase('' + expected);\n\t return actual.indexOf(expected) !== -1;\n\t };\n\t }\n\t\n\t predicateFn = function(item) {\n\t if (shouldMatchPrimitives && !isObject(item)) {\n\t return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);\n\t }\n\t return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);\n\t };\n\t\n\t return predicateFn;\n\t}\n\t\n\tfunction deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {\n\t var actualType = getTypeForFilter(actual);\n\t var expectedType = getTypeForFilter(expected);\n\t\n\t if ((expectedType === 'string') && (expected.charAt(0) === '!')) {\n\t return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);\n\t } else if (isArray(actual)) {\n\t // In case `actual` is an array, consider it a match\n\t // if ANY of it's items matches `expected`\n\t return actual.some(function(item) {\n\t return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);\n\t });\n\t }\n\t\n\t switch (actualType) {\n\t case 'object':\n\t var key;\n\t if (matchAgainstAnyProp) {\n\t for (key in actual) {\n\t if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {\n\t return true;\n\t }\n\t }\n\t return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);\n\t } else if (expectedType === 'object') {\n\t for (key in expected) {\n\t var expectedVal = expected[key];\n\t if (isFunction(expectedVal) || isUndefined(expectedVal)) {\n\t continue;\n\t }\n\t\n\t var matchAnyProperty = key === anyPropertyKey;\n\t var actualVal = matchAnyProperty ? actual : actual[key];\n\t if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {\n\t return false;\n\t }\n\t }\n\t return true;\n\t } else {\n\t return comparator(actual, expected);\n\t }\n\t break;\n\t case 'function':\n\t return false;\n\t default:\n\t return comparator(actual, expected);\n\t }\n\t}\n\t\n\t// Used for easily differentiating between `null` and actual `object`\n\tfunction getTypeForFilter(val) {\n\t return (val === null) ? 'null' : typeof val;\n\t}\n\t\n\tvar MAX_DIGITS = 22;\n\tvar DECIMAL_SEP = '.';\n\tvar ZERO_CHAR = '0';\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name currency\n\t * @kind function\n\t *\n\t * @description\n\t * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default\n\t * symbol for current locale is used.\n\t *\n\t * @param {number} amount Input to filter.\n\t * @param {string=} symbol Currency symbol or identifier to be displayed.\n\t * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale\n\t * @returns {string} Formatted number.\n\t *\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t default currency symbol ($): {{amount | currency}}
\n\t custom currency identifier (USD$): {{amount | currency:\"USD$\"}}\n\t no fractions (0): {{amount | currency:\"USD$\":0}}\n\t
\n\t
\n\t \n\t it('should init with 1234.56', function() {\n\t expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');\n\t expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');\n\t expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');\n\t });\n\t it('should update', function() {\n\t if (browser.params.browser == 'safari') {\n\t // Safari does not understand the minus key. See\n\t // https://github.com/angular/protractor/issues/481\n\t return;\n\t }\n\t element(by.model('amount')).clear();\n\t element(by.model('amount')).sendKeys('-1234');\n\t expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');\n\t expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');\n\t expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');\n\t });\n\t \n\t
\n\t */\n\tcurrencyFilter.$inject = ['$locale'];\n\tfunction currencyFilter($locale) {\n\t var formats = $locale.NUMBER_FORMATS;\n\t return function(amount, currencySymbol, fractionSize) {\n\t if (isUndefined(currencySymbol)) {\n\t currencySymbol = formats.CURRENCY_SYM;\n\t }\n\t\n\t if (isUndefined(fractionSize)) {\n\t fractionSize = formats.PATTERNS[1].maxFrac;\n\t }\n\t\n\t // if null or undefined pass it through\n\t return (amount == null)\n\t ? amount\n\t : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).\n\t replace(/\\u00A4/g, currencySymbol);\n\t };\n\t}\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name number\n\t * @kind function\n\t *\n\t * @description\n\t * Formats a number as text.\n\t *\n\t * If the input is null or undefined, it will just be returned.\n\t * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.\n\t * If the input is not a number an empty string is returned.\n\t *\n\t *\n\t * @param {number|string} number Number to format.\n\t * @param {(number|string)=} fractionSize Number of decimal places to round the number to.\n\t * If this is not provided then the fraction size is computed from the current locale's number\n\t * formatting pattern. In the case of the default locale, it will be 3.\n\t * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current\n\t * locale (e.g., in the en_US locale it will have \".\" as the decimal separator and\n\t * include \",\" group separators after each third digit).\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t Default formatting: {{val | number}}
\n\t No fractions: {{val | number:0}}
\n\t Negative number: {{-val | number:4}}\n\t
\n\t
\n\t \n\t it('should format numbers', function() {\n\t expect(element(by.id('number-default')).getText()).toBe('1,234.568');\n\t expect(element(by.binding('val | number:0')).getText()).toBe('1,235');\n\t expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');\n\t });\n\t\n\t it('should update', function() {\n\t element(by.model('val')).clear();\n\t element(by.model('val')).sendKeys('3374.333');\n\t expect(element(by.id('number-default')).getText()).toBe('3,374.333');\n\t expect(element(by.binding('val | number:0')).getText()).toBe('3,374');\n\t expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');\n\t });\n\t \n\t
\n\t */\n\tnumberFilter.$inject = ['$locale'];\n\tfunction numberFilter($locale) {\n\t var formats = $locale.NUMBER_FORMATS;\n\t return function(number, fractionSize) {\n\t\n\t // if null or undefined pass it through\n\t return (number == null)\n\t ? number\n\t : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,\n\t fractionSize);\n\t };\n\t}\n\t\n\t/**\n\t * Parse a number (as a string) into three components that can be used\n\t * for formatting the number.\n\t *\n\t * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)\n\t *\n\t * @param {string} numStr The number to parse\n\t * @return {object} An object describing this number, containing the following keys:\n\t * - d : an array of digits containing leading zeros as necessary\n\t * - i : the number of the digits in `d` that are to the left of the decimal point\n\t * - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`\n\t *\n\t */\n\tfunction parse(numStr) {\n\t var exponent = 0, digits, numberOfIntegerDigits;\n\t var i, j, zeros;\n\t\n\t // Decimal point?\n\t if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {\n\t numStr = numStr.replace(DECIMAL_SEP, '');\n\t }\n\t\n\t // Exponential form?\n\t if ((i = numStr.search(/e/i)) > 0) {\n\t // Work out the exponent.\n\t if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;\n\t numberOfIntegerDigits += +numStr.slice(i + 1);\n\t numStr = numStr.substring(0, i);\n\t } else if (numberOfIntegerDigits < 0) {\n\t // There was no decimal point or exponent so it is an integer.\n\t numberOfIntegerDigits = numStr.length;\n\t }\n\t\n\t // Count the number of leading zeros.\n\t for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++) {/* jshint noempty: false */}\n\t\n\t if (i == (zeros = numStr.length)) {\n\t // The digits are all zero.\n\t digits = [0];\n\t numberOfIntegerDigits = 1;\n\t } else {\n\t // Count the number of trailing zeros\n\t zeros--;\n\t while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;\n\t\n\t // Trailing zeros are insignificant so ignore them\n\t numberOfIntegerDigits -= i;\n\t digits = [];\n\t // Convert string to array of digits without leading/trailing zeros.\n\t for (j = 0; i <= zeros; i++, j++) {\n\t digits[j] = +numStr.charAt(i);\n\t }\n\t }\n\t\n\t // If the number overflows the maximum allowed digits then use an exponent.\n\t if (numberOfIntegerDigits > MAX_DIGITS) {\n\t digits = digits.splice(0, MAX_DIGITS - 1);\n\t exponent = numberOfIntegerDigits - 1;\n\t numberOfIntegerDigits = 1;\n\t }\n\t\n\t return { d: digits, e: exponent, i: numberOfIntegerDigits };\n\t}\n\t\n\t/**\n\t * Round the parsed number to the specified number of decimal places\n\t * This function changed the parsedNumber in-place\n\t */\n\tfunction roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {\n\t var digits = parsedNumber.d;\n\t var fractionLen = digits.length - parsedNumber.i;\n\t\n\t // determine fractionSize if it is not specified; `+fractionSize` converts it to a number\n\t fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;\n\t\n\t // The index of the digit to where rounding is to occur\n\t var roundAt = fractionSize + parsedNumber.i;\n\t var digit = digits[roundAt];\n\t\n\t if (roundAt > 0) {\n\t // Drop fractional digits beyond `roundAt`\n\t digits.splice(Math.max(parsedNumber.i, roundAt));\n\t\n\t // Set non-fractional digits beyond `roundAt` to 0\n\t for (var j = roundAt; j < digits.length; j++) {\n\t digits[j] = 0;\n\t }\n\t } else {\n\t // We rounded to zero so reset the parsedNumber\n\t fractionLen = Math.max(0, fractionLen);\n\t parsedNumber.i = 1;\n\t digits.length = Math.max(1, roundAt = fractionSize + 1);\n\t digits[0] = 0;\n\t for (var i = 1; i < roundAt; i++) digits[i] = 0;\n\t }\n\t\n\t if (digit >= 5) {\n\t if (roundAt - 1 < 0) {\n\t for (var k = 0; k > roundAt; k--) {\n\t digits.unshift(0);\n\t parsedNumber.i++;\n\t }\n\t digits.unshift(1);\n\t parsedNumber.i++;\n\t } else {\n\t digits[roundAt - 1]++;\n\t }\n\t }\n\t\n\t // Pad out with zeros to get the required fraction length\n\t for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);\n\t\n\t\n\t // Do any carrying, e.g. a digit was rounded up to 10\n\t var carry = digits.reduceRight(function(carry, d, i, digits) {\n\t d = d + carry;\n\t digits[i] = d % 10;\n\t return Math.floor(d / 10);\n\t }, 0);\n\t if (carry) {\n\t digits.unshift(carry);\n\t parsedNumber.i++;\n\t }\n\t}\n\t\n\t/**\n\t * Format a number into a string\n\t * @param {number} number The number to format\n\t * @param {{\n\t * minFrac, // the minimum number of digits required in the fraction part of the number\n\t * maxFrac, // the maximum number of digits required in the fraction part of the number\n\t * gSize, // number of digits in each group of separated digits\n\t * lgSize, // number of digits in the last group of digits before the decimal separator\n\t * negPre, // the string to go in front of a negative number (e.g. `-` or `(`))\n\t * posPre, // the string to go in front of a positive number\n\t * negSuf, // the string to go after a negative number (e.g. `)`)\n\t * posSuf // the string to go after a positive number\n\t * }} pattern\n\t * @param {string} groupSep The string to separate groups of number (e.g. `,`)\n\t * @param {string} decimalSep The string to act as the decimal separator (e.g. `.`)\n\t * @param {[type]} fractionSize The size of the fractional part of the number\n\t * @return {string} The number formatted as a string\n\t */\n\tfunction formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {\n\t\n\t if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';\n\t\n\t var isInfinity = !isFinite(number);\n\t var isZero = false;\n\t var numStr = Math.abs(number) + '',\n\t formattedText = '',\n\t parsedNumber;\n\t\n\t if (isInfinity) {\n\t formattedText = '\\u221e';\n\t } else {\n\t parsedNumber = parse(numStr);\n\t\n\t roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);\n\t\n\t var digits = parsedNumber.d;\n\t var integerLen = parsedNumber.i;\n\t var exponent = parsedNumber.e;\n\t var decimals = [];\n\t isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);\n\t\n\t // pad zeros for small numbers\n\t while (integerLen < 0) {\n\t digits.unshift(0);\n\t integerLen++;\n\t }\n\t\n\t // extract decimals digits\n\t if (integerLen > 0) {\n\t decimals = digits.splice(integerLen, digits.length);\n\t } else {\n\t decimals = digits;\n\t digits = [0];\n\t }\n\t\n\t // format the integer digits with grouping separators\n\t var groups = [];\n\t if (digits.length >= pattern.lgSize) {\n\t groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));\n\t }\n\t while (digits.length > pattern.gSize) {\n\t groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));\n\t }\n\t if (digits.length) {\n\t groups.unshift(digits.join(''));\n\t }\n\t formattedText = groups.join(groupSep);\n\t\n\t // append the decimal digits\n\t if (decimals.length) {\n\t formattedText += decimalSep + decimals.join('');\n\t }\n\t\n\t if (exponent) {\n\t formattedText += 'e+' + exponent;\n\t }\n\t }\n\t if (number < 0 && !isZero) {\n\t return pattern.negPre + formattedText + pattern.negSuf;\n\t } else {\n\t return pattern.posPre + formattedText + pattern.posSuf;\n\t }\n\t}\n\t\n\tfunction padNumber(num, digits, trim, negWrap) {\n\t var neg = '';\n\t if (num < 0 || (negWrap && num <= 0)) {\n\t if (negWrap) {\n\t num = -num + 1;\n\t } else {\n\t num = -num;\n\t neg = '-';\n\t }\n\t }\n\t num = '' + num;\n\t while (num.length < digits) num = ZERO_CHAR + num;\n\t if (trim) {\n\t num = num.substr(num.length - digits);\n\t }\n\t return neg + num;\n\t}\n\t\n\t\n\tfunction dateGetter(name, size, offset, trim, negWrap) {\n\t offset = offset || 0;\n\t return function(date) {\n\t var value = date['get' + name]();\n\t if (offset > 0 || value > -offset) {\n\t value += offset;\n\t }\n\t if (value === 0 && offset == -12) value = 12;\n\t return padNumber(value, size, trim, negWrap);\n\t };\n\t}\n\t\n\tfunction dateStrGetter(name, shortForm, standAlone) {\n\t return function(date, formats) {\n\t var value = date['get' + name]();\n\t var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');\n\t var get = uppercase(propPrefix + name);\n\t\n\t return formats[get][value];\n\t };\n\t}\n\t\n\tfunction timeZoneGetter(date, formats, offset) {\n\t var zone = -1 * offset;\n\t var paddedZone = (zone >= 0) ? \"+\" : \"\";\n\t\n\t paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +\n\t padNumber(Math.abs(zone % 60), 2);\n\t\n\t return paddedZone;\n\t}\n\t\n\tfunction getFirstThursdayOfYear(year) {\n\t // 0 = index of January\n\t var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();\n\t // 4 = index of Thursday (+1 to account for 1st = 5)\n\t // 11 = index of *next* Thursday (+1 account for 1st = 12)\n\t return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);\n\t}\n\t\n\tfunction getThursdayThisWeek(datetime) {\n\t return new Date(datetime.getFullYear(), datetime.getMonth(),\n\t // 4 = index of Thursday\n\t datetime.getDate() + (4 - datetime.getDay()));\n\t}\n\t\n\tfunction weekGetter(size) {\n\t return function(date) {\n\t var firstThurs = getFirstThursdayOfYear(date.getFullYear()),\n\t thisThurs = getThursdayThisWeek(date);\n\t\n\t var diff = +thisThurs - +firstThurs,\n\t result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week\n\t\n\t return padNumber(result, size);\n\t };\n\t}\n\t\n\tfunction ampmGetter(date, formats) {\n\t return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];\n\t}\n\t\n\tfunction eraGetter(date, formats) {\n\t return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];\n\t}\n\t\n\tfunction longEraGetter(date, formats) {\n\t return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];\n\t}\n\t\n\tvar DATE_FORMATS = {\n\t yyyy: dateGetter('FullYear', 4, 0, false, true),\n\t yy: dateGetter('FullYear', 2, 0, true, true),\n\t y: dateGetter('FullYear', 1, 0, false, true),\n\t MMMM: dateStrGetter('Month'),\n\t MMM: dateStrGetter('Month', true),\n\t MM: dateGetter('Month', 2, 1),\n\t M: dateGetter('Month', 1, 1),\n\t LLLL: dateStrGetter('Month', false, true),\n\t dd: dateGetter('Date', 2),\n\t d: dateGetter('Date', 1),\n\t HH: dateGetter('Hours', 2),\n\t H: dateGetter('Hours', 1),\n\t hh: dateGetter('Hours', 2, -12),\n\t h: dateGetter('Hours', 1, -12),\n\t mm: dateGetter('Minutes', 2),\n\t m: dateGetter('Minutes', 1),\n\t ss: dateGetter('Seconds', 2),\n\t s: dateGetter('Seconds', 1),\n\t // while ISO 8601 requires fractions to be prefixed with `.` or `,`\n\t // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions\n\t sss: dateGetter('Milliseconds', 3),\n\t EEEE: dateStrGetter('Day'),\n\t EEE: dateStrGetter('Day', true),\n\t a: ampmGetter,\n\t Z: timeZoneGetter,\n\t ww: weekGetter(2),\n\t w: weekGetter(1),\n\t G: eraGetter,\n\t GG: eraGetter,\n\t GGG: eraGetter,\n\t GGGG: longEraGetter\n\t};\n\t\n\tvar DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,\n\t NUMBER_STRING = /^\\-?\\d+$/;\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name date\n\t * @kind function\n\t *\n\t * @description\n\t * Formats `date` to a string based on the requested `format`.\n\t *\n\t * `format` string can be composed of the following elements:\n\t *\n\t * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)\n\t * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)\n\t * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)\n\t * * `'MMMM'`: Month in year (January-December)\n\t * * `'MMM'`: Month in year (Jan-Dec)\n\t * * `'MM'`: Month in year, padded (01-12)\n\t * * `'M'`: Month in year (1-12)\n\t * * `'LLLL'`: Stand-alone month in year (January-December)\n\t * * `'dd'`: Day in month, padded (01-31)\n\t * * `'d'`: Day in month (1-31)\n\t * * `'EEEE'`: Day in Week,(Sunday-Saturday)\n\t * * `'EEE'`: Day in Week, (Sun-Sat)\n\t * * `'HH'`: Hour in day, padded (00-23)\n\t * * `'H'`: Hour in day (0-23)\n\t * * `'hh'`: Hour in AM/PM, padded (01-12)\n\t * * `'h'`: Hour in AM/PM, (1-12)\n\t * * `'mm'`: Minute in hour, padded (00-59)\n\t * * `'m'`: Minute in hour (0-59)\n\t * * `'ss'`: Second in minute, padded (00-59)\n\t * * `'s'`: Second in minute (0-59)\n\t * * `'sss'`: Millisecond in second, padded (000-999)\n\t * * `'a'`: AM/PM marker\n\t * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)\n\t * * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year\n\t * * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year\n\t * * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')\n\t * * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')\n\t *\n\t * `format` string can also be one of the following predefined\n\t * {@link guide/i18n localizable formats}:\n\t *\n\t * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale\n\t * (e.g. Sep 3, 2010 12:05:08 PM)\n\t * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 PM)\n\t * * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale\n\t * (e.g. Friday, September 3, 2010)\n\t * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)\n\t * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)\n\t * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)\n\t * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)\n\t * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)\n\t *\n\t * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.\n\t * `\"h 'in the morning'\"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence\n\t * (e.g. `\"h 'o''clock'\"`).\n\t *\n\t * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or\n\t * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its\n\t * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is\n\t * specified in the string input, the time is considered to be in the local timezone.\n\t * @param {string=} format Formatting rules (see Description). If not specified,\n\t * `mediumDate` is used.\n\t * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the\n\t * continental US time zone abbreviations, but for general use, use a time zone offset, for\n\t * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)\n\t * If not specified, the timezone of the browser will be used.\n\t * @returns {string} Formatted string or the input if input is not recognized as date/millis.\n\t *\n\t * @example\n\t \n\t \n\t {{1288323623006 | date:'medium'}}:\n\t {{1288323623006 | date:'medium'}}
\n\t {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}:\n\t {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
\n\t {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}:\n\t {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
\n\t {{1288323623006 | date:\"MM/dd/yyyy 'at' h:mma\"}}:\n\t {{'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"}}
\n\t
\n\t \n\t it('should format date', function() {\n\t expect(element(by.binding(\"1288323623006 | date:'medium'\")).getText()).\n\t toMatch(/Oct 2\\d, 2010 \\d{1,2}:\\d{2}:\\d{2} (AM|PM)/);\n\t expect(element(by.binding(\"1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'\")).getText()).\n\t toMatch(/2010\\-10\\-2\\d \\d{2}:\\d{2}:\\d{2} (\\-|\\+)?\\d{4}/);\n\t expect(element(by.binding(\"'1288323623006' | date:'MM/dd/yyyy @ h:mma'\")).getText()).\n\t toMatch(/10\\/2\\d\\/2010 @ \\d{1,2}:\\d{2}(AM|PM)/);\n\t expect(element(by.binding(\"'1288323623006' | date:\\\"MM/dd/yyyy 'at' h:mma\\\"\")).getText()).\n\t toMatch(/10\\/2\\d\\/2010 at \\d{1,2}:\\d{2}(AM|PM)/);\n\t });\n\t \n\t
\n\t */\n\tdateFilter.$inject = ['$locale'];\n\tfunction dateFilter($locale) {\n\t\n\t\n\t var R_ISO8601_STR = /^(\\d{4})-?(\\d\\d)-?(\\d\\d)(?:T(\\d\\d)(?::?(\\d\\d)(?::?(\\d\\d)(?:\\.(\\d+))?)?)?(Z|([+-])(\\d\\d):?(\\d\\d))?)?$/;\n\t // 1 2 3 4 5 6 7 8 9 10 11\n\t function jsonStringToDate(string) {\n\t var match;\n\t if (match = string.match(R_ISO8601_STR)) {\n\t var date = new Date(0),\n\t tzHour = 0,\n\t tzMin = 0,\n\t dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,\n\t timeSetter = match[8] ? date.setUTCHours : date.setHours;\n\t\n\t if (match[9]) {\n\t tzHour = toInt(match[9] + match[10]);\n\t tzMin = toInt(match[9] + match[11]);\n\t }\n\t dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));\n\t var h = toInt(match[4] || 0) - tzHour;\n\t var m = toInt(match[5] || 0) - tzMin;\n\t var s = toInt(match[6] || 0);\n\t var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);\n\t timeSetter.call(date, h, m, s, ms);\n\t return date;\n\t }\n\t return string;\n\t }\n\t\n\t\n\t return function(date, format, timezone) {\n\t var text = '',\n\t parts = [],\n\t fn, match;\n\t\n\t format = format || 'mediumDate';\n\t format = $locale.DATETIME_FORMATS[format] || format;\n\t if (isString(date)) {\n\t date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);\n\t }\n\t\n\t if (isNumber(date)) {\n\t date = new Date(date);\n\t }\n\t\n\t if (!isDate(date) || !isFinite(date.getTime())) {\n\t return date;\n\t }\n\t\n\t while (format) {\n\t match = DATE_FORMATS_SPLIT.exec(format);\n\t if (match) {\n\t parts = concat(parts, match, 1);\n\t format = parts.pop();\n\t } else {\n\t parts.push(format);\n\t format = null;\n\t }\n\t }\n\t\n\t var dateTimezoneOffset = date.getTimezoneOffset();\n\t if (timezone) {\n\t dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);\n\t date = convertTimezoneToLocal(date, timezone, true);\n\t }\n\t forEach(parts, function(value) {\n\t fn = DATE_FORMATS[value];\n\t text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)\n\t : value === \"''\" ? \"'\" : value.replace(/(^'|'$)/g, '').replace(/''/g, \"'\");\n\t });\n\t\n\t return text;\n\t };\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name json\n\t * @kind function\n\t *\n\t * @description\n\t * Allows you to convert a JavaScript object into JSON string.\n\t *\n\t * This filter is mostly useful for debugging. When using the double curly {{value}} notation\n\t * the binding is automatically converted to JSON.\n\t *\n\t * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.\n\t * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.\n\t * @returns {string} JSON string.\n\t *\n\t *\n\t * @example\n\t \n\t \n\t
{{ {'name':'value'} | json }}
\n\t
{{ {'name':'value'} | json:4 }}
\n\t
\n\t \n\t it('should jsonify filtered objects', function() {\n\t expect(element(by.id('default-spacing')).getText()).toMatch(/\\{\\n \"name\": ?\"value\"\\n}/);\n\t expect(element(by.id('custom-spacing')).getText()).toMatch(/\\{\\n \"name\": ?\"value\"\\n}/);\n\t });\n\t \n\t
\n\t *\n\t */\n\tfunction jsonFilter() {\n\t return function(object, spacing) {\n\t if (isUndefined(spacing)) {\n\t spacing = 2;\n\t }\n\t return toJson(object, spacing);\n\t };\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name lowercase\n\t * @kind function\n\t * @description\n\t * Converts string to lowercase.\n\t * @see angular.lowercase\n\t */\n\tvar lowercaseFilter = valueFn(lowercase);\n\t\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name uppercase\n\t * @kind function\n\t * @description\n\t * Converts string to uppercase.\n\t * @see angular.uppercase\n\t */\n\tvar uppercaseFilter = valueFn(uppercase);\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name limitTo\n\t * @kind function\n\t *\n\t * @description\n\t * Creates a new array or string containing only a specified number of elements. The elements are\n\t * taken from either the beginning or the end of the source array, string or number, as specified by\n\t * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported\n\t * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,\n\t * it is converted to a string.\n\t *\n\t * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.\n\t * @param {string|number} limit - The length of the returned array or string. If the `limit` number\n\t * is positive, `limit` number of items from the beginning of the source array/string are copied.\n\t * If the number is negative, `limit` number of items from the end of the source array/string\n\t * are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,\n\t * the input will be returned unchanged.\n\t * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,\n\t * `begin` indicates an offset from the end of `input`. Defaults to `0`.\n\t * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had\n\t * less than `limit` elements.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t

Output numbers: {{ numbers | limitTo:numLimit }}

\n\t \n\t

Output letters: {{ letters | limitTo:letterLimit }}

\n\t \n\t

Output long number: {{ longNumber | limitTo:longNumberLimit }}

\n\t
\n\t
\n\t \n\t var numLimitInput = element(by.model('numLimit'));\n\t var letterLimitInput = element(by.model('letterLimit'));\n\t var longNumberLimitInput = element(by.model('longNumberLimit'));\n\t var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));\n\t var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));\n\t var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));\n\t\n\t it('should limit the number array to first three items', function() {\n\t expect(numLimitInput.getAttribute('value')).toBe('3');\n\t expect(letterLimitInput.getAttribute('value')).toBe('3');\n\t expect(longNumberLimitInput.getAttribute('value')).toBe('3');\n\t expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');\n\t expect(limitedLetters.getText()).toEqual('Output letters: abc');\n\t expect(limitedLongNumber.getText()).toEqual('Output long number: 234');\n\t });\n\t\n\t // There is a bug in safari and protractor that doesn't like the minus key\n\t // it('should update the output when -3 is entered', function() {\n\t // numLimitInput.clear();\n\t // numLimitInput.sendKeys('-3');\n\t // letterLimitInput.clear();\n\t // letterLimitInput.sendKeys('-3');\n\t // longNumberLimitInput.clear();\n\t // longNumberLimitInput.sendKeys('-3');\n\t // expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');\n\t // expect(limitedLetters.getText()).toEqual('Output letters: ghi');\n\t // expect(limitedLongNumber.getText()).toEqual('Output long number: 342');\n\t // });\n\t\n\t it('should not exceed the maximum size of input array', function() {\n\t numLimitInput.clear();\n\t numLimitInput.sendKeys('100');\n\t letterLimitInput.clear();\n\t letterLimitInput.sendKeys('100');\n\t longNumberLimitInput.clear();\n\t longNumberLimitInput.sendKeys('100');\n\t expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');\n\t expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');\n\t expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');\n\t });\n\t \n\t
\n\t*/\n\tfunction limitToFilter() {\n\t return function(input, limit, begin) {\n\t if (Math.abs(Number(limit)) === Infinity) {\n\t limit = Number(limit);\n\t } else {\n\t limit = toInt(limit);\n\t }\n\t if (isNaN(limit)) return input;\n\t\n\t if (isNumber(input)) input = input.toString();\n\t if (!isArrayLike(input)) return input;\n\t\n\t begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);\n\t begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;\n\t\n\t if (limit >= 0) {\n\t return sliceFn(input, begin, begin + limit);\n\t } else {\n\t if (begin === 0) {\n\t return sliceFn(input, limit, input.length);\n\t } else {\n\t return sliceFn(input, Math.max(0, begin + limit), begin);\n\t }\n\t }\n\t };\n\t}\n\t\n\tfunction sliceFn(input, begin, end) {\n\t if (isString(input)) return input.slice(begin, end);\n\t\n\t return slice.call(input, begin, end);\n\t}\n\t\n\t/**\n\t * @ngdoc filter\n\t * @name orderBy\n\t * @kind function\n\t *\n\t * @description\n\t * Returns an array containing the items from the specified `collection`, ordered by a `comparator`\n\t * function based on the values computed using the `expression` predicate.\n\t *\n\t * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in\n\t * `[{id: 'bar'}, {id: 'foo'}]`.\n\t *\n\t * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,\n\t * String, etc).\n\t *\n\t * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker\n\t * for the preceeding one. The `expression` is evaluated against each item and the output is used\n\t * for comparing with other items.\n\t *\n\t * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in\n\t * ascending order.\n\t *\n\t * The comparison is done using the `comparator` function. If none is specified, a default, built-in\n\t * comparator is used (see below for details - in a nutshell, it compares numbers numerically and\n\t * strings alphabetically).\n\t *\n\t * ### Under the hood\n\t *\n\t * Ordering the specified `collection` happens in two phases:\n\t *\n\t * 1. All items are passed through the predicate (or predicates), and the returned values are saved\n\t * along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed\n\t * through a predicate that extracts the value of the `label` property, would be transformed to:\n\t * ```\n\t * {\n\t * value: 'foo',\n\t * type: 'string',\n\t * index: ...\n\t * }\n\t * ```\n\t * 2. The comparator function is used to sort the items, based on the derived values, types and\n\t * indices.\n\t *\n\t * If you use a custom comparator, it will be called with pairs of objects of the form\n\t * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal\n\t * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the\n\t * second, or `1` otherwise.\n\t *\n\t * In order to ensure that the sorting will be deterministic across platforms, if none of the\n\t * specified predicates can distinguish between two items, `orderBy` will automatically introduce a\n\t * dummy predicate that returns the item's index as `value`.\n\t * (If you are using a custom comparator, make sure it can handle this predicate as well.)\n\t *\n\t * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted\n\t * value for an item, `orderBy` will try to convert that object to a primitive value, before passing\n\t * it to the comparator. The following rules govern the conversion:\n\t *\n\t * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be\n\t * used instead.
\n\t * (If the object has a `valueOf()` method that returns another object, then the returned object\n\t * will be used in subsequent steps.)\n\t * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that\n\t * returns a primitive, its return value will be used instead.
\n\t * (If the object has a `toString()` method that returns another object, then the returned object\n\t * will be used in subsequent steps.)\n\t * 3. No conversion; the object itself is used.\n\t *\n\t * ### The default comparator\n\t *\n\t * The default, built-in comparator should be sufficient for most usecases. In short, it compares\n\t * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to\n\t * using their index in the original collection, and sorts values of different types by type.\n\t *\n\t * More specifically, it follows these steps to determine the relative order of items:\n\t *\n\t * 1. If the compared values are of different types, compare the types themselves alphabetically.\n\t * 2. If both values are of type `string`, compare them alphabetically in a case- and\n\t * locale-insensitive way.\n\t * 3. If both values are objects, compare their indices instead.\n\t * 4. Otherwise, return:\n\t * - `0`, if the values are equal (by strict equality comparison, i.e. using `===`).\n\t * - `-1`, if the 1st value is \"less than\" the 2nd value (compared using the `<` operator).\n\t * - `1`, otherwise.\n\t *\n\t * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being\n\t * saved as numbers and not strings.\n\t *\n\t * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.\n\t * @param {(Function|string|Array.)=} expression - A predicate (or list of\n\t * predicates) to be used by the comparator to determine the order of elements.\n\t *\n\t * Can be one of:\n\t *\n\t * - `Function`: A getter function. This function will be called with each item as argument and\n\t * the return value will be used for sorting.\n\t * - `string`: An Angular expression. This expression will be evaluated against each item and the\n\t * result will be used for sorting. For example, use `'label'` to sort by a property called\n\t * `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`\n\t * property.
\n\t * (The result of a constant expression is interpreted as a property name to be used for\n\t * comparison. For example, use `'\"special name\"'` (note the extra pair of quotes) to sort by a\n\t * property called `special name`.)
\n\t * An expression can be optionally prefixed with `+` or `-` to control the sorting direction,\n\t * ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,\n\t * (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.\n\t * - `Array`: An array of function and/or string predicates. If a predicate cannot determine the\n\t * relative order of two items, the next predicate is used as a tie-breaker.\n\t *\n\t * **Note:** If the predicate is missing or empty then it defaults to `'+'`.\n\t *\n\t * @param {boolean=} reverse - If `true`, reverse the sorting order.\n\t * @param {(Function)=} comparator - The comparator function used to determine the relative order of\n\t * value pairs. If omitted, the built-in comparator will be used.\n\t *\n\t * @returns {Array} - The sorted array.\n\t *\n\t *\n\t * @example\n\t * ### Ordering a table with `ngRepeat`\n\t *\n\t * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by\n\t * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means\n\t * it defaults to the built-in comparator.\n\t *\n\t \n\t \n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
NamePhone NumberAge
{{friend.name}}{{friend.phone}}{{friend.age}}
\n\t
\n\t
\n\t \n\t angular.module('orderByExample1', [])\n\t .controller('ExampleController', ['$scope', function($scope) {\n\t $scope.friends = [\n\t {name: 'John', phone: '555-1212', age: 10},\n\t {name: 'Mary', phone: '555-9876', age: 19},\n\t {name: 'Mike', phone: '555-4321', age: 21},\n\t {name: 'Adam', phone: '555-5678', age: 35},\n\t {name: 'Julie', phone: '555-8765', age: 29}\n\t ];\n\t }]);\n\t \n\t \n\t .friends {\n\t border-collapse: collapse;\n\t }\n\t\n\t .friends th {\n\t border-bottom: 1px solid;\n\t }\n\t .friends td, .friends th {\n\t border-left: 1px solid;\n\t padding: 5px 10px;\n\t }\n\t .friends td:first-child, .friends th:first-child {\n\t border-left: none;\n\t }\n\t \n\t \n\t // Element locators\n\t var names = element.all(by.repeater('friends').column('friend.name'));\n\t\n\t it('should sort friends by age in reverse order', function() {\n\t expect(names.get(0).getText()).toBe('Adam');\n\t expect(names.get(1).getText()).toBe('Julie');\n\t expect(names.get(2).getText()).toBe('Mike');\n\t expect(names.get(3).getText()).toBe('Mary');\n\t expect(names.get(4).getText()).toBe('John');\n\t });\n\t \n\t
\n\t *
\n\t *\n\t * @example\n\t * ### Changing parameters dynamically\n\t *\n\t * All parameters can be changed dynamically. The next example shows how you can make the columns of\n\t * a table sortable, by binding the `expression` and `reverse` parameters to scope properties.\n\t *\n\t \n\t \n\t
\n\t
Sort by = {{propertyName}}; reverse = {{reverse}}
\n\t
\n\t \n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
{{friend.name}}{{friend.phone}}{{friend.age}}
\n\t
\n\t
\n\t \n\t angular.module('orderByExample2', [])\n\t .controller('ExampleController', ['$scope', function($scope) {\n\t var friends = [\n\t {name: 'John', phone: '555-1212', age: 10},\n\t {name: 'Mary', phone: '555-9876', age: 19},\n\t {name: 'Mike', phone: '555-4321', age: 21},\n\t {name: 'Adam', phone: '555-5678', age: 35},\n\t {name: 'Julie', phone: '555-8765', age: 29}\n\t ];\n\t\n\t $scope.propertyName = 'age';\n\t $scope.reverse = true;\n\t $scope.friends = friends;\n\t\n\t $scope.sortBy = function(propertyName) {\n\t $scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;\n\t $scope.propertyName = propertyName;\n\t };\n\t }]);\n\t \n\t \n\t .friends {\n\t border-collapse: collapse;\n\t }\n\t\n\t .friends th {\n\t border-bottom: 1px solid;\n\t }\n\t .friends td, .friends th {\n\t border-left: 1px solid;\n\t padding: 5px 10px;\n\t }\n\t .friends td:first-child, .friends th:first-child {\n\t border-left: none;\n\t }\n\t\n\t .sortorder:after {\n\t content: '\\25b2'; // BLACK UP-POINTING TRIANGLE\n\t }\n\t .sortorder.reverse:after {\n\t content: '\\25bc'; // BLACK DOWN-POINTING TRIANGLE\n\t }\n\t \n\t \n\t // Element locators\n\t var unsortButton = element(by.partialButtonText('unsorted'));\n\t var nameHeader = element(by.partialButtonText('Name'));\n\t var phoneHeader = element(by.partialButtonText('Phone'));\n\t var ageHeader = element(by.partialButtonText('Age'));\n\t var firstName = element(by.repeater('friends').column('friend.name').row(0));\n\t var lastName = element(by.repeater('friends').column('friend.name').row(4));\n\t\n\t it('should sort friends by some property, when clicking on the column header', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t phoneHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Mary');\n\t\n\t nameHeader.click();\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('Mike');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Adam');\n\t });\n\t\n\t it('should sort friends in reverse order, when clicking on the same column', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Adam');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t });\n\t\n\t it('should restore the original order, when clicking \"Set to unsorted\"', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t unsortButton.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Julie');\n\t });\n\t \n\t
\n\t *
\n\t *\n\t * @example\n\t * ### Using `orderBy` inside a controller\n\t *\n\t * It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and\n\t * calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory\n\t * and retrieve the `orderBy` filter with `$filter('orderBy')`.)\n\t *\n\t \n\t \n\t
\n\t
Sort by = {{propertyName}}; reverse = {{reverse}}
\n\t
\n\t \n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
{{friend.name}}{{friend.phone}}{{friend.age}}
\n\t
\n\t
\n\t \n\t angular.module('orderByExample3', [])\n\t .controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) {\n\t var friends = [\n\t {name: 'John', phone: '555-1212', age: 10},\n\t {name: 'Mary', phone: '555-9876', age: 19},\n\t {name: 'Mike', phone: '555-4321', age: 21},\n\t {name: 'Adam', phone: '555-5678', age: 35},\n\t {name: 'Julie', phone: '555-8765', age: 29}\n\t ];\n\t\n\t $scope.propertyName = 'age';\n\t $scope.reverse = true;\n\t $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);\n\t\n\t $scope.sortBy = function(propertyName) {\n\t $scope.reverse = (propertyName !== null && $scope.propertyName === propertyName)\n\t ? !$scope.reverse : false;\n\t $scope.propertyName = propertyName;\n\t $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);\n\t };\n\t }]);\n\t \n\t \n\t .friends {\n\t border-collapse: collapse;\n\t }\n\t\n\t .friends th {\n\t border-bottom: 1px solid;\n\t }\n\t .friends td, .friends th {\n\t border-left: 1px solid;\n\t padding: 5px 10px;\n\t }\n\t .friends td:first-child, .friends th:first-child {\n\t border-left: none;\n\t }\n\t\n\t .sortorder:after {\n\t content: '\\25b2'; // BLACK UP-POINTING TRIANGLE\n\t }\n\t .sortorder.reverse:after {\n\t content: '\\25bc'; // BLACK DOWN-POINTING TRIANGLE\n\t }\n\t \n\t \n\t // Element locators\n\t var unsortButton = element(by.partialButtonText('unsorted'));\n\t var nameHeader = element(by.partialButtonText('Name'));\n\t var phoneHeader = element(by.partialButtonText('Phone'));\n\t var ageHeader = element(by.partialButtonText('Age'));\n\t var firstName = element(by.repeater('friends').column('friend.name').row(0));\n\t var lastName = element(by.repeater('friends').column('friend.name').row(4));\n\t\n\t it('should sort friends by some property, when clicking on the column header', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t phoneHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Mary');\n\t\n\t nameHeader.click();\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('Mike');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Adam');\n\t });\n\t\n\t it('should sort friends in reverse order, when clicking on the same column', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Adam');\n\t\n\t ageHeader.click();\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t });\n\t\n\t it('should restore the original order, when clicking \"Set to unsorted\"', function() {\n\t expect(firstName.getText()).toBe('Adam');\n\t expect(lastName.getText()).toBe('John');\n\t\n\t unsortButton.click();\n\t expect(firstName.getText()).toBe('John');\n\t expect(lastName.getText()).toBe('Julie');\n\t });\n\t \n\t
\n\t *
\n\t *\n\t * @example\n\t * ### Using a custom comparator\n\t *\n\t * If you have very specific requirements about the way items are sorted, you can pass your own\n\t * comparator function. For example, you might need to compare some strings in a locale-sensitive\n\t * way. (When specifying a custom comparator, you also need to pass a value for the `reverse`\n\t * argument - passing `false` retains the default sorting order, i.e. ascending.)\n\t *\n\t \n\t \n\t
\n\t
\n\t

Locale-sensitive Comparator

\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
NameFavorite Letter
{{friend.name}}{{friend.favoriteLetter}}
\n\t
\n\t
\n\t

Default Comparator

\n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t
NameFavorite Letter
{{friend.name}}{{friend.favoriteLetter}}
\n\t
\n\t
\n\t
\n\t \n\t angular.module('orderByExample4', [])\n\t .controller('ExampleController', ['$scope', function($scope) {\n\t $scope.friends = [\n\t {name: 'John', favoriteLetter: 'Ä'},\n\t {name: 'Mary', favoriteLetter: 'Ü'},\n\t {name: 'Mike', favoriteLetter: 'Ö'},\n\t {name: 'Adam', favoriteLetter: 'H'},\n\t {name: 'Julie', favoriteLetter: 'Z'}\n\t ];\n\t\n\t $scope.localeSensitiveComparator = function(v1, v2) {\n\t // If we don't get strings, just compare by index\n\t if (v1.type !== 'string' || v2.type !== 'string') {\n\t return (v1.index < v2.index) ? -1 : 1;\n\t }\n\t\n\t // Compare strings alphabetically, taking locale into account\n\t return v1.value.localeCompare(v2.value);\n\t };\n\t }]);\n\t \n\t \n\t .friends-container {\n\t display: inline-block;\n\t margin: 0 30px;\n\t }\n\t\n\t .friends {\n\t border-collapse: collapse;\n\t }\n\t\n\t .friends th {\n\t border-bottom: 1px solid;\n\t }\n\t .friends td, .friends th {\n\t border-left: 1px solid;\n\t padding: 5px 10px;\n\t }\n\t .friends td:first-child, .friends th:first-child {\n\t border-left: none;\n\t }\n\t \n\t \n\t // Element locators\n\t var container = element(by.css('.custom-comparator'));\n\t var names = container.all(by.repeater('friends').column('friend.name'));\n\t\n\t it('should sort friends by favorite letter (in correct alphabetical order)', function() {\n\t expect(names.get(0).getText()).toBe('John');\n\t expect(names.get(1).getText()).toBe('Adam');\n\t expect(names.get(2).getText()).toBe('Mike');\n\t expect(names.get(3).getText()).toBe('Mary');\n\t expect(names.get(4).getText()).toBe('Julie');\n\t });\n\t \n\t
\n\t *\n\t */\n\torderByFilter.$inject = ['$parse'];\n\tfunction orderByFilter($parse) {\n\t return function(array, sortPredicate, reverseOrder, compareFn) {\n\t\n\t if (array == null) return array;\n\t if (!isArrayLike(array)) {\n\t throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);\n\t }\n\t\n\t if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }\n\t if (sortPredicate.length === 0) { sortPredicate = ['+']; }\n\t\n\t var predicates = processPredicates(sortPredicate);\n\t\n\t var descending = reverseOrder ? -1 : 1;\n\t\n\t // Define the `compare()` function. Use a default comparator if none is specified.\n\t var compare = isFunction(compareFn) ? compareFn : defaultCompare;\n\t\n\t // The next three lines are a version of a Swartzian Transform idiom from Perl\n\t // (sometimes called the Decorate-Sort-Undecorate idiom)\n\t // See https://en.wikipedia.org/wiki/Schwartzian_transform\n\t var compareValues = Array.prototype.map.call(array, getComparisonObject);\n\t compareValues.sort(doComparison);\n\t array = compareValues.map(function(item) { return item.value; });\n\t\n\t return array;\n\t\n\t function getComparisonObject(value, index) {\n\t // NOTE: We are adding an extra `tieBreaker` value based on the element's index.\n\t // This will be used to keep the sort stable when none of the input predicates can\n\t // distinguish between two elements.\n\t return {\n\t value: value,\n\t tieBreaker: {value: index, type: 'number', index: index},\n\t predicateValues: predicates.map(function(predicate) {\n\t return getPredicateValue(predicate.get(value), index);\n\t })\n\t };\n\t }\n\t\n\t function doComparison(v1, v2) {\n\t for (var i = 0, ii = predicates.length; i < ii; i++) {\n\t var result = compare(v1.predicateValues[i], v2.predicateValues[i]);\n\t if (result) {\n\t return result * predicates[i].descending * descending;\n\t }\n\t }\n\t\n\t return compare(v1.tieBreaker, v2.tieBreaker) * descending;\n\t }\n\t };\n\t\n\t function processPredicates(sortPredicates) {\n\t return sortPredicates.map(function(predicate) {\n\t var descending = 1, get = identity;\n\t\n\t if (isFunction(predicate)) {\n\t get = predicate;\n\t } else if (isString(predicate)) {\n\t if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {\n\t descending = predicate.charAt(0) == '-' ? -1 : 1;\n\t predicate = predicate.substring(1);\n\t }\n\t if (predicate !== '') {\n\t get = $parse(predicate);\n\t if (get.constant) {\n\t var key = get();\n\t get = function(value) { return value[key]; };\n\t }\n\t }\n\t }\n\t return {get: get, descending: descending};\n\t });\n\t }\n\t\n\t function isPrimitive(value) {\n\t switch (typeof value) {\n\t case 'number': /* falls through */\n\t case 'boolean': /* falls through */\n\t case 'string':\n\t return true;\n\t default:\n\t return false;\n\t }\n\t }\n\t\n\t function objectValue(value) {\n\t // If `valueOf` is a valid function use that\n\t if (isFunction(value.valueOf)) {\n\t value = value.valueOf();\n\t if (isPrimitive(value)) return value;\n\t }\n\t // If `toString` is a valid function and not the one from `Object.prototype` use that\n\t if (hasCustomToString(value)) {\n\t value = value.toString();\n\t if (isPrimitive(value)) return value;\n\t }\n\t\n\t return value;\n\t }\n\t\n\t function getPredicateValue(value, index) {\n\t var type = typeof value;\n\t if (value === null) {\n\t type = 'string';\n\t value = 'null';\n\t } else if (type === 'object') {\n\t value = objectValue(value);\n\t }\n\t return {value: value, type: type, index: index};\n\t }\n\t\n\t function defaultCompare(v1, v2) {\n\t var result = 0;\n\t var type1 = v1.type;\n\t var type2 = v2.type;\n\t\n\t if (type1 === type2) {\n\t var value1 = v1.value;\n\t var value2 = v2.value;\n\t\n\t if (type1 === 'string') {\n\t // Compare strings case-insensitively\n\t value1 = value1.toLowerCase();\n\t value2 = value2.toLowerCase();\n\t } else if (type1 === 'object') {\n\t // For basic objects, use the position of the object\n\t // in the collection instead of the value\n\t if (isObject(value1)) value1 = v1.index;\n\t if (isObject(value2)) value2 = v2.index;\n\t }\n\t\n\t if (value1 !== value2) {\n\t result = value1 < value2 ? -1 : 1;\n\t }\n\t } else {\n\t result = type1 < type2 ? -1 : 1;\n\t }\n\t\n\t return result;\n\t }\n\t}\n\t\n\tfunction ngDirective(directive) {\n\t if (isFunction(directive)) {\n\t directive = {\n\t link: directive\n\t };\n\t }\n\t directive.restrict = directive.restrict || 'AC';\n\t return valueFn(directive);\n\t}\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name a\n\t * @restrict E\n\t *\n\t * @description\n\t * Modifies the default behavior of the html A tag so that the default action is prevented when\n\t * the href attribute is empty.\n\t *\n\t * This change permits the easy creation of action links with the `ngClick` directive\n\t * without changing the location or causing page reloads, e.g.:\n\t * `Add Item`\n\t */\n\tvar htmlAnchorDirective = valueFn({\n\t restrict: 'E',\n\t compile: function(element, attr) {\n\t if (!attr.href && !attr.xlinkHref) {\n\t return function(scope, element) {\n\t // If the linked element is not an anchor tag anymore, do nothing\n\t if (element[0].nodeName.toLowerCase() !== 'a') return;\n\t\n\t // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.\n\t var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?\n\t 'xlink:href' : 'href';\n\t element.on('click', function(event) {\n\t // if we have no href url, then don't navigate anywhere.\n\t if (!element.attr(href)) {\n\t event.preventDefault();\n\t }\n\t });\n\t };\n\t }\n\t }\n\t});\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngHref\n\t * @restrict A\n\t * @priority 99\n\t *\n\t * @description\n\t * Using Angular markup like `{{hash}}` in an href attribute will\n\t * make the link go to the wrong URL if the user clicks it before\n\t * Angular has a chance to replace the `{{hash}}` markup with its\n\t * value. Until Angular replaces the markup the link will be broken\n\t * and will most likely return a 404 error. The `ngHref` directive\n\t * solves this problem.\n\t *\n\t * The wrong way to write it:\n\t * ```html\n\t * link1\n\t * ```\n\t *\n\t * The correct way to write it:\n\t * ```html\n\t * link1\n\t * ```\n\t *\n\t * @element A\n\t * @param {template} ngHref any string which can contain `{{}}` markup.\n\t *\n\t * @example\n\t * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes\n\t * in links and their different behaviors:\n\t \n\t \n\t
\n\t link 1 (link, don't reload)
\n\t link 2 (link, don't reload)
\n\t link 3 (link, reload!)
\n\t anchor (link, don't reload)
\n\t anchor (no link)
\n\t link (link, change location)\n\t
\n\t \n\t it('should execute ng-click but not reload when href without value', function() {\n\t element(by.id('link-1')).click();\n\t expect(element(by.model('value')).getAttribute('value')).toEqual('1');\n\t expect(element(by.id('link-1')).getAttribute('href')).toBe('');\n\t });\n\t\n\t it('should execute ng-click but not reload when href empty string', function() {\n\t element(by.id('link-2')).click();\n\t expect(element(by.model('value')).getAttribute('value')).toEqual('2');\n\t expect(element(by.id('link-2')).getAttribute('href')).toBe('');\n\t });\n\t\n\t it('should execute ng-click and change url when ng-href specified', function() {\n\t expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\\/123$/);\n\t\n\t element(by.id('link-3')).click();\n\t\n\t // At this point, we navigate away from an Angular page, so we need\n\t // to use browser.driver to get the base webdriver.\n\t\n\t browser.wait(function() {\n\t return browser.driver.getCurrentUrl().then(function(url) {\n\t return url.match(/\\/123$/);\n\t });\n\t }, 5000, 'page should navigate to /123');\n\t });\n\t\n\t it('should execute ng-click but not reload when href empty string and name specified', function() {\n\t element(by.id('link-4')).click();\n\t expect(element(by.model('value')).getAttribute('value')).toEqual('4');\n\t expect(element(by.id('link-4')).getAttribute('href')).toBe('');\n\t });\n\t\n\t it('should execute ng-click but not reload when no href but name specified', function() {\n\t element(by.id('link-5')).click();\n\t expect(element(by.model('value')).getAttribute('value')).toEqual('5');\n\t expect(element(by.id('link-5')).getAttribute('href')).toBe(null);\n\t });\n\t\n\t it('should only change url when only ng-href', function() {\n\t element(by.model('value')).clear();\n\t element(by.model('value')).sendKeys('6');\n\t expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\\/6$/);\n\t\n\t element(by.id('link-6')).click();\n\t\n\t // At this point, we navigate away from an Angular page, so we need\n\t // to use browser.driver to get the base webdriver.\n\t browser.wait(function() {\n\t return browser.driver.getCurrentUrl().then(function(url) {\n\t return url.match(/\\/6$/);\n\t });\n\t }, 5000, 'page should navigate to /6');\n\t });\n\t \n\t
\n\t */\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngSrc\n\t * @restrict A\n\t * @priority 99\n\t *\n\t * @description\n\t * Using Angular markup like `{{hash}}` in a `src` attribute doesn't\n\t * work right: The browser will fetch from the URL with the literal\n\t * text `{{hash}}` until Angular replaces the expression inside\n\t * `{{hash}}`. The `ngSrc` directive solves this problem.\n\t *\n\t * The buggy way to write it:\n\t * ```html\n\t * \"Description\"/\n\t * ```\n\t *\n\t * The correct way to write it:\n\t * ```html\n\t * \"Description\"\n\t * ```\n\t *\n\t * @element IMG\n\t * @param {template} ngSrc any string which can contain `{{}}` markup.\n\t */\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngSrcset\n\t * @restrict A\n\t * @priority 99\n\t *\n\t * @description\n\t * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't\n\t * work right: The browser will fetch from the URL with the literal\n\t * text `{{hash}}` until Angular replaces the expression inside\n\t * `{{hash}}`. The `ngSrcset` directive solves this problem.\n\t *\n\t * The buggy way to write it:\n\t * ```html\n\t * \"Description\"/\n\t * ```\n\t *\n\t * The correct way to write it:\n\t * ```html\n\t * \"Description\"\n\t * ```\n\t *\n\t * @element IMG\n\t * @param {template} ngSrcset any string which can contain `{{}}` markup.\n\t */\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngDisabled\n\t * @restrict A\n\t * @priority 100\n\t *\n\t * @description\n\t *\n\t * This directive sets the `disabled` attribute on the element if the\n\t * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.\n\t *\n\t * A special directive is necessary because we cannot use interpolation inside the `disabled`\n\t * attribute. See the {@link guide/interpolation interpolation guide} for more info.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t
\n\t \n\t it('should toggle button', function() {\n\t expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();\n\t element(by.model('checked')).click();\n\t expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();\n\t });\n\t \n\t
\n\t *\n\t * @element INPUT\n\t * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,\n\t * then the `disabled` attribute will be set on the element\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngChecked\n\t * @restrict A\n\t * @priority 100\n\t *\n\t * @description\n\t * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.\n\t *\n\t * Note that this directive should not be used together with {@link ngModel `ngModel`},\n\t * as this can lead to unexpected behavior.\n\t *\n\t * A special directive is necessary because we cannot use interpolation inside the `checked`\n\t * attribute. See the {@link guide/interpolation interpolation guide} for more info.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t
\n\t \n\t it('should check both checkBoxes', function() {\n\t expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();\n\t element(by.model('master')).click();\n\t expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();\n\t });\n\t \n\t
\n\t *\n\t * @element INPUT\n\t * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,\n\t * then the `checked` attribute will be set on the element\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngReadonly\n\t * @restrict A\n\t * @priority 100\n\t *\n\t * @description\n\t *\n\t * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.\n\t * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on\n\t * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.\n\t *\n\t * A special directive is necessary because we cannot use interpolation inside the `readonly`\n\t * attribute. See the {@link guide/interpolation interpolation guide} for more info.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t
\n\t \n\t it('should toggle readonly attr', function() {\n\t expect(element(by.css('[type=\"text\"]')).getAttribute('readonly')).toBeFalsy();\n\t element(by.model('checked')).click();\n\t expect(element(by.css('[type=\"text\"]')).getAttribute('readonly')).toBeTruthy();\n\t });\n\t \n\t
\n\t *\n\t * @element INPUT\n\t * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,\n\t * then special attribute \"readonly\" will be set on the element\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngSelected\n\t * @restrict A\n\t * @priority 100\n\t *\n\t * @description\n\t *\n\t * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.\n\t *\n\t * A special directive is necessary because we cannot use interpolation inside the `selected`\n\t * attribute. See the {@link guide/interpolation interpolation guide} for more info.\n\t *\n\t *
\n\t * **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only\n\t * sets the `selected` attribute on the element. If you are using `ngModel` on the select, you\n\t * should not use `ngSelected` on the options, as `ngModel` will set the select value and\n\t * selected options.\n\t *
\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t
\n\t \n\t it('should select Greetings!', function() {\n\t expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();\n\t element(by.model('selected')).click();\n\t expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();\n\t });\n\t \n\t
\n\t *\n\t * @element OPTION\n\t * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,\n\t * then special attribute \"selected\" will be set on the element\n\t */\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngOpen\n\t * @restrict A\n\t * @priority 100\n\t *\n\t * @description\n\t *\n\t * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.\n\t *\n\t * A special directive is necessary because we cannot use interpolation inside the `open`\n\t * attribute. See the {@link guide/interpolation interpolation guide} for more info.\n\t *\n\t * ## A note about browser compatibility\n\t *\n\t * Edge, Firefox, and Internet Explorer do not support the `details` element, it is\n\t * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.\n\t *\n\t * @example\n\t \n\t \n\t
\n\t
\n\t Show/Hide me\n\t
\n\t
\n\t \n\t it('should toggle open', function() {\n\t expect(element(by.id('details')).getAttribute('open')).toBeFalsy();\n\t element(by.model('open')).click();\n\t expect(element(by.id('details')).getAttribute('open')).toBeTruthy();\n\t });\n\t \n\t
\n\t *\n\t * @element DETAILS\n\t * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,\n\t * then special attribute \"open\" will be set on the element\n\t */\n\t\n\tvar ngAttributeAliasDirectives = {};\n\t\n\t// boolean attrs are evaluated\n\tforEach(BOOLEAN_ATTR, function(propName, attrName) {\n\t // binding to multiple is not supported\n\t if (propName == \"multiple\") return;\n\t\n\t function defaultLinkFn(scope, element, attr) {\n\t scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {\n\t attr.$set(attrName, !!value);\n\t });\n\t }\n\t\n\t var normalized = directiveNormalize('ng-' + attrName);\n\t var linkFn = defaultLinkFn;\n\t\n\t if (propName === 'checked') {\n\t linkFn = function(scope, element, attr) {\n\t // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input\n\t if (attr.ngModel !== attr[normalized]) {\n\t defaultLinkFn(scope, element, attr);\n\t }\n\t };\n\t }\n\t\n\t ngAttributeAliasDirectives[normalized] = function() {\n\t return {\n\t restrict: 'A',\n\t priority: 100,\n\t link: linkFn\n\t };\n\t };\n\t});\n\t\n\t// aliased input attrs are evaluated\n\tforEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {\n\t ngAttributeAliasDirectives[ngAttr] = function() {\n\t return {\n\t priority: 100,\n\t link: function(scope, element, attr) {\n\t //special case ngPattern when a literal regular expression value\n\t //is used as the expression (this way we don't have to watch anything).\n\t if (ngAttr === \"ngPattern\" && attr.ngPattern.charAt(0) == \"/\") {\n\t var match = attr.ngPattern.match(REGEX_STRING_REGEXP);\n\t if (match) {\n\t attr.$set(\"ngPattern\", new RegExp(match[1], match[2]));\n\t return;\n\t }\n\t }\n\t\n\t scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {\n\t attr.$set(ngAttr, value);\n\t });\n\t }\n\t };\n\t };\n\t});\n\t\n\t// ng-src, ng-srcset, ng-href are interpolated\n\tforEach(['src', 'srcset', 'href'], function(attrName) {\n\t var normalized = directiveNormalize('ng-' + attrName);\n\t ngAttributeAliasDirectives[normalized] = function() {\n\t return {\n\t priority: 99, // it needs to run after the attributes are interpolated\n\t link: function(scope, element, attr) {\n\t var propName = attrName,\n\t name = attrName;\n\t\n\t if (attrName === 'href' &&\n\t toString.call(element.prop('href')) === '[object SVGAnimatedString]') {\n\t name = 'xlinkHref';\n\t attr.$attr[name] = 'xlink:href';\n\t propName = null;\n\t }\n\t\n\t attr.$observe(normalized, function(value) {\n\t if (!value) {\n\t if (attrName === 'href') {\n\t attr.$set(name, null);\n\t }\n\t return;\n\t }\n\t\n\t attr.$set(name, value);\n\t\n\t // on IE, if \"ng:src\" directive declaration is used and \"src\" attribute doesn't exist\n\t // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need\n\t // to set the property as well to achieve the desired effect.\n\t // we use attr[attrName] value since $set can sanitize the url.\n\t if (msie && propName) element.prop(propName, attr[name]);\n\t });\n\t }\n\t };\n\t };\n\t});\n\t\n\t/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true\n\t */\n\tvar nullFormCtrl = {\n\t $addControl: noop,\n\t $$renameControl: nullFormRenameControl,\n\t $removeControl: noop,\n\t $setValidity: noop,\n\t $setDirty: noop,\n\t $setPristine: noop,\n\t $setSubmitted: noop\n\t},\n\tSUBMITTED_CLASS = 'ng-submitted';\n\t\n\tfunction nullFormRenameControl(control, name) {\n\t control.$name = name;\n\t}\n\t\n\t/**\n\t * @ngdoc type\n\t * @name form.FormController\n\t *\n\t * @property {boolean} $pristine True if user has not interacted with the form yet.\n\t * @property {boolean} $dirty True if user has already interacted with the form.\n\t * @property {boolean} $valid True if all of the containing forms and controls are valid.\n\t * @property {boolean} $invalid True if at least one containing control or form is invalid.\n\t * @property {boolean} $pending True if at least one containing control or form is pending.\n\t * @property {boolean} $submitted True if user has submitted the form even if its invalid.\n\t *\n\t * @property {Object} $error Is an object hash, containing references to controls or\n\t * forms with failing validators, where:\n\t *\n\t * - keys are validation tokens (error names),\n\t * - values are arrays of controls or forms that have a failing validator for given error name.\n\t *\n\t * Built-in validation tokens:\n\t *\n\t * - `email`\n\t * - `max`\n\t * - `maxlength`\n\t * - `min`\n\t * - `minlength`\n\t * - `number`\n\t * - `pattern`\n\t * - `required`\n\t * - `url`\n\t * - `date`\n\t * - `datetimelocal`\n\t * - `time`\n\t * - `week`\n\t * - `month`\n\t *\n\t * @description\n\t * `FormController` keeps track of all its controls and nested forms as well as the state of them,\n\t * such as being valid/invalid or dirty/pristine.\n\t *\n\t * Each {@link ng.directive:form form} directive creates an instance\n\t * of `FormController`.\n\t *\n\t */\n\t//asks for $scope to fool the BC controller module\n\tFormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];\n\tfunction FormController(element, attrs, $scope, $animate, $interpolate) {\n\t var form = this,\n\t controls = [];\n\t\n\t // init state\n\t form.$error = {};\n\t form.$$success = {};\n\t form.$pending = undefined;\n\t form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);\n\t form.$dirty = false;\n\t form.$pristine = true;\n\t form.$valid = true;\n\t form.$invalid = false;\n\t form.$submitted = false;\n\t form.$$parentForm = nullFormCtrl;\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$rollbackViewValue\n\t *\n\t * @description\n\t * Rollback all form controls pending updates to the `$modelValue`.\n\t *\n\t * Updates may be pending by a debounced event or because the input is waiting for a some future\n\t * event defined in `ng-model-options`. This method is typically needed by the reset button of\n\t * a form that uses `ng-model-options` to pend updates.\n\t */\n\t form.$rollbackViewValue = function() {\n\t forEach(controls, function(control) {\n\t control.$rollbackViewValue();\n\t });\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$commitViewValue\n\t *\n\t * @description\n\t * Commit all form controls pending updates to the `$modelValue`.\n\t *\n\t * Updates may be pending by a debounced event or because the input is waiting for a some future\n\t * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`\n\t * usually handles calling this in response to input events.\n\t */\n\t form.$commitViewValue = function() {\n\t forEach(controls, function(control) {\n\t control.$commitViewValue();\n\t });\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$addControl\n\t * @param {object} control control object, either a {@link form.FormController} or an\n\t * {@link ngModel.NgModelController}\n\t *\n\t * @description\n\t * Register a control with the form. Input elements using ngModelController do this automatically\n\t * when they are linked.\n\t *\n\t * Note that the current state of the control will not be reflected on the new parent form. This\n\t * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`\n\t * state.\n\t *\n\t * However, if the method is used programmatically, for example by adding dynamically created controls,\n\t * or controls that have been previously removed without destroying their corresponding DOM element,\n\t * it's the developers responsibility to make sure the current state propagates to the parent form.\n\t *\n\t * For example, if an input control is added that is already `$dirty` and has `$error` properties,\n\t * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.\n\t */\n\t form.$addControl = function(control) {\n\t // Breaking change - before, inputs whose name was \"hasOwnProperty\" were quietly ignored\n\t // and not added to the scope. Now we throw an error.\n\t assertNotHasOwnProperty(control.$name, 'input');\n\t controls.push(control);\n\t\n\t if (control.$name) {\n\t form[control.$name] = control;\n\t }\n\t\n\t control.$$parentForm = form;\n\t };\n\t\n\t // Private API: rename a form control\n\t form.$$renameControl = function(control, newName) {\n\t var oldName = control.$name;\n\t\n\t if (form[oldName] === control) {\n\t delete form[oldName];\n\t }\n\t form[newName] = control;\n\t control.$name = newName;\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$removeControl\n\t * @param {object} control control object, either a {@link form.FormController} or an\n\t * {@link ngModel.NgModelController}\n\t *\n\t * @description\n\t * Deregister a control from the form.\n\t *\n\t * Input elements using ngModelController do this automatically when they are destroyed.\n\t *\n\t * Note that only the removed control's validation state (`$errors`etc.) will be removed from the\n\t * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be\n\t * different from case to case. For example, removing the only `$dirty` control from a form may or\n\t * may not mean that the form is still `$dirty`.\n\t */\n\t form.$removeControl = function(control) {\n\t if (control.$name && form[control.$name] === control) {\n\t delete form[control.$name];\n\t }\n\t forEach(form.$pending, function(value, name) {\n\t form.$setValidity(name, null, control);\n\t });\n\t forEach(form.$error, function(value, name) {\n\t form.$setValidity(name, null, control);\n\t });\n\t forEach(form.$$success, function(value, name) {\n\t form.$setValidity(name, null, control);\n\t });\n\t\n\t arrayRemove(controls, control);\n\t control.$$parentForm = nullFormCtrl;\n\t };\n\t\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$setValidity\n\t *\n\t * @description\n\t * Sets the validity of a form control.\n\t *\n\t * This method will also propagate to parent forms.\n\t */\n\t addSetValidityMethod({\n\t ctrl: this,\n\t $element: element,\n\t set: function(object, property, controller) {\n\t var list = object[property];\n\t if (!list) {\n\t object[property] = [controller];\n\t } else {\n\t var index = list.indexOf(controller);\n\t if (index === -1) {\n\t list.push(controller);\n\t }\n\t }\n\t },\n\t unset: function(object, property, controller) {\n\t var list = object[property];\n\t if (!list) {\n\t return;\n\t }\n\t arrayRemove(list, controller);\n\t if (list.length === 0) {\n\t delete object[property];\n\t }\n\t },\n\t $animate: $animate\n\t });\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$setDirty\n\t *\n\t * @description\n\t * Sets the form to a dirty state.\n\t *\n\t * This method can be called to add the 'ng-dirty' class and set the form to a dirty\n\t * state (ng-dirty class). This method will also propagate to parent forms.\n\t */\n\t form.$setDirty = function() {\n\t $animate.removeClass(element, PRISTINE_CLASS);\n\t $animate.addClass(element, DIRTY_CLASS);\n\t form.$dirty = true;\n\t form.$pristine = false;\n\t form.$$parentForm.$setDirty();\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$setPristine\n\t *\n\t * @description\n\t * Sets the form to its pristine state.\n\t *\n\t * This method can be called to remove the 'ng-dirty' class and set the form to its pristine\n\t * state (ng-pristine class). This method will also propagate to all the controls contained\n\t * in this form.\n\t *\n\t * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after\n\t * saving or resetting it.\n\t */\n\t form.$setPristine = function() {\n\t $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);\n\t form.$dirty = false;\n\t form.$pristine = true;\n\t form.$submitted = false;\n\t forEach(controls, function(control) {\n\t control.$setPristine();\n\t });\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$setUntouched\n\t *\n\t * @description\n\t * Sets the form to its untouched state.\n\t *\n\t * This method can be called to remove the 'ng-touched' class and set the form controls to their\n\t * untouched state (ng-untouched class).\n\t *\n\t * Setting a form controls back to their untouched state is often useful when setting the form\n\t * back to its pristine state.\n\t */\n\t form.$setUntouched = function() {\n\t forEach(controls, function(control) {\n\t control.$setUntouched();\n\t });\n\t };\n\t\n\t /**\n\t * @ngdoc method\n\t * @name form.FormController#$setSubmitted\n\t *\n\t * @description\n\t * Sets the form to its submitted state.\n\t */\n\t form.$setSubmitted = function() {\n\t $animate.addClass(element, SUBMITTED_CLASS);\n\t form.$submitted = true;\n\t form.$$parentForm.$setSubmitted();\n\t };\n\t}\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngForm\n\t * @restrict EAC\n\t *\n\t * @description\n\t * Nestable alias of {@link ng.directive:form `form`} directive. HTML\n\t * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a\n\t * sub-group of controls needs to be determined.\n\t *\n\t * Note: the purpose of `ngForm` is to group controls,\n\t * but not to be a replacement for the `
` tag with all of its capabilities\n\t * (e.g. posting to the server, ...).\n\t *\n\t * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into\n\t * related scope, under this name.\n\t *\n\t */\n\t\n\t /**\n\t * @ngdoc directive\n\t * @name form\n\t * @restrict E\n\t *\n\t * @description\n\t * Directive that instantiates\n\t * {@link form.FormController FormController}.\n\t *\n\t * If the `name` attribute is specified, the form controller is published onto the current scope under\n\t * this name.\n\t *\n\t * # Alias: {@link ng.directive:ngForm `ngForm`}\n\t *\n\t * In Angular, forms can be nested. This means that the outer form is valid when all of the child\n\t * forms are valid as well. However, browsers do not allow nesting of `` elements, so\n\t * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to\n\t * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group\n\t * of controls needs to be determined.\n\t *\n\t * # CSS classes\n\t * - `ng-valid` is set if the form is valid.\n\t * - `ng-invalid` is set if the form is invalid.\n\t * - `ng-pending` is set if the form is pending.\n\t * - `ng-pristine` is set if the form is pristine.\n\t * - `ng-dirty` is set if the form is dirty.\n\t * - `ng-submitted` is set if the form was submitted.\n\t *\n\t * Keep in mind that ngAnimate can detect each of these classes when added and removed.\n\t *\n\t *\n\t * # Submitting a form and preventing the default action\n\t *\n\t * Since the role of forms in client-side Angular applications is different than in classical\n\t * roundtrip apps, it is desirable for the browser not to translate the form submission into a full\n\t * page reload that sends the data to the server. Instead some javascript logic should be triggered\n\t * to handle the form submission in an application-specific way.\n\t *\n\t * For this reason, Angular prevents the default action (form submission to the server) unless the\n\t * `` element has an `action` attribute specified.\n\t *\n\t * You can use one of the following two ways to specify what javascript method should be called when\n\t * a form is submitted:\n\t *\n\t * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element\n\t * - {@link ng.directive:ngClick ngClick} directive on the first\n\t * button or input field of type submit (input[type=submit])\n\t *\n\t * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}\n\t * or {@link ng.directive:ngClick ngClick} directives.\n\t * This is because of the following form submission rules in the HTML specification:\n\t *\n\t * - If a form has only one input field then hitting enter in this field triggers form submit\n\t * (`ngSubmit`)\n\t * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter\n\t * doesn't trigger submit\n\t * - if a form has one or more input fields and one or more buttons or input[type=submit] then\n\t * hitting enter in any of the input fields will trigger the click handler on the *first* button or\n\t * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)\n\t *\n\t * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is\n\t * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`\n\t * to have access to the updated model.\n\t *\n\t * ## Animation Hooks\n\t *\n\t * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.\n\t * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any\n\t * other validations that are performed within the form. Animations in ngForm are similar to how\n\t * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well\n\t * as JS animations.\n\t *\n\t * The following example shows a simple way to utilize CSS transitions to style a form element\n\t * that has been rendered as invalid after it has been validated:\n\t *\n\t *
\n\t * //be sure to include ngAnimate as a module to hook into more\n\t * //advanced animations\n\t * .my-form {\n\t *   transition:0.5s linear all;\n\t *   background: white;\n\t * }\n\t * .my-form.ng-invalid {\n\t *   background: red;\n\t *   color:white;\n\t * }\n\t * 
\n\t *\n\t * @example\n\t \n\t \n\t \n\t \n\t \n\t userType: \n\t Required!
\n\t userType = {{userType}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t \n\t
\n\t \n\t it('should initialize to model', function() {\n\t var userType = element(by.binding('userType'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t\n\t expect(userType.getText()).toContain('guest');\n\t expect(valid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t var userType = element(by.binding('userType'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var userInput = element(by.model('userType'));\n\t\n\t userInput.clear();\n\t userInput.sendKeys('');\n\t\n\t expect(userType.getText()).toEqual('userType =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t *\n\t * @param {string=} name Name of the form. If specified, the form controller will be published into\n\t * related scope, under this name.\n\t */\n\tvar formDirectiveFactory = function(isNgForm) {\n\t return ['$timeout', '$parse', function($timeout, $parse) {\n\t var formDirective = {\n\t name: 'form',\n\t restrict: isNgForm ? 'EAC' : 'E',\n\t require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form\n\t controller: FormController,\n\t compile: function ngFormCompile(formElement, attr) {\n\t // Setup initial state of the control\n\t formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);\n\t\n\t var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);\n\t\n\t return {\n\t pre: function ngFormPreLink(scope, formElement, attr, ctrls) {\n\t var controller = ctrls[0];\n\t\n\t // if `action` attr is not present on the form, prevent the default action (submission)\n\t if (!('action' in attr)) {\n\t // we can't use jq events because if a form is destroyed during submission the default\n\t // action is not prevented. see #1238\n\t //\n\t // IE 9 is not affected because it doesn't fire a submit event and try to do a full\n\t // page reload if the form was destroyed by submission of the form via a click handler\n\t // on a button in the form. Looks like an IE9 specific bug.\n\t var handleFormSubmission = function(event) {\n\t scope.$apply(function() {\n\t controller.$commitViewValue();\n\t controller.$setSubmitted();\n\t });\n\t\n\t event.preventDefault();\n\t };\n\t\n\t addEventListenerFn(formElement[0], 'submit', handleFormSubmission);\n\t\n\t // unregister the preventDefault listener so that we don't not leak memory but in a\n\t // way that will achieve the prevention of the default action.\n\t formElement.on('$destroy', function() {\n\t $timeout(function() {\n\t removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);\n\t }, 0, false);\n\t });\n\t }\n\t\n\t var parentFormCtrl = ctrls[1] || controller.$$parentForm;\n\t parentFormCtrl.$addControl(controller);\n\t\n\t var setter = nameAttr ? getSetter(controller.$name) : noop;\n\t\n\t if (nameAttr) {\n\t setter(scope, controller);\n\t attr.$observe(nameAttr, function(newValue) {\n\t if (controller.$name === newValue) return;\n\t setter(scope, undefined);\n\t controller.$$parentForm.$$renameControl(controller, newValue);\n\t setter = getSetter(controller.$name);\n\t setter(scope, controller);\n\t });\n\t }\n\t formElement.on('$destroy', function() {\n\t controller.$$parentForm.$removeControl(controller);\n\t setter(scope, undefined);\n\t extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards\n\t });\n\t }\n\t };\n\t }\n\t };\n\t\n\t return formDirective;\n\t\n\t function getSetter(expression) {\n\t if (expression === '') {\n\t //create an assignable expression, so forms with an empty name can be renamed later\n\t return $parse('this[\"\"]').assign;\n\t }\n\t return $parse(expression).assign || noop;\n\t }\n\t }];\n\t};\n\t\n\tvar formDirective = formDirectiveFactory();\n\tvar ngFormDirective = formDirectiveFactory(true);\n\t\n\t/* global VALID_CLASS: false,\n\t INVALID_CLASS: false,\n\t PRISTINE_CLASS: false,\n\t DIRTY_CLASS: false,\n\t UNTOUCHED_CLASS: false,\n\t TOUCHED_CLASS: false,\n\t ngModelMinErr: false,\n\t*/\n\t\n\t// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231\n\tvar 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)$/;\n\t// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)\n\t// Note: We are being more lenient, because browsers are too.\n\t// 1. Scheme\n\t// 2. Slashes\n\t// 3. Username\n\t// 4. Password\n\t// 5. Hostname\n\t// 6. Port\n\t// 7. Path\n\t// 8. Query\n\t// 9. Fragment\n\t// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999\n\tvar URL_REGEXP = /^[a-z][a-z\\d.+-]*:\\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\\s:/?#]+|\\[[a-f\\d:]+\\])(?::\\d+)?(?:\\/[^?#]*)?(?:\\?[^#]*)?(?:#.*)?$/i;\n\t/* jshint maxlen:220 */\n\tvar 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])?)*$/;\n\t/* jshint maxlen:200 */\n\tvar NUMBER_REGEXP = /^\\s*(\\-|\\+)?(\\d+|(\\d*(\\.\\d*)))([eE][+-]?\\d+)?\\s*$/;\n\tvar DATE_REGEXP = /^(\\d{4,})-(\\d{2})-(\\d{2})$/;\n\tvar DATETIMELOCAL_REGEXP = /^(\\d{4,})-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d)(?::(\\d\\d)(\\.\\d{1,3})?)?$/;\n\tvar WEEK_REGEXP = /^(\\d{4,})-W(\\d\\d)$/;\n\tvar MONTH_REGEXP = /^(\\d{4,})-(\\d\\d)$/;\n\tvar TIME_REGEXP = /^(\\d\\d):(\\d\\d)(?::(\\d\\d)(\\.\\d{1,3})?)?$/;\n\t\n\tvar PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';\n\tvar PARTIAL_VALIDATION_TYPES = createMap();\n\tforEach('date,datetime-local,month,time,week'.split(','), function(type) {\n\t PARTIAL_VALIDATION_TYPES[type] = true;\n\t});\n\t\n\tvar inputType = {\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[text]\n\t *\n\t * @description\n\t * Standard HTML text input with angular data binding, inherited by most of the `input` elements.\n\t *\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} required Adds `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of\n\t * any length.\n\t * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string\n\t * that contains the regular expression body that will be converted to a regular expression\n\t * as in the ngPattern directive.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.\n\t * This parameter is ignored for input[type=password] controls, which will never trim the\n\t * input.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t
\n\t \n\t Required!\n\t \n\t Single word only!\n\t
\n\t text = {{example.text}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var text = element(by.binding('example.text'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.text'));\n\t\n\t it('should initialize to model', function() {\n\t expect(text.getText()).toContain('guest');\n\t expect(valid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t input.clear();\n\t input.sendKeys('');\n\t\n\t expect(text.getText()).toEqual('text =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t\n\t it('should be invalid if multi word', function() {\n\t input.clear();\n\t input.sendKeys('hello world');\n\t\n\t expect(valid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t */\n\t 'text': textInputType,\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[date]\n\t *\n\t * @description\n\t * Input with date validation and transformation. In browsers that do not yet support\n\t * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601\n\t * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many\n\t * modern browsers do not yet support this input type, it is important to provide cues to users on the\n\t * expected input format via a placeholder or label.\n\t *\n\t * The model must always be a Date object, otherwise Angular will throw an error.\n\t * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.\n\t *\n\t * The timezone to be used to read/write the `Date` instance in the model can be defined using\n\t * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a\n\t * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute\n\t * (e.g. `min=\"{{minDate | date:'yyyy-MM-dd'}}\"`). Note that `min` will also add native HTML5\n\t * constraint validation.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be\n\t * a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute\n\t * (e.g. `max=\"{{maxDate | date:'yyyy-MM-dd'}}\"`). Note that `max` will also add native HTML5\n\t * constraint validation.\n\t * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string\n\t * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.\n\t * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string\n\t * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t \n\t
\n\t \n\t Required!\n\t \n\t Not a valid date!\n\t
\n\t value = {{example.value | date: \"yyyy-MM-dd\"}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value | date: \"yyyy-MM-dd\"'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t // currently protractor/webdriver does not support\n\t // sending keys to all known HTML5 input controls\n\t // for various browsers (see https://github.com/angular/protractor/issues/562).\n\t function setInput(val) {\n\t // set the value of the element and force validation.\n\t var scr = \"var ipt = document.getElementById('exampleInput'); \" +\n\t \"ipt.value = '\" + val + \"';\" +\n\t \"angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('\" + val + \"'); });\";\n\t browser.executeScript(scr);\n\t }\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('2013-10-22');\n\t expect(valid.getText()).toContain('myForm.input.$valid = true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t setInput('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t setInput('2015-01-01');\n\t expect(value.getText()).toContain('');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t \n\t
\n\t */\n\t 'date': createDateInputType('date', DATE_REGEXP,\n\t createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),\n\t 'yyyy-MM-dd'),\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[datetime-local]\n\t *\n\t * @description\n\t * Input with datetime validation and transformation. In browsers that do not yet support\n\t * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601\n\t * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.\n\t *\n\t * The model must always be a Date object, otherwise Angular will throw an error.\n\t * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.\n\t *\n\t * The timezone to be used to read/write the `Date` instance in the model can be defined using\n\t * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.\n\t * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation\n\t * inside this attribute (e.g. `min=\"{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}\"`).\n\t * Note that `min` will also add native HTML5 constraint validation.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.\n\t * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation\n\t * inside this attribute (e.g. `max=\"{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}\"`).\n\t * Note that `max` will also add native HTML5 constraint validation.\n\t * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string\n\t * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.\n\t * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string\n\t * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t \n\t
\n\t \n\t Required!\n\t \n\t Not a valid date!\n\t
\n\t value = {{example.value | date: \"yyyy-MM-ddTHH:mm:ss\"}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value | date: \"yyyy-MM-ddTHH:mm:ss\"'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t // currently protractor/webdriver does not support\n\t // sending keys to all known HTML5 input controls\n\t // for various browsers (https://github.com/angular/protractor/issues/562).\n\t function setInput(val) {\n\t // set the value of the element and force validation.\n\t var scr = \"var ipt = document.getElementById('exampleInput'); \" +\n\t \"ipt.value = '\" + val + \"';\" +\n\t \"angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('\" + val + \"'); });\";\n\t browser.executeScript(scr);\n\t }\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('2010-12-28T14:57:00');\n\t expect(valid.getText()).toContain('myForm.input.$valid = true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t setInput('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t setInput('2015-01-01T23:59:00');\n\t expect(value.getText()).toContain('');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t \n\t
\n\t */\n\t 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,\n\t createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),\n\t 'yyyy-MM-ddTHH:mm:ss.sss'),\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[time]\n\t *\n\t * @description\n\t * Input with time validation and transformation. In browsers that do not yet support\n\t * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601\n\t * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a\n\t * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.\n\t *\n\t * The model must always be a Date object, otherwise Angular will throw an error.\n\t * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.\n\t *\n\t * The timezone to be used to read/write the `Date` instance in the model can be defined using\n\t * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.\n\t * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this\n\t * attribute (e.g. `min=\"{{minTime | date:'HH:mm:ss'}}\"`). Note that `min` will also add\n\t * native HTML5 constraint validation.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.\n\t * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this\n\t * attribute (e.g. `max=\"{{maxTime | date:'HH:mm:ss'}}\"`). Note that `max` will also add\n\t * native HTML5 constraint validation.\n\t * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the\n\t * `ngMin` expression evaluates to. Note that it does not set the `min` attribute.\n\t * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the\n\t * `ngMax` expression evaluates to. Note that it does not set the `max` attribute.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t \n\t
\n\t \n\t Required!\n\t \n\t Not a valid date!\n\t
\n\t value = {{example.value | date: \"HH:mm:ss\"}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value | date: \"HH:mm:ss\"'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t // currently protractor/webdriver does not support\n\t // sending keys to all known HTML5 input controls\n\t // for various browsers (https://github.com/angular/protractor/issues/562).\n\t function setInput(val) {\n\t // set the value of the element and force validation.\n\t var scr = \"var ipt = document.getElementById('exampleInput'); \" +\n\t \"ipt.value = '\" + val + \"';\" +\n\t \"angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('\" + val + \"'); });\";\n\t browser.executeScript(scr);\n\t }\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('14:57:00');\n\t expect(valid.getText()).toContain('myForm.input.$valid = true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t setInput('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t setInput('23:59:00');\n\t expect(value.getText()).toContain('');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t \n\t
\n\t */\n\t 'time': createDateInputType('time', TIME_REGEXP,\n\t createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),\n\t 'HH:mm:ss.sss'),\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[week]\n\t *\n\t * @description\n\t * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support\n\t * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601\n\t * week format (yyyy-W##), for example: `2013-W02`.\n\t *\n\t * The model must always be a Date object, otherwise Angular will throw an error.\n\t * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.\n\t *\n\t * The timezone to be used to read/write the `Date` instance in the model can be defined using\n\t * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.\n\t * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this\n\t * attribute (e.g. `min=\"{{minWeek | date:'yyyy-Www'}}\"`). Note that `min` will also add\n\t * native HTML5 constraint validation.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.\n\t * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this\n\t * attribute (e.g. `max=\"{{maxWeek | date:'yyyy-Www'}}\"`). Note that `max` will also add\n\t * native HTML5 constraint validation.\n\t * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string\n\t * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.\n\t * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string\n\t * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t
\n\t \n\t Required!\n\t \n\t Not a valid date!\n\t
\n\t value = {{example.value | date: \"yyyy-Www\"}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value | date: \"yyyy-Www\"'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t // currently protractor/webdriver does not support\n\t // sending keys to all known HTML5 input controls\n\t // for various browsers (https://github.com/angular/protractor/issues/562).\n\t function setInput(val) {\n\t // set the value of the element and force validation.\n\t var scr = \"var ipt = document.getElementById('exampleInput'); \" +\n\t \"ipt.value = '\" + val + \"';\" +\n\t \"angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('\" + val + \"'); });\";\n\t browser.executeScript(scr);\n\t }\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('2013-W01');\n\t expect(valid.getText()).toContain('myForm.input.$valid = true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t setInput('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t setInput('2015-W01');\n\t expect(value.getText()).toContain('');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t \n\t
\n\t */\n\t 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[month]\n\t *\n\t * @description\n\t * Input with month validation and transformation. In browsers that do not yet support\n\t * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601\n\t * month format (yyyy-MM), for example: `2009-01`.\n\t *\n\t * The model must always be a Date object, otherwise Angular will throw an error.\n\t * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.\n\t * If the model is not set to the first of the month, the next view to model update will set it\n\t * to the first of the month.\n\t *\n\t * The timezone to be used to read/write the `Date` instance in the model can be defined using\n\t * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.\n\t * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this\n\t * attribute (e.g. `min=\"{{minMonth | date:'yyyy-MM'}}\"`). Note that `min` will also add\n\t * native HTML5 constraint validation.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.\n\t * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this\n\t * attribute (e.g. `max=\"{{maxMonth | date:'yyyy-MM'}}\"`). Note that `max` will also add\n\t * native HTML5 constraint validation.\n\t * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string\n\t * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.\n\t * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string\n\t * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.\n\t\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t \n\t
\n\t \n\t Required!\n\t \n\t Not a valid month!\n\t
\n\t value = {{example.value | date: \"yyyy-MM\"}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value | date: \"yyyy-MM\"'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t // currently protractor/webdriver does not support\n\t // sending keys to all known HTML5 input controls\n\t // for various browsers (https://github.com/angular/protractor/issues/562).\n\t function setInput(val) {\n\t // set the value of the element and force validation.\n\t var scr = \"var ipt = document.getElementById('exampleInput'); \" +\n\t \"ipt.value = '\" + val + \"';\" +\n\t \"angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('\" + val + \"'); });\";\n\t browser.executeScript(scr);\n\t }\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('2013-10');\n\t expect(valid.getText()).toContain('myForm.input.$valid = true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t setInput('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t setInput('2015-01');\n\t expect(value.getText()).toContain('');\n\t expect(valid.getText()).toContain('myForm.input.$valid = false');\n\t });\n\t \n\t
\n\t */\n\t 'month': createDateInputType('month', MONTH_REGEXP,\n\t createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),\n\t 'yyyy-MM'),\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[number]\n\t *\n\t * @description\n\t * Text input with number validation and transformation. Sets the `number` validation\n\t * error if not a valid number.\n\t *\n\t *
\n\t * The model must always be of type `number` otherwise Angular will throw an error.\n\t * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}\n\t * error docs for more information and an example of how to convert your model if necessary.\n\t *
\n\t *\n\t * ## Issues with HTML5 constraint validation\n\t *\n\t * In browsers that follow the\n\t * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),\n\t * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.\n\t * If a non-number is entered in the input, the browser will report the value as an empty string,\n\t * which means the view / model values in `ngModel` and subsequently the scope value\n\t * will also be an empty string.\n\t *\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.\n\t * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of\n\t * any length.\n\t * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string\n\t * that contains the regular expression body that will be converted to a regular expression\n\t * as in the ngPattern directive.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t
\n\t \n\t Required!\n\t \n\t Not valid number!\n\t
\n\t value = {{example.value}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t
\n\t
\n\t \n\t var value = element(by.binding('example.value'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('example.value'));\n\t\n\t it('should initialize to model', function() {\n\t expect(value.getText()).toContain('12');\n\t expect(valid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t input.clear();\n\t input.sendKeys('');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t\n\t it('should be invalid if over max', function() {\n\t input.clear();\n\t input.sendKeys('123');\n\t expect(value.getText()).toEqual('value =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t */\n\t 'number': numberInputType,\n\t\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[url]\n\t *\n\t * @description\n\t * Text input with URL validation. Sets the `url` validation error key if the content is not a\n\t * valid URL.\n\t *\n\t *
\n\t * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex\n\t * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify\n\t * the built-in validators (see the {@link guide/forms Forms guide})\n\t *
\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of\n\t * any length.\n\t * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string\n\t * that contains the regular expression body that will be converted to a regular expression\n\t * as in the ngPattern directive.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t \n\t var text = element(by.binding('url.text'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('url.text'));\n\t\n\t it('should initialize to model', function() {\n\t expect(text.getText()).toContain('http://google.com');\n\t expect(valid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t input.clear();\n\t input.sendKeys('');\n\t\n\t expect(text.getText()).toEqual('text =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t\n\t it('should be invalid if not url', function() {\n\t input.clear();\n\t input.sendKeys('box');\n\t\n\t expect(valid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t */\n\t 'url': urlInputType,\n\t\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[email]\n\t *\n\t * @description\n\t * Text input with email validation. Sets the `email` validation error key if not a valid email\n\t * address.\n\t *\n\t *
\n\t * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex\n\t * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can\n\t * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})\n\t *
\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of\n\t * any length.\n\t * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string\n\t * that contains the regular expression body that will be converted to a regular expression\n\t * as in the ngPattern directive.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t \n\t
\n\t \n\t Required!\n\t \n\t Not valid email!\n\t
\n\t text = {{email.text}}
\n\t myForm.input.$valid = {{myForm.input.$valid}}
\n\t myForm.input.$error = {{myForm.input.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t myForm.$error.email = {{!!myForm.$error.email}}
\n\t
\n\t
\n\t \n\t var text = element(by.binding('email.text'));\n\t var valid = element(by.binding('myForm.input.$valid'));\n\t var input = element(by.model('email.text'));\n\t\n\t it('should initialize to model', function() {\n\t expect(text.getText()).toContain('me@example.com');\n\t expect(valid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty', function() {\n\t input.clear();\n\t input.sendKeys('');\n\t expect(text.getText()).toEqual('text =');\n\t expect(valid.getText()).toContain('false');\n\t });\n\t\n\t it('should be invalid if not email', function() {\n\t input.clear();\n\t input.sendKeys('xxx');\n\t\n\t expect(valid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t */\n\t 'email': emailInputType,\n\t\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[radio]\n\t *\n\t * @description\n\t * HTML radio button.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string} value The value to which the `ngModel` expression should be set when selected.\n\t * Note that `value` only supports `string` values, i.e. the scope model needs to be a string,\n\t * too. Use `ngValue` if you need complex models (`number`, `object`, ...).\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio\n\t * is selected. Should be used instead of the `value` attribute if you need\n\t * a non-string `ngModel` (`boolean`, `array`, ...).\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t
\n\t
\n\t color = {{color.name | json}}
\n\t
\n\t Note that `ng-value=\"specialValue\"` sets radio item's value to be the value of `$scope.specialValue`.\n\t
\n\t \n\t it('should change state', function() {\n\t var color = element(by.binding('color.name'));\n\t\n\t expect(color.getText()).toContain('blue');\n\t\n\t element.all(by.model('color.name')).get(0).click();\n\t\n\t expect(color.getText()).toContain('red');\n\t });\n\t \n\t
\n\t */\n\t 'radio': radioInputType,\n\t\n\t\n\t /**\n\t * @ngdoc input\n\t * @name input[checkbox]\n\t *\n\t * @description\n\t * HTML checkbox.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {expression=} ngTrueValue The value to which the expression should be set when selected.\n\t * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t
\n\t value1 = {{checkboxModel.value1}}
\n\t value2 = {{checkboxModel.value2}}
\n\t
\n\t
\n\t \n\t it('should change state', function() {\n\t var value1 = element(by.binding('checkboxModel.value1'));\n\t var value2 = element(by.binding('checkboxModel.value2'));\n\t\n\t expect(value1.getText()).toContain('true');\n\t expect(value2.getText()).toContain('YES');\n\t\n\t element(by.model('checkboxModel.value1')).click();\n\t element(by.model('checkboxModel.value2')).click();\n\t\n\t expect(value1.getText()).toContain('false');\n\t expect(value2.getText()).toContain('NO');\n\t });\n\t \n\t
\n\t */\n\t 'checkbox': checkboxInputType,\n\t\n\t 'hidden': noop,\n\t 'button': noop,\n\t 'submit': noop,\n\t 'reset': noop,\n\t 'file': noop\n\t};\n\t\n\tfunction stringBasedInputType(ctrl) {\n\t ctrl.$formatters.push(function(value) {\n\t return ctrl.$isEmpty(value) ? value : value.toString();\n\t });\n\t}\n\t\n\tfunction textInputType(scope, element, attr, ctrl, $sniffer, $browser) {\n\t baseInputType(scope, element, attr, ctrl, $sniffer, $browser);\n\t stringBasedInputType(ctrl);\n\t}\n\t\n\tfunction baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {\n\t var type = lowercase(element[0].type);\n\t\n\t // In composition mode, users are still inputing intermediate text buffer,\n\t // hold the listener until composition is done.\n\t // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent\n\t if (!$sniffer.android) {\n\t var composing = false;\n\t\n\t element.on('compositionstart', function() {\n\t composing = true;\n\t });\n\t\n\t element.on('compositionend', function() {\n\t composing = false;\n\t listener();\n\t });\n\t }\n\t\n\t var timeout;\n\t\n\t var listener = function(ev) {\n\t if (timeout) {\n\t $browser.defer.cancel(timeout);\n\t timeout = null;\n\t }\n\t if (composing) return;\n\t var value = element.val(),\n\t event = ev && ev.type;\n\t\n\t // By default we will trim the value\n\t // If the attribute ng-trim exists we will avoid trimming\n\t // If input type is 'password', the value is never trimmed\n\t if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {\n\t value = trim(value);\n\t }\n\t\n\t // If a control is suffering from bad input (due to native validators), browsers discard its\n\t // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the\n\t // control's value is the same empty value twice in a row.\n\t if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {\n\t ctrl.$setViewValue(value, event);\n\t }\n\t };\n\t\n\t // if the browser does support \"input\" event, we are fine - except on IE9 which doesn't fire the\n\t // input event on backspace, delete or cut\n\t if ($sniffer.hasEvent('input')) {\n\t element.on('input', listener);\n\t } else {\n\t var deferListener = function(ev, input, origValue) {\n\t if (!timeout) {\n\t timeout = $browser.defer(function() {\n\t timeout = null;\n\t if (!input || input.value !== origValue) {\n\t listener(ev);\n\t }\n\t });\n\t }\n\t };\n\t\n\t element.on('keydown', function(event) {\n\t var key = event.keyCode;\n\t\n\t // ignore\n\t // command modifiers arrows\n\t if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;\n\t\n\t deferListener(event, this, this.value);\n\t });\n\t\n\t // if user modifies input value using context menu in IE, we need \"paste\" and \"cut\" events to catch it\n\t if ($sniffer.hasEvent('paste')) {\n\t element.on('paste cut', deferListener);\n\t }\n\t }\n\t\n\t // if user paste into input using mouse on older browser\n\t // or form autocomplete on newer browser, we need \"change\" event to catch it\n\t element.on('change', listener);\n\t\n\t // Some native input types (date-family) have the ability to change validity without\n\t // firing any input/change events.\n\t // For these event types, when native validators are present and the browser supports the type,\n\t // check for validity changes on various DOM events.\n\t if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {\n\t element.on(PARTIAL_VALIDATION_EVENTS, function(ev) {\n\t if (!timeout) {\n\t var validity = this[VALIDITY_STATE_PROPERTY];\n\t var origBadInput = validity.badInput;\n\t var origTypeMismatch = validity.typeMismatch;\n\t timeout = $browser.defer(function() {\n\t timeout = null;\n\t if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {\n\t listener(ev);\n\t }\n\t });\n\t }\n\t });\n\t }\n\t\n\t ctrl.$render = function() {\n\t // Workaround for Firefox validation #12102.\n\t var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;\n\t if (element.val() !== value) {\n\t element.val(value);\n\t }\n\t };\n\t}\n\t\n\tfunction weekParser(isoWeek, existingDate) {\n\t if (isDate(isoWeek)) {\n\t return isoWeek;\n\t }\n\t\n\t if (isString(isoWeek)) {\n\t WEEK_REGEXP.lastIndex = 0;\n\t var parts = WEEK_REGEXP.exec(isoWeek);\n\t if (parts) {\n\t var year = +parts[1],\n\t week = +parts[2],\n\t hours = 0,\n\t minutes = 0,\n\t seconds = 0,\n\t milliseconds = 0,\n\t firstThurs = getFirstThursdayOfYear(year),\n\t addDays = (week - 1) * 7;\n\t\n\t if (existingDate) {\n\t hours = existingDate.getHours();\n\t minutes = existingDate.getMinutes();\n\t seconds = existingDate.getSeconds();\n\t milliseconds = existingDate.getMilliseconds();\n\t }\n\t\n\t return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);\n\t }\n\t }\n\t\n\t return NaN;\n\t}\n\t\n\tfunction createDateParser(regexp, mapping) {\n\t return function(iso, date) {\n\t var parts, map;\n\t\n\t if (isDate(iso)) {\n\t return iso;\n\t }\n\t\n\t if (isString(iso)) {\n\t // When a date is JSON'ified to wraps itself inside of an extra\n\t // set of double quotes. This makes the date parsing code unable\n\t // to match the date string and parse it as a date.\n\t if (iso.charAt(0) == '\"' && iso.charAt(iso.length - 1) == '\"') {\n\t iso = iso.substring(1, iso.length - 1);\n\t }\n\t if (ISO_DATE_REGEXP.test(iso)) {\n\t return new Date(iso);\n\t }\n\t regexp.lastIndex = 0;\n\t parts = regexp.exec(iso);\n\t\n\t if (parts) {\n\t parts.shift();\n\t if (date) {\n\t map = {\n\t yyyy: date.getFullYear(),\n\t MM: date.getMonth() + 1,\n\t dd: date.getDate(),\n\t HH: date.getHours(),\n\t mm: date.getMinutes(),\n\t ss: date.getSeconds(),\n\t sss: date.getMilliseconds() / 1000\n\t };\n\t } else {\n\t map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };\n\t }\n\t\n\t forEach(parts, function(part, index) {\n\t if (index < mapping.length) {\n\t map[mapping[index]] = +part;\n\t }\n\t });\n\t return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);\n\t }\n\t }\n\t\n\t return NaN;\n\t };\n\t}\n\t\n\tfunction createDateInputType(type, regexp, parseDate, format) {\n\t return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {\n\t badInputChecker(scope, element, attr, ctrl);\n\t baseInputType(scope, element, attr, ctrl, $sniffer, $browser);\n\t var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;\n\t var previousDate;\n\t\n\t ctrl.$$parserName = type;\n\t ctrl.$parsers.push(function(value) {\n\t if (ctrl.$isEmpty(value)) return null;\n\t if (regexp.test(value)) {\n\t // Note: We cannot read ctrl.$modelValue, as there might be a different\n\t // parser/formatter in the processing chain so that the model\n\t // contains some different data format!\n\t var parsedDate = parseDate(value, previousDate);\n\t if (timezone) {\n\t parsedDate = convertTimezoneToLocal(parsedDate, timezone);\n\t }\n\t return parsedDate;\n\t }\n\t return undefined;\n\t });\n\t\n\t ctrl.$formatters.push(function(value) {\n\t if (value && !isDate(value)) {\n\t throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);\n\t }\n\t if (isValidDate(value)) {\n\t previousDate = value;\n\t if (previousDate && timezone) {\n\t previousDate = convertTimezoneToLocal(previousDate, timezone, true);\n\t }\n\t return $filter('date')(value, format, timezone);\n\t } else {\n\t previousDate = null;\n\t return '';\n\t }\n\t });\n\t\n\t if (isDefined(attr.min) || attr.ngMin) {\n\t var minVal;\n\t ctrl.$validators.min = function(value) {\n\t return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;\n\t };\n\t attr.$observe('min', function(val) {\n\t minVal = parseObservedDateValue(val);\n\t ctrl.$validate();\n\t });\n\t }\n\t\n\t if (isDefined(attr.max) || attr.ngMax) {\n\t var maxVal;\n\t ctrl.$validators.max = function(value) {\n\t return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;\n\t };\n\t attr.$observe('max', function(val) {\n\t maxVal = parseObservedDateValue(val);\n\t ctrl.$validate();\n\t });\n\t }\n\t\n\t function isValidDate(value) {\n\t // Invalid Date: getTime() returns NaN\n\t return value && !(value.getTime && value.getTime() !== value.getTime());\n\t }\n\t\n\t function parseObservedDateValue(val) {\n\t return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;\n\t }\n\t };\n\t}\n\t\n\tfunction badInputChecker(scope, element, attr, ctrl) {\n\t var node = element[0];\n\t var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);\n\t if (nativeValidation) {\n\t ctrl.$parsers.push(function(value) {\n\t var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};\n\t return validity.badInput || validity.typeMismatch ? undefined : value;\n\t });\n\t }\n\t}\n\t\n\tfunction numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {\n\t badInputChecker(scope, element, attr, ctrl);\n\t baseInputType(scope, element, attr, ctrl, $sniffer, $browser);\n\t\n\t ctrl.$$parserName = 'number';\n\t ctrl.$parsers.push(function(value) {\n\t if (ctrl.$isEmpty(value)) return null;\n\t if (NUMBER_REGEXP.test(value)) return parseFloat(value);\n\t return undefined;\n\t });\n\t\n\t ctrl.$formatters.push(function(value) {\n\t if (!ctrl.$isEmpty(value)) {\n\t if (!isNumber(value)) {\n\t throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);\n\t }\n\t value = value.toString();\n\t }\n\t return value;\n\t });\n\t\n\t if (isDefined(attr.min) || attr.ngMin) {\n\t var minVal;\n\t ctrl.$validators.min = function(value) {\n\t return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;\n\t };\n\t\n\t attr.$observe('min', function(val) {\n\t if (isDefined(val) && !isNumber(val)) {\n\t val = parseFloat(val);\n\t }\n\t minVal = isNumber(val) && !isNaN(val) ? val : undefined;\n\t // TODO(matsko): implement validateLater to reduce number of validations\n\t ctrl.$validate();\n\t });\n\t }\n\t\n\t if (isDefined(attr.max) || attr.ngMax) {\n\t var maxVal;\n\t ctrl.$validators.max = function(value) {\n\t return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;\n\t };\n\t\n\t attr.$observe('max', function(val) {\n\t if (isDefined(val) && !isNumber(val)) {\n\t val = parseFloat(val);\n\t }\n\t maxVal = isNumber(val) && !isNaN(val) ? val : undefined;\n\t // TODO(matsko): implement validateLater to reduce number of validations\n\t ctrl.$validate();\n\t });\n\t }\n\t}\n\t\n\tfunction urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {\n\t // Note: no badInputChecker here by purpose as `url` is only a validation\n\t // in browsers, i.e. we can always read out input.value even if it is not valid!\n\t baseInputType(scope, element, attr, ctrl, $sniffer, $browser);\n\t stringBasedInputType(ctrl);\n\t\n\t ctrl.$$parserName = 'url';\n\t ctrl.$validators.url = function(modelValue, viewValue) {\n\t var value = modelValue || viewValue;\n\t return ctrl.$isEmpty(value) || URL_REGEXP.test(value);\n\t };\n\t}\n\t\n\tfunction emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {\n\t // Note: no badInputChecker here by purpose as `url` is only a validation\n\t // in browsers, i.e. we can always read out input.value even if it is not valid!\n\t baseInputType(scope, element, attr, ctrl, $sniffer, $browser);\n\t stringBasedInputType(ctrl);\n\t\n\t ctrl.$$parserName = 'email';\n\t ctrl.$validators.email = function(modelValue, viewValue) {\n\t var value = modelValue || viewValue;\n\t return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);\n\t };\n\t}\n\t\n\tfunction radioInputType(scope, element, attr, ctrl) {\n\t // make the name unique, if not defined\n\t if (isUndefined(attr.name)) {\n\t element.attr('name', nextUid());\n\t }\n\t\n\t var listener = function(ev) {\n\t if (element[0].checked) {\n\t ctrl.$setViewValue(attr.value, ev && ev.type);\n\t }\n\t };\n\t\n\t element.on('click', listener);\n\t\n\t ctrl.$render = function() {\n\t var value = attr.value;\n\t element[0].checked = (value == ctrl.$viewValue);\n\t };\n\t\n\t attr.$observe('value', ctrl.$render);\n\t}\n\t\n\tfunction parseConstantExpr($parse, context, name, expression, fallback) {\n\t var parseFn;\n\t if (isDefined(expression)) {\n\t parseFn = $parse(expression);\n\t if (!parseFn.constant) {\n\t throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +\n\t '`{1}`.', name, expression);\n\t }\n\t return parseFn(context);\n\t }\n\t return fallback;\n\t}\n\t\n\tfunction checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {\n\t var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);\n\t var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);\n\t\n\t var listener = function(ev) {\n\t ctrl.$setViewValue(element[0].checked, ev && ev.type);\n\t };\n\t\n\t element.on('click', listener);\n\t\n\t ctrl.$render = function() {\n\t element[0].checked = ctrl.$viewValue;\n\t };\n\t\n\t // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`\n\t // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert\n\t // it to a boolean.\n\t ctrl.$isEmpty = function(value) {\n\t return value === false;\n\t };\n\t\n\t ctrl.$formatters.push(function(value) {\n\t return equals(value, trueValue);\n\t });\n\t\n\t ctrl.$parsers.push(function(value) {\n\t return value ? trueValue : falseValue;\n\t });\n\t}\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name textarea\n\t * @restrict E\n\t *\n\t * @description\n\t * HTML textarea element control with angular data-binding. The data-binding and validation\n\t * properties of this element are exactly the same as those of the\n\t * {@link ng.directive:input input element}.\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to\n\t * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of\n\t * `required` when you want to data-bind to the `required` attribute.\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any\n\t * length.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.\n\t */\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name input\n\t * @restrict E\n\t *\n\t * @description\n\t * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,\n\t * input state control, and validation.\n\t * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.\n\t *\n\t *
\n\t * **Note:** Not every feature offered is available for all input types.\n\t * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.\n\t *
\n\t *\n\t * @param {string} ngModel Assignable angular expression to data-bind to.\n\t * @param {string=} name Property name of the form under which the control is published.\n\t * @param {string=} required Sets `required` validation error key if the value is not entered.\n\t * @param {boolean=} ngRequired Sets `required` attribute if set to true\n\t * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than\n\t * minlength.\n\t * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than\n\t * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any\n\t * length.\n\t * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}\n\t * value does not match a RegExp found by evaluating the Angular expression given in the attribute value.\n\t * If the expression evaluates to a RegExp object, then this is used directly.\n\t * If the expression evaluates to a string, then it will be converted to a RegExp\n\t * after wrapping it in `^` and `$` characters. For instance, `\"abc\"` will be converted to\n\t * `new RegExp('^abc$')`.
\n\t * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to\n\t * start at the index of the last search's match, thus not taking the whole input value into\n\t * account.\n\t * @param {string=} ngChange Angular expression to be executed when input changes due to user\n\t * interaction with the input element.\n\t * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.\n\t * This parameter is ignored for input[type=password] controls, which will never trim the\n\t * input.\n\t *\n\t * @example\n\t \n\t \n\t \n\t
\n\t
\n\t \n\t
\n\t \n\t Required!\n\t
\n\t \n\t
\n\t \n\t Too short!\n\t \n\t Too long!\n\t
\n\t
\n\t
\n\t user = {{user}}
\n\t myForm.userName.$valid = {{myForm.userName.$valid}}
\n\t myForm.userName.$error = {{myForm.userName.$error}}
\n\t myForm.lastName.$valid = {{myForm.lastName.$valid}}
\n\t myForm.lastName.$error = {{myForm.lastName.$error}}
\n\t myForm.$valid = {{myForm.$valid}}
\n\t myForm.$error.required = {{!!myForm.$error.required}}
\n\t myForm.$error.minlength = {{!!myForm.$error.minlength}}
\n\t myForm.$error.maxlength = {{!!myForm.$error.maxlength}}
\n\t
\n\t
\n\t \n\t var user = element(by.exactBinding('user'));\n\t var userNameValid = element(by.binding('myForm.userName.$valid'));\n\t var lastNameValid = element(by.binding('myForm.lastName.$valid'));\n\t var lastNameError = element(by.binding('myForm.lastName.$error'));\n\t var formValid = element(by.binding('myForm.$valid'));\n\t var userNameInput = element(by.model('user.name'));\n\t var userLastInput = element(by.model('user.last'));\n\t\n\t it('should initialize to model', function() {\n\t expect(user.getText()).toContain('{\"name\":\"guest\",\"last\":\"visitor\"}');\n\t expect(userNameValid.getText()).toContain('true');\n\t expect(formValid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if empty when required', function() {\n\t userNameInput.clear();\n\t userNameInput.sendKeys('');\n\t\n\t expect(user.getText()).toContain('{\"last\":\"visitor\"}');\n\t expect(userNameValid.getText()).toContain('false');\n\t expect(formValid.getText()).toContain('false');\n\t });\n\t\n\t it('should be valid if empty when min length is set', function() {\n\t userLastInput.clear();\n\t userLastInput.sendKeys('');\n\t\n\t expect(user.getText()).toContain('{\"name\":\"guest\",\"last\":\"\"}');\n\t expect(lastNameValid.getText()).toContain('true');\n\t expect(formValid.getText()).toContain('true');\n\t });\n\t\n\t it('should be invalid if less than required min length', function() {\n\t userLastInput.clear();\n\t userLastInput.sendKeys('xx');\n\t\n\t expect(user.getText()).toContain('{\"name\":\"guest\"}');\n\t expect(lastNameValid.getText()).toContain('false');\n\t expect(lastNameError.getText()).toContain('minlength');\n\t expect(formValid.getText()).toContain('false');\n\t });\n\t\n\t it('should be invalid if longer than max length', function() {\n\t userLastInput.clear();\n\t userLastInput.sendKeys('some ridiculously long name');\n\t\n\t expect(user.getText()).toContain('{\"name\":\"guest\"}');\n\t expect(lastNameValid.getText()).toContain('false');\n\t expect(lastNameError.getText()).toContain('maxlength');\n\t expect(formValid.getText()).toContain('false');\n\t });\n\t \n\t
\n\t */\n\tvar inputDirective = ['$browser', '$sniffer', '$filter', '$parse',\n\t function($browser, $sniffer, $filter, $parse) {\n\t return {\n\t restrict: 'E',\n\t require: ['?ngModel'],\n\t link: {\n\t pre: function(scope, element, attr, ctrls) {\n\t if (ctrls[0]) {\n\t (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,\n\t $browser, $filter, $parse);\n\t }\n\t }\n\t }\n\t };\n\t}];\n\t\n\t\n\t\n\tvar CONSTANT_VALUE_REGEXP = /^(true|false|\\d+)$/;\n\t/**\n\t * @ngdoc directive\n\t * @name ngValue\n\t *\n\t * @description\n\t * Binds the given expression to the value of `
\n\t \n\t \n\t it('should show correct pluralized string', function() {\n\t var withoutOffset = element.all(by.css('ng-pluralize')).get(0);\n\t var withOffset = element.all(by.css('ng-pluralize')).get(1);\n\t var countInput = element(by.model('personCount'));\n\t\n\t expect(withoutOffset.getText()).toEqual('1 person is viewing.');\n\t expect(withOffset.getText()).toEqual('Igor is viewing.');\n\t\n\t countInput.clear();\n\t countInput.sendKeys('0');\n\t\n\t expect(withoutOffset.getText()).toEqual('Nobody is viewing.');\n\t expect(withOffset.getText()).toEqual('Nobody is viewing.');\n\t\n\t countInput.clear();\n\t countInput.sendKeys('2');\n\t\n\t expect(withoutOffset.getText()).toEqual('2 people are viewing.');\n\t expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');\n\t\n\t countInput.clear();\n\t countInput.sendKeys('3');\n\t\n\t expect(withoutOffset.getText()).toEqual('3 people are viewing.');\n\t expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');\n\t\n\t countInput.clear();\n\t countInput.sendKeys('4');\n\t\n\t expect(withoutOffset.getText()).toEqual('4 people are viewing.');\n\t expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');\n\t });\n\t it('should show data-bound names', function() {\n\t var withOffset = element.all(by.css('ng-pluralize')).get(1);\n\t var personCount = element(by.model('personCount'));\n\t var person1 = element(by.model('person1'));\n\t var person2 = element(by.model('person2'));\n\t personCount.clear();\n\t personCount.sendKeys('4');\n\t person1.clear();\n\t person1.sendKeys('Di');\n\t person2.clear();\n\t person2.sendKeys('Vojta');\n\t expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');\n\t });\n\t \n\t \n\t */\n\tvar ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {\n\t var BRACE = /{}/g,\n\t IS_WHEN = /^when(Minus)?(.+)$/;\n\t\n\t return {\n\t link: function(scope, element, attr) {\n\t var numberExp = attr.count,\n\t whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs\n\t offset = attr.offset || 0,\n\t whens = scope.$eval(whenExp) || {},\n\t whensExpFns = {},\n\t startSymbol = $interpolate.startSymbol(),\n\t endSymbol = $interpolate.endSymbol(),\n\t braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,\n\t watchRemover = angular.noop,\n\t lastCount;\n\t\n\t forEach(attr, function(expression, attributeName) {\n\t var tmpMatch = IS_WHEN.exec(attributeName);\n\t if (tmpMatch) {\n\t var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);\n\t whens[whenKey] = element.attr(attr.$attr[attributeName]);\n\t }\n\t });\n\t forEach(whens, function(expression, key) {\n\t whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));\n\t\n\t });\n\t\n\t scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {\n\t var count = parseFloat(newVal);\n\t var countIsNaN = isNaN(count);\n\t\n\t if (!countIsNaN && !(count in whens)) {\n\t // If an explicit number rule such as 1, 2, 3... is defined, just use it.\n\t // Otherwise, check it against pluralization rules in $locale service.\n\t count = $locale.pluralCat(count - offset);\n\t }\n\t\n\t // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.\n\t // In JS `NaN !== NaN`, so we have to explicitly check.\n\t if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {\n\t watchRemover();\n\t var whenExpFn = whensExpFns[count];\n\t if (isUndefined(whenExpFn)) {\n\t if (newVal != null) {\n\t $log.debug(\"ngPluralize: no rule defined for '\" + count + \"' in \" + whenExp);\n\t }\n\t watchRemover = noop;\n\t updateElementText();\n\t } else {\n\t watchRemover = scope.$watch(whenExpFn, updateElementText);\n\t }\n\t lastCount = count;\n\t }\n\t });\n\t\n\t function updateElementText(newText) {\n\t element.text(newText || '');\n\t }\n\t }\n\t };\n\t}];\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngRepeat\n\t * @multiElement\n\t *\n\t * @description\n\t * The `ngRepeat` directive instantiates a template once per item from a collection. Each template\n\t * instance gets its own scope, where the given loop variable is set to the current collection item,\n\t * and `$index` is set to the item index or key.\n\t *\n\t * Special properties are exposed on the local scope of each template instance, including:\n\t *\n\t * | Variable | Type | Details |\n\t * |-----------|-----------------|-----------------------------------------------------------------------------|\n\t * | `$index` | {@type number} | iterator offset of the repeated element (0..length-1) |\n\t * | `$first` | {@type boolean} | true if the repeated element is first in the iterator. |\n\t * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |\n\t * | `$last` | {@type boolean} | true if the repeated element is last in the iterator. |\n\t * | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |\n\t * | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |\n\t *\n\t *
\n\t * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.\n\t * This may be useful when, for instance, nesting ngRepeats.\n\t *
\n\t *\n\t *\n\t * # Iterating over object properties\n\t *\n\t * It is possible to get `ngRepeat` to iterate over the properties of an object using the following\n\t * syntax:\n\t *\n\t * ```js\n\t *
...
\n\t * ```\n\t *\n\t * However, there are a limitations compared to array iteration:\n\t *\n\t * - The JavaScript specification does not define the order of keys\n\t * returned for an object, so Angular relies on the order returned by the browser\n\t * when running `for key in myObj`. Browsers generally follow the strategy of providing\n\t * keys in the order in which they were defined, although there are exceptions when keys are deleted\n\t * and reinstated. See the\n\t * [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).\n\t *\n\t * - `ngRepeat` will silently *ignore* object keys starting with `$`, because\n\t * it's a prefix used by Angular for public (`$`) and private (`$$`) properties.\n\t *\n\t * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with\n\t * objects, and will throw an error if used with one.\n\t *\n\t * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array\n\t * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could\n\t * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)\n\t * or implement a `$watch` on the object yourself.\n\t *\n\t *\n\t * # Tracking and Duplicates\n\t *\n\t * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in\n\t * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:\n\t *\n\t * * When an item is added, a new instance of the template is added to the DOM.\n\t * * When an item is removed, its template instance is removed from the DOM.\n\t * * When items are reordered, their respective templates are reordered in the DOM.\n\t *\n\t * To minimize creation of DOM elements, `ngRepeat` uses a function\n\t * to \"keep track\" of all items in the collection and their corresponding DOM elements.\n\t * For example, if an item is added to the collection, ngRepeat will know that all other items\n\t * already have DOM elements, and will not re-render them.\n\t *\n\t * The default tracking function (which tracks items by their identity) does not allow\n\t * duplicate items in arrays. This is because when there are duplicates, it is not possible\n\t * to maintain a one-to-one mapping between collection items and DOM elements.\n\t *\n\t * If you do need to repeat duplicate items, you can substitute the default tracking behavior\n\t * with your own using the `track by` expression.\n\t *\n\t * For example, you may track items by the index of each item in the collection, using the\n\t * special scope property `$index`:\n\t * ```html\n\t *
\n\t * {{n}}\n\t *
\n\t * ```\n\t *\n\t * You may also use arbitrary expressions in `track by`, including references to custom functions\n\t * on the scope:\n\t * ```html\n\t *
\n\t * {{n}}\n\t *
\n\t * ```\n\t *\n\t *
\n\t * If you are working with objects that have an identifier property, you should track\n\t * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`\n\t * will not have to rebuild the DOM elements for items it has already rendered, even if the\n\t * JavaScript objects in the collection have been substituted for new ones. For large collections,\n\t * this significantly improves rendering performance. If you don't have a unique identifier,\n\t * `track by $index` can also provide a performance boost.\n\t *
\n\t * ```html\n\t *
\n\t * {{model.name}}\n\t *
\n\t * ```\n\t *\n\t * When no `track by` expression is provided, it is equivalent to tracking by the built-in\n\t * `$id` function, which tracks items by their identity:\n\t * ```html\n\t *
\n\t * {{obj.prop}}\n\t *
\n\t * ```\n\t *\n\t *
\n\t * **Note:** `track by` must always be the last expression:\n\t *
\n\t * ```\n\t *
\n\t * {{model.name}}\n\t *
\n\t * ```\n\t *\n\t * # Special repeat start and end points\n\t * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending\n\t * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.\n\t * 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)\n\t * up to and including the ending HTML tag where **ng-repeat-end** is placed.\n\t *\n\t * The example below makes use of this feature:\n\t * ```html\n\t *
\n\t * Header {{ item }}\n\t *
\n\t *
\n\t * Body {{ item }}\n\t *
\n\t *
\n\t * Footer {{ item }}\n\t *
\n\t * ```\n\t *\n\t * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:\n\t * ```html\n\t *
\n\t * Header A\n\t *
\n\t *
\n\t * Body A\n\t *
\n\t *
\n\t * Footer A\n\t *
\n\t *
\n\t * Header B\n\t *
\n\t *
\n\t * Body B\n\t *
\n\t *
\n\t * Footer B\n\t *
\n\t * ```\n\t *\n\t * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such\n\t * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).\n\t *\n\t * @animations\n\t * | Animation | Occurs |\n\t * |----------------------------------|-------------------------------------|\n\t * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |\n\t * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |\n\t * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |\n\t *\n\t * See the example below for defining CSS animations with ngRepeat.\n\t *\n\t * @element ANY\n\t * @scope\n\t * @priority 1000\n\t * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These\n\t * formats are currently supported:\n\t *\n\t * * `variable in expression` – where variable is the user defined loop variable and `expression`\n\t * is a scope expression giving the collection to enumerate.\n\t *\n\t * For example: `album in artist.albums`.\n\t *\n\t * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,\n\t * and `expression` is the scope expression giving the collection to enumerate.\n\t *\n\t * For example: `(name, age) in {'adam':10, 'amalie':12}`.\n\t *\n\t * * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression\n\t * which can be used to associate the objects in the collection with the DOM elements. If no tracking expression\n\t * is specified, ng-repeat associates elements by identity. It is an error to have\n\t * more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are\n\t * mapped to the same DOM element, which is not possible.)\n\t *\n\t * Note that the tracking expression must come last, after any filters, and the alias expression.\n\t *\n\t * For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements\n\t * will be associated by item identity in the array.\n\t *\n\t * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique\n\t * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements\n\t * with the corresponding item in the array by identity. Moving the same object in array would move the DOM\n\t * element in the same way in the DOM.\n\t *\n\t * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this\n\t * case the object identity does not matter. Two objects are considered equivalent as long as their `id`\n\t * property is same.\n\t *\n\t * For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter\n\t * to items in conjunction with a tracking expression.\n\t *\n\t * * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the\n\t * intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message\n\t * when a filter is active on the repeater, but the filtered result set is empty.\n\t *\n\t * For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after\n\t * the items have been processed through the filter.\n\t *\n\t * Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax so it can be used only at the end\n\t * (and not as operator, inside an expression).\n\t *\n\t * For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .\n\t *\n\t * @example\n\t * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed\n\t * results by name. New (entering) and removed (leaving) items are animated.\n\t \n\t \n\t
\n\t I have {{friends.length}} friends. They are:\n\t \n\t
    \n\t
  • \n\t [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.\n\t
  • \n\t
  • \n\t No results found...\n\t
  • \n\t
\n\t
\n\t
\n\t \n\t angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {\n\t $scope.friends = [\n\t {name:'John', age:25, gender:'boy'},\n\t {name:'Jessie', age:30, gender:'girl'},\n\t {name:'Johanna', age:28, gender:'girl'},\n\t {name:'Joy', age:15, gender:'girl'},\n\t {name:'Mary', age:28, gender:'girl'},\n\t {name:'Peter', age:95, gender:'boy'},\n\t {name:'Sebastian', age:50, gender:'boy'},\n\t {name:'Erika', age:27, gender:'girl'},\n\t {name:'Patrick', age:40, gender:'boy'},\n\t {name:'Samantha', age:60, gender:'girl'}\n\t ];\n\t });\n\t \n\t \n\t .example-animate-container {\n\t background:white;\n\t border:1px solid black;\n\t list-style:none;\n\t margin:0;\n\t padding:0 10px;\n\t }\n\t\n\t .animate-repeat {\n\t line-height:30px;\n\t list-style:none;\n\t box-sizing:border-box;\n\t }\n\t\n\t .animate-repeat.ng-move,\n\t .animate-repeat.ng-enter,\n\t .animate-repeat.ng-leave {\n\t transition:all linear 0.5s;\n\t }\n\t\n\t .animate-repeat.ng-leave.ng-leave-active,\n\t .animate-repeat.ng-move,\n\t .animate-repeat.ng-enter {\n\t opacity:0;\n\t max-height:0;\n\t }\n\t\n\t .animate-repeat.ng-leave,\n\t .animate-repeat.ng-move.ng-move-active,\n\t .animate-repeat.ng-enter.ng-enter-active {\n\t opacity:1;\n\t max-height:30px;\n\t }\n\t \n\t \n\t var friends = element.all(by.repeater('friend in friends'));\n\t\n\t it('should render initial data set', function() {\n\t expect(friends.count()).toBe(10);\n\t expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');\n\t expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');\n\t expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');\n\t expect(element(by.binding('friends.length')).getText())\n\t .toMatch(\"I have 10 friends. They are:\");\n\t });\n\t\n\t it('should update repeater when filter predicate changes', function() {\n\t expect(friends.count()).toBe(10);\n\t\n\t element(by.model('q')).sendKeys('ma');\n\t\n\t expect(friends.count()).toBe(2);\n\t expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');\n\t expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');\n\t });\n\t \n\t
\n\t */\n\tvar ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {\n\t var NG_REMOVED = '$$NG_REMOVED';\n\t var ngRepeatMinErr = minErr('ngRepeat');\n\t\n\t var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {\n\t // TODO(perf): generate setters to shave off ~40ms or 1-1.5%\n\t scope[valueIdentifier] = value;\n\t if (keyIdentifier) scope[keyIdentifier] = key;\n\t scope.$index = index;\n\t scope.$first = (index === 0);\n\t scope.$last = (index === (arrayLength - 1));\n\t scope.$middle = !(scope.$first || scope.$last);\n\t // jshint bitwise: false\n\t scope.$odd = !(scope.$even = (index&1) === 0);\n\t // jshint bitwise: true\n\t };\n\t\n\t var getBlockStart = function(block) {\n\t return block.clone[0];\n\t };\n\t\n\t var getBlockEnd = function(block) {\n\t return block.clone[block.clone.length - 1];\n\t };\n\t\n\t\n\t return {\n\t restrict: 'A',\n\t multiElement: true,\n\t transclude: 'element',\n\t priority: 1000,\n\t terminal: true,\n\t $$tlb: true,\n\t compile: function ngRepeatCompile($element, $attr) {\n\t var expression = $attr.ngRepeat;\n\t var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);\n\t\n\t 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*$/);\n\t\n\t if (!match) {\n\t throw ngRepeatMinErr('iexp', \"Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.\",\n\t expression);\n\t }\n\t\n\t var lhs = match[1];\n\t var rhs = match[2];\n\t var aliasAs = match[3];\n\t var trackByExp = match[4];\n\t\n\t match = lhs.match(/^(?:(\\s*[\\$\\w]+)|\\(\\s*([\\$\\w]+)\\s*,\\s*([\\$\\w]+)\\s*\\))$/);\n\t\n\t if (!match) {\n\t throw ngRepeatMinErr('iidexp', \"'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.\",\n\t lhs);\n\t }\n\t var valueIdentifier = match[3] || match[1];\n\t var keyIdentifier = match[2];\n\t\n\t if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||\n\t /^(null|undefined|this|\\$index|\\$first|\\$middle|\\$last|\\$even|\\$odd|\\$parent|\\$root|\\$id)$/.test(aliasAs))) {\n\t throw ngRepeatMinErr('badident', \"alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.\",\n\t aliasAs);\n\t }\n\t\n\t var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;\n\t var hashFnLocals = {$id: hashKey};\n\t\n\t if (trackByExp) {\n\t trackByExpGetter = $parse(trackByExp);\n\t } else {\n\t trackByIdArrayFn = function(key, value) {\n\t return hashKey(value);\n\t };\n\t trackByIdObjFn = function(key) {\n\t return key;\n\t };\n\t }\n\t\n\t return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {\n\t\n\t if (trackByExpGetter) {\n\t trackByIdExpFn = function(key, value, index) {\n\t // assign key, value, and $index to the locals so that they can be used in hash functions\n\t if (keyIdentifier) hashFnLocals[keyIdentifier] = key;\n\t hashFnLocals[valueIdentifier] = value;\n\t hashFnLocals.$index = index;\n\t return trackByExpGetter($scope, hashFnLocals);\n\t };\n\t }\n\t\n\t // Store a list of elements from previous run. This is a hash where key is the item from the\n\t // iterator, and the value is objects with following properties.\n\t // - scope: bound scope\n\t // - element: previous element.\n\t // - index: position\n\t //\n\t // We are using no-proto object so that we don't need to guard against inherited props via\n\t // hasOwnProperty.\n\t var lastBlockMap = createMap();\n\t\n\t //watch props\n\t $scope.$watchCollection(rhs, function ngRepeatAction(collection) {\n\t var index, length,\n\t previousNode = $element[0], // node that cloned nodes should be inserted after\n\t // initialized to the comment node anchor\n\t nextNode,\n\t // Same as lastBlockMap but it has the current state. It will become the\n\t // lastBlockMap on the next iteration.\n\t nextBlockMap = createMap(),\n\t collectionLength,\n\t key, value, // key/value of iteration\n\t trackById,\n\t trackByIdFn,\n\t collectionKeys,\n\t block, // last object information {scope, element, id}\n\t nextBlockOrder,\n\t elementsToRemove;\n\t\n\t if (aliasAs) {\n\t $scope[aliasAs] = collection;\n\t }\n\t\n\t if (isArrayLike(collection)) {\n\t collectionKeys = collection;\n\t trackByIdFn = trackByIdExpFn || trackByIdArrayFn;\n\t } else {\n\t trackByIdFn = trackByIdExpFn || trackByIdObjFn;\n\t // if object, extract keys, in enumeration order, unsorted\n\t collectionKeys = [];\n\t for (var itemKey in collection) {\n\t if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {\n\t collectionKeys.push(itemKey);\n\t }\n\t }\n\t }\n\t\n\t collectionLength = collectionKeys.length;\n\t nextBlockOrder = new Array(collectionLength);\n\t\n\t // locate existing items\n\t for (index = 0; index < collectionLength; index++) {\n\t key = (collection === collectionKeys) ? index : collectionKeys[index];\n\t value = collection[key];\n\t trackById = trackByIdFn(key, value, index);\n\t if (lastBlockMap[trackById]) {\n\t // found previously seen block\n\t block = lastBlockMap[trackById];\n\t delete lastBlockMap[trackById];\n\t nextBlockMap[trackById] = block;\n\t nextBlockOrder[index] = block;\n\t } else if (nextBlockMap[trackById]) {\n\t // if collision detected. restore lastBlockMap and throw an error\n\t forEach(nextBlockOrder, function(block) {\n\t if (block && block.scope) lastBlockMap[block.id] = block;\n\t });\n\t throw ngRepeatMinErr('dupes',\n\t \"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}\",\n\t expression, trackById, value);\n\t } else {\n\t // new never before seen block\n\t nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};\n\t nextBlockMap[trackById] = true;\n\t }\n\t }\n\t\n\t // remove leftover items\n\t for (var blockKey in lastBlockMap) {\n\t block = lastBlockMap[blockKey];\n\t elementsToRemove = getBlockNodes(block.clone);\n\t $animate.leave(elementsToRemove);\n\t if (elementsToRemove[0].parentNode) {\n\t // if the element was not removed yet because of pending animation, mark it as deleted\n\t // so that we can ignore it later\n\t for (index = 0, length = elementsToRemove.length; index < length; index++) {\n\t elementsToRemove[index][NG_REMOVED] = true;\n\t }\n\t }\n\t block.scope.$destroy();\n\t }\n\t\n\t // we are not using forEach for perf reasons (trying to avoid #call)\n\t for (index = 0; index < collectionLength; index++) {\n\t key = (collection === collectionKeys) ? index : collectionKeys[index];\n\t value = collection[key];\n\t block = nextBlockOrder[index];\n\t\n\t if (block.scope) {\n\t // if we have already seen this object, then we need to reuse the\n\t // associated scope/element\n\t\n\t nextNode = previousNode;\n\t\n\t // skip nodes that are already pending removal via leave animation\n\t do {\n\t nextNode = nextNode.nextSibling;\n\t } while (nextNode && nextNode[NG_REMOVED]);\n\t\n\t if (getBlockStart(block) != nextNode) {\n\t // existing item which got moved\n\t $animate.move(getBlockNodes(block.clone), null, previousNode);\n\t }\n\t previousNode = getBlockEnd(block);\n\t updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);\n\t } else {\n\t // new item which we don't know about\n\t $transclude(function ngRepeatTransclude(clone, scope) {\n\t block.scope = scope;\n\t // http://jsperf.com/clone-vs-createcomment\n\t var endNode = ngRepeatEndComment.cloneNode(false);\n\t clone[clone.length++] = endNode;\n\t\n\t $animate.enter(clone, null, previousNode);\n\t previousNode = endNode;\n\t // Note: We only need the first/last node of the cloned nodes.\n\t // However, we need to keep the reference to the jqlite wrapper as it might be changed later\n\t // by a directive with templateUrl when its template arrives.\n\t block.clone = clone;\n\t nextBlockMap[block.id] = block;\n\t updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);\n\t });\n\t }\n\t }\n\t lastBlockMap = nextBlockMap;\n\t });\n\t };\n\t }\n\t };\n\t}];\n\t\n\tvar NG_HIDE_CLASS = 'ng-hide';\n\tvar NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';\n\t/**\n\t * @ngdoc directive\n\t * @name ngShow\n\t * @multiElement\n\t *\n\t * @description\n\t * The `ngShow` directive shows or hides the given HTML element based on the expression\n\t * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding\n\t * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined\n\t * in AngularJS and sets the display style to none (using an !important flag).\n\t * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).\n\t *\n\t * ```html\n\t * \n\t *
\n\t *\n\t * \n\t *
\n\t * ```\n\t *\n\t * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class\n\t * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed\n\t * from the element causing the element not to appear hidden.\n\t *\n\t * ## Why is !important used?\n\t *\n\t * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector\n\t * can be easily overridden by heavier selectors. For example, something as simple\n\t * as changing the display style on a HTML list item would make hidden elements appear visible.\n\t * This also becomes a bigger issue when dealing with CSS frameworks.\n\t *\n\t * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector\n\t * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the\n\t * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.\n\t *\n\t * ### Overriding `.ng-hide`\n\t *\n\t * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change\n\t * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`\n\t * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope\n\t * with extra animation classes that can be added.\n\t *\n\t * ```css\n\t * .ng-hide:not(.ng-hide-animate) {\n\t * /* this is just another form of hiding an element */\n\t * display: block!important;\n\t * position: absolute;\n\t * top: -9999px;\n\t * left: -9999px;\n\t * }\n\t * ```\n\t *\n\t * By default you don't need to override in CSS anything and the animations will work around the display style.\n\t *\n\t * ## A note about animations with `ngShow`\n\t *\n\t * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression\n\t * is true and false. This system works like the animation system present with ngClass except that\n\t * you must also include the !important flag to override the display property\n\t * so that you can perform an animation when the element is hidden during the time of the animation.\n\t *\n\t * ```css\n\t * //\n\t * //a working example can be found at the bottom of this page\n\t * //\n\t * .my-element.ng-hide-add, .my-element.ng-hide-remove {\n\t * /* this is required as of 1.3x to properly\n\t * apply all styling in a show/hide animation */\n\t * transition: 0s linear all;\n\t * }\n\t *\n\t * .my-element.ng-hide-add-active,\n\t * .my-element.ng-hide-remove-active {\n\t * /* the transition is defined in the active class */\n\t * transition: 1s linear all;\n\t * }\n\t *\n\t * .my-element.ng-hide-add { ... }\n\t * .my-element.ng-hide-add.ng-hide-add-active { ... }\n\t * .my-element.ng-hide-remove { ... }\n\t * .my-element.ng-hide-remove.ng-hide-remove-active { ... }\n\t * ```\n\t *\n\t * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display\n\t * property to block during animation states--ngAnimate will handle the style toggling automatically for you.\n\t *\n\t * @animations\n\t * | Animation | Occurs |\n\t * |----------------------------------|-------------------------------------|\n\t * | {@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 |\n\t * | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |\n\t *\n\t * @element ANY\n\t * @param {expression} ngShow If the {@link guide/expression expression} is truthy\n\t * then the element is shown or hidden respectively.\n\t *\n\t * @example\n\t \n\t \n\t Click me:
\n\t
\n\t Show:\n\t
\n\t I show up when your checkbox is checked.\n\t
\n\t
\n\t
\n\t Hide:\n\t
\n\t I hide when your checkbox is checked.\n\t
\n\t
\n\t
\n\t \n\t @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);\n\t \n\t \n\t .animate-show {\n\t line-height: 20px;\n\t opacity: 1;\n\t padding: 10px;\n\t border: 1px solid black;\n\t background: white;\n\t }\n\t\n\t .animate-show.ng-hide-add, .animate-show.ng-hide-remove {\n\t transition: all linear 0.5s;\n\t }\n\t\n\t .animate-show.ng-hide {\n\t line-height: 0;\n\t opacity: 0;\n\t padding: 0 10px;\n\t }\n\t\n\t .check-element {\n\t padding: 10px;\n\t border: 1px solid black;\n\t background: white;\n\t }\n\t \n\t \n\t var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));\n\t var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));\n\t\n\t it('should check ng-show / ng-hide', function() {\n\t expect(thumbsUp.isDisplayed()).toBeFalsy();\n\t expect(thumbsDown.isDisplayed()).toBeTruthy();\n\t\n\t element(by.model('checked')).click();\n\t\n\t expect(thumbsUp.isDisplayed()).toBeTruthy();\n\t expect(thumbsDown.isDisplayed()).toBeFalsy();\n\t });\n\t \n\t
\n\t */\n\tvar ngShowDirective = ['$animate', function($animate) {\n\t return {\n\t restrict: 'A',\n\t multiElement: true,\n\t link: function(scope, element, attr) {\n\t scope.$watch(attr.ngShow, function ngShowWatchAction(value) {\n\t // we're adding a temporary, animation-specific class for ng-hide since this way\n\t // we can control when the element is actually displayed on screen without having\n\t // to have a global/greedy CSS selector that breaks when other animations are run.\n\t // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845\n\t $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {\n\t tempClasses: NG_HIDE_IN_PROGRESS_CLASS\n\t });\n\t });\n\t }\n\t };\n\t}];\n\t\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngHide\n\t * @multiElement\n\t *\n\t * @description\n\t * The `ngHide` directive shows or hides the given HTML element based on the expression\n\t * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding\n\t * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined\n\t * in AngularJS and sets the display style to none (using an !important flag).\n\t * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).\n\t *\n\t * ```html\n\t * \n\t *
\n\t *\n\t * \n\t *
\n\t * ```\n\t *\n\t * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class\n\t * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed\n\t * from the element causing the element not to appear hidden.\n\t *\n\t * ## Why is !important used?\n\t *\n\t * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector\n\t * can be easily overridden by heavier selectors. For example, something as simple\n\t * as changing the display style on a HTML list item would make hidden elements appear visible.\n\t * This also becomes a bigger issue when dealing with CSS frameworks.\n\t *\n\t * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector\n\t * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the\n\t * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.\n\t *\n\t * ### Overriding `.ng-hide`\n\t *\n\t * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change\n\t * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`\n\t * class in CSS:\n\t *\n\t * ```css\n\t * .ng-hide {\n\t * /* this is just another form of hiding an element */\n\t * display: block!important;\n\t * position: absolute;\n\t * top: -9999px;\n\t * left: -9999px;\n\t * }\n\t * ```\n\t *\n\t * By default you don't need to override in CSS anything and the animations will work around the display style.\n\t *\n\t * ## A note about animations with `ngHide`\n\t *\n\t * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression\n\t * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`\n\t * CSS class is added and removed for you instead of your own CSS class.\n\t *\n\t * ```css\n\t * //\n\t * //a working example can be found at the bottom of this page\n\t * //\n\t * .my-element.ng-hide-add, .my-element.ng-hide-remove {\n\t * transition: 0.5s linear all;\n\t * }\n\t *\n\t * .my-element.ng-hide-add { ... }\n\t * .my-element.ng-hide-add.ng-hide-add-active { ... }\n\t * .my-element.ng-hide-remove { ... }\n\t * .my-element.ng-hide-remove.ng-hide-remove-active { ... }\n\t * ```\n\t *\n\t * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display\n\t * property to block during animation states--ngAnimate will handle the style toggling automatically for you.\n\t *\n\t * @animations\n\t * | Animation | Occurs |\n\t * |----------------------------------|-------------------------------------|\n\t * | {@link $animate#addClass addClass} `.ng-hide` | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |\n\t * | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |\n\t *\n\t *\n\t * @element ANY\n\t * @param {expression} ngHide If the {@link guide/expression expression} is truthy then\n\t * the element is shown or hidden respectively.\n\t *\n\t * @example\n\t \n\t \n\t Click me:
\n\t
\n\t Show:\n\t
\n\t I show up when your checkbox is checked.\n\t
\n\t
\n\t
\n\t Hide:\n\t
\n\t I hide when your checkbox is checked.\n\t
\n\t
\n\t
\n\t \n\t @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);\n\t \n\t \n\t .animate-hide {\n\t transition: all linear 0.5s;\n\t line-height: 20px;\n\t opacity: 1;\n\t padding: 10px;\n\t border: 1px solid black;\n\t background: white;\n\t }\n\t\n\t .animate-hide.ng-hide {\n\t line-height: 0;\n\t opacity: 0;\n\t padding: 0 10px;\n\t }\n\t\n\t .check-element {\n\t padding: 10px;\n\t border: 1px solid black;\n\t background: white;\n\t }\n\t \n\t \n\t var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));\n\t var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));\n\t\n\t it('should check ng-show / ng-hide', function() {\n\t expect(thumbsUp.isDisplayed()).toBeFalsy();\n\t expect(thumbsDown.isDisplayed()).toBeTruthy();\n\t\n\t element(by.model('checked')).click();\n\t\n\t expect(thumbsUp.isDisplayed()).toBeTruthy();\n\t expect(thumbsDown.isDisplayed()).toBeFalsy();\n\t });\n\t \n\t
\n\t */\n\tvar ngHideDirective = ['$animate', function($animate) {\n\t return {\n\t restrict: 'A',\n\t multiElement: true,\n\t link: function(scope, element, attr) {\n\t scope.$watch(attr.ngHide, function ngHideWatchAction(value) {\n\t // The comment inside of the ngShowDirective explains why we add and\n\t // remove a temporary class for the show/hide animation\n\t $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {\n\t tempClasses: NG_HIDE_IN_PROGRESS_CLASS\n\t });\n\t });\n\t }\n\t };\n\t}];\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngStyle\n\t * @restrict AC\n\t *\n\t * @description\n\t * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.\n\t *\n\t * @knownIssue\n\t * You should not use {@link guide/interpolation interpolation} in the value of the `style`\n\t * attribute, when using the `ngStyle` directive on the same element.\n\t * See {@link guide/interpolation#known-issues here} for more info.\n\t *\n\t * @element ANY\n\t * @param {expression} ngStyle\n\t *\n\t * {@link guide/expression Expression} which evals to an\n\t * object whose keys are CSS style names and values are corresponding values for those CSS\n\t * keys.\n\t *\n\t * Since some CSS style names are not valid keys for an object, they must be quoted.\n\t * See the 'background-color' style in the example below.\n\t *\n\t * @example\n\t \n\t \n\t \n\t \n\t \n\t
\n\t Sample Text\n\t
myStyle={{myStyle}}
\n\t
\n\t \n\t span {\n\t color: black;\n\t }\n\t \n\t \n\t var colorSpan = element(by.css('span'));\n\t\n\t it('should check ng-style', function() {\n\t expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');\n\t element(by.css('input[value=\\'set color\\']')).click();\n\t expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');\n\t element(by.css('input[value=clear]')).click();\n\t expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');\n\t });\n\t \n\t
\n\t */\n\tvar ngStyleDirective = ngDirective(function(scope, element, attr) {\n\t scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {\n\t if (oldStyles && (newStyles !== oldStyles)) {\n\t forEach(oldStyles, function(val, style) { element.css(style, '');});\n\t }\n\t if (newStyles) element.css(newStyles);\n\t }, true);\n\t});\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngSwitch\n\t * @restrict EA\n\t *\n\t * @description\n\t * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.\n\t * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location\n\t * as specified in the template.\n\t *\n\t * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it\n\t * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element\n\t * matches the value obtained from the evaluated expression. In other words, you define a container element\n\t * (where you place the directive), place an expression on the **`on=\"...\"` attribute**\n\t * (or the **`ng-switch=\"...\"` attribute**), define any inner elements inside of the directive and place\n\t * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on\n\t * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default\n\t * attribute is displayed.\n\t *\n\t *
\n\t * Be aware that the attribute values to match against cannot be expressions. They are interpreted\n\t * as literal string values to match against.\n\t * For example, **`ng-switch-when=\"someVal\"`** will match against the string `\"someVal\"` not against the\n\t * value of the expression `$scope.someVal`.\n\t *
\n\t\n\t * @animations\n\t * | Animation | Occurs |\n\t * |----------------------------------|-------------------------------------|\n\t * | {@link ng.$animate#enter enter} | after the ngSwitch contents change and the matched child element is placed inside the container |\n\t * | {@link ng.$animate#leave leave} | after the ngSwitch contents change and just before the former contents are removed from the DOM |\n\t *\n\t * @usage\n\t *\n\t * ```\n\t * \n\t * ...\n\t * ...\n\t * ...\n\t * \n\t * ```\n\t *\n\t *\n\t * @scope\n\t * @priority 1200\n\t * @param {*} ngSwitch|on expression to match against ng-switch-when.\n\t * On child elements add:\n\t *\n\t * * `ngSwitchWhen`: the case statement to match against. If match then this\n\t * case will be displayed. If the same match appears multiple times, all the\n\t * elements will be displayed.\n\t * * `ngSwitchDefault`: the default case when no other case match. If there\n\t * are multiple default cases, all of them will be displayed when no other\n\t * case match.\n\t *\n\t *\n\t * @example\n\t \n\t \n\t
\n\t \n\t selection={{selection}}\n\t
\n\t
\n\t
Settings Div
\n\t
Home Span
\n\t
default
\n\t
\n\t
\n\t
\n\t \n\t angular.module('switchExample', ['ngAnimate'])\n\t .controller('ExampleController', ['$scope', function($scope) {\n\t $scope.items = ['settings', 'home', 'other'];\n\t $scope.selection = $scope.items[0];\n\t }]);\n\t \n\t \n\t .animate-switch-container {\n\t position:relative;\n\t background:white;\n\t border:1px solid black;\n\t height:40px;\n\t overflow:hidden;\n\t }\n\t\n\t .animate-switch {\n\t padding:10px;\n\t }\n\t\n\t .animate-switch.ng-animate {\n\t transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;\n\t\n\t position:absolute;\n\t top:0;\n\t left:0;\n\t right:0;\n\t bottom:0;\n\t }\n\t\n\t .animate-switch.ng-leave.ng-leave-active,\n\t .animate-switch.ng-enter {\n\t top:-50px;\n\t }\n\t .animate-switch.ng-leave,\n\t .animate-switch.ng-enter.ng-enter-active {\n\t top:0;\n\t }\n\t \n\t \n\t var switchElem = element(by.css('[ng-switch]'));\n\t var select = element(by.model('selection'));\n\t\n\t it('should start in settings', function() {\n\t expect(switchElem.getText()).toMatch(/Settings Div/);\n\t });\n\t it('should change to home', function() {\n\t select.all(by.css('option')).get(1).click();\n\t expect(switchElem.getText()).toMatch(/Home Span/);\n\t });\n\t it('should select default', function() {\n\t select.all(by.css('option')).get(2).click();\n\t expect(switchElem.getText()).toMatch(/default/);\n\t });\n\t \n\t
\n\t */\n\tvar ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {\n\t return {\n\t require: 'ngSwitch',\n\t\n\t // asks for $scope to fool the BC controller module\n\t controller: ['$scope', function ngSwitchController() {\n\t this.cases = {};\n\t }],\n\t link: function(scope, element, attr, ngSwitchController) {\n\t var watchExpr = attr.ngSwitch || attr.on,\n\t selectedTranscludes = [],\n\t selectedElements = [],\n\t previousLeaveAnimations = [],\n\t selectedScopes = [];\n\t\n\t var spliceFactory = function(array, index) {\n\t return function() { array.splice(index, 1); };\n\t };\n\t\n\t scope.$watch(watchExpr, function ngSwitchWatchAction(value) {\n\t var i, ii;\n\t for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {\n\t $animate.cancel(previousLeaveAnimations[i]);\n\t }\n\t previousLeaveAnimations.length = 0;\n\t\n\t for (i = 0, ii = selectedScopes.length; i < ii; ++i) {\n\t var selected = getBlockNodes(selectedElements[i].clone);\n\t selectedScopes[i].$destroy();\n\t var promise = previousLeaveAnimations[i] = $animate.leave(selected);\n\t promise.then(spliceFactory(previousLeaveAnimations, i));\n\t }\n\t\n\t selectedElements.length = 0;\n\t selectedScopes.length = 0;\n\t\n\t if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {\n\t forEach(selectedTranscludes, function(selectedTransclude) {\n\t selectedTransclude.transclude(function(caseElement, selectedScope) {\n\t selectedScopes.push(selectedScope);\n\t var anchor = selectedTransclude.element;\n\t caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');\n\t var block = { clone: caseElement };\n\t\n\t selectedElements.push(block);\n\t $animate.enter(caseElement, anchor.parent(), anchor);\n\t });\n\t });\n\t }\n\t });\n\t }\n\t };\n\t}];\n\t\n\tvar ngSwitchWhenDirective = ngDirective({\n\t transclude: 'element',\n\t priority: 1200,\n\t require: '^ngSwitch',\n\t multiElement: true,\n\t link: function(scope, element, attrs, ctrl, $transclude) {\n\t ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);\n\t ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });\n\t }\n\t});\n\t\n\tvar ngSwitchDefaultDirective = ngDirective({\n\t transclude: 'element',\n\t priority: 1200,\n\t require: '^ngSwitch',\n\t multiElement: true,\n\t link: function(scope, element, attr, ctrl, $transclude) {\n\t ctrl.cases['?'] = (ctrl.cases['?'] || []);\n\t ctrl.cases['?'].push({ transclude: $transclude, element: element });\n\t }\n\t});\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name ngTransclude\n\t * @restrict EAC\n\t *\n\t * @description\n\t * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.\n\t *\n\t * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name\n\t * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.\n\t *\n\t * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing\n\t * content of this element will be removed before the transcluded content is inserted.\n\t * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case\n\t * that no transcluded content is provided.\n\t *\n\t * @element ANY\n\t *\n\t * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty\n\t * or its value is the same as the name of the attribute then the default slot is used.\n\t *\n\t * @example\n\t * ### Basic transclusion\n\t * This example demonstrates basic transclusion of content into a component directive.\n\t * \n\t * \n\t * \n\t *
\n\t *
\n\t *
\n\t * {{text}}\n\t *
\n\t *
\n\t * \n\t * it('should have transcluded', function() {\n\t * var titleElement = element(by.model('title'));\n\t * titleElement.clear();\n\t * titleElement.sendKeys('TITLE');\n\t * var textElement = element(by.model('text'));\n\t * textElement.clear();\n\t * textElement.sendKeys('TEXT');\n\t * expect(element(by.binding('title')).getText()).toEqual('TITLE');\n\t * expect(element(by.binding('text')).getText()).toEqual('TEXT');\n\t * });\n\t * \n\t *
\n\t *\n\t * @example\n\t * ### Transclude fallback content\n\t * This example shows how to use `NgTransclude` with fallback content, that\n\t * is displayed if no transcluded content is provided.\n\t *\n\t * \n\t * \n\t * \n\t * \n\t * \n\t * \n\t * \n\t * Button2\n\t * \n\t * \n\t * \n\t * it('should have different transclude element content', function() {\n\t * expect(element(by.id('fallback')).getText()).toBe('Button1');\n\t * expect(element(by.id('modified')).getText()).toBe('Button2');\n\t * });\n\t * \n\t * \n\t *\n\t * @example\n\t * ### Multi-slot transclusion\n\t * This example demonstrates using multi-slot transclusion in a component directive.\n\t * \n\t * \n\t * \n\t *
\n\t *
\n\t *
\n\t * \n\t * {{title}}\n\t *

{{text}}

\n\t *
\n\t *
\n\t *
\n\t * \n\t * angular.module('multiSlotTranscludeExample', [])\n\t * .directive('pane', function(){\n\t * return {\n\t * restrict: 'E',\n\t * transclude: {\n\t * 'title': '?paneTitle',\n\t * 'body': 'paneBody',\n\t * 'footer': '?paneFooter'\n\t * },\n\t * template: '
' +\n\t * '
Fallback Title
' +\n\t * '
' +\n\t * '
Fallback Footer
' +\n\t * '
'\n\t * };\n\t * })\n\t * .controller('ExampleController', ['$scope', function($scope) {\n\t * $scope.title = 'Lorem Ipsum';\n\t * $scope.link = \"https://google.com\";\n\t * $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';\n\t * }]);\n\t *
\n\t * \n\t * it('should have transcluded the title and the body', function() {\n\t * var titleElement = element(by.model('title'));\n\t * titleElement.clear();\n\t * titleElement.sendKeys('TITLE');\n\t * var textElement = element(by.model('text'));\n\t * textElement.clear();\n\t * textElement.sendKeys('TEXT');\n\t * expect(element(by.css('.title')).getText()).toEqual('TITLE');\n\t * expect(element(by.binding('text')).getText()).toEqual('TEXT');\n\t * expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');\n\t * });\n\t * \n\t *
\n\t */\n\tvar ngTranscludeMinErr = minErr('ngTransclude');\n\tvar ngTranscludeDirective = ['$compile', function($compile) {\n\t return {\n\t restrict: 'EAC',\n\t terminal: true,\n\t compile: function ngTranscludeCompile(tElement) {\n\t\n\t // Remove and cache any original content to act as a fallback\n\t var fallbackLinkFn = $compile(tElement.contents());\n\t tElement.empty();\n\t\n\t return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {\n\t\n\t if (!$transclude) {\n\t throw ngTranscludeMinErr('orphan',\n\t 'Illegal use of ngTransclude directive in the template! ' +\n\t 'No parent directive that requires a transclusion found. ' +\n\t 'Element: {0}',\n\t startingTag($element));\n\t }\n\t\n\t\n\t // If the attribute is of the form: `ng-transclude=\"ng-transclude\"` then treat it like the default\n\t if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {\n\t $attrs.ngTransclude = '';\n\t }\n\t var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;\n\t\n\t // If the slot is required and no transclusion content is provided then this call will throw an error\n\t $transclude(ngTranscludeCloneAttachFn, null, slotName);\n\t\n\t // If the slot is optional and no transclusion content is provided then use the fallback content\n\t if (slotName && !$transclude.isSlotFilled(slotName)) {\n\t useFallbackContent();\n\t }\n\t\n\t function ngTranscludeCloneAttachFn(clone, transcludedScope) {\n\t if (clone.length) {\n\t $element.append(clone);\n\t } else {\n\t useFallbackContent();\n\t // There is nothing linked against the transcluded scope since no content was available,\n\t // so it should be safe to clean up the generated scope.\n\t transcludedScope.$destroy();\n\t }\n\t }\n\t\n\t function useFallbackContent() {\n\t // Since this is the fallback content rather than the transcluded content,\n\t // we link against the scope of this directive rather than the transcluded scope\n\t fallbackLinkFn($scope, function(clone) {\n\t $element.append(clone);\n\t });\n\t }\n\t };\n\t }\n\t };\n\t}];\n\t\n\t/**\n\t * @ngdoc directive\n\t * @name script\n\t * @restrict E\n\t *\n\t * @description\n\t * Load the content of a `\n\t\n\t Load inlined template\n\t
\n\t \n\t \n\t it('should load template defined inside script tag', function() {\n\t element(by.css('#tpl-link')).click();\n\t expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);\n\t });\n\t \n\t \n\t */\n\tvar scriptDirective = ['$templateCache', function($templateCache) {\n\t return {\n\t restrict: 'E',\n\t terminal: true,\n\t compile: function(element, attr) {\n\t if (attr.type == 'text/ng-template') {\n\t var templateUrl = attr.id,\n\t text = element[0].text;\n\t\n\t $templateCache.put(templateUrl, text);\n\t }\n\t }\n\t };\n\t}];\n\t\n\tvar noopNgModelController = { $setViewValue: noop, $render: noop };\n\t\n\tfunction chromeHack(optionElement) {\n\t // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459\n\t // Adding an