作者 zhangFan

机场口岸通关物流辅助管理系统

运行版
正在显示 23 个修改的文件 包含 4516 行增加0 行删除

要显示太多修改。

为保证性能只显示 23 of 23+ 个文件。

  1 +/*
  2 + AngularJS v1.2.13
  3 + (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + License: MIT
  5 +*/
  6 +(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&d.$apply())})();k=!0;d.$watch(function(){var a,e,d;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)(e=c[a],f.isString(e))?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(m(e[a])?delete c[a]:c[a]=e[a])});
  7 +return c}]).factory("$cookieStore",["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular);
  8 +//# sourceMappingURL=angular-cookies.min.js.map
  1 +{
  2 +"version":3,
  3 +"file":"angular-cookies.min.js",
  4 +"lineCount":7,
  5 +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAoBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA4BW,UA5BX,CA4BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CAEE,CADAY,CACK,CADGZ,CAAA,CAAQW,CAAR,CACH,CAAAjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAAL,EAMWA,CANX,GAMqBX,CAAA,CAAYU,CAAZ,CANrB,GAOEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CARZ,EACMnB,CAAAqB,UAAA,CAAkBd,CAAA,CAAYU,CAAZ,CAAlB,CAAJ,CACEX,CAAA,CAAQW,CAAR,CADF,CACkBV,CAAA,CAAYU,CAAZ,CADlB,CAGE,OAAOX,CAAA,CAAQW,CAAR,CASb,IAAIE,CAAJ,CAIE,IAAKF,CAAL,GAFAK,EAEahB,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBK,CAAA,CAAeL,CAAf,CAAtB,GAEMN,CAAA,CAAYW,CAAA,CAAeL,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBK,CAAA,CAAeL,CAAf,CALpB,CAlCU,CAThB,CAEA;MAAOX,EA1BqE,CAA3D,CA5BvB,CAAAH,QAAA,CA4HW,cA5HX,CA4H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAYAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAZd,KA4BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA5BrB,QA0CGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CA1CjB,CAF8C,CAAhC,CA5H3B,CApBsC,CAArC,CAAA,CAoME1B,MApMF,CAoMUA,MAAAC,QApMV;",
  6 +"sources":["angular-cookies.js"],
  7 +"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","isDefined","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"]
  8 +}
  1 +/**
  2 + * Implementing Drag and Drop functionality in AngularJS is easier than ever.
  3 + * Demo: http://codef0rmer.github.com/angular-dragdrop/
  4 + *
  5 + * @version 1.0.3
  6 + *
  7 + * (c) 2013 Amit Gharat a.k.a codef0rmer <amit.2006.it@gmail.com> - amitgharat.wordpress.com
  8 + */
  9 +var jqyoui=angular.module("ngDragDrop",[]).service("ngDragDropService",["$timeout","$parse",function($timeout,$parse){this.callEventCallback=function(scope,callbackName,event,ui){if(!callbackName){return}var args=[event,ui];var match=callbackName.match(/^(.+)\((.+)\)$/);if(match!==null){callbackName=match[1];values=eval("["+match[0].replace(/^(.+)\(/,"").replace(/\)/,"")+"]");args.push.apply(args,values)}scope[callbackName].apply(scope,args)};this.invokeDrop=function(e,t,n,r){var i="",s="",o={},u={},a=null,f={},l={},c,h,p=null,d=t.scope(),v=e.scope();i=e.attr("ng-model");s=t.attr("ng-model");c=v.$eval(i);h=d.$eval(s);p=t.find("[jqyoui-draggable]:last");u=d.$eval(t.attr("jqyoui-droppable"))||[];o=v.$eval(e.attr("jqyoui-draggable"))||[];o.index=this.fixIndex(v,o,c);u.index=this.fixIndex(d,u,h);a=angular.isArray(c)?o.index:null;f=angular.isArray(c)?c[a]:c;if(angular.isArray(h)&&u&&u.index!==undefined){l=h[u.index]}else if(!angular.isArray(h)){l=h}else{l={}}if(o.animate===true){this.move(e,p.length>0?p:t,null,"fast",u,null);this.move(p.length>0&&!u.multiple?p:[],e.parent("[jqyoui-droppable]"),jqyoui.startXY,"fast",u,function(){$timeout(function(){e.css({position:"relative",left:"",top:""});p.css({position:"relative",left:"",top:""});this.mutateDraggable(v,u,o,i,s,l,e);this.mutateDroppable(d,u,o,s,f,a);this.callEventCallback(d,u.onDrop,n,r)}.bind(this))}.bind(this))}else{$timeout(function(){this.mutateDraggable(v,u,o,i,s,l,e);this.mutateDroppable(d,u,o,s,f,a);this.callEventCallback(d,u.onDrop,n,r)}.bind(this))}};this.move=function(e,t,n,r,i,s){if(e.length===0){if(s){window.setTimeout(function(){s()},300)}return false}var o=9999,u=e.offset(),a=t&&t.is(":visible");if(n===null&&t.length>0){if(t.attr("jqyoui-draggable")!==undefined&&t.attr("ng-model")!==undefined&&t.is(":visible")&&i&&i.multiple){n=t.offset();if(i.stack===false){n.left+=t.outerWidth(true)}else{n.top+=t.outerHeight(true)}}else{n=t.css({visibility:"hidden",display:"block"}).offset();t.css({visibility:"",display:a?"":"none"})}}e.css({position:"absolute","z-index":o}).css(u).animate(n,r,function(){if(s)s()})};this.mutateDroppable=function(e,t,n,r,i,s){var o=e.$eval(r);e.__dragItem=i;if(angular.isArray(o)){if(t&&t.index>=0){o[t.index]=i}else{o.push(i)}if(n&&n.placeholder===true){o[o.length-1]["jqyoui_pos"]=s}}else{$parse(r+" = __dragItem")(e);if(n&&n.placeholder===true){o["jqyoui_pos"]=s}}};this.mutateDraggable=function(e,t,n,r,i,s,o){var u=angular.equals(angular.copy(s),{}),a=e.$eval(r);e.__dropItem=s;if(n&&n.placeholder){if(n.placeholder!="keep"){if(angular.isArray(a)&&n.index!==undefined){a[n.index]=s}else{$parse(r+" = __dropItem")(e)}}}else{if(angular.isArray(a)){if(u){if(n&&n.placeholder!==true&&n.placeholder!=="keep"){a.splice(n.index,1)}}else{a[n.index]=s}}else{$parse(r+" = __dropItem")(e);if(e.$parent){$parse(r+" = __dropItem")(e.$parent)}}}o.css({"z-index":"",left:"",top:""})};this.fixIndex=function(e,t,n){if(t.applyFilter&&angular.isArray(n)&&n.length>0){var r=e[t.applyFilter](),i=r[t.index],s=undefined;n.forEach(function(e,t){if(angular.equals(e,i)){s=t}});return s}return t.index}}]).directive("jqyouiDraggable",["ngDragDropService",function(e){return{require:"?jqyouiDroppable",restrict:"A",link:function(t,n,r){var i,s;var o=function(o,u){if(o){i=t.$eval(n.attr("jqyoui-draggable"))||[];n.draggable({disabled:false}).draggable(t.$eval(r.jqyouiOptions)||{}).draggable({start:function(n,r){s=angular.element(this).css("z-index");angular.element(this).css("z-index",99999);jqyoui.startXY=angular.element(this).offset();e.callEventCallback(t,i.onStart,n,r)},stop:function(n,r){angular.element(this).css("z-index",s);e.callEventCallback(t,i.onStop,n,r)},drag:function(n,r){e.callEventCallback(t,i.onDrag,n,r)}})}else{n.draggable({disabled:true})}};t.$watch(function(){return t.$eval(r.drag)},o);o()}}}]).directive("jqyouiDroppable",["ngDragDropService",function(e){return{restrict:"A",priority:1,link:function(t,n,r){var i=function(i,s){if(i){n.droppable({disabled:false}).droppable(t.$eval(r.jqyouiOptions)||{}).droppable({over:function(n,r){var i=t.$eval(angular.element(this).attr("jqyoui-droppable"))||[];e.callEventCallback(t,i.onOver,n,r)},out:function(n,r){var i=t.$eval(angular.element(this).attr("jqyoui-droppable"))||[];e.callEventCallback(t,i.onOut,n,r)},drop:function(t,n){e.invokeDrop(angular.element(n.draggable),angular.element(this),t,n)}})}else{n.droppable({disabled:true})}};t.$watch(function(){return t.$eval(r.drop)},i);i()}}}])
  1 +/**
  2 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  3 + * of this software and associated documentation files (the "Software"), to
  4 + * deal in the Software without restriction, including without limitation the
  5 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  6 + * sell copies of the Software, and to permit persons to whom the Software is
  7 + * furnished to do so, subject to the following conditions:
  8 + *
  9 + * The above copyright notice and this permission notice shall be included in
  10 + * all copies or substantial portions of the Software.
  11 + *
  12 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  18 + * IN THE SOFTWARE.
  19 + */
  20 +
  21 +/**
  22 + * Implementing Drag and Drop functionality in AngularJS is easier than ever.
  23 + * Demo: http://codef0rmer.github.com/angular-dragdrop/
  24 + *
  25 + * @version 1.0.7
  26 + *
  27 + * (c) 2013 Amit Gharat a.k.a codef0rmer <amit.2006.it@gmail.com> - amitgharat.wordpress.com
  28 + */
  29 +(function(e,t,n){"use strict";var r=t.module("ngDragDrop",[]).service("ngDragDropService",["$timeout","$parse",function(i,s){this.callEventCallback=function(e,t,n,r){function f(t){var n=t.indexOf("(")!==-1?t.indexOf("("):t.length,r=t.lastIndexOf(")")!==-1?t.lastIndexOf(")"):t.length,i=t.substring(n+1,r),o=t.match(/^[^.]+.\s*/)[0].slice(0,-1);o=e[o]&&typeof e[o].constructor==="function"?o:null;return{callback:t.substring(o&&o.length+1||0,n),args:(i&&i.split(",")||[]).map(function(t){return s(t)(e)}),constructor:o}}if(!t)return;var i=f(t),o=i.callback,u=i.constructor,a=[n,r].concat(i.args);e.$apply((e[o]||e[u][o]).apply(e,a))};this.invokeDrop=function(e,s,o,u){var a="",f="",l={},c={},h=null,p={},d={},v,m,g=null,y=s.scope(),b=e.scope();a=e.ngattr("ng-model");f=s.ngattr("ng-model");v=b.$eval(a);m=y.$eval(f);g=s.find("[jqyoui-draggable]:last,[data-jqyoui-draggable]:last");c=y.$eval(s.attr("jqyoui-droppable")||s.attr("data-jqyoui-droppable"))||[];l=b.$eval(e.attr("jqyoui-draggable")||e.attr("data-jqyoui-draggable"))||[];l.index=this.fixIndex(b,l,v);c.index=this.fixIndex(y,c,m);h=t.isArray(v)?l.index:null;p=t.copy(t.isArray(v)?v[h]:v);if(t.isArray(m)&&c&&c.index!==n){d=m[c.index]}else if(!t.isArray(m)){d=m}else{d={}}d=t.copy(d);if(l.animate===true){this.move(e,g.length>0?g:s,null,"fast",c,null);this.move(g.length>0&&!c.multiple?g:[],e.parent("[jqyoui-droppable],[data-jqyoui-droppable]"),r.startXY,"fast",c,t.bind(this,function(){i(t.bind(this,function(){e.css({position:"relative",left:"",top:""});g.css({position:"relative",left:"",top:"",display:""});this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}))}else{i(t.bind(this,function(){this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}};this.move=function(t,r,i,s,o,u){if(t.length===0){if(u){e.setTimeout(function(){u()},300)}return false}var a=9999,f=t[o.containment||"offset"](),l=r&&r.is(":visible"),c=r.hasClass("ng-hide");if(i===null&&r.length>0){if((r.attr("jqyoui-draggable")||r.attr("data-jqyoui-draggable"))!==n&&r.ngattr("ng-model")!==n&&r.is(":visible")&&o&&o.multiple){i=r[o.containment||"offset"]();if(o.stack===false){i.left+=r.outerWidth(true)}else{i.top+=r.outerHeight(true)}}else{if(c)r.removeClass("ng-hide");i=r.css({visibility:"hidden",display:"block"})[o.containment||"offset"]();r.css({visibility:"",display:l?"block":"none"})}}t.css({position:"absolute","z-index":a}).css(f).animate(i,s,function(){if(c)r.addClass("ng-hide");if(u)u()})};this.mutateDroppable=function(e,n,r,i,o,u){var a=e.$eval(i);e.dndDragItem=o;if(t.isArray(a)){if(n&&n.index>=0){a[n.index]=o}else{a.push(o)}if(r&&r.placeholder===true){a[a.length-1]["jqyoui_pos"]=u}}else{s(i+" = dndDragItem")(e);if(r&&r.placeholder===true){a["jqyoui_pos"]=u}}};this.mutateDraggable=function(e,r,i,o,u,a,f){var l=t.equals(a,{}),c=e.$eval(o);e.dndDropItem=a;if(i&&i.placeholder){if(i.placeholder!="keep"){if(t.isArray(c)&&i.index!==n){c[i.index]=a}else{s(o+" = dndDropItem")(e)}}}else{if(t.isArray(c)){if(l){if(i&&i.placeholder!==true&&i.placeholder!=="keep"){c.splice(i.index,1)}}else{c[i.index]=a}}else{s(o+" = dndDropItem")(e);if(e.$parent){s(o+" = dndDropItem")(e.$parent)}}}f.css({"z-index":"",left:"",top:""})};this.fixIndex=function(e,r,i){if(r.applyFilter&&t.isArray(i)&&i.length>0){var s=e[r.applyFilter](),o=s[r.index],u=n;i.forEach(function(e,n){if(t.equals(e,o)){u=n}});return u}return r.index}}]).directive("jqyouiDraggable",["ngDragDropService",function(e){return{require:"?jqyouiDroppable",restrict:"A",link:function(n,i,s){var o,u,a;var f=function(f,l){if(f){o=n.$eval(i.attr("jqyoui-draggable")||i.attr("data-jqyoui-draggable"))||{};u=n.$eval(s.jqyouiOptions)||{};i.draggable({disabled:false}).draggable(u).draggable({start:function(i,s){a=t.element(u.helper?s.helper:this).css("z-index");t.element(u.helper?s.helper:this).css("z-index",9999);r.startXY=t.element(this)[o.containment||"offset"]();e.callEventCallback(n,o.onStart,i,s)},stop:function(r,i){t.element(u.helper?i.helper:this).css("z-index",a);e.callEventCallback(n,o.onStop,r,i)},drag:function(t,r){e.callEventCallback(n,o.onDrag,t,r)}})}else{i.draggable({disabled:true})}};n.$watch(function(){return n.$eval(s.drag)},f);f();i.on("$destroy",function(){i.draggable("destroy")})}}}]).directive("jqyouiDroppable",["ngDragDropService",function(e){return{restrict:"A",priority:1,link:function(n,r,i){var s;var o=function(o,u){if(o){s=n.$eval(t.element(r).attr("jqyoui-droppable")||t.element(r).attr("data-jqyoui-droppable"))||{};r.droppable({disabled:false}).droppable(n.$eval(i.jqyouiOptions)||{}).droppable({over:function(t,r){e.callEventCallback(n,s.onOver,t,r)},out:function(t,r){e.callEventCallback(n,s.onOut,t,r)},drop:function(r,o){if(t.element(o.draggable).ngattr("ng-model")&&i.ngModel){e.invokeDrop(t.element(o.draggable),t.element(this),r,o)}else{e.callEventCallback(n,s.onDrop,r,o)}}})}else{r.droppable({disabled:true})}};n.$watch(function(){return n.$eval(i.drop)},o);o();r.on("$destroy",function(){r.droppable("destroy")})}}}]);$.fn.ngattr=function(e,n){var r=t.element(this).get(0);return r.getAttribute(e)||r.getAttribute("data-"+e)}})(window,window.angular)
  1 +/**
  2 + * @license AngularJS v1.2.13
  3 + * (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + * License: MIT
  5 + */
  6 +(function(window, angular, undefined) {
  7 +
  8 +'use strict';
  9 +
  10 +/**
  11 + * @ngdoc overview
  12 + * @name angular.mock
  13 + * @description
  14 + *
  15 + * Namespace from 'angular-mocks.js' which contains testing related code.
  16 + */
  17 +angular.mock = {};
  18 +
  19 +/**
  20 + * ! This is a private undocumented service !
  21 + *
  22 + * @name ngMock.$browser
  23 + *
  24 + * @description
  25 + * This service is a mock implementation of {@link ng.$browser}. It provides fake
  26 + * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
  27 + * cookies, etc...
  28 + *
  29 + * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
  30 + * that there are several helper methods available which can be used in tests.
  31 + */
  32 +angular.mock.$BrowserProvider = function() {
  33 + this.$get = function() {
  34 + return new angular.mock.$Browser();
  35 + };
  36 +};
  37 +
  38 +angular.mock.$Browser = function() {
  39 + var self = this;
  40 +
  41 + this.isMock = true;
  42 + self.$$url = "http://server/";
  43 + self.$$lastUrl = self.$$url; // used by url polling fn
  44 + self.pollFns = [];
  45 +
  46 + // TODO(vojta): remove this temporary api
  47 + self.$$completeOutstandingRequest = angular.noop;
  48 + self.$$incOutstandingRequestCount = angular.noop;
  49 +
  50 +
  51 + // register url polling fn
  52 +
  53 + self.onUrlChange = function(listener) {
  54 + self.pollFns.push(
  55 + function() {
  56 + if (self.$$lastUrl != self.$$url) {
  57 + self.$$lastUrl = self.$$url;
  58 + listener(self.$$url);
  59 + }
  60 + }
  61 + );
  62 +
  63 + return listener;
  64 + };
  65 +
  66 + self.cookieHash = {};
  67 + self.lastCookieHash = {};
  68 + self.deferredFns = [];
  69 + self.deferredNextId = 0;
  70 +
  71 + self.defer = function(fn, delay) {
  72 + delay = delay || 0;
  73 + self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
  74 + self.deferredFns.sort(function(a,b){ return a.time - b.time;});
  75 + return self.deferredNextId++;
  76 + };
  77 +
  78 +
  79 + /**
  80 + * @name ngMock.$browser#defer.now
  81 + * @propertyOf ngMock.$browser
  82 + *
  83 + * @description
  84 + * Current milliseconds mock time.
  85 + */
  86 + self.defer.now = 0;
  87 +
  88 +
  89 + self.defer.cancel = function(deferId) {
  90 + var fnIndex;
  91 +
  92 + angular.forEach(self.deferredFns, function(fn, index) {
  93 + if (fn.id === deferId) fnIndex = index;
  94 + });
  95 +
  96 + if (fnIndex !== undefined) {
  97 + self.deferredFns.splice(fnIndex, 1);
  98 + return true;
  99 + }
  100 +
  101 + return false;
  102 + };
  103 +
  104 +
  105 + /**
  106 + * @name ngMock.$browser#defer.flush
  107 + * @methodOf ngMock.$browser
  108 + *
  109 + * @description
  110 + * Flushes all pending requests and executes the defer callbacks.
  111 + *
  112 + * @param {number=} number of milliseconds to flush. See {@link #defer.now}
  113 + */
  114 + self.defer.flush = function(delay) {
  115 + if (angular.isDefined(delay)) {
  116 + self.defer.now += delay;
  117 + } else {
  118 + if (self.deferredFns.length) {
  119 + self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
  120 + } else {
  121 + throw new Error('No deferred tasks to be flushed');
  122 + }
  123 + }
  124 +
  125 + while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
  126 + self.deferredFns.shift().fn();
  127 + }
  128 + };
  129 +
  130 + self.$$baseHref = '';
  131 + self.baseHref = function() {
  132 + return this.$$baseHref;
  133 + };
  134 +};
  135 +angular.mock.$Browser.prototype = {
  136 +
  137 +/**
  138 + * @name ngMock.$browser#poll
  139 + * @methodOf ngMock.$browser
  140 + *
  141 + * @description
  142 + * run all fns in pollFns
  143 + */
  144 + poll: function poll() {
  145 + angular.forEach(this.pollFns, function(pollFn){
  146 + pollFn();
  147 + });
  148 + },
  149 +
  150 + addPollFn: function(pollFn) {
  151 + this.pollFns.push(pollFn);
  152 + return pollFn;
  153 + },
  154 +
  155 + url: function(url, replace) {
  156 + if (url) {
  157 + this.$$url = url;
  158 + return this;
  159 + }
  160 +
  161 + return this.$$url;
  162 + },
  163 +
  164 + cookies: function(name, value) {
  165 + if (name) {
  166 + if (angular.isUndefined(value)) {
  167 + delete this.cookieHash[name];
  168 + } else {
  169 + if (angular.isString(value) && //strings only
  170 + value.length <= 4096) { //strict cookie storage limits
  171 + this.cookieHash[name] = value;
  172 + }
  173 + }
  174 + } else {
  175 + if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
  176 + this.lastCookieHash = angular.copy(this.cookieHash);
  177 + this.cookieHash = angular.copy(this.cookieHash);
  178 + }
  179 + return this.cookieHash;
  180 + }
  181 + },
  182 +
  183 + notifyWhenNoOutstandingRequests: function(fn) {
  184 + fn();
  185 + }
  186 +};
  187 +
  188 +
  189 +/**
  190 + * @ngdoc object
  191 + * @name ngMock.$exceptionHandlerProvider
  192 + *
  193 + * @description
  194 + * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
  195 + * passed into the `$exceptionHandler`.
  196 + */
  197 +
  198 +/**
  199 + * @ngdoc object
  200 + * @name ngMock.$exceptionHandler
  201 + *
  202 + * @description
  203 + * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
  204 + * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
  205 + * information.
  206 + *
  207 + *
  208 + * <pre>
  209 + * describe('$exceptionHandlerProvider', function() {
  210 + *
  211 + * it('should capture log messages and exceptions', function() {
  212 + *
  213 + * module(function($exceptionHandlerProvider) {
  214 + * $exceptionHandlerProvider.mode('log');
  215 + * });
  216 + *
  217 + * inject(function($log, $exceptionHandler, $timeout) {
  218 + * $timeout(function() { $log.log(1); });
  219 + * $timeout(function() { $log.log(2); throw 'banana peel'; });
  220 + * $timeout(function() { $log.log(3); });
  221 + * expect($exceptionHandler.errors).toEqual([]);
  222 + * expect($log.assertEmpty());
  223 + * $timeout.flush();
  224 + * expect($exceptionHandler.errors).toEqual(['banana peel']);
  225 + * expect($log.log.logs).toEqual([[1], [2], [3]]);
  226 + * });
  227 + * });
  228 + * });
  229 + * </pre>
  230 + */
  231 +
  232 +angular.mock.$ExceptionHandlerProvider = function() {
  233 + var handler;
  234 +
  235 + /**
  236 + * @ngdoc method
  237 + * @name ngMock.$exceptionHandlerProvider#mode
  238 + * @methodOf ngMock.$exceptionHandlerProvider
  239 + *
  240 + * @description
  241 + * Sets the logging mode.
  242 + *
  243 + * @param {string} mode Mode of operation, defaults to `rethrow`.
  244 + *
  245 + * - `rethrow`: If any errors are passed into the handler in tests, it typically
  246 + * means that there is a bug in the application or test, so this mock will
  247 + * make these tests fail.
  248 + * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
  249 + * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
  250 + * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
  251 + * {@link ngMock.$log#reset reset()}
  252 + */
  253 + this.mode = function(mode) {
  254 + switch(mode) {
  255 + case 'rethrow':
  256 + handler = function(e) {
  257 + throw e;
  258 + };
  259 + break;
  260 + case 'log':
  261 + var errors = [];
  262 +
  263 + handler = function(e) {
  264 + if (arguments.length == 1) {
  265 + errors.push(e);
  266 + } else {
  267 + errors.push([].slice.call(arguments, 0));
  268 + }
  269 + };
  270 +
  271 + handler.errors = errors;
  272 + break;
  273 + default:
  274 + throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
  275 + }
  276 + };
  277 +
  278 + this.$get = function() {
  279 + return handler;
  280 + };
  281 +
  282 + this.mode('rethrow');
  283 +};
  284 +
  285 +
  286 +/**
  287 + * @ngdoc service
  288 + * @name ngMock.$log
  289 + *
  290 + * @description
  291 + * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
  292 + * (one array per logging level). These arrays are exposed as `logs` property of each of the
  293 + * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
  294 + *
  295 + */
  296 +angular.mock.$LogProvider = function() {
  297 + var debug = true;
  298 +
  299 + function concat(array1, array2, index) {
  300 + return array1.concat(Array.prototype.slice.call(array2, index));
  301 + }
  302 +
  303 + this.debugEnabled = function(flag) {
  304 + if (angular.isDefined(flag)) {
  305 + debug = flag;
  306 + return this;
  307 + } else {
  308 + return debug;
  309 + }
  310 + };
  311 +
  312 + this.$get = function () {
  313 + var $log = {
  314 + log: function() { $log.log.logs.push(concat([], arguments, 0)); },
  315 + warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
  316 + info: function() { $log.info.logs.push(concat([], arguments, 0)); },
  317 + error: function() { $log.error.logs.push(concat([], arguments, 0)); },
  318 + debug: function() {
  319 + if (debug) {
  320 + $log.debug.logs.push(concat([], arguments, 0));
  321 + }
  322 + }
  323 + };
  324 +
  325 + /**
  326 + * @ngdoc method
  327 + * @name ngMock.$log#reset
  328 + * @methodOf ngMock.$log
  329 + *
  330 + * @description
  331 + * Reset all of the logging arrays to empty.
  332 + */
  333 + $log.reset = function () {
  334 + /**
  335 + * @ngdoc property
  336 + * @name ngMock.$log#log.logs
  337 + * @propertyOf ngMock.$log
  338 + *
  339 + * @description
  340 + * Array of messages logged using {@link ngMock.$log#log}.
  341 + *
  342 + * @example
  343 + * <pre>
  344 + * $log.log('Some Log');
  345 + * var first = $log.log.logs.unshift();
  346 + * </pre>
  347 + */
  348 + $log.log.logs = [];
  349 + /**
  350 + * @ngdoc property
  351 + * @name ngMock.$log#info.logs
  352 + * @propertyOf ngMock.$log
  353 + *
  354 + * @description
  355 + * Array of messages logged using {@link ngMock.$log#info}.
  356 + *
  357 + * @example
  358 + * <pre>
  359 + * $log.info('Some Info');
  360 + * var first = $log.info.logs.unshift();
  361 + * </pre>
  362 + */
  363 + $log.info.logs = [];
  364 + /**
  365 + * @ngdoc property
  366 + * @name ngMock.$log#warn.logs
  367 + * @propertyOf ngMock.$log
  368 + *
  369 + * @description
  370 + * Array of messages logged using {@link ngMock.$log#warn}.
  371 + *
  372 + * @example
  373 + * <pre>
  374 + * $log.warn('Some Warning');
  375 + * var first = $log.warn.logs.unshift();
  376 + * </pre>
  377 + */
  378 + $log.warn.logs = [];
  379 + /**
  380 + * @ngdoc property
  381 + * @name ngMock.$log#error.logs
  382 + * @propertyOf ngMock.$log
  383 + *
  384 + * @description
  385 + * Array of messages logged using {@link ngMock.$log#error}.
  386 + *
  387 + * @example
  388 + * <pre>
  389 + * $log.error('Some Error');
  390 + * var first = $log.error.logs.unshift();
  391 + * </pre>
  392 + */
  393 + $log.error.logs = [];
  394 + /**
  395 + * @ngdoc property
  396 + * @name ngMock.$log#debug.logs
  397 + * @propertyOf ngMock.$log
  398 + *
  399 + * @description
  400 + * Array of messages logged using {@link ngMock.$log#debug}.
  401 + *
  402 + * @example
  403 + * <pre>
  404 + * $log.debug('Some Error');
  405 + * var first = $log.debug.logs.unshift();
  406 + * </pre>
  407 + */
  408 + $log.debug.logs = [];
  409 + };
  410 +
  411 + /**
  412 + * @ngdoc method
  413 + * @name ngMock.$log#assertEmpty
  414 + * @methodOf ngMock.$log
  415 + *
  416 + * @description
  417 + * Assert that the all of the logging methods have no logged messages. If messages present, an
  418 + * exception is thrown.
  419 + */
  420 + $log.assertEmpty = function() {
  421 + var errors = [];
  422 + angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
  423 + angular.forEach($log[logLevel].logs, function(log) {
  424 + angular.forEach(log, function (logItem) {
  425 + errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
  426 + (logItem.stack || ''));
  427 + });
  428 + });
  429 + });
  430 + if (errors.length) {
  431 + errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+
  432 + "an expected log message was not checked and removed:");
  433 + errors.push('');
  434 + throw new Error(errors.join('\n---------\n'));
  435 + }
  436 + };
  437 +
  438 + $log.reset();
  439 + return $log;
  440 + };
  441 +};
  442 +
  443 +
  444 +/**
  445 + * @ngdoc service
  446 + * @name ngMock.$interval
  447 + *
  448 + * @description
  449 + * Mock implementation of the $interval service.
  450 + *
  451 + * Use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
  452 + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
  453 + * time.
  454 + *
  455 + * @param {function()} fn A function that should be called repeatedly.
  456 + * @param {number} delay Number of milliseconds between each function call.
  457 + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
  458 + * indefinitely.
  459 + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
  460 + * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
  461 + * @returns {promise} A promise which will be notified on each iteration.
  462 + */
  463 +angular.mock.$IntervalProvider = function() {
  464 + this.$get = ['$rootScope', '$q',
  465 + function($rootScope, $q) {
  466 + var repeatFns = [],
  467 + nextRepeatId = 0,
  468 + now = 0;
  469 +
  470 + var $interval = function(fn, delay, count, invokeApply) {
  471 + var deferred = $q.defer(),
  472 + promise = deferred.promise,
  473 + iteration = 0,
  474 + skipApply = (angular.isDefined(invokeApply) && !invokeApply);
  475 +
  476 + count = (angular.isDefined(count)) ? count : 0,
  477 + promise.then(null, null, fn);
  478 +
  479 + promise.$$intervalId = nextRepeatId;
  480 +
  481 + function tick() {
  482 + deferred.notify(iteration++);
  483 +
  484 + if (count > 0 && iteration >= count) {
  485 + var fnIndex;
  486 + deferred.resolve(iteration);
  487 +
  488 + angular.forEach(repeatFns, function(fn, index) {
  489 + if (fn.id === promise.$$intervalId) fnIndex = index;
  490 + });
  491 +
  492 + if (fnIndex !== undefined) {
  493 + repeatFns.splice(fnIndex, 1);
  494 + }
  495 + }
  496 +
  497 + if (!skipApply) $rootScope.$apply();
  498 + }
  499 +
  500 + repeatFns.push({
  501 + nextTime:(now + delay),
  502 + delay: delay,
  503 + fn: tick,
  504 + id: nextRepeatId,
  505 + deferred: deferred
  506 + });
  507 + repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
  508 +
  509 + nextRepeatId++;
  510 + return promise;
  511 + };
  512 +
  513 + $interval.cancel = function(promise) {
  514 + if(!promise) return false;
  515 + var fnIndex;
  516 +
  517 + angular.forEach(repeatFns, function(fn, index) {
  518 + if (fn.id === promise.$$intervalId) fnIndex = index;
  519 + });
  520 +
  521 + if (fnIndex !== undefined) {
  522 + repeatFns[fnIndex].deferred.reject('canceled');
  523 + repeatFns.splice(fnIndex, 1);
  524 + return true;
  525 + }
  526 +
  527 + return false;
  528 + };
  529 +
  530 + /**
  531 + * @ngdoc method
  532 + * @name ngMock.$interval#flush
  533 + * @methodOf ngMock.$interval
  534 + * @description
  535 + *
  536 + * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
  537 + *
  538 + * @param {number=} millis maximum timeout amount to flush up until.
  539 + *
  540 + * @return {number} The amount of time moved forward.
  541 + */
  542 + $interval.flush = function(millis) {
  543 + now += millis;
  544 + while (repeatFns.length && repeatFns[0].nextTime <= now) {
  545 + var task = repeatFns[0];
  546 + task.fn();
  547 + task.nextTime += task.delay;
  548 + repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
  549 + }
  550 + return millis;
  551 + };
  552 +
  553 + return $interval;
  554 + }];
  555 +};
  556 +
  557 +
  558 +/* jshint -W101 */
  559 +/* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
  560 + * This directive should go inside the anonymous function but a bug in JSHint means that it would
  561 + * not be enacted early enough to prevent the warning.
  562 + */
  563 +var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
  564 +
  565 +function jsonStringToDate(string) {
  566 + var match;
  567 + if (match = string.match(R_ISO8061_STR)) {
  568 + var date = new Date(0),
  569 + tzHour = 0,
  570 + tzMin = 0;
  571 + if (match[9]) {
  572 + tzHour = int(match[9] + match[10]);
  573 + tzMin = int(match[9] + match[11]);
  574 + }
  575 + date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
  576 + date.setUTCHours(int(match[4]||0) - tzHour,
  577 + int(match[5]||0) - tzMin,
  578 + int(match[6]||0),
  579 + int(match[7]||0));
  580 + return date;
  581 + }
  582 + return string;
  583 +}
  584 +
  585 +function int(str) {
  586 + return parseInt(str, 10);
  587 +}
  588 +
  589 +function padNumber(num, digits, trim) {
  590 + var neg = '';
  591 + if (num < 0) {
  592 + neg = '-';
  593 + num = -num;
  594 + }
  595 + num = '' + num;
  596 + while(num.length < digits) num = '0' + num;
  597 + if (trim)
  598 + num = num.substr(num.length - digits);
  599 + return neg + num;
  600 +}
  601 +
  602 +
  603 +/**
  604 + * @ngdoc object
  605 + * @name angular.mock.TzDate
  606 + * @description
  607 + *
  608 + * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
  609 + *
  610 + * Mock of the Date type which has its timezone specified via constructor arg.
  611 + *
  612 + * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
  613 + * offset, so that we can test code that depends on local timezone settings without dependency on
  614 + * the time zone settings of the machine where the code is running.
  615 + *
  616 + * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
  617 + * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
  618 + *
  619 + * @example
  620 + * !!!! WARNING !!!!!
  621 + * This is not a complete Date object so only methods that were implemented can be called safely.
  622 + * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
  623 + *
  624 + * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
  625 + * incomplete we might be missing some non-standard methods. This can result in errors like:
  626 + * "Date.prototype.foo called on incompatible Object".
  627 + *
  628 + * <pre>
  629 + * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
  630 + * newYearInBratislava.getTimezoneOffset() => -60;
  631 + * newYearInBratislava.getFullYear() => 2010;
  632 + * newYearInBratislava.getMonth() => 0;
  633 + * newYearInBratislava.getDate() => 1;
  634 + * newYearInBratislava.getHours() => 0;
  635 + * newYearInBratislava.getMinutes() => 0;
  636 + * newYearInBratislava.getSeconds() => 0;
  637 + * </pre>
  638 + *
  639 + */
  640 +angular.mock.TzDate = function (offset, timestamp) {
  641 + var self = new Date(0);
  642 + if (angular.isString(timestamp)) {
  643 + var tsStr = timestamp;
  644 +
  645 + self.origDate = jsonStringToDate(timestamp);
  646 +
  647 + timestamp = self.origDate.getTime();
  648 + if (isNaN(timestamp))
  649 + throw {
  650 + name: "Illegal Argument",
  651 + message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
  652 + };
  653 + } else {
  654 + self.origDate = new Date(timestamp);
  655 + }
  656 +
  657 + var localOffset = new Date(timestamp).getTimezoneOffset();
  658 + self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
  659 + self.date = new Date(timestamp + self.offsetDiff);
  660 +
  661 + self.getTime = function() {
  662 + return self.date.getTime() - self.offsetDiff;
  663 + };
  664 +
  665 + self.toLocaleDateString = function() {
  666 + return self.date.toLocaleDateString();
  667 + };
  668 +
  669 + self.getFullYear = function() {
  670 + return self.date.getFullYear();
  671 + };
  672 +
  673 + self.getMonth = function() {
  674 + return self.date.getMonth();
  675 + };
  676 +
  677 + self.getDate = function() {
  678 + return self.date.getDate();
  679 + };
  680 +
  681 + self.getHours = function() {
  682 + return self.date.getHours();
  683 + };
  684 +
  685 + self.getMinutes = function() {
  686 + return self.date.getMinutes();
  687 + };
  688 +
  689 + self.getSeconds = function() {
  690 + return self.date.getSeconds();
  691 + };
  692 +
  693 + self.getMilliseconds = function() {
  694 + return self.date.getMilliseconds();
  695 + };
  696 +
  697 + self.getTimezoneOffset = function() {
  698 + return offset * 60;
  699 + };
  700 +
  701 + self.getUTCFullYear = function() {
  702 + return self.origDate.getUTCFullYear();
  703 + };
  704 +
  705 + self.getUTCMonth = function() {
  706 + return self.origDate.getUTCMonth();
  707 + };
  708 +
  709 + self.getUTCDate = function() {
  710 + return self.origDate.getUTCDate();
  711 + };
  712 +
  713 + self.getUTCHours = function() {
  714 + return self.origDate.getUTCHours();
  715 + };
  716 +
  717 + self.getUTCMinutes = function() {
  718 + return self.origDate.getUTCMinutes();
  719 + };
  720 +
  721 + self.getUTCSeconds = function() {
  722 + return self.origDate.getUTCSeconds();
  723 + };
  724 +
  725 + self.getUTCMilliseconds = function() {
  726 + return self.origDate.getUTCMilliseconds();
  727 + };
  728 +
  729 + self.getDay = function() {
  730 + return self.date.getDay();
  731 + };
  732 +
  733 + // provide this method only on browsers that already have it
  734 + if (self.toISOString) {
  735 + self.toISOString = function() {
  736 + return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
  737 + padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
  738 + padNumber(self.origDate.getUTCDate(), 2) + 'T' +
  739 + padNumber(self.origDate.getUTCHours(), 2) + ':' +
  740 + padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
  741 + padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
  742 + padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
  743 + };
  744 + }
  745 +
  746 + //hide all methods not implemented in this mock that the Date prototype exposes
  747 + var unimplementedMethods = ['getUTCDay',
  748 + 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
  749 + 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
  750 + 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
  751 + 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
  752 + 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
  753 +
  754 + angular.forEach(unimplementedMethods, function(methodName) {
  755 + self[methodName] = function() {
  756 + throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
  757 + };
  758 + });
  759 +
  760 + return self;
  761 +};
  762 +
  763 +//make "tzDateInstance instanceof Date" return true
  764 +angular.mock.TzDate.prototype = Date.prototype;
  765 +/* jshint +W101 */
  766 +
  767 +angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
  768 +
  769 + .config(['$provide', function($provide) {
  770 + var reflowQueue = [];
  771 +
  772 + $provide.value('$$animateReflow', function(fn) {
  773 + reflowQueue.push(fn);
  774 + return angular.noop;
  775 + });
  776 +
  777 + $provide.decorator('$animate', function($delegate) {
  778 + var animate = {
  779 + queue : [],
  780 + enabled : $delegate.enabled,
  781 + triggerReflow : function() {
  782 + if(reflowQueue.length === 0) {
  783 + throw new Error('No animation reflows present');
  784 + }
  785 + angular.forEach(reflowQueue, function(fn) {
  786 + fn();
  787 + });
  788 + reflowQueue = [];
  789 + }
  790 + };
  791 +
  792 + angular.forEach(
  793 + ['enter','leave','move','addClass','removeClass','setClass'], function(method) {
  794 + animate[method] = function() {
  795 + animate.queue.push({
  796 + event : method,
  797 + element : arguments[0],
  798 + args : arguments
  799 + });
  800 + $delegate[method].apply($delegate, arguments);
  801 + };
  802 + });
  803 +
  804 + return animate;
  805 + });
  806 +
  807 + }]);
  808 +
  809 +
  810 +/**
  811 + * @ngdoc function
  812 + * @name angular.mock.dump
  813 + * @description
  814 + *
  815 + * *NOTE*: this is not an injectable instance, just a globally available function.
  816 + *
  817 + * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
  818 + * debugging.
  819 + *
  820 + * This method is also available on window, where it can be used to display objects on debug
  821 + * console.
  822 + *
  823 + * @param {*} object - any object to turn into string.
  824 + * @return {string} a serialized string of the argument
  825 + */
  826 +angular.mock.dump = function(object) {
  827 + return serialize(object);
  828 +
  829 + function serialize(object) {
  830 + var out;
  831 +
  832 + if (angular.isElement(object)) {
  833 + object = angular.element(object);
  834 + out = angular.element('<div></div>');
  835 + angular.forEach(object, function(element) {
  836 + out.append(angular.element(element).clone());
  837 + });
  838 + out = out.html();
  839 + } else if (angular.isArray(object)) {
  840 + out = [];
  841 + angular.forEach(object, function(o) {
  842 + out.push(serialize(o));
  843 + });
  844 + out = '[ ' + out.join(', ') + ' ]';
  845 + } else if (angular.isObject(object)) {
  846 + if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
  847 + out = serializeScope(object);
  848 + } else if (object instanceof Error) {
  849 + out = object.stack || ('' + object.name + ': ' + object.message);
  850 + } else {
  851 + // TODO(i): this prevents methods being logged,
  852 + // we should have a better way to serialize objects
  853 + out = angular.toJson(object, true);
  854 + }
  855 + } else {
  856 + out = String(object);
  857 + }
  858 +
  859 + return out;
  860 + }
  861 +
  862 + function serializeScope(scope, offset) {
  863 + offset = offset || ' ';
  864 + var log = [offset + 'Scope(' + scope.$id + '): {'];
  865 + for ( var key in scope ) {
  866 + if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
  867 + log.push(' ' + key + ': ' + angular.toJson(scope[key]));
  868 + }
  869 + }
  870 + var child = scope.$$childHead;
  871 + while(child) {
  872 + log.push(serializeScope(child, offset + ' '));
  873 + child = child.$$nextSibling;
  874 + }
  875 + log.push('}');
  876 + return log.join('\n' + offset);
  877 + }
  878 +};
  879 +
  880 +/**
  881 + * @ngdoc object
  882 + * @name ngMock.$httpBackend
  883 + * @description
  884 + * Fake HTTP backend implementation suitable for unit testing applications that use the
  885 + * {@link ng.$http $http service}.
  886 + *
  887 + * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
  888 + * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
  889 + *
  890 + * During unit testing, we want our unit tests to run quickly and have no external dependencies so
  891 + * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
  892 + * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
  893 + * to verify whether a certain request has been sent or not, or alternatively just let the
  894 + * application make requests, respond with pre-trained responses and assert that the end result is
  895 + * what we expect it to be.
  896 + *
  897 + * This mock implementation can be used to respond with static or dynamic responses via the
  898 + * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
  899 + *
  900 + * When an Angular application needs some data from a server, it calls the $http service, which
  901 + * sends the request to a real server using $httpBackend service. With dependency injection, it is
  902 + * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
  903 + * the requests and respond with some testing data without sending a request to real server.
  904 + *
  905 + * There are two ways to specify what test data should be returned as http responses by the mock
  906 + * backend when the code under test makes http requests:
  907 + *
  908 + * - `$httpBackend.expect` - specifies a request expectation
  909 + * - `$httpBackend.when` - specifies a backend definition
  910 + *
  911 + *
  912 + * # Request Expectations vs Backend Definitions
  913 + *
  914 + * Request expectations provide a way to make assertions about requests made by the application and
  915 + * to define responses for those requests. The test will fail if the expected requests are not made
  916 + * or they are made in the wrong order.
  917 + *
  918 + * Backend definitions allow you to define a fake backend for your application which doesn't assert
  919 + * if a particular request was made or not, it just returns a trained response if a request is made.
  920 + * The test will pass whether or not the request gets made during testing.
  921 + *
  922 + *
  923 + * <table class="table">
  924 + * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
  925 + * <tr>
  926 + * <th>Syntax</th>
  927 + * <td>.expect(...).respond(...)</td>
  928 + * <td>.when(...).respond(...)</td>
  929 + * </tr>
  930 + * <tr>
  931 + * <th>Typical usage</th>
  932 + * <td>strict unit tests</td>
  933 + * <td>loose (black-box) unit testing</td>
  934 + * </tr>
  935 + * <tr>
  936 + * <th>Fulfills multiple requests</th>
  937 + * <td>NO</td>
  938 + * <td>YES</td>
  939 + * </tr>
  940 + * <tr>
  941 + * <th>Order of requests matters</th>
  942 + * <td>YES</td>
  943 + * <td>NO</td>
  944 + * </tr>
  945 + * <tr>
  946 + * <th>Request required</th>
  947 + * <td>YES</td>
  948 + * <td>NO</td>
  949 + * </tr>
  950 + * <tr>
  951 + * <th>Response required</th>
  952 + * <td>optional (see below)</td>
  953 + * <td>YES</td>
  954 + * </tr>
  955 + * </table>
  956 + *
  957 + * In cases where both backend definitions and request expectations are specified during unit
  958 + * testing, the request expectations are evaluated first.
  959 + *
  960 + * If a request expectation has no response specified, the algorithm will search your backend
  961 + * definitions for an appropriate response.
  962 + *
  963 + * If a request didn't match any expectation or if the expectation doesn't have the response
  964 + * defined, the backend definitions are evaluated in sequential order to see if any of them match
  965 + * the request. The response from the first matched definition is returned.
  966 + *
  967 + *
  968 + * # Flushing HTTP requests
  969 + *
  970 + * The $httpBackend used in production always responds to requests with responses asynchronously.
  971 + * If we preserved this behavior in unit testing we'd have to create async unit tests, which are
  972 + * hard to write, understand, and maintain. However, the testing mock can't respond
  973 + * synchronously because that would change the execution of the code under test. For this reason the
  974 + * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
  975 + * requests and thus preserve the async api of the backend while allowing the test to execute
  976 + * synchronously.
  977 + *
  978 + *
  979 + * # Unit testing with mock $httpBackend
  980 + * The following code shows how to setup and use the mock backend when unit testing a controller.
  981 + * First we create the controller under test:
  982 + *
  983 + <pre>
  984 + // The controller code
  985 + function MyController($scope, $http) {
  986 + var authToken;
  987 +
  988 + $http.get('/auth.py').success(function(data, status, headers) {
  989 + authToken = headers('A-Token');
  990 + $scope.user = data;
  991 + });
  992 +
  993 + $scope.saveMessage = function(message) {
  994 + var headers = { 'Authorization': authToken };
  995 + $scope.status = 'Saving...';
  996 +
  997 + $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
  998 + $scope.status = '';
  999 + }).error(function() {
  1000 + $scope.status = 'ERROR!';
  1001 + });
  1002 + };
  1003 + }
  1004 + </pre>
  1005 + *
  1006 + * Now we setup the mock backend and create the test specs:
  1007 + *
  1008 + <pre>
  1009 + // testing controller
  1010 + describe('MyController', function() {
  1011 + var $httpBackend, $rootScope, createController;
  1012 +
  1013 + beforeEach(inject(function($injector) {
  1014 + // Set up the mock http service responses
  1015 + $httpBackend = $injector.get('$httpBackend');
  1016 + // backend definition common for all tests
  1017 + $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
  1018 +
  1019 + // Get hold of a scope (i.e. the root scope)
  1020 + $rootScope = $injector.get('$rootScope');
  1021 + // The $controller service is used to create instances of controllers
  1022 + var $controller = $injector.get('$controller');
  1023 +
  1024 + createController = function() {
  1025 + return $controller('MyController', {'$scope' : $rootScope });
  1026 + };
  1027 + }));
  1028 +
  1029 +
  1030 + afterEach(function() {
  1031 + $httpBackend.verifyNoOutstandingExpectation();
  1032 + $httpBackend.verifyNoOutstandingRequest();
  1033 + });
  1034 +
  1035 +
  1036 + it('should fetch authentication token', function() {
  1037 + $httpBackend.expectGET('/auth.py');
  1038 + var controller = createController();
  1039 + $httpBackend.flush();
  1040 + });
  1041 +
  1042 +
  1043 + it('should send msg to server', function() {
  1044 + var controller = createController();
  1045 + $httpBackend.flush();
  1046 +
  1047 + // now you don’t care about the authentication, but
  1048 + // the controller will still send the request and
  1049 + // $httpBackend will respond without you having to
  1050 + // specify the expectation and response for this request
  1051 +
  1052 + $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
  1053 + $rootScope.saveMessage('message content');
  1054 + expect($rootScope.status).toBe('Saving...');
  1055 + $httpBackend.flush();
  1056 + expect($rootScope.status).toBe('');
  1057 + });
  1058 +
  1059 +
  1060 + it('should send auth header', function() {
  1061 + var controller = createController();
  1062 + $httpBackend.flush();
  1063 +
  1064 + $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
  1065 + // check if the header was send, if it wasn't the expectation won't
  1066 + // match the request and the test will fail
  1067 + return headers['Authorization'] == 'xxx';
  1068 + }).respond(201, '');
  1069 +
  1070 + $rootScope.saveMessage('whatever');
  1071 + $httpBackend.flush();
  1072 + });
  1073 + });
  1074 + </pre>
  1075 + */
  1076 +angular.mock.$HttpBackendProvider = function() {
  1077 + this.$get = ['$rootScope', createHttpBackendMock];
  1078 +};
  1079 +
  1080 +/**
  1081 + * General factory function for $httpBackend mock.
  1082 + * Returns instance for unit testing (when no arguments specified):
  1083 + * - passing through is disabled
  1084 + * - auto flushing is disabled
  1085 + *
  1086 + * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
  1087 + * - passing through (delegating request to real backend) is enabled
  1088 + * - auto flushing is enabled
  1089 + *
  1090 + * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
  1091 + * @param {Object=} $browser Auto-flushing enabled if specified
  1092 + * @return {Object} Instance of $httpBackend mock
  1093 + */
  1094 +function createHttpBackendMock($rootScope, $delegate, $browser) {
  1095 + var definitions = [],
  1096 + expectations = [],
  1097 + responses = [],
  1098 + responsesPush = angular.bind(responses, responses.push),
  1099 + copy = angular.copy;
  1100 +
  1101 + function createResponse(status, data, headers) {
  1102 + if (angular.isFunction(status)) return status;
  1103 +
  1104 + return function() {
  1105 + return angular.isNumber(status)
  1106 + ? [status, data, headers]
  1107 + : [200, status, data];
  1108 + };
  1109 + }
  1110 +
  1111 + // TODO(vojta): change params to: method, url, data, headers, callback
  1112 + function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
  1113 + var xhr = new MockXhr(),
  1114 + expectation = expectations[0],
  1115 + wasExpected = false;
  1116 +
  1117 + function prettyPrint(data) {
  1118 + return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
  1119 + ? data
  1120 + : angular.toJson(data);
  1121 + }
  1122 +
  1123 + function wrapResponse(wrapped) {
  1124 + if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
  1125 +
  1126 + return handleResponse;
  1127 +
  1128 + function handleResponse() {
  1129 + var response = wrapped.response(method, url, data, headers);
  1130 + xhr.$$respHeaders = response[2];
  1131 + callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
  1132 + }
  1133 +
  1134 + function handleTimeout() {
  1135 + for (var i = 0, ii = responses.length; i < ii; i++) {
  1136 + if (responses[i] === handleResponse) {
  1137 + responses.splice(i, 1);
  1138 + callback(-1, undefined, '');
  1139 + break;
  1140 + }
  1141 + }
  1142 + }
  1143 + }
  1144 +
  1145 + if (expectation && expectation.match(method, url)) {
  1146 + if (!expectation.matchData(data))
  1147 + throw new Error('Expected ' + expectation + ' with different data\n' +
  1148 + 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
  1149 +
  1150 + if (!expectation.matchHeaders(headers))
  1151 + throw new Error('Expected ' + expectation + ' with different headers\n' +
  1152 + 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
  1153 + prettyPrint(headers));
  1154 +
  1155 + expectations.shift();
  1156 +
  1157 + if (expectation.response) {
  1158 + responses.push(wrapResponse(expectation));
  1159 + return;
  1160 + }
  1161 + wasExpected = true;
  1162 + }
  1163 +
  1164 + var i = -1, definition;
  1165 + while ((definition = definitions[++i])) {
  1166 + if (definition.match(method, url, data, headers || {})) {
  1167 + if (definition.response) {
  1168 + // if $browser specified, we do auto flush all requests
  1169 + ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
  1170 + } else if (definition.passThrough) {
  1171 + $delegate(method, url, data, callback, headers, timeout, withCredentials);
  1172 + } else throw new Error('No response defined !');
  1173 + return;
  1174 + }
  1175 + }
  1176 + throw wasExpected ?
  1177 + new Error('No response defined !') :
  1178 + new Error('Unexpected request: ' + method + ' ' + url + '\n' +
  1179 + (expectation ? 'Expected ' + expectation : 'No more request expected'));
  1180 + }
  1181 +
  1182 + /**
  1183 + * @ngdoc method
  1184 + * @name ngMock.$httpBackend#when
  1185 + * @methodOf ngMock.$httpBackend
  1186 + * @description
  1187 + * Creates a new backend definition.
  1188 + *
  1189 + * @param {string} method HTTP method.
  1190 + * @param {string|RegExp} url HTTP url.
  1191 + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
  1192 + * data string and returns true if the data is as expected.
  1193 + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  1194 + * object and returns true if the headers match the current definition.
  1195 + * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
  1196 + * request is handled.
  1197 + *
  1198 + * - respond –
  1199 + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  1200 + * – The respond method takes a set of static data to be returned or a function that can return
  1201 + * an array containing response status (number), response data (string) and response headers
  1202 + * (Object).
  1203 + */
  1204 + $httpBackend.when = function(method, url, data, headers) {
  1205 + var definition = new MockHttpExpectation(method, url, data, headers),
  1206 + chain = {
  1207 + respond: function(status, data, headers) {
  1208 + definition.response = createResponse(status, data, headers);
  1209 + }
  1210 + };
  1211 +
  1212 + if ($browser) {
  1213 + chain.passThrough = function() {
  1214 + definition.passThrough = true;
  1215 + };
  1216 + }
  1217 +
  1218 + definitions.push(definition);
  1219 + return chain;
  1220 + };
  1221 +
  1222 + /**
  1223 + * @ngdoc method
  1224 + * @name ngMock.$httpBackend#whenGET
  1225 + * @methodOf ngMock.$httpBackend
  1226 + * @description
  1227 + * Creates a new backend definition for GET requests. For more info see `when()`.
  1228 + *
  1229 + * @param {string|RegExp} url HTTP url.
  1230 + * @param {(Object|function(Object))=} headers HTTP headers.
  1231 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1232 + * request is handled.
  1233 + */
  1234 +
  1235 + /**
  1236 + * @ngdoc method
  1237 + * @name ngMock.$httpBackend#whenHEAD
  1238 + * @methodOf ngMock.$httpBackend
  1239 + * @description
  1240 + * Creates a new backend definition for HEAD requests. For more info see `when()`.
  1241 + *
  1242 + * @param {string|RegExp} url HTTP url.
  1243 + * @param {(Object|function(Object))=} headers HTTP headers.
  1244 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1245 + * request is handled.
  1246 + */
  1247 +
  1248 + /**
  1249 + * @ngdoc method
  1250 + * @name ngMock.$httpBackend#whenDELETE
  1251 + * @methodOf ngMock.$httpBackend
  1252 + * @description
  1253 + * Creates a new backend definition for DELETE requests. For more info see `when()`.
  1254 + *
  1255 + * @param {string|RegExp} url HTTP url.
  1256 + * @param {(Object|function(Object))=} headers HTTP headers.
  1257 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1258 + * request is handled.
  1259 + */
  1260 +
  1261 + /**
  1262 + * @ngdoc method
  1263 + * @name ngMock.$httpBackend#whenPOST
  1264 + * @methodOf ngMock.$httpBackend
  1265 + * @description
  1266 + * Creates a new backend definition for POST requests. For more info see `when()`.
  1267 + *
  1268 + * @param {string|RegExp} url HTTP url.
  1269 + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
  1270 + * data string and returns true if the data is as expected.
  1271 + * @param {(Object|function(Object))=} headers HTTP headers.
  1272 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1273 + * request is handled.
  1274 + */
  1275 +
  1276 + /**
  1277 + * @ngdoc method
  1278 + * @name ngMock.$httpBackend#whenPUT
  1279 + * @methodOf ngMock.$httpBackend
  1280 + * @description
  1281 + * Creates a new backend definition for PUT requests. For more info see `when()`.
  1282 + *
  1283 + * @param {string|RegExp} url HTTP url.
  1284 + * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
  1285 + * data string and returns true if the data is as expected.
  1286 + * @param {(Object|function(Object))=} headers HTTP headers.
  1287 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1288 + * request is handled.
  1289 + */
  1290 +
  1291 + /**
  1292 + * @ngdoc method
  1293 + * @name ngMock.$httpBackend#whenJSONP
  1294 + * @methodOf ngMock.$httpBackend
  1295 + * @description
  1296 + * Creates a new backend definition for JSONP requests. For more info see `when()`.
  1297 + *
  1298 + * @param {string|RegExp} url HTTP url.
  1299 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1300 + * request is handled.
  1301 + */
  1302 + createShortMethods('when');
  1303 +
  1304 +
  1305 + /**
  1306 + * @ngdoc method
  1307 + * @name ngMock.$httpBackend#expect
  1308 + * @methodOf ngMock.$httpBackend
  1309 + * @description
  1310 + * Creates a new request expectation.
  1311 + *
  1312 + * @param {string} method HTTP method.
  1313 + * @param {string|RegExp} url HTTP url.
  1314 + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
  1315 + * receives data string and returns true if the data is as expected, or Object if request body
  1316 + * is in JSON format.
  1317 + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  1318 + * object and returns true if the headers match the current expectation.
  1319 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1320 + * request is handled.
  1321 + *
  1322 + * - respond –
  1323 + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  1324 + * – The respond method takes a set of static data to be returned or a function that can return
  1325 + * an array containing response status (number), response data (string) and response headers
  1326 + * (Object).
  1327 + */
  1328 + $httpBackend.expect = function(method, url, data, headers) {
  1329 + var expectation = new MockHttpExpectation(method, url, data, headers);
  1330 + expectations.push(expectation);
  1331 + return {
  1332 + respond: function(status, data, headers) {
  1333 + expectation.response = createResponse(status, data, headers);
  1334 + }
  1335 + };
  1336 + };
  1337 +
  1338 +
  1339 + /**
  1340 + * @ngdoc method
  1341 + * @name ngMock.$httpBackend#expectGET
  1342 + * @methodOf ngMock.$httpBackend
  1343 + * @description
  1344 + * Creates a new request expectation for GET requests. For more info see `expect()`.
  1345 + *
  1346 + * @param {string|RegExp} url HTTP url.
  1347 + * @param {Object=} headers HTTP headers.
  1348 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1349 + * request is handled. See #expect for more info.
  1350 + */
  1351 +
  1352 + /**
  1353 + * @ngdoc method
  1354 + * @name ngMock.$httpBackend#expectHEAD
  1355 + * @methodOf ngMock.$httpBackend
  1356 + * @description
  1357 + * Creates a new request expectation for HEAD requests. For more info see `expect()`.
  1358 + *
  1359 + * @param {string|RegExp} url HTTP url.
  1360 + * @param {Object=} headers HTTP headers.
  1361 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1362 + * request is handled.
  1363 + */
  1364 +
  1365 + /**
  1366 + * @ngdoc method
  1367 + * @name ngMock.$httpBackend#expectDELETE
  1368 + * @methodOf ngMock.$httpBackend
  1369 + * @description
  1370 + * Creates a new request expectation for DELETE requests. For more info see `expect()`.
  1371 + *
  1372 + * @param {string|RegExp} url HTTP url.
  1373 + * @param {Object=} headers HTTP headers.
  1374 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1375 + * request is handled.
  1376 + */
  1377 +
  1378 + /**
  1379 + * @ngdoc method
  1380 + * @name ngMock.$httpBackend#expectPOST
  1381 + * @methodOf ngMock.$httpBackend
  1382 + * @description
  1383 + * Creates a new request expectation for POST requests. For more info see `expect()`.
  1384 + *
  1385 + * @param {string|RegExp} url HTTP url.
  1386 + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
  1387 + * receives data string and returns true if the data is as expected, or Object if request body
  1388 + * is in JSON format.
  1389 + * @param {Object=} headers HTTP headers.
  1390 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1391 + * request is handled.
  1392 + */
  1393 +
  1394 + /**
  1395 + * @ngdoc method
  1396 + * @name ngMock.$httpBackend#expectPUT
  1397 + * @methodOf ngMock.$httpBackend
  1398 + * @description
  1399 + * Creates a new request expectation for PUT requests. For more info see `expect()`.
  1400 + *
  1401 + * @param {string|RegExp} url HTTP url.
  1402 + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
  1403 + * receives data string and returns true if the data is as expected, or Object if request body
  1404 + * is in JSON format.
  1405 + * @param {Object=} headers HTTP headers.
  1406 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1407 + * request is handled.
  1408 + */
  1409 +
  1410 + /**
  1411 + * @ngdoc method
  1412 + * @name ngMock.$httpBackend#expectPATCH
  1413 + * @methodOf ngMock.$httpBackend
  1414 + * @description
  1415 + * Creates a new request expectation for PATCH requests. For more info see `expect()`.
  1416 + *
  1417 + * @param {string|RegExp} url HTTP url.
  1418 + * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
  1419 + * receives data string and returns true if the data is as expected, or Object if request body
  1420 + * is in JSON format.
  1421 + * @param {Object=} headers HTTP headers.
  1422 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1423 + * request is handled.
  1424 + */
  1425 +
  1426 + /**
  1427 + * @ngdoc method
  1428 + * @name ngMock.$httpBackend#expectJSONP
  1429 + * @methodOf ngMock.$httpBackend
  1430 + * @description
  1431 + * Creates a new request expectation for JSONP requests. For more info see `expect()`.
  1432 + *
  1433 + * @param {string|RegExp} url HTTP url.
  1434 + * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1435 + * request is handled.
  1436 + */
  1437 + createShortMethods('expect');
  1438 +
  1439 +
  1440 + /**
  1441 + * @ngdoc method
  1442 + * @name ngMock.$httpBackend#flush
  1443 + * @methodOf ngMock.$httpBackend
  1444 + * @description
  1445 + * Flushes all pending requests using the trained responses.
  1446 + *
  1447 + * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
  1448 + * all pending requests will be flushed. If there are no pending requests when the flush method
  1449 + * is called an exception is thrown (as this typically a sign of programming error).
  1450 + */
  1451 + $httpBackend.flush = function(count) {
  1452 + $rootScope.$digest();
  1453 + if (!responses.length) throw new Error('No pending request to flush !');
  1454 +
  1455 + if (angular.isDefined(count)) {
  1456 + while (count--) {
  1457 + if (!responses.length) throw new Error('No more pending request to flush !');
  1458 + responses.shift()();
  1459 + }
  1460 + } else {
  1461 + while (responses.length) {
  1462 + responses.shift()();
  1463 + }
  1464 + }
  1465 + $httpBackend.verifyNoOutstandingExpectation();
  1466 + };
  1467 +
  1468 +
  1469 + /**
  1470 + * @ngdoc method
  1471 + * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
  1472 + * @methodOf ngMock.$httpBackend
  1473 + * @description
  1474 + * Verifies that all of the requests defined via the `expect` api were made. If any of the
  1475 + * requests were not made, verifyNoOutstandingExpectation throws an exception.
  1476 + *
  1477 + * Typically, you would call this method following each test case that asserts requests using an
  1478 + * "afterEach" clause.
  1479 + *
  1480 + * <pre>
  1481 + * afterEach($httpBackend.verifyNoOutstandingExpectation);
  1482 + * </pre>
  1483 + */
  1484 + $httpBackend.verifyNoOutstandingExpectation = function() {
  1485 + $rootScope.$digest();
  1486 + if (expectations.length) {
  1487 + throw new Error('Unsatisfied requests: ' + expectations.join(', '));
  1488 + }
  1489 + };
  1490 +
  1491 +
  1492 + /**
  1493 + * @ngdoc method
  1494 + * @name ngMock.$httpBackend#verifyNoOutstandingRequest
  1495 + * @methodOf ngMock.$httpBackend
  1496 + * @description
  1497 + * Verifies that there are no outstanding requests that need to be flushed.
  1498 + *
  1499 + * Typically, you would call this method following each test case that asserts requests using an
  1500 + * "afterEach" clause.
  1501 + *
  1502 + * <pre>
  1503 + * afterEach($httpBackend.verifyNoOutstandingRequest);
  1504 + * </pre>
  1505 + */
  1506 + $httpBackend.verifyNoOutstandingRequest = function() {
  1507 + if (responses.length) {
  1508 + throw new Error('Unflushed requests: ' + responses.length);
  1509 + }
  1510 + };
  1511 +
  1512 +
  1513 + /**
  1514 + * @ngdoc method
  1515 + * @name ngMock.$httpBackend#resetExpectations
  1516 + * @methodOf ngMock.$httpBackend
  1517 + * @description
  1518 + * Resets all request expectations, but preserves all backend definitions. Typically, you would
  1519 + * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
  1520 + * $httpBackend mock.
  1521 + */
  1522 + $httpBackend.resetExpectations = function() {
  1523 + expectations.length = 0;
  1524 + responses.length = 0;
  1525 + };
  1526 +
  1527 + return $httpBackend;
  1528 +
  1529 +
  1530 + function createShortMethods(prefix) {
  1531 + angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
  1532 + $httpBackend[prefix + method] = function(url, headers) {
  1533 + return $httpBackend[prefix](method, url, undefined, headers);
  1534 + };
  1535 + });
  1536 +
  1537 + angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
  1538 + $httpBackend[prefix + method] = function(url, data, headers) {
  1539 + return $httpBackend[prefix](method, url, data, headers);
  1540 + };
  1541 + });
  1542 + }
  1543 +}
  1544 +
  1545 +function MockHttpExpectation(method, url, data, headers) {
  1546 +
  1547 + this.data = data;
  1548 + this.headers = headers;
  1549 +
  1550 + this.match = function(m, u, d, h) {
  1551 + if (method != m) return false;
  1552 + if (!this.matchUrl(u)) return false;
  1553 + if (angular.isDefined(d) && !this.matchData(d)) return false;
  1554 + if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
  1555 + return true;
  1556 + };
  1557 +
  1558 + this.matchUrl = function(u) {
  1559 + if (!url) return true;
  1560 + if (angular.isFunction(url.test)) return url.test(u);
  1561 + return url == u;
  1562 + };
  1563 +
  1564 + this.matchHeaders = function(h) {
  1565 + if (angular.isUndefined(headers)) return true;
  1566 + if (angular.isFunction(headers)) return headers(h);
  1567 + return angular.equals(headers, h);
  1568 + };
  1569 +
  1570 + this.matchData = function(d) {
  1571 + if (angular.isUndefined(data)) return true;
  1572 + if (data && angular.isFunction(data.test)) return data.test(d);
  1573 + if (data && angular.isFunction(data)) return data(d);
  1574 + if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d));
  1575 + return data == d;
  1576 + };
  1577 +
  1578 + this.toString = function() {
  1579 + return method + ' ' + url;
  1580 + };
  1581 +}
  1582 +
  1583 +function createMockXhr() {
  1584 + return new MockXhr();
  1585 +}
  1586 +
  1587 +function MockXhr() {
  1588 +
  1589 + // hack for testing $http, $httpBackend
  1590 + MockXhr.$$lastInstance = this;
  1591 +
  1592 + this.open = function(method, url, async) {
  1593 + this.$$method = method;
  1594 + this.$$url = url;
  1595 + this.$$async = async;
  1596 + this.$$reqHeaders = {};
  1597 + this.$$respHeaders = {};
  1598 + };
  1599 +
  1600 + this.send = function(data) {
  1601 + this.$$data = data;
  1602 + };
  1603 +
  1604 + this.setRequestHeader = function(key, value) {
  1605 + this.$$reqHeaders[key] = value;
  1606 + };
  1607 +
  1608 + this.getResponseHeader = function(name) {
  1609 + // the lookup must be case insensitive,
  1610 + // that's why we try two quick lookups first and full scan last
  1611 + var header = this.$$respHeaders[name];
  1612 + if (header) return header;
  1613 +
  1614 + name = angular.lowercase(name);
  1615 + header = this.$$respHeaders[name];
  1616 + if (header) return header;
  1617 +
  1618 + header = undefined;
  1619 + angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
  1620 + if (!header && angular.lowercase(headerName) == name) header = headerVal;
  1621 + });
  1622 + return header;
  1623 + };
  1624 +
  1625 + this.getAllResponseHeaders = function() {
  1626 + var lines = [];
  1627 +
  1628 + angular.forEach(this.$$respHeaders, function(value, key) {
  1629 + lines.push(key + ': ' + value);
  1630 + });
  1631 + return lines.join('\n');
  1632 + };
  1633 +
  1634 + this.abort = angular.noop;
  1635 +}
  1636 +
  1637 +
  1638 +/**
  1639 + * @ngdoc function
  1640 + * @name ngMock.$timeout
  1641 + * @description
  1642 + *
  1643 + * This service is just a simple decorator for {@link ng.$timeout $timeout} service
  1644 + * that adds a "flush" and "verifyNoPendingTasks" methods.
  1645 + */
  1646 +
  1647 +angular.mock.$TimeoutDecorator = function($delegate, $browser) {
  1648 +
  1649 + /**
  1650 + * @ngdoc method
  1651 + * @name ngMock.$timeout#flush
  1652 + * @methodOf ngMock.$timeout
  1653 + * @description
  1654 + *
  1655 + * Flushes the queue of pending tasks.
  1656 + *
  1657 + * @param {number=} delay maximum timeout amount to flush up until
  1658 + */
  1659 + $delegate.flush = function(delay) {
  1660 + $browser.defer.flush(delay);
  1661 + };
  1662 +
  1663 + /**
  1664 + * @ngdoc method
  1665 + * @name ngMock.$timeout#verifyNoPendingTasks
  1666 + * @methodOf ngMock.$timeout
  1667 + * @description
  1668 + *
  1669 + * Verifies that there are no pending tasks that need to be flushed.
  1670 + */
  1671 + $delegate.verifyNoPendingTasks = function() {
  1672 + if ($browser.deferredFns.length) {
  1673 + throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
  1674 + formatPendingTasksAsString($browser.deferredFns));
  1675 + }
  1676 + };
  1677 +
  1678 + function formatPendingTasksAsString(tasks) {
  1679 + var result = [];
  1680 + angular.forEach(tasks, function(task) {
  1681 + result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
  1682 + });
  1683 +
  1684 + return result.join(', ');
  1685 + }
  1686 +
  1687 + return $delegate;
  1688 +};
  1689 +
  1690 +/**
  1691 + *
  1692 + */
  1693 +angular.mock.$RootElementProvider = function() {
  1694 + this.$get = function() {
  1695 + return angular.element('<div ng-app></div>');
  1696 + };
  1697 +};
  1698 +
  1699 +/**
  1700 + * @ngdoc overview
  1701 + * @name ngMock
  1702 + * @description
  1703 + *
  1704 + * # ngMock
  1705 + *
  1706 + * The `ngMock` module providers support to inject and mock Angular services into unit tests.
  1707 + * In addition, ngMock also extends various core ng services such that they can be
  1708 + * inspected and controlled in a synchronous manner within test code.
  1709 + *
  1710 + * {@installModule mock}
  1711 + *
  1712 + * <div doc-module-components="ngMock"></div>
  1713 + *
  1714 + */
  1715 +angular.module('ngMock', ['ng']).provider({
  1716 + $browser: angular.mock.$BrowserProvider,
  1717 + $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
  1718 + $log: angular.mock.$LogProvider,
  1719 + $interval: angular.mock.$IntervalProvider,
  1720 + $httpBackend: angular.mock.$HttpBackendProvider,
  1721 + $rootElement: angular.mock.$RootElementProvider
  1722 +}).config(['$provide', function($provide) {
  1723 + $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
  1724 +}]);
  1725 +
  1726 +/**
  1727 + * @ngdoc overview
  1728 + * @name ngMockE2E
  1729 + * @description
  1730 + *
  1731 + * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
  1732 + * Currently there is only one mock present in this module -
  1733 + * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
  1734 + */
  1735 +angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
  1736 + $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
  1737 +}]);
  1738 +
  1739 +/**
  1740 + * @ngdoc object
  1741 + * @name ngMockE2E.$httpBackend
  1742 + * @description
  1743 + * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
  1744 + * applications that use the {@link ng.$http $http service}.
  1745 + *
  1746 + * *Note*: For fake http backend implementation suitable for unit testing please see
  1747 + * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
  1748 + *
  1749 + * This implementation can be used to respond with static or dynamic responses via the `when` api
  1750 + * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
  1751 + * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
  1752 + * templates from a webserver).
  1753 + *
  1754 + * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
  1755 + * is being developed with the real backend api replaced with a mock, it is often desirable for
  1756 + * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
  1757 + * templates or static files from the webserver). To configure the backend with this behavior
  1758 + * use the `passThrough` request handler of `when` instead of `respond`.
  1759 + *
  1760 + * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
  1761 + * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests
  1762 + * automatically, closely simulating the behavior of the XMLHttpRequest object.
  1763 + *
  1764 + * To setup the application to run with this http backend, you have to create a module that depends
  1765 + * on the `ngMockE2E` and your application modules and defines the fake backend:
  1766 + *
  1767 + * <pre>
  1768 + * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
  1769 + * myAppDev.run(function($httpBackend) {
  1770 + * phones = [{name: 'phone1'}, {name: 'phone2'}];
  1771 + *
  1772 + * // returns the current list of phones
  1773 + * $httpBackend.whenGET('/phones').respond(phones);
  1774 + *
  1775 + * // adds a new phone to the phones array
  1776 + * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
  1777 + * phones.push(angular.fromJson(data));
  1778 + * });
  1779 + * $httpBackend.whenGET(/^\/templates\//).passThrough();
  1780 + * //...
  1781 + * });
  1782 + * </pre>
  1783 + *
  1784 + * Afterwards, bootstrap your app with this new module.
  1785 + */
  1786 +
  1787 +/**
  1788 + * @ngdoc method
  1789 + * @name ngMockE2E.$httpBackend#when
  1790 + * @methodOf ngMockE2E.$httpBackend
  1791 + * @description
  1792 + * Creates a new backend definition.
  1793 + *
  1794 + * @param {string} method HTTP method.
  1795 + * @param {string|RegExp} url HTTP url.
  1796 + * @param {(string|RegExp)=} data HTTP request body.
  1797 + * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  1798 + * object and returns true if the headers match the current definition.
  1799 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1800 + * control how a matched request is handled.
  1801 + *
  1802 + * - respond –
  1803 + * `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  1804 + * – The respond method takes a set of static data to be returned or a function that can return
  1805 + * an array containing response status (number), response data (string) and response headers
  1806 + * (Object).
  1807 + * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
  1808 + * handler, will be pass through to the real backend (an XHR request will be made to the
  1809 + * server.
  1810 + */
  1811 +
  1812 +/**
  1813 + * @ngdoc method
  1814 + * @name ngMockE2E.$httpBackend#whenGET
  1815 + * @methodOf ngMockE2E.$httpBackend
  1816 + * @description
  1817 + * Creates a new backend definition for GET requests. For more info see `when()`.
  1818 + *
  1819 + * @param {string|RegExp} url HTTP url.
  1820 + * @param {(Object|function(Object))=} headers HTTP headers.
  1821 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1822 + * control how a matched request is handled.
  1823 + */
  1824 +
  1825 +/**
  1826 + * @ngdoc method
  1827 + * @name ngMockE2E.$httpBackend#whenHEAD
  1828 + * @methodOf ngMockE2E.$httpBackend
  1829 + * @description
  1830 + * Creates a new backend definition for HEAD requests. For more info see `when()`.
  1831 + *
  1832 + * @param {string|RegExp} url HTTP url.
  1833 + * @param {(Object|function(Object))=} headers HTTP headers.
  1834 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1835 + * control how a matched request is handled.
  1836 + */
  1837 +
  1838 +/**
  1839 + * @ngdoc method
  1840 + * @name ngMockE2E.$httpBackend#whenDELETE
  1841 + * @methodOf ngMockE2E.$httpBackend
  1842 + * @description
  1843 + * Creates a new backend definition for DELETE requests. For more info see `when()`.
  1844 + *
  1845 + * @param {string|RegExp} url HTTP url.
  1846 + * @param {(Object|function(Object))=} headers HTTP headers.
  1847 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1848 + * control how a matched request is handled.
  1849 + */
  1850 +
  1851 +/**
  1852 + * @ngdoc method
  1853 + * @name ngMockE2E.$httpBackend#whenPOST
  1854 + * @methodOf ngMockE2E.$httpBackend
  1855 + * @description
  1856 + * Creates a new backend definition for POST requests. For more info see `when()`.
  1857 + *
  1858 + * @param {string|RegExp} url HTTP url.
  1859 + * @param {(string|RegExp)=} data HTTP request body.
  1860 + * @param {(Object|function(Object))=} headers HTTP headers.
  1861 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1862 + * control how a matched request is handled.
  1863 + */
  1864 +
  1865 +/**
  1866 + * @ngdoc method
  1867 + * @name ngMockE2E.$httpBackend#whenPUT
  1868 + * @methodOf ngMockE2E.$httpBackend
  1869 + * @description
  1870 + * Creates a new backend definition for PUT requests. For more info see `when()`.
  1871 + *
  1872 + * @param {string|RegExp} url HTTP url.
  1873 + * @param {(string|RegExp)=} data HTTP request body.
  1874 + * @param {(Object|function(Object))=} headers HTTP headers.
  1875 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1876 + * control how a matched request is handled.
  1877 + */
  1878 +
  1879 +/**
  1880 + * @ngdoc method
  1881 + * @name ngMockE2E.$httpBackend#whenPATCH
  1882 + * @methodOf ngMockE2E.$httpBackend
  1883 + * @description
  1884 + * Creates a new backend definition for PATCH requests. For more info see `when()`.
  1885 + *
  1886 + * @param {string|RegExp} url HTTP url.
  1887 + * @param {(string|RegExp)=} data HTTP request body.
  1888 + * @param {(Object|function(Object))=} headers HTTP headers.
  1889 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1890 + * control how a matched request is handled.
  1891 + */
  1892 +
  1893 +/**
  1894 + * @ngdoc method
  1895 + * @name ngMockE2E.$httpBackend#whenJSONP
  1896 + * @methodOf ngMockE2E.$httpBackend
  1897 + * @description
  1898 + * Creates a new backend definition for JSONP requests. For more info see `when()`.
  1899 + *
  1900 + * @param {string|RegExp} url HTTP url.
  1901 + * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1902 + * control how a matched request is handled.
  1903 + */
  1904 +angular.mock.e2e = {};
  1905 +angular.mock.e2e.$httpBackendDecorator =
  1906 + ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
  1907 +
  1908 +
  1909 +angular.mock.clearDataCache = function() {
  1910 + var key,
  1911 + cache = angular.element.cache;
  1912 +
  1913 + for(key in cache) {
  1914 + if (Object.prototype.hasOwnProperty.call(cache,key)) {
  1915 + var handle = cache[key].handle;
  1916 +
  1917 + handle && angular.element(handle.elem).off();
  1918 + delete cache[key];
  1919 + }
  1920 + }
  1921 +};
  1922 +
  1923 +
  1924 +if(window.jasmine || window.mocha) {
  1925 +
  1926 + var currentSpec = null,
  1927 + isSpecRunning = function() {
  1928 + return !!currentSpec;
  1929 + };
  1930 +
  1931 +
  1932 + beforeEach(function() {
  1933 + currentSpec = this;
  1934 + });
  1935 +
  1936 + afterEach(function() {
  1937 + var injector = currentSpec.$injector;
  1938 +
  1939 + currentSpec.$injector = null;
  1940 + currentSpec.$modules = null;
  1941 + currentSpec = null;
  1942 +
  1943 + if (injector) {
  1944 + injector.get('$rootElement').off();
  1945 + injector.get('$browser').pollFns.length = 0;
  1946 + }
  1947 +
  1948 + angular.mock.clearDataCache();
  1949 +
  1950 + // clean up jquery's fragment cache
  1951 + angular.forEach(angular.element.fragments, function(val, key) {
  1952 + delete angular.element.fragments[key];
  1953 + });
  1954 +
  1955 + MockXhr.$$lastInstance = null;
  1956 +
  1957 + angular.forEach(angular.callbacks, function(val, key) {
  1958 + delete angular.callbacks[key];
  1959 + });
  1960 + angular.callbacks.counter = 0;
  1961 + });
  1962 +
  1963 + /**
  1964 + * @ngdoc function
  1965 + * @name angular.mock.module
  1966 + * @description
  1967 + *
  1968 + * *NOTE*: This function is also published on window for easy access.<br>
  1969 + *
  1970 + * This function registers a module configuration code. It collects the configuration information
  1971 + * which will be used when the injector is created by {@link angular.mock.inject inject}.
  1972 + *
  1973 + * See {@link angular.mock.inject inject} for usage example
  1974 + *
  1975 + * @param {...(string|Function|Object)} fns any number of modules which are represented as string
  1976 + * aliases or as anonymous module initialization functions. The modules are used to
  1977 + * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
  1978 + * object literal is passed they will be register as values in the module, the key being
  1979 + * the module name and the value being what is returned.
  1980 + */
  1981 + window.module = angular.mock.module = function() {
  1982 + var moduleFns = Array.prototype.slice.call(arguments, 0);
  1983 + return isSpecRunning() ? workFn() : workFn;
  1984 + /////////////////////
  1985 + function workFn() {
  1986 + if (currentSpec.$injector) {
  1987 + throw new Error('Injector already created, can not register a module!');
  1988 + } else {
  1989 + var modules = currentSpec.$modules || (currentSpec.$modules = []);
  1990 + angular.forEach(moduleFns, function(module) {
  1991 + if (angular.isObject(module) && !angular.isArray(module)) {
  1992 + modules.push(function($provide) {
  1993 + angular.forEach(module, function(value, key) {
  1994 + $provide.value(key, value);
  1995 + });
  1996 + });
  1997 + } else {
  1998 + modules.push(module);
  1999 + }
  2000 + });
  2001 + }
  2002 + }
  2003 + };
  2004 +
  2005 + /**
  2006 + * @ngdoc function
  2007 + * @name angular.mock.inject
  2008 + * @description
  2009 + *
  2010 + * *NOTE*: This function is also published on window for easy access.<br>
  2011 + *
  2012 + * The inject function wraps a function into an injectable function. The inject() creates new
  2013 + * instance of {@link AUTO.$injector $injector} per test, which is then used for
  2014 + * resolving references.
  2015 + *
  2016 + *
  2017 + * ## Resolving References (Underscore Wrapping)
  2018 + * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
  2019 + * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
  2020 + * that is declared in the scope of the `describe()` block. Since we would, most likely, want
  2021 + * the variable to have the same name of the reference we have a problem, since the parameter
  2022 + * to the `inject()` function would hide the outer variable.
  2023 + *
  2024 + * To help with this, the injected parameters can, optionally, be enclosed with underscores.
  2025 + * These are ignored by the injector when the reference name is resolved.
  2026 + *
  2027 + * For example, the parameter `_myService_` would be resolved as the reference `myService`.
  2028 + * Since it is available in the function body as _myService_, we can then assign it to a variable
  2029 + * defined in an outer scope.
  2030 + *
  2031 + * ```
  2032 + * // Defined out reference variable outside
  2033 + * var myService;
  2034 + *
  2035 + * // Wrap the parameter in underscores
  2036 + * beforeEach( inject( function(_myService_){
  2037 + * myService = _myService_;
  2038 + * }));
  2039 + *
  2040 + * // Use myService in a series of tests.
  2041 + * it('makes use of myService', function() {
  2042 + * myService.doStuff();
  2043 + * });
  2044 + *
  2045 + * ```
  2046 + *
  2047 + * See also {@link angular.mock.module angular.mock.module}
  2048 + *
  2049 + * ## Example
  2050 + * Example of what a typical jasmine tests looks like with the inject method.
  2051 + * <pre>
  2052 + *
  2053 + * angular.module('myApplicationModule', [])
  2054 + * .value('mode', 'app')
  2055 + * .value('version', 'v1.0.1');
  2056 + *
  2057 + *
  2058 + * describe('MyApp', function() {
  2059 + *
  2060 + * // You need to load modules that you want to test,
  2061 + * // it loads only the "ng" module by default.
  2062 + * beforeEach(module('myApplicationModule'));
  2063 + *
  2064 + *
  2065 + * // inject() is used to inject arguments of all given functions
  2066 + * it('should provide a version', inject(function(mode, version) {
  2067 + * expect(version).toEqual('v1.0.1');
  2068 + * expect(mode).toEqual('app');
  2069 + * }));
  2070 + *
  2071 + *
  2072 + * // The inject and module method can also be used inside of the it or beforeEach
  2073 + * it('should override a version and test the new version is injected', function() {
  2074 + * // module() takes functions or strings (module aliases)
  2075 + * module(function($provide) {
  2076 + * $provide.value('version', 'overridden'); // override version here
  2077 + * });
  2078 + *
  2079 + * inject(function(version) {
  2080 + * expect(version).toEqual('overridden');
  2081 + * });
  2082 + * });
  2083 + * });
  2084 + *
  2085 + * </pre>
  2086 + *
  2087 + * @param {...Function} fns any number of functions which will be injected using the injector.
  2088 + */
  2089 +
  2090 +
  2091 +
  2092 + var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
  2093 + this.message = e.message;
  2094 + this.name = e.name;
  2095 + if (e.line) this.line = e.line;
  2096 + if (e.sourceId) this.sourceId = e.sourceId;
  2097 + if (e.stack && errorForStack)
  2098 + this.stack = e.stack + '\n' + errorForStack.stack;
  2099 + if (e.stackArray) this.stackArray = e.stackArray;
  2100 + };
  2101 + ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
  2102 +
  2103 + window.inject = angular.mock.inject = function() {
  2104 + var blockFns = Array.prototype.slice.call(arguments, 0);
  2105 + var errorForStack = new Error('Declaration Location');
  2106 + return isSpecRunning() ? workFn.call(currentSpec) : workFn;
  2107 + /////////////////////
  2108 + function workFn() {
  2109 + var modules = currentSpec.$modules || [];
  2110 +
  2111 + modules.unshift('ngMock');
  2112 + modules.unshift('ng');
  2113 + var injector = currentSpec.$injector;
  2114 + if (!injector) {
  2115 + injector = currentSpec.$injector = angular.injector(modules);
  2116 + }
  2117 + for(var i = 0, ii = blockFns.length; i < ii; i++) {
  2118 + try {
  2119 + /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
  2120 + injector.invoke(blockFns[i] || angular.noop, this);
  2121 + /* jshint +W040 */
  2122 + } catch (e) {
  2123 + if (e.stack && errorForStack) {
  2124 + throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
  2125 + }
  2126 + throw e;
  2127 + } finally {
  2128 + errorForStack = null;
  2129 + }
  2130 + }
  2131 + }
  2132 + };
  2133 +}
  2134 +
  2135 +
  2136 +})(window, window.angular);
  1 +/**
  2 + * @license AngularJS v1.2.13
  3 + * (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + * License: MIT
  5 + */
  6 +(function(window, angular, undefined) {'use strict';
  7 +
  8 +var $resourceMinErr = angular.$$minErr('$resource');
  9 +
  10 +// Helper functions and regex to lookup a dotted path on an object
  11 +// stopping at undefined/null. The path must be composed of ASCII
  12 +// identifiers (just like $parse)
  13 +var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
  14 +
  15 +function isValidDottedPath(path) {
  16 + return (path != null && path !== '' && path !== 'hasOwnProperty' &&
  17 + MEMBER_NAME_REGEX.test('.' + path));
  18 +}
  19 +
  20 +function lookupDottedPath(obj, path) {
  21 + if (!isValidDottedPath(path)) {
  22 + throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
  23 + }
  24 + var keys = path.split('.');
  25 + for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
  26 + var key = keys[i];
  27 + obj = (obj !== null) ? obj[key] : undefined;
  28 + }
  29 + return obj;
  30 +}
  31 +
  32 +/**
  33 + * Create a shallow copy of an object and clear other fields from the destination
  34 + */
  35 +function shallowClearAndCopy(src, dst) {
  36 + dst = dst || {};
  37 +
  38 + angular.forEach(dst, function(value, key){
  39 + delete dst[key];
  40 + });
  41 +
  42 + for (var key in src) {
  43 + if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
  44 + dst[key] = src[key];
  45 + }
  46 + }
  47 +
  48 + return dst;
  49 +}
  50 +
  51 +/**
  52 + * @ngdoc overview
  53 + * @name ngResource
  54 + * @description
  55 + *
  56 + * # ngResource
  57 + *
  58 + * The `ngResource` module provides interaction support with RESTful services
  59 + * via the $resource service.
  60 + *
  61 + * {@installModule resource}
  62 + *
  63 + * <div doc-module-components="ngResource"></div>
  64 + *
  65 + * See {@link ngResource.$resource `$resource`} for usage.
  66 + */
  67 +
  68 +/**
  69 + * @ngdoc object
  70 + * @name ngResource.$resource
  71 + * @requires $http
  72 + *
  73 + * @description
  74 + * A factory which creates a resource object that lets you interact with
  75 + * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
  76 + *
  77 + * The returned resource object has action methods which provide high-level behaviors without
  78 + * the need to interact with the low level {@link ng.$http $http} service.
  79 + *
  80 + * Requires the {@link ngResource `ngResource`} module to be installed.
  81 + *
  82 + * @param {string} url A parametrized URL template with parameters prefixed by `:` as in
  83 + * `/user/:username`. If you are using a URL with a port number (e.g.
  84 + * `http://example.com:8080/api`), it will be respected.
  85 + *
  86 + * If you are using a url with a suffix, just add the suffix, like this:
  87 + * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
  88 + * or even `$resource('http://example.com/resource/:resource_id.:format')`
  89 + * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
  90 + * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
  91 + * can escape it with `/\.`.
  92 + *
  93 + * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
  94 + * `actions` methods. If any of the parameter value is a function, it will be executed every time
  95 + * when a param value needs to be obtained for a request (unless the param was overridden).
  96 + *
  97 + * Each key value in the parameter object is first bound to url template if present and then any
  98 + * excess keys are appended to the url search query after the `?`.
  99 + *
  100 + * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
  101 + * URL `/path/greet?salutation=Hello`.
  102 + *
  103 + * If the parameter value is prefixed with `@` then the value of that parameter is extracted from
  104 + * the data object (useful for non-GET operations).
  105 + *
  106 + * @param {Object.<Object>=} actions Hash with declaration of custom action that should extend the
  107 + * default set of resource actions. The declaration should be created in the format of {@link
  108 + * ng.$http#usage_parameters $http.config}:
  109 + *
  110 + * {action1: {method:?, params:?, isArray:?, headers:?, ...},
  111 + * action2: {method:?, params:?, isArray:?, headers:?, ...},
  112 + * ...}
  113 + *
  114 + * Where:
  115 + *
  116 + * - **`action`** – {string} – The name of action. This name becomes the name of the method on
  117 + * your resource object.
  118 + * - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`,
  119 + * `DELETE`, and `JSONP`.
  120 + * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
  121 + * the parameter value is a function, it will be executed every time when a param value needs to
  122 + * be obtained for a request (unless the param was overridden).
  123 + * - **`url`** – {string} – action specific `url` override. The url templating is supported just
  124 + * like for the resource-level urls.
  125 + * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
  126 + * see `returns` section.
  127 + * - **`transformRequest`** –
  128 + * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
  129 + * transform function or an array of such functions. The transform function takes the http
  130 + * request body and headers and returns its transformed (typically serialized) version.
  131 + * - **`transformResponse`** –
  132 + * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
  133 + * transform function or an array of such functions. The transform function takes the http
  134 + * response body and headers and returns its transformed (typically deserialized) version.
  135 + * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
  136 + * GET request, otherwise if a cache instance built with
  137 + * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
  138 + * caching.
  139 + * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
  140 + * should abort the request when resolved.
  141 + * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
  142 + * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
  143 + * requests with credentials} for more information.
  144 + * - **`responseType`** - `{string}` - see {@link
  145 + * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
  146 + * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
  147 + * `response` and `responseError`. Both `response` and `responseError` interceptors get called
  148 + * with `http response` object. See {@link ng.$http $http interceptors}.
  149 + *
  150 + * @returns {Object} A resource "class" object with methods for the default set of resource actions
  151 + * optionally extended with custom `actions`. The default set contains these actions:
  152 + *
  153 + * { 'get': {method:'GET'},
  154 + * 'save': {method:'POST'},
  155 + * 'query': {method:'GET', isArray:true},
  156 + * 'remove': {method:'DELETE'},
  157 + * 'delete': {method:'DELETE'} };
  158 + *
  159 + * Calling these methods invoke an {@link ng.$http} with the specified http method,
  160 + * destination and parameters. When the data is returned from the server then the object is an
  161 + * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
  162 + * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
  163 + * read, update, delete) on server-side data like this:
  164 + * <pre>
  165 + var User = $resource('/user/:userId', {userId:'@id'});
  166 + var user = User.get({userId:123}, function() {
  167 + user.abc = true;
  168 + user.$save();
  169 + });
  170 + </pre>
  171 + *
  172 + * It is important to realize that invoking a $resource object method immediately returns an
  173 + * empty reference (object or array depending on `isArray`). Once the data is returned from the
  174 + * server the existing reference is populated with the actual data. This is a useful trick since
  175 + * usually the resource is assigned to a model which is then rendered by the view. Having an empty
  176 + * object results in no rendering, once the data arrives from the server then the object is
  177 + * populated with the data and the view automatically re-renders itself showing the new data. This
  178 + * means that in most cases one never has to write a callback function for the action methods.
  179 + *
  180 + * The action methods on the class object or instance object can be invoked with the following
  181 + * parameters:
  182 + *
  183 + * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
  184 + * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
  185 + * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
  186 + *
  187 + * Success callback is called with (value, responseHeaders) arguments. Error callback is called
  188 + * with (httpResponse) argument.
  189 + *
  190 + * Class actions return empty instance (with additional properties below).
  191 + * Instance actions return promise of the action.
  192 + *
  193 + * The Resource instances and collection have these additional properties:
  194 + *
  195 + * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
  196 + * instance or collection.
  197 + *
  198 + * On success, the promise is resolved with the same resource instance or collection object,
  199 + * updated with data from server. This makes it easy to use in
  200 + * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
  201 + * rendering until the resource(s) are loaded.
  202 + *
  203 + * On failure, the promise is resolved with the {@link ng.$http http response} object, without
  204 + * the `resource` property.
  205 + *
  206 + * - `$resolved`: `true` after first server interaction is completed (either with success or
  207 + * rejection), `false` before that. Knowing if the Resource has been resolved is useful in
  208 + * data-binding.
  209 + *
  210 + * @example
  211 + *
  212 + * # Credit card resource
  213 + *
  214 + * <pre>
  215 + // Define CreditCard class
  216 + var CreditCard = $resource('/user/:userId/card/:cardId',
  217 + {userId:123, cardId:'@id'}, {
  218 + charge: {method:'POST', params:{charge:true}}
  219 + });
  220 +
  221 + // We can retrieve a collection from the server
  222 + var cards = CreditCard.query(function() {
  223 + // GET: /user/123/card
  224 + // server returns: [ {id:456, number:'1234', name:'Smith'} ];
  225 +
  226 + var card = cards[0];
  227 + // each item is an instance of CreditCard
  228 + expect(card instanceof CreditCard).toEqual(true);
  229 + card.name = "J. Smith";
  230 + // non GET methods are mapped onto the instances
  231 + card.$save();
  232 + // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
  233 + // server returns: {id:456, number:'1234', name: 'J. Smith'};
  234 +
  235 + // our custom method is mapped as well.
  236 + card.$charge({amount:9.99});
  237 + // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
  238 + });
  239 +
  240 + // we can create an instance as well
  241 + var newCard = new CreditCard({number:'0123'});
  242 + newCard.name = "Mike Smith";
  243 + newCard.$save();
  244 + // POST: /user/123/card {number:'0123', name:'Mike Smith'}
  245 + // server returns: {id:789, number:'0123', name: 'Mike Smith'};
  246 + expect(newCard.id).toEqual(789);
  247 + * </pre>
  248 + *
  249 + * The object returned from this function execution is a resource "class" which has "static" method
  250 + * for each action in the definition.
  251 + *
  252 + * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
  253 + * `headers`.
  254 + * When the data is returned from the server then the object is an instance of the resource type and
  255 + * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
  256 + * operations (create, read, update, delete) on server-side data.
  257 +
  258 + <pre>
  259 + var User = $resource('/user/:userId', {userId:'@id'});
  260 + var user = User.get({userId:123}, function() {
  261 + user.abc = true;
  262 + user.$save();
  263 + });
  264 + </pre>
  265 + *
  266 + * It's worth noting that the success callback for `get`, `query` and other methods gets passed
  267 + * in the response that came from the server as well as $http header getter function, so one
  268 + * could rewrite the above example and get access to http headers as:
  269 + *
  270 + <pre>
  271 + var User = $resource('/user/:userId', {userId:'@id'});
  272 + User.get({userId:123}, function(u, getResponseHeaders){
  273 + u.abc = true;
  274 + u.$save(function(u, putResponseHeaders) {
  275 + //u => saved user object
  276 + //putResponseHeaders => $http header getter
  277 + });
  278 + });
  279 + </pre>
  280 +
  281 + * # Creating a custom 'PUT' request
  282 + * In this example we create a custom method on our resource to make a PUT request
  283 + * <pre>
  284 + * var app = angular.module('app', ['ngResource', 'ngRoute']);
  285 + *
  286 + * // Some APIs expect a PUT request in the format URL/object/ID
  287 + * // Here we are creating an 'update' method
  288 + * app.factory('Notes', ['$resource', function($resource) {
  289 + * return $resource('/notes/:id', null,
  290 + * {
  291 + * 'update': { method:'PUT' }
  292 + * });
  293 + * }]);
  294 + *
  295 + * // In our controller we get the ID from the URL using ngRoute and $routeParams
  296 + * // We pass in $routeParams and our Notes factory along with $scope
  297 + * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
  298 + function($scope, $routeParams, Notes) {
  299 + * // First get a note object from the factory
  300 + * var note = Notes.get({ id:$routeParams.id });
  301 + * $id = note.id;
  302 + *
  303 + * // Now call update passing in the ID first then the object you are updating
  304 + * Notes.update({ id:$id }, note);
  305 + *
  306 + * // This will PUT /notes/ID with the note object in the request payload
  307 + * }]);
  308 + * </pre>
  309 + */
  310 +angular.module('ngResource', ['ng']).
  311 + factory('$resource', ['$http', '$q', function($http, $q) {
  312 +
  313 + var DEFAULT_ACTIONS = {
  314 + 'get': {method:'GET'},
  315 + 'save': {method:'POST'},
  316 + 'query': {method:'GET', isArray:true},
  317 + 'remove': {method:'DELETE'},
  318 + 'delete': {method:'DELETE'}
  319 + };
  320 + var noop = angular.noop,
  321 + forEach = angular.forEach,
  322 + extend = angular.extend,
  323 + copy = angular.copy,
  324 + isFunction = angular.isFunction;
  325 +
  326 + /**
  327 + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
  328 + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
  329 + * segments:
  330 + * segment = *pchar
  331 + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
  332 + * pct-encoded = "%" HEXDIG HEXDIG
  333 + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
  334 + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
  335 + * / "*" / "+" / "," / ";" / "="
  336 + */
  337 + function encodeUriSegment(val) {
  338 + return encodeUriQuery(val, true).
  339 + replace(/%26/gi, '&').
  340 + replace(/%3D/gi, '=').
  341 + replace(/%2B/gi, '+');
  342 + }
  343 +
  344 +
  345 + /**
  346 + * This method is intended for encoding *key* or *value* parts of query component. We need a
  347 + * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
  348 + * have to be encoded per http://tools.ietf.org/html/rfc3986:
  349 + * query = *( pchar / "/" / "?" )
  350 + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
  351 + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
  352 + * pct-encoded = "%" HEXDIG HEXDIG
  353 + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
  354 + * / "*" / "+" / "," / ";" / "="
  355 + */
  356 + function encodeUriQuery(val, pctEncodeSpaces) {
  357 + return encodeURIComponent(val).
  358 + replace(/%40/gi, '@').
  359 + replace(/%3A/gi, ':').
  360 + replace(/%24/g, '$').
  361 + replace(/%2C/gi, ',').
  362 + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
  363 + }
  364 +
  365 + function Route(template, defaults) {
  366 + this.template = template;
  367 + this.defaults = defaults || {};
  368 + this.urlParams = {};
  369 + }
  370 +
  371 + Route.prototype = {
  372 + setUrlParams: function(config, params, actionUrl) {
  373 + var self = this,
  374 + url = actionUrl || self.template,
  375 + val,
  376 + encodedVal;
  377 +
  378 + var urlParams = self.urlParams = {};
  379 + forEach(url.split(/\W/), function(param){
  380 + if (param === 'hasOwnProperty') {
  381 + throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
  382 + }
  383 + if (!(new RegExp("^\\d+$").test(param)) && param &&
  384 + (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
  385 + urlParams[param] = true;
  386 + }
  387 + });
  388 + url = url.replace(/\\:/g, ':');
  389 +
  390 + params = params || {};
  391 + forEach(self.urlParams, function(_, urlParam){
  392 + val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
  393 + if (angular.isDefined(val) && val !== null) {
  394 + encodedVal = encodeUriSegment(val);
  395 + url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
  396 + return encodedVal + p1;
  397 + });
  398 + } else {
  399 + url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
  400 + leadingSlashes, tail) {
  401 + if (tail.charAt(0) == '/') {
  402 + return tail;
  403 + } else {
  404 + return leadingSlashes + tail;
  405 + }
  406 + });
  407 + }
  408 + });
  409 +
  410 + // strip trailing slashes and set the url
  411 + url = url.replace(/\/+$/, '') || '/';
  412 + // then replace collapse `/.` if found in the last URL path segment before the query
  413 + // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
  414 + url = url.replace(/\/\.(?=\w+($|\?))/, '.');
  415 + // replace escaped `/\.` with `/.`
  416 + config.url = url.replace(/\/\\\./, '/.');
  417 +
  418 +
  419 + // set params - delegate param encoding to $http
  420 + forEach(params, function(value, key){
  421 + if (!self.urlParams[key]) {
  422 + config.params = config.params || {};
  423 + config.params[key] = value;
  424 + }
  425 + });
  426 + }
  427 + };
  428 +
  429 +
  430 + function resourceFactory(url, paramDefaults, actions) {
  431 + var route = new Route(url);
  432 +
  433 + actions = extend({}, DEFAULT_ACTIONS, actions);
  434 +
  435 + function extractParams(data, actionParams){
  436 + var ids = {};
  437 + actionParams = extend({}, paramDefaults, actionParams);
  438 + forEach(actionParams, function(value, key){
  439 + if (isFunction(value)) { value = value(); }
  440 + ids[key] = value && value.charAt && value.charAt(0) == '@' ?
  441 + lookupDottedPath(data, value.substr(1)) : value;
  442 + });
  443 + return ids;
  444 + }
  445 +
  446 + function defaultResponseInterceptor(response) {
  447 + return response.resource;
  448 + }
  449 +
  450 + function Resource(value){
  451 + shallowClearAndCopy(value || {}, this);
  452 + }
  453 +
  454 + forEach(actions, function(action, name) {
  455 + var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
  456 +
  457 + Resource[name] = function(a1, a2, a3, a4) {
  458 + var params = {}, data, success, error;
  459 +
  460 + /* jshint -W086 */ /* (purposefully fall through case statements) */
  461 + switch(arguments.length) {
  462 + case 4:
  463 + error = a4;
  464 + success = a3;
  465 + //fallthrough
  466 + case 3:
  467 + case 2:
  468 + if (isFunction(a2)) {
  469 + if (isFunction(a1)) {
  470 + success = a1;
  471 + error = a2;
  472 + break;
  473 + }
  474 +
  475 + success = a2;
  476 + error = a3;
  477 + //fallthrough
  478 + } else {
  479 + params = a1;
  480 + data = a2;
  481 + success = a3;
  482 + break;
  483 + }
  484 + case 1:
  485 + if (isFunction(a1)) success = a1;
  486 + else if (hasBody) data = a1;
  487 + else params = a1;
  488 + break;
  489 + case 0: break;
  490 + default:
  491 + throw $resourceMinErr('badargs',
  492 + "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
  493 + arguments.length);
  494 + }
  495 + /* jshint +W086 */ /* (purposefully fall through case statements) */
  496 +
  497 + var isInstanceCall = this instanceof Resource;
  498 + var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
  499 + var httpConfig = {};
  500 + var responseInterceptor = action.interceptor && action.interceptor.response ||
  501 + defaultResponseInterceptor;
  502 + var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
  503 + undefined;
  504 +
  505 + forEach(action, function(value, key) {
  506 + if (key != 'params' && key != 'isArray' && key != 'interceptor') {
  507 + httpConfig[key] = copy(value);
  508 + }
  509 + });
  510 +
  511 + if (hasBody) httpConfig.data = data;
  512 + route.setUrlParams(httpConfig,
  513 + extend({}, extractParams(data, action.params || {}), params),
  514 + action.url);
  515 +
  516 + var promise = $http(httpConfig).then(function(response) {
  517 + var data = response.data,
  518 + promise = value.$promise;
  519 +
  520 + if (data) {
  521 + // Need to convert action.isArray to boolean in case it is undefined
  522 + // jshint -W018
  523 + if (angular.isArray(data) !== (!!action.isArray)) {
  524 + throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
  525 + 'response to contain an {0} but got an {1}',
  526 + action.isArray?'array':'object', angular.isArray(data)?'array':'object');
  527 + }
  528 + // jshint +W018
  529 + if (action.isArray) {
  530 + value.length = 0;
  531 + forEach(data, function(item) {
  532 + value.push(new Resource(item));
  533 + });
  534 + } else {
  535 + shallowClearAndCopy(data, value);
  536 + value.$promise = promise;
  537 + }
  538 + }
  539 +
  540 + value.$resolved = true;
  541 +
  542 + response.resource = value;
  543 +
  544 + return response;
  545 + }, function(response) {
  546 + value.$resolved = true;
  547 +
  548 + (error||noop)(response);
  549 +
  550 + return $q.reject(response);
  551 + });
  552 +
  553 + promise = promise.then(
  554 + function(response) {
  555 + var value = responseInterceptor(response);
  556 + (success||noop)(value, response.headers);
  557 + return value;
  558 + },
  559 + responseErrorInterceptor);
  560 +
  561 + if (!isInstanceCall) {
  562 + // we are creating instance / collection
  563 + // - set the initial promise
  564 + // - return the instance / collection
  565 + value.$promise = promise;
  566 + value.$resolved = false;
  567 +
  568 + return value;
  569 + }
  570 +
  571 + // instance call
  572 + return promise;
  573 + };
  574 +
  575 +
  576 + Resource.prototype['$' + name] = function(params, success, error) {
  577 + if (isFunction(params)) {
  578 + error = success; success = params; params = {};
  579 + }
  580 + var result = Resource[name].call(this, params, this, success, error);
  581 + return result.$promise || result;
  582 + };
  583 + });
  584 +
  585 + Resource.bind = function(additionalParamDefaults){
  586 + return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
  587 + };
  588 +
  589 + return Resource;
  590 + }
  591 +
  592 + return resourceFactory;
  593 + }]);
  594 +
  595 +
  596 +})(window, window.angular);
  1 +/*
  2 + AngularJS v1.2.13
  3 + (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + License: MIT
  5 +*/
  6 +(function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&&
  7 +b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
  8 +b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
  9 +h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f}
  10 +var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)?
  11 +g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a,
  12 +e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
  13 +//# sourceMappingURL=angular-resource.min.js.map
  1 +{
  2 +"version":3,
  3 +"file":"angular-resource.min.js",
  4 +"lineCount":12,
  5 +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CA6BtCC,QAASA,EAAmB,CAACC,CAAD,CAAMC,CAAN,CAAW,CACrCA,CAAA,CAAMA,CAAN,EAAa,EAEbJ,EAAAK,QAAA,CAAgBD,CAAhB,CAAqB,QAAQ,CAACE,CAAD,CAAQC,CAAR,CAAY,CACvC,OAAOH,CAAA,CAAIG,CAAJ,CADgC,CAAzC,CAIA,KAAKA,IAAIA,CAAT,GAAgBJ,EAAhB,CACM,CAAAA,CAAAK,eAAA,CAAmBD,CAAnB,CAAJ,EAAmD,GAAnD,GAAiCA,CAAAE,OAAA,CAAW,CAAX,CAAjC,EAA4E,GAA5E,GAA0DF,CAAAE,OAAA,CAAW,CAAX,CAA1D,GACEL,CAAA,CAAIG,CAAJ,CADF,CACaJ,CAAA,CAAII,CAAJ,CADb,CAKF,OAAOH,EAb8B,CA3BvC,IAAIM,EAAkBV,CAAAW,SAAA,CAAiB,WAAjB,CAAtB,CAKIC,EAAoB,iCAySxBZ,EAAAa,OAAA,CAAe,YAAf,CAA6B,CAAC,IAAD,CAA7B,CAAAC,QAAA,CACU,WADV,CACuB,CAAC,OAAD,CAAU,IAAV,CAAgB,QAAQ,CAACC,CAAD,CAAQC,CAAR,CAAY,CAsDvDC,QAASA,EAAK,CAACC,CAAD,CAAWC,CAAX,CAAqB,CACjC,IAAAD,SAAA,CAAgBA,CAChB,KAAAC,SAAA,CAAgBA,CAAhB,EAA4B,EAC5B,KAAAC,UAAA,CAAiB,EAHgB,CAiEnCC,QAASA,EAAe,CAACC,CAAD,CAAMC,CAAN,CAAqBC,CAArB,CAA8B,CAKpDC,QAASA,EAAa,CAACC,CAAD,CAAOC,CAAP,CAAoB,CACxC,IAAIC,EAAM,EACVD,EAAA,CAAeE,CAAA,CAAO,EAAP,CAAWN,CAAX,CAA0BI,CAA1B,CACftB,EAAA,CAAQsB,CAAR,CAAsB,QAAQ,CAACrB,CAAD,CAAQC,CAAR,CAAY,CACpCuB,CAAA,CAAWxB,CAAX,CAAJ,GAAyBA,CAAzB,CAAiCA,CAAA,EAAjC,CACW,KAAA,CAAA,IAAAA,CAAA;AAASA,CAAAG,OAAT,EAA4C,GAA5C,EAAyBH,CAAAG,OAAA,CAAa,CAAb,CAAzB,CAAA,CACT,CAAA,CAAA,CAAA,KAAA,EAAA,CAAA,OAAA,CAAA,CAAA,CApaV,IALgB,IAKhB,EAAuBsB,CAAvB,EALiC,EAKjC,GAAuBA,CAAvB,EALgD,gBAKhD,GAAuBA,CAAvB,EAJI,CAAAnB,CAAAoB,KAAA,CAAuB,GAAvB,CAImBD,CAJnB,CAIJ,CACE,KAAMrB,EAAA,CAAgB,WAAhB,CAAsEqB,CAAtE,CAAN,CAGF,IADIE,IAAAA,EAAOF,CAAAG,MAAA,CAAW,GAAX,CAAPD,CACKE,EAAI,CADTF,CACYG,EAAKH,CAAAI,OAArB,CAAkCF,CAAlC,CAAsCC,CAAtC,EAA4CE,CAA5C,GAAoDrC,CAApD,CAA+DkC,CAAA,EAA/D,CAAoE,CAClE,IAAI5B,EAAM0B,CAAA,CAAKE,CAAL,CACVG,EAAA,CAAe,IAAT,GAACA,CAAD,CAAiBA,CAAA,CAAI/B,CAAJ,CAAjB,CAA4BN,CAFgC,CA+ZjD,CAAA,IACiCK,EAAAA,CAAAA,CAD5CsB,EAAA,CAAIrB,CAAJ,CAAA,CAAW,CAF6B,CAA1C,CAKA,OAAOqB,EARiC,CAW1CW,QAASA,EAA0B,CAACC,CAAD,CAAW,CAC5C,MAAOA,EAAAC,SADqC,CAI9CC,QAASA,EAAQ,CAACpC,CAAD,CAAO,CACtBJ,CAAA,CAAoBI,CAApB,EAA6B,EAA7B,CAAiC,IAAjC,CADsB,CAnBxB,IAAIqC,EAAQ,IAAI1B,CAAJ,CAAUK,CAAV,CAEZE,EAAA,CAAUK,CAAA,CAAO,EAAP,CAAWe,CAAX,CAA4BpB,CAA5B,CAqBVnB,EAAA,CAAQmB,CAAR,CAAiB,QAAQ,CAACqB,CAAD,CAASC,CAAT,CAAe,CACtC,IAAIC,EAAU,qBAAAf,KAAA,CAA2Ba,CAAAG,OAA3B,CAEdN,EAAA,CAASI,CAAT,CAAA,CAAiB,QAAQ,CAACG,CAAD,CAAKC,CAAL,CAASC,CAAT,CAAaC,CAAb,CAAiB,CAAA,IACpCC,EAAS,EAD2B,CACvB3B,CADuB,CACjB4B,CADiB,CACRC,CAGhC,QAAOC,SAAAnB,OAAP,EACA,KAAK,CAAL,CACEkB,CACA,CADQH,CACR,CAAAE,CAAA,CAAUH,CAEZ,MAAK,CAAL,CACA,KAAK,CAAL,CACE,GAAIrB,CAAA,CAAWoB,CAAX,CAAJ,CAAoB,CAClB,GAAIpB,CAAA,CAAWmB,CAAX,CAAJ,CAAoB,CAClBK,CAAA;AAAUL,CACVM,EAAA,CAAQL,CACR,MAHkB,CAMpBI,CAAA,CAAUJ,CACVK,EAAA,CAAQJ,CARU,CAApB,IAUO,CACLE,CAAA,CAASJ,CACTvB,EAAA,CAAOwB,CACPI,EAAA,CAAUH,CACV,MAJK,CAMT,KAAK,CAAL,CACMrB,CAAA,CAAWmB,CAAX,CAAJ,CAAoBK,CAApB,CAA8BL,CAA9B,CACSF,CAAJ,CAAarB,CAAb,CAAoBuB,CAApB,CACAI,CADA,CACSJ,CACd,MACF,MAAK,CAAL,CAAQ,KACR,SACE,KAAMvC,EAAA,CAAgB,SAAhB,CAEJ8C,SAAAnB,OAFI,CAAN,CA9BF,CAoCA,IAAIoB,EAAiB,IAAjBA,WAAiCf,EAArC,CACIpC,EAAQmD,CAAA,CAAiB/B,CAAjB,CAAyBmB,CAAAa,QAAA,CAAiB,EAAjB,CAAsB,IAAIhB,CAAJ,CAAahB,CAAb,CAD3D,CAEIiC,EAAa,EAFjB,CAGIC,EAAsBf,CAAAgB,YAAtBD,EAA4Cf,CAAAgB,YAAArB,SAA5CoB,EACsBrB,CAJ1B,CAKIuB,EAA2BjB,CAAAgB,YAA3BC,EAAiDjB,CAAAgB,YAAAE,cAAjDD,EACsB7D,CAE1BI,EAAA,CAAQwC,CAAR,CAAgB,QAAQ,CAACvC,CAAD,CAAQC,CAAR,CAAa,CACxB,QAAX,EAAIA,CAAJ,GAA8B,SAA9B,EAAuBA,CAAvB,EAAkD,aAAlD,EAA2CA,CAA3C,IACEoD,CAAA,CAAWpD,CAAX,CADF,CACoByD,CAAA,CAAK1D,CAAL,CADpB,CADmC,CAArC,CAMIyC,EAAJ,GAAaY,CAAAjC,KAAb,CAA+BA,CAA/B,CACAiB,EAAAsB,aAAA,CAAmBN,CAAnB,CACmB9B,CAAA,CAAO,EAAP,CAAWJ,CAAA,CAAcC,CAAd,CAAoBmB,CAAAQ,OAApB,EAAqC,EAArC,CAAX,CAAqDA,CAArD,CADnB,CAEmBR,CAAAvB,IAFnB,CAII4C,EAAAA,CAAUnD,CAAA,CAAM4C,CAAN,CAAAQ,KAAA,CAAuB,QAAQ,CAAC3B,CAAD,CAAW,CAAA,IAClDd,EAAOc,CAAAd,KAD2C,CAElDwC,EAAU5D,CAAA8D,SAEd,IAAI1C,CAAJ,CAAU,CAGR,GAAI1B,CAAA0D,QAAA,CAAgBhC,CAAhB,CAAJ,GAA+B,CAAC,CAACmB,CAAAa,QAAjC,CACE,KAAMhD,EAAA,CAAgB,QAAhB;AAEJmC,CAAAa,QAAA,CAAe,OAAf,CAAuB,QAFnB,CAE6B1D,CAAA0D,QAAA,CAAgBhC,CAAhB,CAAA,CAAsB,OAAtB,CAA8B,QAF3D,CAAN,CAKEmB,CAAAa,QAAJ,EACEpD,CAAA+B,OACA,CADe,CACf,CAAAhC,CAAA,CAAQqB,CAAR,CAAc,QAAQ,CAAC2C,CAAD,CAAO,CAC3B/D,CAAAgE,KAAA,CAAW,IAAI5B,CAAJ,CAAa2B,CAAb,CAAX,CAD2B,CAA7B,CAFF,GAMEnE,CAAA,CAAoBwB,CAApB,CAA0BpB,CAA1B,CACA,CAAAA,CAAA8D,SAAA,CAAiBF,CAPnB,CATQ,CAoBV5D,CAAAiE,UAAA,CAAkB,CAAA,CAElB/B,EAAAC,SAAA,CAAoBnC,CAEpB,OAAOkC,EA5B+C,CAA1C,CA6BX,QAAQ,CAACA,CAAD,CAAW,CACpBlC,CAAAiE,UAAA,CAAkB,CAAA,CAEjB,EAAAhB,CAAA,EAAOiB,CAAP,EAAahC,CAAb,CAED,OAAOxB,EAAAyD,OAAA,CAAUjC,CAAV,CALa,CA7BR,CAqCd0B,EAAA,CAAUA,CAAAC,KAAA,CACN,QAAQ,CAAC3B,CAAD,CAAW,CACjB,IAAIlC,EAAQsD,CAAA,CAAoBpB,CAApB,CACX,EAAAc,CAAA,EAASkB,CAAT,EAAelE,CAAf,CAAsBkC,CAAAkC,QAAtB,CACD,OAAOpE,EAHU,CADb,CAMNwD,CANM,CAQV,OAAKL,EAAL,CAWOS,CAXP,EAIE5D,CAAA8D,SAGO9D,CAHU4D,CAGV5D,CAFPA,CAAAiE,UAEOjE,CAFW,CAAA,CAEXA,CAAAA,CAPT,CAxGwC,CAuH1CoC,EAAAiC,UAAA,CAAmB,GAAnB,CAAyB7B,CAAzB,CAAA,CAAiC,QAAQ,CAACO,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAAyB,CAC5DzB,CAAA,CAAWuB,CAAX,CAAJ,GACEE,CAAmC,CAA3BD,CAA2B,CAAlBA,CAAkB,CAARD,CAAQ,CAAAA,CAAA,CAAS,EAD9C,CAGIuB,EAAAA,CAASlC,CAAA,CAASI,CAAT,CAAA+B,KAAA,CAAoB,IAApB,CAA0BxB,CAA1B,CAAkC,IAAlC,CAAwCC,CAAxC,CAAiDC,CAAjD,CACb,OAAOqB,EAAAR,SAAP,EAA0BQ,CALsC,CA1H5B,CAAxC,CAmIAlC,EAAAoC,KAAA,CAAgBC,QAAQ,CAACC,CAAD,CAAyB,CAC/C,MAAO3D,EAAA,CAAgBC,CAAhB,CAAqBO,CAAA,CAAO,EAAP,CAAWN,CAAX,CAA0ByD,CAA1B,CAArB,CAAyExD,CAAzE,CADwC,CAIjD,OAAOkB,EA/J6C,CAvHC;AAEvD,IAAIE,EAAkB,KACV,QAAQ,KAAR,CADU,MAEV,QAAQ,MAAR,CAFU,OAGV,QAAQ,KAAR,SAAuB,CAAA,CAAvB,CAHU,QAIV,QAAQ,QAAR,CAJU,CAKpB,QALoB,CAKV,QAAQ,QAAR,CALU,CAAtB,CAOI4B,EAAOxE,CAAAwE,KAPX,CAQInE,EAAUL,CAAAK,QARd,CASIwB,EAAS7B,CAAA6B,OATb,CAUImC,EAAOhE,CAAAgE,KAVX,CAWIlC,EAAa9B,CAAA8B,WA+CjBb,EAAA0D,UAAA,CAAkB,cACFV,QAAQ,CAACgB,CAAD,CAAS5B,CAAT,CAAiB6B,CAAjB,CAA4B,CAAA,IAC5CC,EAAO,IADqC,CAE5C7D,EAAM4D,CAAN5D,EAAmB6D,CAAAjE,SAFyB,CAG5CkE,CAH4C,CAI5CC,CAJ4C,CAM5CjE,EAAY+D,CAAA/D,UAAZA,CAA6B,EACjCf,EAAA,CAAQiB,CAAAY,MAAA,CAAU,IAAV,CAAR,CAAyB,QAAQ,CAACoD,CAAD,CAAO,CACtC,GAAc,gBAAd,GAAIA,CAAJ,CACE,KAAM5E,EAAA,CAAgB,SAAhB,CAAN,CAEI,CAAA,OAAAsB,KAAA,CAA0BsD,CAA1B,CAAN,GAA2CA,CAA3C,EACUC,MAAJ,CAAW,cAAX,CAA4BD,CAA5B,CAAoC,SAApC,CAAAtD,KAAA,CAAoDV,CAApD,CADN,IAEEF,CAAA,CAAUkE,CAAV,CAFF,CAEqB,CAAA,CAFrB,CAJsC,CAAxC,CASAhE,EAAA,CAAMA,CAAAkE,QAAA,CAAY,MAAZ,CAAoB,GAApB,CAENnC,EAAA,CAASA,CAAT,EAAmB,EACnBhD,EAAA,CAAQ8E,CAAA/D,UAAR,CAAwB,QAAQ,CAACqE,CAAD,CAAIC,CAAJ,CAAa,CAC3CN,CAAA,CAAM/B,CAAA7C,eAAA,CAAsBkF,CAAtB,CAAA;AAAkCrC,CAAA,CAAOqC,CAAP,CAAlC,CAAqDP,CAAAhE,SAAA,CAAcuE,CAAd,CACvD1F,EAAA2F,UAAA,CAAkBP,CAAlB,CAAJ,EAAsC,IAAtC,GAA8BA,CAA9B,EACEC,CACA,CAtCCO,kBAAA,CAqC6BR,CArC7B,CAAAI,QAAA,CACG,OADH,CACY,GADZ,CAAAA,QAAA,CAEG,OAFH,CAEY,GAFZ,CAAAA,QAAA,CAGG,MAHH,CAGW,GAHX,CAAAA,QAAA,CAIG,OAJH,CAIY,GAJZ,CAAAA,QAAA,CAKG,MALH,CAK8B,KAL9B,CAnBAA,QAAA,CACG,OADH,CACY,GADZ,CAAAA,QAAA,CAEG,OAFH,CAEY,GAFZ,CAAAA,QAAA,CAGG,OAHH,CAGY,GAHZ,CAyDD,CAAAlE,CAAA,CAAMA,CAAAkE,QAAA,CAAgBD,MAAJ,CAAW,GAAX,CAAiBG,CAAjB,CAA4B,SAA5B,CAAuC,GAAvC,CAAZ,CAAyD,QAAQ,CAACG,CAAD,CAAQC,CAAR,CAAY,CACjF,MAAOT,EAAP,CAAoBS,CAD6D,CAA7E,CAFR,EAMExE,CANF,CAMQA,CAAAkE,QAAA,CAAgBD,MAAJ,CAAW,OAAX,CAAsBG,CAAtB,CAAiC,SAAjC,CAA4C,GAA5C,CAAZ,CAA8D,QAAQ,CAACG,CAAD,CACxEE,CADwE,CACxDC,CADwD,CAClD,CACxB,MAAsB,GAAtB,EAAIA,CAAAvF,OAAA,CAAY,CAAZ,CAAJ,CACSuF,CADT,CAGSD,CAHT,CAG0BC,CAJF,CADpB,CARmC,CAA7C,CAoBA1E,EAAA,CAAMA,CAAAkE,QAAA,CAAY,MAAZ,CAAoB,EAApB,CAAN,EAAiC,GAGjClE,EAAA,CAAMA,CAAAkE,QAAA,CAAY,mBAAZ,CAAiC,GAAjC,CAENP,EAAA3D,IAAA,CAAaA,CAAAkE,QAAA,CAAY,QAAZ,CAAsB,IAAtB,CAIbnF,EAAA,CAAQgD,CAAR,CAAgB,QAAQ,CAAC/C,CAAD;AAAQC,CAAR,CAAY,CAC7B4E,CAAA/D,UAAA,CAAeb,CAAf,CAAL,GACE0E,CAAA5B,OACA,CADgB4B,CAAA5B,OAChB,EADiC,EACjC,CAAA4B,CAAA5B,OAAA,CAAc9C,CAAd,CAAA,CAAqBD,CAFvB,CADkC,CAApC,CAhDgD,CADlC,CA6NlB,OAAOe,EAzRgD,CAApC,CADvB,CAhTsC,CAArC,CAAA,CA8kBEtB,MA9kBF,CA8kBUA,MAAAC,QA9kBV;",
  6 +"sources":["angular-resource.js"],
  7 +"names":["window","angular","undefined","shallowClearAndCopy","src","dst","forEach","value","key","hasOwnProperty","charAt","$resourceMinErr","$$minErr","MEMBER_NAME_REGEX","module","factory","$http","$q","Route","template","defaults","urlParams","resourceFactory","url","paramDefaults","actions","extractParams","data","actionParams","ids","extend","isFunction","path","test","keys","split","i","ii","length","obj","defaultResponseInterceptor","response","resource","Resource","route","DEFAULT_ACTIONS","action","name","hasBody","method","a1","a2","a3","a4","params","success","error","arguments","isInstanceCall","isArray","httpConfig","responseInterceptor","interceptor","responseErrorInterceptor","responseError","copy","setUrlParams","promise","then","$promise","item","push","$resolved","noop","reject","headers","prototype","result","call","bind","Resource.bind","additionalParamDefaults","config","actionUrl","self","val","encodedVal","param","RegExp","replace","_","urlParam","isDefined","encodeURIComponent","match","p1","leadingSlashes","tail"]
  8 +}
  1 +/**
  2 + * @license AngularJS v1.2.13
  3 + * (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + * License: MIT
  5 + */
  6 +(function(window, angular, undefined) {'use strict';
  7 +
  8 +/**
  9 + * @ngdoc overview
  10 + * @name ngRoute
  11 + * @description
  12 + *
  13 + * # ngRoute
  14 + *
  15 + * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
  16 + *
  17 + * ## Example
  18 + * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
  19 + *
  20 + * {@installModule route}
  21 + *
  22 + * <div doc-module-components="ngRoute"></div>
  23 + */
  24 + /* global -ngRouteModule */
  25 +var ngRouteModule = angular.module('ngRoute', ['ng']).
  26 + provider('$route', $RouteProvider);
  27 +
  28 +/**
  29 + * @ngdoc object
  30 + * @name ngRoute.$routeProvider
  31 + * @function
  32 + *
  33 + * @description
  34 + *
  35 + * Used for configuring routes.
  36 + *
  37 + * ## Example
  38 + * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
  39 + *
  40 + * ## Dependencies
  41 + * Requires the {@link ngRoute `ngRoute`} module to be installed.
  42 + */
  43 +function $RouteProvider(){
  44 + function inherit(parent, extra) {
  45 + return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
  46 + }
  47 +
  48 + var routes = {};
  49 +
  50 + /**
  51 + * @ngdoc method
  52 + * @name ngRoute.$routeProvider#when
  53 + * @methodOf ngRoute.$routeProvider
  54 + *
  55 + * @param {string} path Route path (matched against `$location.path`). If `$location.path`
  56 + * contains redundant trailing slash or is missing one, the route will still match and the
  57 + * `$location.path` will be updated to add or drop the trailing slash to exactly match the
  58 + * route definition.
  59 + *
  60 + * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
  61 + * to the next slash are matched and stored in `$routeParams` under the given `name`
  62 + * when the route matches.
  63 + * * `path` can contain named groups starting with a colon and ending with a star:
  64 + * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
  65 + * when the route matches.
  66 + * * `path` can contain optional named groups with a question mark: e.g.`:name?`.
  67 + *
  68 + * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
  69 + * `/color/brown/largecode/code/with/slashs/edit` and extract:
  70 + *
  71 + * * `color: brown`
  72 + * * `largecode: code/with/slashs`.
  73 + *
  74 + *
  75 + * @param {Object} route Mapping information to be assigned to `$route.current` on route
  76 + * match.
  77 + *
  78 + * Object properties:
  79 + *
  80 + * - `controller` – `{(string|function()=}` – Controller fn that should be associated with
  81 + * newly created scope or the name of a {@link angular.Module#controller registered
  82 + * controller} if passed as a string.
  83 + * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
  84 + * published to scope under the `controllerAs` name.
  85 + * - `template` – `{string=|function()=}` – html template as a string or a function that
  86 + * returns an html template as a string which should be used by {@link
  87 + * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
  88 + * This property takes precedence over `templateUrl`.
  89 + *
  90 + * If `template` is a function, it will be called with the following parameters:
  91 + *
  92 + * - `{Array.<Object>}` - route parameters extracted from the current
  93 + * `$location.path()` by applying the current route
  94 + *
  95 + * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
  96 + * template that should be used by {@link ngRoute.directive:ngView ngView}.
  97 + *
  98 + * If `templateUrl` is a function, it will be called with the following parameters:
  99 + *
  100 + * - `{Array.<Object>}` - route parameters extracted from the current
  101 + * `$location.path()` by applying the current route
  102 + *
  103 + * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
  104 + * be injected into the controller. If any of these dependencies are promises, the router
  105 + * will wait for them all to be resolved or one to be rejected before the controller is
  106 + * instantiated.
  107 + * If all the promises are resolved successfully, the values of the resolved promises are
  108 + * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
  109 + * fired. If any of the promises are rejected the
  110 + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
  111 + * is:
  112 + *
  113 + * - `key` – `{string}`: a name of a dependency to be injected into the controller.
  114 + * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
  115 + * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
  116 + * and the return value is treated as the dependency. If the result is a promise, it is
  117 + * resolved before its value is injected into the controller. Be aware that
  118 + * `ngRoute.$routeParams` will still refer to the previous route within these resolve
  119 + * functions. Use `$route.current.params` to access the new route parameters, instead.
  120 + *
  121 + * - `redirectTo` – {(string|function())=} – value to update
  122 + * {@link ng.$location $location} path with and trigger route redirection.
  123 + *
  124 + * If `redirectTo` is a function, it will be called with the following parameters:
  125 + *
  126 + * - `{Object.<string>}` - route parameters extracted from the current
  127 + * `$location.path()` by applying the current route templateUrl.
  128 + * - `{string}` - current `$location.path()`
  129 + * - `{Object}` - current `$location.search()`
  130 + *
  131 + * The custom `redirectTo` function is expected to return a string which will be used
  132 + * to update `$location.path()` and `$location.search()`.
  133 + *
  134 + * - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
  135 + * or `$location.hash()` changes.
  136 + *
  137 + * If the option is set to `false` and url in the browser changes, then
  138 + * `$routeUpdate` event is broadcasted on the root scope.
  139 + *
  140 + * - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
  141 + *
  142 + * If the option is set to `true`, then the particular route can be matched without being
  143 + * case sensitive
  144 + *
  145 + * @returns {Object} self
  146 + *
  147 + * @description
  148 + * Adds a new route definition to the `$route` service.
  149 + */
  150 + this.when = function(path, route) {
  151 + routes[path] = angular.extend(
  152 + {reloadOnSearch: true},
  153 + route,
  154 + path && pathRegExp(path, route)
  155 + );
  156 +
  157 + // create redirection for trailing slashes
  158 + if (path) {
  159 + var redirectPath = (path[path.length-1] == '/')
  160 + ? path.substr(0, path.length-1)
  161 + : path +'/';
  162 +
  163 + routes[redirectPath] = angular.extend(
  164 + {redirectTo: path},
  165 + pathRegExp(redirectPath, route)
  166 + );
  167 + }
  168 +
  169 + return this;
  170 + };
  171 +
  172 + /**
  173 + * @param path {string} path
  174 + * @param opts {Object} options
  175 + * @return {?Object}
  176 + *
  177 + * @description
  178 + * Normalizes the given path, returning a regular expression
  179 + * and the original path.
  180 + *
  181 + * Inspired by pathRexp in visionmedia/express/lib/utils.js.
  182 + */
  183 + function pathRegExp(path, opts) {
  184 + var insensitive = opts.caseInsensitiveMatch,
  185 + ret = {
  186 + originalPath: path,
  187 + regexp: path
  188 + },
  189 + keys = ret.keys = [];
  190 +
  191 + path = path
  192 + .replace(/([().])/g, '\\$1')
  193 + .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
  194 + var optional = option === '?' ? option : null;
  195 + var star = option === '*' ? option : null;
  196 + keys.push({ name: key, optional: !!optional });
  197 + slash = slash || '';
  198 + return ''
  199 + + (optional ? '' : slash)
  200 + + '(?:'
  201 + + (optional ? slash : '')
  202 + + (star && '(.+?)' || '([^/]+)')
  203 + + (optional || '')
  204 + + ')'
  205 + + (optional || '');
  206 + })
  207 + .replace(/([\/$\*])/g, '\\$1');
  208 +
  209 + ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
  210 + return ret;
  211 + }
  212 +
  213 + /**
  214 + * @ngdoc method
  215 + * @name ngRoute.$routeProvider#otherwise
  216 + * @methodOf ngRoute.$routeProvider
  217 + *
  218 + * @description
  219 + * Sets route definition that will be used on route change when no other route definition
  220 + * is matched.
  221 + *
  222 + * @param {Object} params Mapping information to be assigned to `$route.current`.
  223 + * @returns {Object} self
  224 + */
  225 + this.otherwise = function(params) {
  226 + this.when(null, params);
  227 + return this;
  228 + };
  229 +
  230 +
  231 + this.$get = ['$rootScope',
  232 + '$location',
  233 + '$routeParams',
  234 + '$q',
  235 + '$injector',
  236 + '$http',
  237 + '$templateCache',
  238 + '$sce',
  239 + function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
  240 +
  241 + /**
  242 + * @ngdoc object
  243 + * @name ngRoute.$route
  244 + * @requires $location
  245 + * @requires $routeParams
  246 + *
  247 + * @property {Object} current Reference to the current route definition.
  248 + * The route definition contains:
  249 + *
  250 + * - `controller`: The controller constructor as define in route definition.
  251 + * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
  252 + * controller instantiation. The `locals` contain
  253 + * the resolved values of the `resolve` map. Additionally the `locals` also contain:
  254 + *
  255 + * - `$scope` - The current route scope.
  256 + * - `$template` - The current route template HTML.
  257 + *
  258 + * @property {Array.<Object>} routes Array of all configured routes.
  259 + *
  260 + * @description
  261 + * `$route` is used for deep-linking URLs to controllers and views (HTML partials).
  262 + * It watches `$location.url()` and tries to map the path to an existing route definition.
  263 + *
  264 + * Requires the {@link ngRoute `ngRoute`} module to be installed.
  265 + *
  266 + * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
  267 + *
  268 + * The `$route` service is typically used in conjunction with the
  269 + * {@link ngRoute.directive:ngView `ngView`} directive and the
  270 + * {@link ngRoute.$routeParams `$routeParams`} service.
  271 + *
  272 + * @example
  273 + This example shows how changing the URL hash causes the `$route` to match a route against the
  274 + URL, and the `ngView` pulls in the partial.
  275 +
  276 + Note that this example is using {@link ng.directive:script inlined templates}
  277 + to get it working on jsfiddle as well.
  278 +
  279 + <example module="ngViewExample" deps="angular-route.js">
  280 + <file name="index.html">
  281 + <div ng-controller="MainCntl">
  282 + Choose:
  283 + <a href="Book/Moby">Moby</a> |
  284 + <a href="Book/Moby/ch/1">Moby: Ch1</a> |
  285 + <a href="Book/Gatsby">Gatsby</a> |
  286 + <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
  287 + <a href="Book/Scarlet">Scarlet Letter</a><br/>
  288 +
  289 + <div ng-view></div>
  290 + <hr />
  291 +
  292 + <pre>$location.path() = {{$location.path()}}</pre>
  293 + <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
  294 + <pre>$route.current.params = {{$route.current.params}}</pre>
  295 + <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
  296 + <pre>$routeParams = {{$routeParams}}</pre>
  297 + </div>
  298 + </file>
  299 +
  300 + <file name="book.html">
  301 + controller: {{name}}<br />
  302 + Book Id: {{params.bookId}}<br />
  303 + </file>
  304 +
  305 + <file name="chapter.html">
  306 + controller: {{name}}<br />
  307 + Book Id: {{params.bookId}}<br />
  308 + Chapter Id: {{params.chapterId}}
  309 + </file>
  310 +
  311 + <file name="script.js">
  312 + angular.module('ngViewExample', ['ngRoute'])
  313 +
  314 + .config(function($routeProvider, $locationProvider) {
  315 + $routeProvider.when('/Book/:bookId', {
  316 + templateUrl: 'book.html',
  317 + controller: BookCntl,
  318 + resolve: {
  319 + // I will cause a 1 second delay
  320 + delay: function($q, $timeout) {
  321 + var delay = $q.defer();
  322 + $timeout(delay.resolve, 1000);
  323 + return delay.promise;
  324 + }
  325 + }
  326 + });
  327 + $routeProvider.when('/Book/:bookId/ch/:chapterId', {
  328 + templateUrl: 'chapter.html',
  329 + controller: ChapterCntl
  330 + });
  331 +
  332 + // configure html5 to get links working on jsfiddle
  333 + $locationProvider.html5Mode(true);
  334 + });
  335 +
  336 + function MainCntl($scope, $route, $routeParams, $location) {
  337 + $scope.$route = $route;
  338 + $scope.$location = $location;
  339 + $scope.$routeParams = $routeParams;
  340 + }
  341 +
  342 + function BookCntl($scope, $routeParams) {
  343 + $scope.name = "BookCntl";
  344 + $scope.params = $routeParams;
  345 + }
  346 +
  347 + function ChapterCntl($scope, $routeParams) {
  348 + $scope.name = "ChapterCntl";
  349 + $scope.params = $routeParams;
  350 + }
  351 + </file>
  352 +
  353 + <file name="protractorTest.js">
  354 + it('should load and compile correct template', function() {
  355 + element(by.linkText('Moby: Ch1')).click();
  356 + var content = element(by.css('.doc-example-live [ng-view]')).getText();
  357 + expect(content).toMatch(/controller\: ChapterCntl/);
  358 + expect(content).toMatch(/Book Id\: Moby/);
  359 + expect(content).toMatch(/Chapter Id\: 1/);
  360 +
  361 + element(by.partialLinkText('Scarlet')).click();
  362 +
  363 + content = element(by.css('.doc-example-live [ng-view]')).getText();
  364 + expect(content).toMatch(/controller\: BookCntl/);
  365 + expect(content).toMatch(/Book Id\: Scarlet/);
  366 + });
  367 + </file>
  368 + </example>
  369 + */
  370 +
  371 + /**
  372 + * @ngdoc event
  373 + * @name ngRoute.$route#$routeChangeStart
  374 + * @eventOf ngRoute.$route
  375 + * @eventType broadcast on root scope
  376 + * @description
  377 + * Broadcasted before a route change. At this point the route services starts
  378 + * resolving all of the dependencies needed for the route change to occur.
  379 + * Typically this involves fetching the view template as well as any dependencies
  380 + * defined in `resolve` route property. Once all of the dependencies are resolved
  381 + * `$routeChangeSuccess` is fired.
  382 + *
  383 + * @param {Object} angularEvent Synthetic event object.
  384 + * @param {Route} next Future route information.
  385 + * @param {Route} current Current route information.
  386 + */
  387 +
  388 + /**
  389 + * @ngdoc event
  390 + * @name ngRoute.$route#$routeChangeSuccess
  391 + * @eventOf ngRoute.$route
  392 + * @eventType broadcast on root scope
  393 + * @description
  394 + * Broadcasted after a route dependencies are resolved.
  395 + * {@link ngRoute.directive:ngView ngView} listens for the directive
  396 + * to instantiate the controller and render the view.
  397 + *
  398 + * @param {Object} angularEvent Synthetic event object.
  399 + * @param {Route} current Current route information.
  400 + * @param {Route|Undefined} previous Previous route information, or undefined if current is
  401 + * first route entered.
  402 + */
  403 +
  404 + /**
  405 + * @ngdoc event
  406 + * @name ngRoute.$route#$routeChangeError
  407 + * @eventOf ngRoute.$route
  408 + * @eventType broadcast on root scope
  409 + * @description
  410 + * Broadcasted if any of the resolve promises are rejected.
  411 + *
  412 + * @param {Object} angularEvent Synthetic event object
  413 + * @param {Route} current Current route information.
  414 + * @param {Route} previous Previous route information.
  415 + * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
  416 + */
  417 +
  418 + /**
  419 + * @ngdoc event
  420 + * @name ngRoute.$route#$routeUpdate
  421 + * @eventOf ngRoute.$route
  422 + * @eventType broadcast on root scope
  423 + * @description
  424 + *
  425 + * The `reloadOnSearch` property has been set to false, and we are reusing the same
  426 + * instance of the Controller.
  427 + */
  428 +
  429 + var forceReload = false,
  430 + $route = {
  431 + routes: routes,
  432 +
  433 + /**
  434 + * @ngdoc method
  435 + * @name ngRoute.$route#reload
  436 + * @methodOf ngRoute.$route
  437 + *
  438 + * @description
  439 + * Causes `$route` service to reload the current route even if
  440 + * {@link ng.$location $location} hasn't changed.
  441 + *
  442 + * As a result of that, {@link ngRoute.directive:ngView ngView}
  443 + * creates new scope, reinstantiates the controller.
  444 + */
  445 + reload: function() {
  446 + forceReload = true;
  447 + $rootScope.$evalAsync(updateRoute);
  448 + }
  449 + };
  450 +
  451 + $rootScope.$on('$locationChangeSuccess', updateRoute);
  452 +
  453 + return $route;
  454 +
  455 + /////////////////////////////////////////////////////
  456 +
  457 + /**
  458 + * @param on {string} current url
  459 + * @param route {Object} route regexp to match the url against
  460 + * @return {?Object}
  461 + *
  462 + * @description
  463 + * Check if the route matches the current url.
  464 + *
  465 + * Inspired by match in
  466 + * visionmedia/express/lib/router/router.js.
  467 + */
  468 + function switchRouteMatcher(on, route) {
  469 + var keys = route.keys,
  470 + params = {};
  471 +
  472 + if (!route.regexp) return null;
  473 +
  474 + var m = route.regexp.exec(on);
  475 + if (!m) return null;
  476 +
  477 + for (var i = 1, len = m.length; i < len; ++i) {
  478 + var key = keys[i - 1];
  479 +
  480 + var val = 'string' == typeof m[i]
  481 + ? decodeURIComponent(m[i])
  482 + : m[i];
  483 +
  484 + if (key && val) {
  485 + params[key.name] = val;
  486 + }
  487 + }
  488 + return params;
  489 + }
  490 +
  491 + function updateRoute() {
  492 + var next = parseRoute(),
  493 + last = $route.current;
  494 +
  495 + if (next && last && next.$$route === last.$$route
  496 + && angular.equals(next.pathParams, last.pathParams)
  497 + && !next.reloadOnSearch && !forceReload) {
  498 + last.params = next.params;
  499 + angular.copy(last.params, $routeParams);
  500 + $rootScope.$broadcast('$routeUpdate', last);
  501 + } else if (next || last) {
  502 + forceReload = false;
  503 + $rootScope.$broadcast('$routeChangeStart', next, last);
  504 + $route.current = next;
  505 + if (next) {
  506 + if (next.redirectTo) {
  507 + if (angular.isString(next.redirectTo)) {
  508 + $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
  509 + .replace();
  510 + } else {
  511 + $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
  512 + .replace();
  513 + }
  514 + }
  515 + }
  516 +
  517 + $q.when(next).
  518 + then(function() {
  519 + if (next) {
  520 + var locals = angular.extend({}, next.resolve),
  521 + template, templateUrl;
  522 +
  523 + angular.forEach(locals, function(value, key) {
  524 + locals[key] = angular.isString(value) ?
  525 + $injector.get(value) : $injector.invoke(value);
  526 + });
  527 +
  528 + if (angular.isDefined(template = next.template)) {
  529 + if (angular.isFunction(template)) {
  530 + template = template(next.params);
  531 + }
  532 + } else if (angular.isDefined(templateUrl = next.templateUrl)) {
  533 + if (angular.isFunction(templateUrl)) {
  534 + templateUrl = templateUrl(next.params);
  535 + }
  536 + templateUrl = $sce.getTrustedResourceUrl(templateUrl);
  537 + if (angular.isDefined(templateUrl)) {
  538 + next.loadedTemplateUrl = templateUrl;
  539 + template = $http.get(templateUrl, {cache: $templateCache}).
  540 + then(function(response) { return response.data; });
  541 + }
  542 + }
  543 + if (angular.isDefined(template)) {
  544 + locals['$template'] = template;
  545 + }
  546 + return $q.all(locals);
  547 + }
  548 + }).
  549 + // after route change
  550 + then(function(locals) {
  551 + if (next == $route.current) {
  552 + if (next) {
  553 + next.locals = locals;
  554 + angular.copy(next.params, $routeParams);
  555 + }
  556 + $rootScope.$broadcast('$routeChangeSuccess', next, last);
  557 + }
  558 + }, function(error) {
  559 + if (next == $route.current) {
  560 + $rootScope.$broadcast('$routeChangeError', next, last, error);
  561 + }
  562 + });
  563 + }
  564 + }
  565 +
  566 +
  567 + /**
  568 + * @returns the current active route, by matching it against the URL
  569 + */
  570 + function parseRoute() {
  571 + // Match a route
  572 + var params, match;
  573 + angular.forEach(routes, function(route, path) {
  574 + if (!match && (params = switchRouteMatcher($location.path(), route))) {
  575 + match = inherit(route, {
  576 + params: angular.extend({}, $location.search(), params),
  577 + pathParams: params});
  578 + match.$$route = route;
  579 + }
  580 + });
  581 + // No route matched; fallback to "otherwise" route
  582 + return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
  583 + }
  584 +
  585 + /**
  586 + * @returns interpolation of the redirect path with the parameters
  587 + */
  588 + function interpolate(string, params) {
  589 + var result = [];
  590 + angular.forEach((string||'').split(':'), function(segment, i) {
  591 + if (i === 0) {
  592 + result.push(segment);
  593 + } else {
  594 + var segmentMatch = segment.match(/(\w+)(.*)/);
  595 + var key = segmentMatch[1];
  596 + result.push(params[key]);
  597 + result.push(segmentMatch[2] || '');
  598 + delete params[key];
  599 + }
  600 + });
  601 + return result.join('');
  602 + }
  603 + }];
  604 +}
  605 +
  606 +ngRouteModule.provider('$routeParams', $RouteParamsProvider);
  607 +
  608 +
  609 +/**
  610 + * @ngdoc object
  611 + * @name ngRoute.$routeParams
  612 + * @requires $route
  613 + *
  614 + * @description
  615 + * The `$routeParams` service allows you to retrieve the current set of route parameters.
  616 + *
  617 + * Requires the {@link ngRoute `ngRoute`} module to be installed.
  618 + *
  619 + * The route parameters are a combination of {@link ng.$location `$location`}'s
  620 + * {@link ng.$location#methods_search `search()`} and {@link ng.$location#methods_path `path()`}.
  621 + * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
  622 + *
  623 + * In case of parameter name collision, `path` params take precedence over `search` params.
  624 + *
  625 + * The service guarantees that the identity of the `$routeParams` object will remain unchanged
  626 + * (but its properties will likely change) even when a route change occurs.
  627 + *
  628 + * Note that the `$routeParams` are only updated *after* a route change completes successfully.
  629 + * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
  630 + * Instead you can use `$route.current.params` to access the new route's parameters.
  631 + *
  632 + * @example
  633 + * <pre>
  634 + * // Given:
  635 + * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
  636 + * // Route: /Chapter/:chapterId/Section/:sectionId
  637 + * //
  638 + * // Then
  639 + * $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
  640 + * </pre>
  641 + */
  642 +function $RouteParamsProvider() {
  643 + this.$get = function() { return {}; };
  644 +}
  645 +
  646 +ngRouteModule.directive('ngView', ngViewFactory);
  647 +ngRouteModule.directive('ngView', ngViewFillContentFactory);
  648 +
  649 +
  650 +/**
  651 + * @ngdoc directive
  652 + * @name ngRoute.directive:ngView
  653 + * @restrict ECA
  654 + *
  655 + * @description
  656 + * # Overview
  657 + * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
  658 + * including the rendered template of the current route into the main layout (`index.html`) file.
  659 + * Every time the current route changes, the included view changes with it according to the
  660 + * configuration of the `$route` service.
  661 + *
  662 + * Requires the {@link ngRoute `ngRoute`} module to be installed.
  663 + *
  664 + * @animations
  665 + * enter - animation is used to bring new content into the browser.
  666 + * leave - animation is used to animate existing content away.
  667 + *
  668 + * The enter and leave animation occur concurrently.
  669 + *
  670 + * @scope
  671 + * @priority 400
  672 + * @param {string=} onload Expression to evaluate whenever the view updates.
  673 + *
  674 + * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
  675 + * $anchorScroll} to scroll the viewport after the view is updated.
  676 + *
  677 + * - If the attribute is not set, disable scrolling.
  678 + * - If the attribute is set without value, enable scrolling.
  679 + * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
  680 + * as an expression yields a truthy value.
  681 + * @example
  682 + <example module="ngViewExample" deps="angular-route.js" animations="true">
  683 + <file name="index.html">
  684 + <div ng-controller="MainCntl as main">
  685 + Choose:
  686 + <a href="Book/Moby">Moby</a> |
  687 + <a href="Book/Moby/ch/1">Moby: Ch1</a> |
  688 + <a href="Book/Gatsby">Gatsby</a> |
  689 + <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
  690 + <a href="Book/Scarlet">Scarlet Letter</a><br/>
  691 +
  692 + <div class="view-animate-container">
  693 + <div ng-view class="view-animate"></div>
  694 + </div>
  695 + <hr />
  696 +
  697 + <pre>$location.path() = {{main.$location.path()}}</pre>
  698 + <pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
  699 + <pre>$route.current.params = {{main.$route.current.params}}</pre>
  700 + <pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
  701 + <pre>$routeParams = {{main.$routeParams}}</pre>
  702 + </div>
  703 + </file>
  704 +
  705 + <file name="book.html">
  706 + <div>
  707 + controller: {{book.name}}<br />
  708 + Book Id: {{book.params.bookId}}<br />
  709 + </div>
  710 + </file>
  711 +
  712 + <file name="chapter.html">
  713 + <div>
  714 + controller: {{chapter.name}}<br />
  715 + Book Id: {{chapter.params.bookId}}<br />
  716 + Chapter Id: {{chapter.params.chapterId}}
  717 + </div>
  718 + </file>
  719 +
  720 + <file name="animations.css">
  721 + .view-animate-container {
  722 + position:relative;
  723 + height:100px!important;
  724 + position:relative;
  725 + background:white;
  726 + border:1px solid black;
  727 + height:40px;
  728 + overflow:hidden;
  729 + }
  730 +
  731 + .view-animate {
  732 + padding:10px;
  733 + }
  734 +
  735 + .view-animate.ng-enter, .view-animate.ng-leave {
  736 + -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
  737 + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
  738 +
  739 + display:block;
  740 + width:100%;
  741 + border-left:1px solid black;
  742 +
  743 + position:absolute;
  744 + top:0;
  745 + left:0;
  746 + right:0;
  747 + bottom:0;
  748 + padding:10px;
  749 + }
  750 +
  751 + .view-animate.ng-enter {
  752 + left:100%;
  753 + }
  754 + .view-animate.ng-enter.ng-enter-active {
  755 + left:0;
  756 + }
  757 + .view-animate.ng-leave.ng-leave-active {
  758 + left:-100%;
  759 + }
  760 + </file>
  761 +
  762 + <file name="script.js">
  763 + angular.module('ngViewExample', ['ngRoute', 'ngAnimate'],
  764 + function($routeProvider, $locationProvider) {
  765 + $routeProvider.when('/Book/:bookId', {
  766 + templateUrl: 'book.html',
  767 + controller: BookCntl,
  768 + controllerAs: 'book'
  769 + });
  770 + $routeProvider.when('/Book/:bookId/ch/:chapterId', {
  771 + templateUrl: 'chapter.html',
  772 + controller: ChapterCntl,
  773 + controllerAs: 'chapter'
  774 + });
  775 +
  776 + // configure html5 to get links working on jsfiddle
  777 + $locationProvider.html5Mode(true);
  778 + });
  779 +
  780 + function MainCntl($route, $routeParams, $location) {
  781 + this.$route = $route;
  782 + this.$location = $location;
  783 + this.$routeParams = $routeParams;
  784 + }
  785 +
  786 + function BookCntl($routeParams) {
  787 + this.name = "BookCntl";
  788 + this.params = $routeParams;
  789 + }
  790 +
  791 + function ChapterCntl($routeParams) {
  792 + this.name = "ChapterCntl";
  793 + this.params = $routeParams;
  794 + }
  795 + </file>
  796 +
  797 + <file name="protractorTest.js">
  798 + it('should load and compile correct template', function() {
  799 + element(by.linkText('Moby: Ch1')).click();
  800 + var content = element(by.css('.doc-example-live [ng-view]')).getText();
  801 + expect(content).toMatch(/controller\: ChapterCntl/);
  802 + expect(content).toMatch(/Book Id\: Moby/);
  803 + expect(content).toMatch(/Chapter Id\: 1/);
  804 +
  805 + element(by.partialLinkText('Scarlet')).click();
  806 +
  807 + content = element(by.css('.doc-example-live [ng-view]')).getText();
  808 + expect(content).toMatch(/controller\: BookCntl/);
  809 + expect(content).toMatch(/Book Id\: Scarlet/);
  810 + });
  811 + </file>
  812 + </example>
  813 + */
  814 +
  815 +
  816 +/**
  817 + * @ngdoc event
  818 + * @name ngRoute.directive:ngView#$viewContentLoaded
  819 + * @eventOf ngRoute.directive:ngView
  820 + * @eventType emit on the current ngView scope
  821 + * @description
  822 + * Emitted every time the ngView content is reloaded.
  823 + */
  824 +ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
  825 +function ngViewFactory( $route, $anchorScroll, $animate) {
  826 + return {
  827 + restrict: 'ECA',
  828 + terminal: true,
  829 + priority: 400,
  830 + transclude: 'element',
  831 + link: function(scope, $element, attr, ctrl, $transclude) {
  832 + var currentScope,
  833 + currentElement,
  834 + autoScrollExp = attr.autoscroll,
  835 + onloadExp = attr.onload || '';
  836 +
  837 + scope.$on('$routeChangeSuccess', update);
  838 + update();
  839 +
  840 + function cleanupLastView() {
  841 + if (currentScope) {
  842 + currentScope.$destroy();
  843 + currentScope = null;
  844 + }
  845 + if(currentElement) {
  846 + $animate.leave(currentElement);
  847 + currentElement = null;
  848 + }
  849 + }
  850 +
  851 + function update() {
  852 + var locals = $route.current && $route.current.locals,
  853 + template = locals && locals.$template;
  854 +
  855 + if (angular.isDefined(template)) {
  856 + var newScope = scope.$new();
  857 + var current = $route.current;
  858 +
  859 + // Note: This will also link all children of ng-view that were contained in the original
  860 + // html. If that content contains controllers, ... they could pollute/change the scope.
  861 + // However, using ng-view on an element with additional content does not make sense...
  862 + // Note: We can't remove them in the cloneAttchFn of $transclude as that
  863 + // function is called before linking the content, which would apply child
  864 + // directives to non existing elements.
  865 + var clone = $transclude(newScope, function(clone) {
  866 + $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
  867 + if (angular.isDefined(autoScrollExp)
  868 + && (!autoScrollExp || scope.$eval(autoScrollExp))) {
  869 + $anchorScroll();
  870 + }
  871 + });
  872 + cleanupLastView();
  873 + });
  874 +
  875 + currentElement = clone;
  876 + currentScope = current.scope = newScope;
  877 + currentScope.$emit('$viewContentLoaded');
  878 + currentScope.$eval(onloadExp);
  879 + } else {
  880 + cleanupLastView();
  881 + }
  882 + }
  883 + }
  884 + };
  885 +}
  886 +
  887 +// This directive is called during the $transclude call of the first `ngView` directive.
  888 +// It will replace and compile the content of the element with the loaded template.
  889 +// We need this directive so that the element content is already filled when
  890 +// the link function of another directive on the same element as ngView
  891 +// is called.
  892 +ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
  893 +function ngViewFillContentFactory($compile, $controller, $route) {
  894 + return {
  895 + restrict: 'ECA',
  896 + priority: -400,
  897 + link: function(scope, $element) {
  898 + var current = $route.current,
  899 + locals = current.locals;
  900 +
  901 + $element.html(locals.$template);
  902 +
  903 + var link = $compile($element.contents());
  904 +
  905 + if (current.controller) {
  906 + locals.$scope = scope;
  907 + var controller = $controller(current.controller, locals);
  908 + if (current.controllerAs) {
  909 + scope[current.controllerAs] = controller;
  910 + }
  911 + $element.data('$ngControllerController', controller);
  912 + $element.children().data('$ngControllerController', controller);
  913 + }
  914 +
  915 + link(scope);
  916 + }
  917 + };
  918 +}
  919 +
  920 +
  921 +})(window, window.angular);
  1 +/*
  2 + AngularJS v1.2.13
  3 + (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + License: MIT
  5 +*/
  6 +(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||"";
  7 +a.$on("$routeChangeSuccess",v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a,
  8 +e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&q(a,c));if(a){var b="/"==a[a.length-1]?a.substr(0,a.length-
  9 +1):a+"/";k[b]=e.extend({redirectTo:a},q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current=
  10 +d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b,
  11 +{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g<q;++g){var n=p[g-1],r="string"==typeof s[g]?decodeURIComponent(s[g]):s[g];
  12 +n&&r&&(l[n.name]=r)}p=l}else p=null;else p=null;p=a=p}p&&(b=h(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&h(k[null],{params:{},pathParams:{}})}function u(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var x=!1,r={routes:k,reload:function(){x=!0;a.$evalAsync(g)}};a.$on("$locationChangeSuccess",g);return r}]});h.provider("$routeParams",
  13 +function(){this.$get=function(){return{}}});h.directive("ngView",u);h.directive("ngView",z);u.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
  14 +//# sourceMappingURL=angular-route.min.js.map
  1 +{
  2 +"version":3,
  3 +"file":"angular-route.min.js",
  4 +"lineCount":13,
  5 +"mappings":"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",
  6 +"sources":["angular-route.js"],
  7 +"names":["window","angular","undefined","ngViewFactory","$route","$anchorScroll","$animate","link","scope","$element","attr","ctrl","$transclude","cleanupLastView","currentScope","$destroy","currentElement","leave","update","locals","current","isDefined","$template","newScope","$new","clone","enter","onNgViewEnter","autoScrollExp","$eval","$emit","onloadExp","autoscroll","onload","$on","ngViewFillContentFactory","$compile","$controller","html","contents","controller","$scope","controllerAs","data","children","ngRouteModule","module","provider","$RouteProvider","inherit","parent","extra","extend","pathRegExp","path","opts","insensitive","caseInsensitiveMatch","ret","keys","replace","_","slash","key","option","optional","star","push","regexp","RegExp","routes","when","this.when","route","redirectPath","length","substr","otherwise","this.otherwise","params","$get","$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce","updateRoute","next","parseRoute","last","$$route","equals","pathParams","reloadOnSearch","forceReload","copy","$broadcast","redirectTo","isString","interpolate","search","url","then","resolve","template","templateUrl","forEach","value","get","invoke","isFunction","getTrustedResourceUrl","loadedTemplateUrl","response","all","error","match","m","exec","on","i","len","val","decodeURIComponent","name","string","result","split","segment","segmentMatch","join","reload","$evalAsync","$RouteParamsProvider","this.$get","directive","$inject"]
  8 +}
  1 +/**
  2 + * @license AngularJS v1.2.13
  3 + * (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + * License: MIT
  5 + */
  6 +(function(window, angular, undefined) {'use strict';
  7 +
  8 +var $sanitizeMinErr = angular.$$minErr('$sanitize');
  9 +
  10 +/**
  11 + * @ngdoc overview
  12 + * @name ngSanitize
  13 + * @description
  14 + *
  15 + * # ngSanitize
  16 + *
  17 + * The `ngSanitize` module provides functionality to sanitize HTML.
  18 + *
  19 + * {@installModule sanitize}
  20 + *
  21 + * <div doc-module-components="ngSanitize"></div>
  22 + *
  23 + * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
  24 + */
  25 +
  26 +/*
  27 + * HTML Parser By Misko Hevery (misko@hevery.com)
  28 + * based on: HTML Parser By John Resig (ejohn.org)
  29 + * Original code by Erik Arvidsson, Mozilla Public License
  30 + * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
  31 + *
  32 + * // Use like so:
  33 + * htmlParser(htmlString, {
  34 + * start: function(tag, attrs, unary) {},
  35 + * end: function(tag) {},
  36 + * chars: function(text) {},
  37 + * comment: function(text) {}
  38 + * });
  39 + *
  40 + */
  41 +
  42 +
  43 +/**
  44 + * @ngdoc service
  45 + * @name ngSanitize.$sanitize
  46 + * @function
  47 + *
  48 + * @description
  49 + * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are
  50 + * then serialized back to properly escaped html string. This means that no unsafe input can make
  51 + * it into the returned string, however, since our parser is more strict than a typical browser
  52 + * parser, it's possible that some obscure input, which would be recognized as valid HTML by a
  53 + * browser, won't make it through the sanitizer.
  54 + * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
  55 + * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
  56 + *
  57 + * @param {string} html Html input.
  58 + * @returns {string} Sanitized html.
  59 + *
  60 + * @example
  61 + <doc:example module="ngSanitize">
  62 + <doc:source>
  63 + <script>
  64 + function Ctrl($scope, $sce) {
  65 + $scope.snippet =
  66 + '<p style="color:blue">an html\n' +
  67 + '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
  68 + 'snippet</p>';
  69 + $scope.deliberatelyTrustDangerousSnippet = function() {
  70 + return $sce.trustAsHtml($scope.snippet);
  71 + };
  72 + }
  73 + </script>
  74 + <div ng-controller="Ctrl">
  75 + Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
  76 + <table>
  77 + <tr>
  78 + <td>Directive</td>
  79 + <td>How</td>
  80 + <td>Source</td>
  81 + <td>Rendered</td>
  82 + </tr>
  83 + <tr id="bind-html-with-sanitize">
  84 + <td>ng-bind-html</td>
  85 + <td>Automatically uses $sanitize</td>
  86 + <td><pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
  87 + <td><div ng-bind-html="snippet"></div></td>
  88 + </tr>
  89 + <tr id="bind-html-with-trust">
  90 + <td>ng-bind-html</td>
  91 + <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
  92 + <td>
  93 + <pre>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
  94 +&lt;/div&gt;</pre>
  95 + </td>
  96 + <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
  97 + </tr>
  98 + <tr id="bind-default">
  99 + <td>ng-bind</td>
  100 + <td>Automatically escapes</td>
  101 + <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
  102 + <td><div ng-bind="snippet"></div></td>
  103 + </tr>
  104 + </table>
  105 + </div>
  106 + </doc:source>
  107 + <doc:protractor>
  108 + it('should sanitize the html snippet by default', function() {
  109 + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
  110 + toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
  111 + });
  112 +
  113 + it('should inline raw snippet if bound to a trusted value', function() {
  114 + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
  115 + toBe("<p style=\"color:blue\">an html\n" +
  116 + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
  117 + "snippet</p>");
  118 + });
  119 +
  120 + it('should escape snippet without any filter', function() {
  121 + expect(element(by.css('#bind-default div')).getInnerHtml()).
  122 + toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
  123 + "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
  124 + "snippet&lt;/p&gt;");
  125 + });
  126 +
  127 + it('should update', function() {
  128 + element(by.model('snippet')).clear();
  129 + element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
  130 + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
  131 + toBe('new <b>text</b>');
  132 + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
  133 + 'new <b onclick="alert(1)">text</b>');
  134 + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
  135 + "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
  136 + });
  137 + </doc:protractor>
  138 + </doc:example>
  139 + */
  140 +function $SanitizeProvider() {
  141 + this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
  142 + return function(html) {
  143 + var buf = [];
  144 + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
  145 + return !/^unsafe/.test($$sanitizeUri(uri, isImage));
  146 + }));
  147 + return buf.join('');
  148 + };
  149 + }];
  150 +}
  151 +
  152 +function sanitizeText(chars) {
  153 + var buf = [];
  154 + var writer = htmlSanitizeWriter(buf, angular.noop);
  155 + writer.chars(chars);
  156 + return buf.join('');
  157 +}
  158 +
  159 +
  160 +// Regular Expressions for parsing tags and attributes
  161 +var START_TAG_REGEXP =
  162 + /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
  163 + END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
  164 + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
  165 + BEGIN_TAG_REGEXP = /^</,
  166 + BEGING_END_TAGE_REGEXP = /^<\s*\//,
  167 + COMMENT_REGEXP = /<!--(.*?)-->/g,
  168 + DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
  169 + CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
  170 + // Match everything outside of normal chars and " (quote character)
  171 + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
  172 +
  173 +
  174 +// Good source of info about elements and attributes
  175 +// http://dev.w3.org/html5/spec/Overview.html#semantics
  176 +// http://simon.html5.org/html-elements
  177 +
  178 +// Safe Void Elements - HTML5
  179 +// http://dev.w3.org/html5/spec/Overview.html#void-elements
  180 +var voidElements = makeMap("area,br,col,hr,img,wbr");
  181 +
  182 +// Elements that you can, intentionally, leave open (and which close themselves)
  183 +// http://dev.w3.org/html5/spec/Overview.html#optional-tags
  184 +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
  185 + optionalEndTagInlineElements = makeMap("rp,rt"),
  186 + optionalEndTagElements = angular.extend({},
  187 + optionalEndTagInlineElements,
  188 + optionalEndTagBlockElements);
  189 +
  190 +// Safe Block Elements - HTML5
  191 +var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
  192 + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
  193 + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
  194 +
  195 +// Inline Elements - HTML5
  196 +var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
  197 + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
  198 + "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
  199 +
  200 +
  201 +// Special Elements (can contain anything)
  202 +var specialElements = makeMap("script,style");
  203 +
  204 +var validElements = angular.extend({},
  205 + voidElements,
  206 + blockElements,
  207 + inlineElements,
  208 + optionalEndTagElements);
  209 +
  210 +//Attributes that have href and hence need to be sanitized
  211 +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
  212 +var validAttrs = angular.extend({}, uriAttrs, makeMap(
  213 + 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
  214 + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
  215 + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
  216 + 'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
  217 + 'valign,value,vspace,width'));
  218 +
  219 +function makeMap(str) {
  220 + var obj = {}, items = str.split(','), i;
  221 + for (i = 0; i < items.length; i++) obj[items[i]] = true;
  222 + return obj;
  223 +}
  224 +
  225 +
  226 +/**
  227 + * @example
  228 + * htmlParser(htmlString, {
  229 + * start: function(tag, attrs, unary) {},
  230 + * end: function(tag) {},
  231 + * chars: function(text) {},
  232 + * comment: function(text) {}
  233 + * });
  234 + *
  235 + * @param {string} html string
  236 + * @param {object} handler
  237 + */
  238 +function htmlParser( html, handler ) {
  239 + var index, chars, match, stack = [], last = html;
  240 + stack.last = function() { return stack[ stack.length - 1 ]; };
  241 +
  242 + while ( html ) {
  243 + chars = true;
  244 +
  245 + // Make sure we're not in a script or style element
  246 + if ( !stack.last() || !specialElements[ stack.last() ] ) {
  247 +
  248 + // Comment
  249 + if ( html.indexOf("<!--") === 0 ) {
  250 + // comments containing -- are not allowed unless they terminate the comment
  251 + index = html.indexOf("--", 4);
  252 +
  253 + if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
  254 + if (handler.comment) handler.comment( html.substring( 4, index ) );
  255 + html = html.substring( index + 3 );
  256 + chars = false;
  257 + }
  258 + // DOCTYPE
  259 + } else if ( DOCTYPE_REGEXP.test(html) ) {
  260 + match = html.match( DOCTYPE_REGEXP );
  261 +
  262 + if ( match ) {
  263 + html = html.replace( match[0] , '');
  264 + chars = false;
  265 + }
  266 + // end tag
  267 + } else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
  268 + match = html.match( END_TAG_REGEXP );
  269 +
  270 + if ( match ) {
  271 + html = html.substring( match[0].length );
  272 + match[0].replace( END_TAG_REGEXP, parseEndTag );
  273 + chars = false;
  274 + }
  275 +
  276 + // start tag
  277 + } else if ( BEGIN_TAG_REGEXP.test(html) ) {
  278 + match = html.match( START_TAG_REGEXP );
  279 +
  280 + if ( match ) {
  281 + html = html.substring( match[0].length );
  282 + match[0].replace( START_TAG_REGEXP, parseStartTag );
  283 + chars = false;
  284 + }
  285 + }
  286 +
  287 + if ( chars ) {
  288 + index = html.indexOf("<");
  289 +
  290 + var text = index < 0 ? html : html.substring( 0, index );
  291 + html = index < 0 ? "" : html.substring( index );
  292 +
  293 + if (handler.chars) handler.chars( decodeEntities(text) );
  294 + }
  295 +
  296 + } else {
  297 + html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
  298 + function(all, text){
  299 + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
  300 +
  301 + if (handler.chars) handler.chars( decodeEntities(text) );
  302 +
  303 + return "";
  304 + });
  305 +
  306 + parseEndTag( "", stack.last() );
  307 + }
  308 +
  309 + if ( html == last ) {
  310 + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
  311 + "of html: {0}", html);
  312 + }
  313 + last = html;
  314 + }
  315 +
  316 + // Clean up any remaining tags
  317 + parseEndTag();
  318 +
  319 + function parseStartTag( tag, tagName, rest, unary ) {
  320 + tagName = angular.lowercase(tagName);
  321 + if ( blockElements[ tagName ] ) {
  322 + while ( stack.last() && inlineElements[ stack.last() ] ) {
  323 + parseEndTag( "", stack.last() );
  324 + }
  325 + }
  326 +
  327 + if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
  328 + parseEndTag( "", tagName );
  329 + }
  330 +
  331 + unary = voidElements[ tagName ] || !!unary;
  332 +
  333 + if ( !unary )
  334 + stack.push( tagName );
  335 +
  336 + var attrs = {};
  337 +
  338 + rest.replace(ATTR_REGEXP,
  339 + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
  340 + var value = doubleQuotedValue
  341 + || singleQuotedValue
  342 + || unquotedValue
  343 + || '';
  344 +
  345 + attrs[name] = decodeEntities(value);
  346 + });
  347 + if (handler.start) handler.start( tagName, attrs, unary );
  348 + }
  349 +
  350 + function parseEndTag( tag, tagName ) {
  351 + var pos = 0, i;
  352 + tagName = angular.lowercase(tagName);
  353 + if ( tagName )
  354 + // Find the closest opened tag of the same type
  355 + for ( pos = stack.length - 1; pos >= 0; pos-- )
  356 + if ( stack[ pos ] == tagName )
  357 + break;
  358 +
  359 + if ( pos >= 0 ) {
  360 + // Close all the open elements, up the stack
  361 + for ( i = stack.length - 1; i >= pos; i-- )
  362 + if (handler.end) handler.end( stack[ i ] );
  363 +
  364 + // Remove the open elements from the stack
  365 + stack.length = pos;
  366 + }
  367 + }
  368 +}
  369 +
  370 +var hiddenPre=document.createElement("pre");
  371 +var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
  372 +/**
  373 + * decodes all entities into regular string
  374 + * @param value
  375 + * @returns {string} A string with decoded entities.
  376 + */
  377 +function decodeEntities(value) {
  378 + if (!value) { return ''; }
  379 +
  380 + // Note: IE8 does not preserve spaces at the start/end of innerHTML
  381 + // so we must capture them and reattach them afterward
  382 + var parts = spaceRe.exec(value);
  383 + var spaceBefore = parts[1];
  384 + var spaceAfter = parts[3];
  385 + var content = parts[2];
  386 + if (content) {
  387 + hiddenPre.innerHTML=content.replace(/</g,"&lt;");
  388 + // innerText depends on styling as it doesn't display hidden elements.
  389 + // Therefore, it's better to use textContent not to cause unnecessary
  390 + // reflows. However, IE<9 don't support textContent so the innerText
  391 + // fallback is necessary.
  392 + content = 'textContent' in hiddenPre ?
  393 + hiddenPre.textContent : hiddenPre.innerText;
  394 + }
  395 + return spaceBefore + content + spaceAfter;
  396 +}
  397 +
  398 +/**
  399 + * Escapes all potentially dangerous characters, so that the
  400 + * resulting string can be safely inserted into attribute or
  401 + * element text.
  402 + * @param value
  403 + * @returns escaped text
  404 + */
  405 +function encodeEntities(value) {
  406 + return value.
  407 + replace(/&/g, '&amp;').
  408 + replace(NON_ALPHANUMERIC_REGEXP, function(value){
  409 + return '&#' + value.charCodeAt(0) + ';';
  410 + }).
  411 + replace(/</g, '&lt;').
  412 + replace(/>/g, '&gt;');
  413 +}
  414 +
  415 +/**
  416 + * create an HTML/XML writer which writes to buffer
  417 + * @param {Array} buf use buf.jain('') to get out sanitized html string
  418 + * @returns {object} in the form of {
  419 + * start: function(tag, attrs, unary) {},
  420 + * end: function(tag) {},
  421 + * chars: function(text) {},
  422 + * comment: function(text) {}
  423 + * }
  424 + */
  425 +function htmlSanitizeWriter(buf, uriValidator){
  426 + var ignore = false;
  427 + var out = angular.bind(buf, buf.push);
  428 + return {
  429 + start: function(tag, attrs, unary){
  430 + tag = angular.lowercase(tag);
  431 + if (!ignore && specialElements[tag]) {
  432 + ignore = tag;
  433 + }
  434 + if (!ignore && validElements[tag] === true) {
  435 + out('<');
  436 + out(tag);
  437 + angular.forEach(attrs, function(value, key){
  438 + var lkey=angular.lowercase(key);
  439 + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
  440 + if (validAttrs[lkey] === true &&
  441 + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
  442 + out(' ');
  443 + out(key);
  444 + out('="');
  445 + out(encodeEntities(value));
  446 + out('"');
  447 + }
  448 + });
  449 + out(unary ? '/>' : '>');
  450 + }
  451 + },
  452 + end: function(tag){
  453 + tag = angular.lowercase(tag);
  454 + if (!ignore && validElements[tag] === true) {
  455 + out('</');
  456 + out(tag);
  457 + out('>');
  458 + }
  459 + if (tag == ignore) {
  460 + ignore = false;
  461 + }
  462 + },
  463 + chars: function(chars){
  464 + if (!ignore) {
  465 + out(encodeEntities(chars));
  466 + }
  467 + }
  468 + };
  469 +}
  470 +
  471 +
  472 +// define ngSanitize module and register $sanitize service
  473 +angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
  474 +
  475 +/* global sanitizeText: false */
  476 +
  477 +/**
  478 + * @ngdoc filter
  479 + * @name ngSanitize.filter:linky
  480 + * @function
  481 + *
  482 + * @description
  483 + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
  484 + * plain email address links.
  485 + *
  486 + * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
  487 + *
  488 + * @param {string} text Input text.
  489 + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
  490 + * @returns {string} Html-linkified text.
  491 + *
  492 + * @usage
  493 + <span ng-bind-html="linky_expression | linky"></span>
  494 + *
  495 + * @example
  496 + <doc:example module="ngSanitize">
  497 + <doc:source>
  498 + <script>
  499 + function Ctrl($scope) {
  500 + $scope.snippet =
  501 + 'Pretty text with some links:\n'+
  502 + 'http://angularjs.org/,\n'+
  503 + 'mailto:us@somewhere.org,\n'+
  504 + 'another@somewhere.org,\n'+
  505 + 'and one more: ftp://127.0.0.1/.';
  506 + $scope.snippetWithTarget = 'http://angularjs.org/';
  507 + }
  508 + </script>
  509 + <div ng-controller="Ctrl">
  510 + Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
  511 + <table>
  512 + <tr>
  513 + <td>Filter</td>
  514 + <td>Source</td>
  515 + <td>Rendered</td>
  516 + </tr>
  517 + <tr id="linky-filter">
  518 + <td>linky filter</td>
  519 + <td>
  520 + <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
  521 + </td>
  522 + <td>
  523 + <div ng-bind-html="snippet | linky"></div>
  524 + </td>
  525 + </tr>
  526 + <tr id="linky-target">
  527 + <td>linky target</td>
  528 + <td>
  529 + <pre>&lt;div ng-bind-html="snippetWithTarget | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
  530 + </td>
  531 + <td>
  532 + <div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
  533 + </td>
  534 + </tr>
  535 + <tr id="escaped-html">
  536 + <td>no filter</td>
  537 + <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
  538 + <td><div ng-bind="snippet"></div></td>
  539 + </tr>
  540 + </table>
  541 + </doc:source>
  542 + <doc:protractor>
  543 + it('should linkify the snippet with urls', function() {
  544 + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
  545 + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
  546 + 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
  547 + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
  548 + });
  549 +
  550 + it('should not linkify snippet without the linky filter', function() {
  551 + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
  552 + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
  553 + 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
  554 + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
  555 + });
  556 +
  557 + it('should update', function() {
  558 + element(by.model('snippet')).clear();
  559 + element(by.model('snippet')).sendKeys('new http://link.');
  560 + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
  561 + toBe('new http://link.');
  562 + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
  563 + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
  564 + .toBe('new http://link.');
  565 + });
  566 +
  567 + it('should work with the target property', function() {
  568 + expect(element(by.id('linky-target')).
  569 + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
  570 + toBe('http://angularjs.org/');
  571 + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
  572 + });
  573 + </doc:protractor>
  574 + </doc:example>
  575 + */
  576 +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
  577 + var LINKY_URL_REGEXP =
  578 + /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,
  579 + MAILTO_REGEXP = /^mailto:/;
  580 +
  581 + return function(text, target) {
  582 + if (!text) return text;
  583 + var match;
  584 + var raw = text;
  585 + var html = [];
  586 + var url;
  587 + var i;
  588 + while ((match = raw.match(LINKY_URL_REGEXP))) {
  589 + // We can not end in these as they are sometimes found at the end of the sentence
  590 + url = match[0];
  591 + // if we did not match ftp/http/mailto then assume mailto
  592 + if (match[2] == match[3]) url = 'mailto:' + url;
  593 + i = match.index;
  594 + addText(raw.substr(0, i));
  595 + addLink(url, match[0].replace(MAILTO_REGEXP, ''));
  596 + raw = raw.substring(i + match[0].length);
  597 + }
  598 + addText(raw);
  599 + return $sanitize(html.join(''));
  600 +
  601 + function addText(text) {
  602 + if (!text) {
  603 + return;
  604 + }
  605 + html.push(sanitizeText(text));
  606 + }
  607 +
  608 + function addLink(url, text) {
  609 + html.push('<a ');
  610 + if (angular.isDefined(target)) {
  611 + html.push('target="');
  612 + html.push(target);
  613 + html.push('" ');
  614 + }
  615 + html.push('href="');
  616 + html.push(url);
  617 + html.push('">');
  618 + addText(text);
  619 + html.push('</a>');
  620 + }
  621 + };
  622 +}]);
  623 +
  624 +
  625 +})(window, window.angular);
  1 +/*
  2 + AngularJS v1.2.13
  3 + (c) 2010-2014 Google, Inc. http://angularjs.org
  4 + License: MIT
  5 +*/
  6 +(function(p,h,q){'use strict';function E(a){var e=[];s(e,h.noop).chars(a);return e.join("")}function k(a){var e={};a=a.split(",");var d;for(d=0;d<a.length;d++)e[a[d]]=!0;return e}function F(a,e){function d(a,b,d,g){b=h.lowercase(b);if(t[b])for(;f.last()&&u[f.last()];)c("",f.last());v[b]&&f.last()==b&&c("",b);(g=w[b]||!!g)||f.push(b);var l={};d.replace(G,function(a,b,e,c,d){l[b]=r(e||c||d||"")});e.start&&e.start(b,l,g)}function c(a,b){var c=0,d;if(b=h.lowercase(b))for(c=f.length-1;0<=c&&f[c]!=b;c--);
  7 +if(0<=c){for(d=f.length-1;d>=c;d--)e.end&&e.end(f[d]);f.length=c}}var b,g,f=[],l=a;for(f.last=function(){return f[f.length-1]};a;){g=!0;if(f.last()&&x[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(b,a){a=a.replace(H,"$1").replace(I,"$1");e.chars&&e.chars(r(a));return""}),c("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(e.comment&&e.comment(a.substring(4,b)),a=a.substring(b+3),g=!1);else if(y.test(a)){if(b=a.match(y))a=
  8 +a.replace(b[0],""),g=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,c),g=!1}else K.test(a)&&(b=a.match(A))&&(a=a.substring(b[0].length),b[0].replace(A,d),g=!1);g&&(b=a.indexOf("<"),g=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),e.chars&&e.chars(r(g)))}if(a==l)throw L("badparse",a);l=a}c()}function r(a){if(!a)return"";var e=M.exec(a);a=e[1];var d=e[3];if(e=e[2])n.innerHTML=e.replace(/</g,"&lt;"),e="textContent"in n?n.textContent:n.innerText;return a+e+d}function B(a){return a.replace(/&/g,
  9 +"&amp;").replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function s(a,e){var d=!1,c=h.bind(a,a.push);return{start:function(a,g,f){a=h.lowercase(a);!d&&x[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(g,function(d,f){var g=h.lowercase(f),k="img"===a&&"src"===g||"background"===g;!0!==O[g]||!0===D[g]&&!e(d,k)||(c(" "),c(f),c('="'),c(B(d)),c('"'))}),c(f?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||
  10 +c(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,z=/^<\s*\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\s*\//,H=/\x3c!--(.*?)--\x3e/g,y=/<!DOCTYPE([^>]*?)>/i,I=/<!\[CDATA\[(.*?)]]\x3e/g,N=/([^\#-~| |!])/g,w=k("area,br,col,hr,img,wbr");p=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");q=k("rp,rt");var v=h.extend({},q,p),t=h.extend({},p,k("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),
  11 +u=h.extend({},q,k("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),x=k("script,style"),C=h.extend({},w,t,u,v),D=k("background,cite,href,longdesc,src,usemap"),O=h.extend({},D,k("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,target,title,type,valign,value,vspace,width")),
  12 +n=document.createElement("pre"),M=/^(\s*)([\s\S]*?)(\s*)$/;h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(e){var d=[];F(e,s(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var e=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,d=/^mailto:/;return function(c,b){function g(a){a&&m.push(E(a))}function f(a,c){m.push("<a ");h.isDefined(b)&&
  13 +(m.push('target="'),m.push(b),m.push('" '));m.push('href="');m.push(a);m.push('">');g(c);m.push("</a>")}if(!c)return c;for(var l,k=c,m=[],n,p;l=k.match(e);)n=l[0],l[2]==l[3]&&(n="mailto:"+n),p=l.index,g(k.substr(0,p)),f(n,l[0].replace(d,"")),k=k.substring(p+l[0].length);g(k);return a(m.join(""))}}])})(window,window.angular);
  14 +//# sourceMappingURL=angular-sanitize.min.js.map
  1 +{
  2 +"version":3,
  3 +"file":"angular-sanitize.min.js",
  4 +"lineCount":13,
  5 +"mappings":"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",
  6 +"sources":["angular-sanitize.js"],
  7 +"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","stack.last","specialElements","RegExp","all","text","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","NON_ALPHANUMERIC_REGEXP","charCodeAt","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"]
  8 +}
  1 +var duScrollDefaultEasing=function(e){return.5>e?Math.pow(2*e,2)/2:1-Math.pow(2*(1-e),2)/2};angular.module("duScroll",["duScroll.scrollspy","duScroll.requestAnimation","duScroll.smoothScroll","duScroll.scrollContainer","duScroll.scrollHelpers"]).value("duScrollDuration",350).value("duScrollGreedy",!1).value("duScrollEasing",duScrollDefaultEasing),angular.module("duScroll.scrollHelpers",[]).run(["$window","$q","cancelAnimation","requestAnimation","duScrollEasing",function(e,t,n,r,o){var l=angular.element.prototype;this.$get=function(){return l};var i=function(e){return"undefined"!=typeof HTMLDocument&&e instanceof HTMLDocument||e.nodeType&&e.nodeType===e.DOCUMENT_NODE},u=function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement||e.nodeType&&e.nodeType===e.ELEMENT_NODE},c=function(e){return u(e)||i(e)?e:e[0]};l.scrollTo=function(t,n,r){var o;if(angular.isElement(t)?o=this.scrollToElement:r&&(o=this.scrollToAnimated),o)return o.apply(this,arguments);var l=c(this);return i(l)?e.scrollTo(t,n):(l.scrollLeft=t,void(l.scrollTop=n))};var a,s;l.scrollToAnimated=function(e,l,i,u){i&&!u&&(u=o);var c=this.scrollLeft(),d=this.scrollTop(),f=Math.round(e-c),p=Math.round(l-d),m=null;a&&(n(a),s.reject());var g=this;if(s=t.defer(),!f&&!p)return s.resolve(),s.promise;var v=function(e){null===m&&(m=e);var t=e-m,n=t>=i?1:u(t/i);g.scrollTo(c+Math.ceil(f*n),d+Math.ceil(p*n)),1>n?a=r(v):(a=null,s.resolve())};return g.scrollTo(c,d),a=r(v),s.promise},l.scrollToElement=function(e,t,n,r){var o=c(this),l=this.scrollTop()+c(e).getBoundingClientRect().top-t;return u(o)&&(l-=o.getBoundingClientRect().top),this.scrollTo(0,l,n,r)};var d={scrollLeft:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(t,this.scrollTop(),n,r);var o=c(this);return i(o)?e.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft:o.scrollLeft},scrollTop:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(this.scrollTop(),t,n,r);var o=c(this);return i(o)?e.scrollY||document.documentElement.scrollTop||document.body.scrollTop:o.scrollTop}},f=function(e,t){return function(n,r){return r?t.apply(this,arguments):e.apply(this,arguments)}};for(var p in d)l[p]=l[p]?f(l[p],d[p]):d[p]}]),angular.module("duScroll.polyfill",[]).factory("polyfill",["$window",function(e){var t=["webkit","moz","o","ms"];return function(n,r){if(e[n])return e[n];for(var o,l=n.substr(0,1).toUpperCase()+n.substr(1),i=0;i<t.length;i++)if(o=t[i]+l,e[o])return e[o];return r}}]),angular.module("duScroll.requestAnimation",["duScroll.polyfill"]).factory("requestAnimation",["polyfill","$timeout",function(e,t){var n=0,r=function(e){var r=(new Date).getTime(),o=Math.max(0,16-(r-n)),l=t(function(){e(r+o)},o);return n=r+o,l};return e("requestAnimationFrame",r)}]).factory("cancelAnimation",["polyfill","$timeout",function(e,t){var n=function(e){t.cancel(e)};return e("cancelAnimationFrame",n)}]),angular.module("duScroll.spyAPI",["duScroll.scrollContainerAPI"]).factory("spyAPI",["$rootScope","scrollContainerAPI","duScrollGreedy",function(e,t,n){var r=function(t){return function(){var r=t.container,o=r[0],l=0;o instanceof HTMLElement&&(l=o.getBoundingClientRect().top);var i,u,c,a,s,d;for(a=t.spies,u=t.currentlyActive,c=void 0,i=0;i<a.length;i++)s=a[i],d=s.getTargetPosition(),d&&d.top+s.offset-l<20&&-1*d.top+l<d.height&&(!c||c.top<d.top)&&(c={top:d.top,spy:s});c&&(c=c.spy),u===c||n&&!c||(u&&(u.$element.removeClass("active"),e.$broadcast("duScrollspy:becameInactive",u.$element)),c&&(c.$element.addClass("active"),e.$broadcast("duScrollspy:becameActive",c.$element)),t.currentlyActive=c)}},o={},l=function(e){var t=e.$id,n={spies:[]};return n.handler=r(n),o[t]=n,e.$on("$destroy",function(){i(e)}),t},i=function(e){var t=e.$id,n=o[t],r=n.container;r&&r.off("scroll",n.handler),delete o[t]},u=l(e),c=function(e){return o[e.$id]?o[e.$id]:e.$parent?c(e.$parent):o[u]},a=function(e){var t,n,r=e.$element.scope();if(r)return c(r);for(n in o)if(t=o[n],-1!==t.spies.indexOf(e))return t},s=function(e){var n=a(e);a(e).spies.push(e),n.container||(n.container=t.getContainer(e.$element.scope()),n.container.on("scroll",n.handler).triggerHandler("scroll"))},d=function(e){var t=a(e);e===t.currentlyActive&&(t.currentlyActive=null);var n=t.spies.indexOf(e);-1!==n&&t.spies.splice(n,1)};return{addSpy:s,removeSpy:d,createContext:l,destroyContext:i,getContextForScope:c}}]),angular.module("duScroll.scrollContainerAPI",[]).factory("scrollContainerAPI",["$document",function(e){var t={},n=function(e,n){var r=e.$id;return t[r]=n,r},r=function(e){return t[e.$id]?e.$id:e.$parent?r(e.$parent):void 0},o=function(n){var o=r(n);return o?t[o]:e},l=function(e){var n=r(e);n&&delete t[n]};return{getContainerId:r,getContainer:o,setContainer:n,removeContainer:l}}]),angular.module("duScroll.smoothScroll",["duScroll.scrollHelpers","duScroll.scrollContainerAPI"]).directive("duSmoothScroll",["duScrollDuration","scrollContainerAPI",function(e,t){return{link:function(n,r,o){r.on("click",function(r){if(o.href&&-1!==o.href.indexOf("#")){var l=document.getElementById(o.href.replace(/.*(?=#[^\s]+$)/,"").substring(1));if(l&&l.getBoundingClientRect){r.stopPropagation&&r.stopPropagation(),r.preventDefault&&r.preventDefault();var i=o.offset?parseInt(o.offset,10):0,u=o.duration?parseInt(o.duration,10):e,c=t.getContainer(n);c.scrollToElement(angular.element(l),isNaN(i)?0:i,isNaN(u)?0:u)}}})}}}]),angular.module("duScroll.spyContext",["duScroll.spyAPI"]).directive("duSpyContext",["spyAPI",function(e){return{restrict:"A",scope:!0,compile:function(){return{pre:function(t){e.createContext(t)}}}}}]),angular.module("duScroll.scrollContainer",["duScroll.scrollContainerAPI"]).directive("duScrollContainer",["scrollContainerAPI",function(e){return{restrict:"A",scope:!0,compile:function(){return{pre:function(t,n,r){r.$observe("duScrollContainer",function(r){angular.isString(r)&&(r=document.getElementById(r)),r=angular.isElement(r)?angular.element(r):n,e.setContainer(t,r),t.$on("$destroy",function(){e.removeContainer(t)})})}}}}}]),angular.module("duScroll.scrollspy",["duScroll.spyAPI"]).directive("duScrollspy",["spyAPI","$timeout",function(e,t){var n=function(e,t,n){angular.isElement(e)?this.target=e:angular.isString(e)&&(this.targetId=e),this.$element=t,this.offset=n};return n.prototype.getTargetElement=function(){return!this.target&&this.targetId&&(this.target=document.getElementById(this.targetId)),this.target},n.prototype.getTargetPosition=function(){var e=this.getTargetElement();return e?e.getBoundingClientRect():void 0},n.prototype.flushTargetCache=function(){this.targetId&&(this.target=void 0)},{link:function(r,o,l){var i,u=l.ngHref||l.href;u&&-1!==u.indexOf("#")?i=u.replace(/.*(?=#[^\s]+$)/,"").substring(1):l.duScrollspy&&(i=l.duScrollspy),i&&t(function(){var t=new n(i,o,-(l.offset?parseInt(l.offset,10):0));e.addSpy(t),r.$on("$destroy",function(){e.removeSpy(t)}),r.$on("$locationChangeSuccess",t.flushTargetCache.bind(t)),r.$on("$stateChangeSuccess",t.flushTargetCache.bind(t))},0)}}}]);
  1 +/**
  2 + * angular-strap
  3 + * @version v2.0.5 - 2014-09-03
  4 + * @link http://mgcrea.github.io/angular-strap
  5 + * @author Olivier Louvignes (olivier@mg-crea.com)
  6 + * @license MIT License, http://www.opensource.org/licenses/MIT
  7 + */
  8 +!function(e,t){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return h>=a?"top":null!==e&&a+e<=t.top?"middle":null!==v&&t.top+n+g>=o-v?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,m="affix affix-top affix-bottom",g=0,$=0,h=0,v=0,y=null,w=null,b=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var D=0;D<1*f.offsetParent-1;D++)b=b.parent();else b=angular.element(f.offsetParent);return d.init=function(){d.$parseOffsets(),$=a.offset(o[0]).top+g,p.on("scroll",d.checkPosition),p.on("click",d.checkPositionWithEventLoop),r.on("resize",d.$debouncedOnResize),d.checkPosition(),d.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",d.checkPosition),p.off("click",d.checkPositionWithEventLoop),r.off("resize",d.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(w,t,n);y!==r&&(y=r,o.removeClass(m).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(w=null,o.css("position",f.offsetParent?"":"relative"),o.css("top","")):"bottom"===r?(w=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-v-n-$+"px")):(w=null,o.css("position","fixed"),o.css("top",g+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?(g=1*-f.offsetTop,h=f.offsetParent?a.offset(b[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):h=1*f.offsetTop),f.offsetBottom&&(v=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(b[0]).top+a.height(b[0]))+1*f.offsetBottom+1:1*f.offsetBottom)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",template:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",modelDateFormat:null,dayFormat:"dd",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:+1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$locale","dateFilter","datepickerViews","$tooltip",function(t,n,a,o,i,r,s,l){function u(t,n,a){function o(e){e.selected=r.$isSelected(e.date)}function i(){t[0].focus()}var r=l(t,angular.extend({},e,a)),u=a.scope,f=r.$options,p=r.$scope;f.startView&&(f.startView-=f.minView);var m=s(r);r.$views=m.views;var g=m.viewDate;p.$mode=f.startView,p.$iconLeft=f.iconLeft,p.$iconRight=f.iconRight;var $=r.$views[p.$mode];p.$select=function(e){r.select(e)},p.$selectPane=function(e){r.$selectPane(e)},p.$toggleMode=function(){r.setMode((p.$mode+1)%r.$views.length)},r.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(r.$date=e,$.update.call($,e)),r.$build(!0)},r.updateDisabledDates=function(e){f.disabledDateRanges=e;for(var t=0,n=p.rows.length;n>t;t++)angular.forEach(p.rows[t],r.$setDisabledEl)},r.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!p.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),f.autoclose&&!t&&r.hide(!0)):(angular.extend(g,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),r.setMode(p.$mode-1),r.$build())},r.setMode=function(e){p.$mode=e,$=r.$views[p.$mode],r.$build()},r.$build=function(e){e===!0&&$.built||(e!==!1||$.built)&&$.build.call($)},r.$updateSelected=function(){for(var e=0,t=p.rows.length;t>e;e++)angular.forEach(p.rows[e],o)},r.$isSelected=function(e){return $.isSelected(e)},r.$setDisabledEl=function(e){e.disabled=$.isDisabled(e.date)},r.$selectPane=function(e){var t=$.steps,n=new Date(Date.UTC(g.year+(t.year||0)*e,g.month+(t.month||0)*e,g.date+(t.day||0)*e));angular.extend(g,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),r.$build()},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return p.$mode?p.$apply(function(){r.setMode(p.$mode-1)}):r.hide(!0);$.onKeyDown(e),u.$digest()}};var h=r.init;r.init=function(){return c&&f.useNative?(t.prop("type","date"),t.css("-webkit-appearance","textfield"),void 0):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),h(),void 0)};var v=r.destroy;r.destroy=function(){c&&f.useNative&&t.off("click",i),v()};var y=r.show;r.show=function(){y(),setTimeout(function(){r.$element.on(d?"touchstart":"mousedown",r.$onMouseDown),f.keyboard&&t.on("keydown",r.$onKeyDown)})};var w=r.hide;return r.hide=function(e){r.$element.off(d?"touchstart":"mousedown",r.$onMouseDown),f.keyboard&&t.off("keydown",r.$onKeyDown),w(e)},r}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.id),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$locale","dateFilter","$datepicker","$dateParser","$timeout",function(e,t,n,a,o,i,r){var s=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent)),l=function(e){return!isNaN(parseFloat(e))&&isFinite(e)};return{restrict:"EAC",require:"ngModel",link:function(e,t,n,a){function u(e){return e&&e.length?e:null}var c={scope:e,controller:a};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled"],function(e){angular.isDefined(n[e])&&(c[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){d&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(",?(datepicker),?")),e===!0?d.show():d.hide())}),s&&c.useNative&&(c.dateFormat="yyyy-MM-dd");var d=i(t,a,c);c=d.$options,angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){if("today"===t){var n=new Date;d.$options[e]=+new Date(n.getFullYear(),n.getMonth(),n.getDate()+("maxDate"===e?1:0),0,0,0,"minDate"===e?0:-1)}else d.$options[e]=angular.isString(t)&&t.match(/^".+"$/)?+new Date(t.substr(1,t.length-2)):l(t)?+new Date(parseInt(t,10)):angular.isString(t)&&0===t.length?"maxDate"===e?+1/0:-1/0:+new Date(t);!isNaN(d.$options[e])&&d.$build(!1)})}),e.$watch(n.ngModel,function(){d.update(a.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=u(e),t=u(t),e!==t&&d.updateDisabledDates(e)});var f=r({format:c.dateFormat,lang:c.lang,strict:c.strictFormat});a.$parsers.unshift(function(e){if(!e)return a.$setValidity("date",!0),void 0;var t=f.parse(e,a.$dateValue);if(!t||isNaN(t.getTime()))return a.$setValidity("date",!1),void 0;var n=isNaN(d.$options.minDate)||t.getTime()>=d.$options.minDate,i=isNaN(d.$options.maxDate)||t.getTime()<=d.$options.maxDate,r=n&&i;return a.$setValidity("date",r),a.$setValidity("min",n),a.$setValidity("max",i),r&&(a.$dateValue=t),"string"===c.dateType?o(t,c.modelDateFormat||c.dateFormat):"number"===c.dateType?a.$dateValue.getTime():"iso"===c.dateType?a.$dateValue.toISOString():new Date(a.$dateValue)}),a.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===c.dateType?f.parse(e,null,c.modelDateFormat):new Date(e),a.$dateValue=t,a.$dateValue}),a.$render=function(){t.val(!a.$dateValue||isNaN(a.$dateValue.getTime())?"":o(a.$dateValue,c.dateFormat))},e.$on("$destroy",function(){d&&d.destroy(),c=null,d=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$locale","$sce","dateFilter",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=n.DATETIME_FORMATS.SHORTDAY,u=l.slice(s.startWeek).concat(l.slice(0,s.startWeek)),c=a.trustAsHtml('<th class="dow text-center">'+u.join('</th><th class="dow text-center">')+"</th>"),d=i.$date||(s.startDate?new Date(s.startDate):new Date),f={year:d.getFullYear(),month:d.getMonth(),date:d.getDate()},p=(6e4*d.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==f.year||e.getMonth()!==f.month?(angular.extend(f,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==f.date&&(f.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(f.year,f.month,1),a=n.getTimezoneOffset(),l=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),u=l.getTimezoneOffset(),d=(new Date).toDateString();u!==a&&(l=new Date(+l+6e4*(u-a)));for(var p,m=[],g=0;42>g;g++)p=new Date(l.getFullYear(),l.getMonth(),l.getDate()+g),m.push({date:p,isToday:p.toDateString()===d,label:o(p,this.format),selected:i.$date&&this.isSelected(p),muted:p.getMonth()!==f.month,disabled:this.isDisabled(p)});r.title=o(n,"MMMM yyyy"),r.showLabels=!0,r.labels=c,r.rows=e(m,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(t<s.minDate||t>s.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n<s.disabledDateRanges.length;n++)if(t>=s.disabledDateRanges[n].start)return t<=s.disabledDateRanges[n].end?!0:!1;return!1},onKeyDown:function(e){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}},{name:"month",format:"MMM",split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===f.year?e.getMonth()!==f.month&&(angular.extend(f,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(f,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(f.year,0,1),[]),a=0;12>a;a++)t=new Date(f.year,a,1),n.push({date:t,label:o(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=o(t,"yyyy"),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return t<s.minDate||e.getTime()>s.maxDate},onKeyDown:function(e){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}},{name:"year",format:"yyyy",split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(f.year/20,10)?(angular.extend(f,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==f.year&&(angular.extend(f,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=f.year-f.year%(3*this.split),a=[],s=0;12>s;s++)t=new Date(n+s,0,1),a.push({date:t,label:o(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return t<s.minDate||e.getTime()>s.maxDate},onKeyDown:function(e){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}]);return{views:s.minView?Array.prototype.slice.call(p,s.minView):p,viewDate:f}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip",function(t,n,a){function o(t,o){function s(e){return e.target!==t[0]?e.target!==t[0]&&l.hide():void 0}{var l={},u=angular.extend({},e,o);l.$scope=u.scope&&u.scope.$new()||n.$new()}l=a(t,u);var c=t.parent();l.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(l.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){r&&r.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&n<t.length-1?n++:angular.isUndefined(n)&&(n=0),t.eq(n)[0].focus()}}};var d=l.show;l.show=function(){d(),setTimeout(function(){u.keyboard&&l.$element.on("keydown",l.$onKeyDown),i.on("click",s)}),c.hasClass("dropdown")&&c.addClass("open")};var f=l.hide;return l.hide=function(){u.keyboard&&l.$element.off("keydown",l.$onKeyDown),i.off("click",s),c.hasClass("dropdown")&&c.removeClass("open"),f()},l}var i=angular.element(t.document.body),r=Element.prototype.matchesSelector||Element.prototype.webkitMatchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector;return o}]}).directive("bsDropdown",["$window","$sce","$dropdown",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,t,a){var o={scope:e};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template"],function(e){angular.isDefined(a[e])&&(o[e]=a[e])}),a.bsDropdown&&e.$watch(a.bsDropdown,function(t){e.content=t},!0),a.bsShow&&e.$watch(a.bsShow,function(e){i&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(",?(dropdown),?")),e===!0?i.show():i.hide())});var i=n(t,o);e.$on("$destroy",function(){i&&i.destroy(),o=null,i=null})}}}]),angular.module("mgcrea.ngStrap.helpers.dateParser",[]).provider("$dateParser",["$localeProvider",function(){function e(){}var t=Date.prototype,n=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(a,o){var i=function(i){function r(e){var t,n=Object.keys(m),a=[],o=[],i=e;for(t=0;t<n.length;t++)if(e.split(n[t]).length>1){var r=i.search(n[t]);e=e.split(n[t]).join(""),m[n[t]]&&(a[r]=m[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function s(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function l(e){var t,n=Object.keys(p),a=e;for(t=0;t<n.length;t++)a=a.split(n[t]).join("${"+t+"}");for(t=0;t<n.length;t++)a=a.split("${"+t+"}").join("("+p[n[t]]+")");return e=s(e),new RegExp("^"+a+"$",["i"])}var u,c,d=angular.extend({},n,i),f={},p={sss:"[0-9]{3}",ss:"[0-5][0-9]",s:d.strict?"[1-5]?[0-9]":"[0-9]|[0-5][0-9]",mm:"[0-5][0-9]",m:d.strict?"[1-5]?[0-9]":"[0-9]|[0-5][0-9]",HH:"[01][0-9]|2[0-3]",H:d.strict?"1?[0-9]|2[0-3]":"[01]?[0-9]|2[0-3]",hh:"[0][1-9]|[1][012]",h:d.strict?"[1-9]|1[012]":"0?[1-9]|1[012]",a:"AM|PM",EEEE:a.DATETIME_FORMATS.DAY.join("|"),EEE:a.DATETIME_FORMATS.SHORTDAY.join("|"),dd:"0[1-9]|[12][0-9]|3[01]",d:d.strict?"[1-9]|[1-2][0-9]|3[01]":"0?[1-9]|[1-2][0-9]|3[01]",MMMM:a.DATETIME_FORMATS.MONTH.join("|"),MMM:a.DATETIME_FORMATS.SHORTMONTH.join("|"),MM:"0[1-9]|1[012]",M:d.strict?"[1-9]|1[012]":"0?[1-9]|1[012]",yyyy:"[1]{1}[0-9]{3}|[2]{1}[0-9]{3}",yy:"[0-9]{2}",y:d.strict?"-?(0|[1-9][0-9]{0,3})":"-?0*[0-9]{1,4}"},m={sss:t.setMilliseconds,ss:t.setSeconds,s:t.setSeconds,mm:t.setMinutes,m:t.setMinutes,HH:t.setHours,H:t.setHours,hh:t.setHours,h:t.setHours,EEEE:e,EEE:e,dd:t.setDate,d:t.setDate,a:function(e){var t=this.getHours();return this.setHours(e.match(/pm/i)?t+12:t)},MMMM:function(e){return this.setMonth(a.DATETIME_FORMATS.MONTH.indexOf(e))},MMM:function(e){return this.setMonth(a.DATETIME_FORMATS.SHORTMONTH.indexOf(e))},MM:function(e){return this.setMonth(1*e-1)},M:function(e){return this.setMonth(1*e-1)},yyyy:t.setFullYear,yy:function(e){return this.setFullYear(2e3+1*e)},y:t.setFullYear};return f.init=function(){f.$format=a.DATETIME_FORMATS[d.format]||d.format,u=l(f.$format),c=r(f.$format)},f.isValid=function(e){return angular.isDate(e)?!isNaN(e.getTime()):u.test(e)},f.parse=function(e,t,n){angular.isDate(e)&&(e=o(e,n||f.$format));var a=n?l(n):u,i=n?r(n):c,s=a.exec(e);if(!s)return!1;for(var d=t||new Date(0,0,1),p=0;p<s.length-1;p++)i[p]&&i[p].call(d,s[p+1]);return d},f.init(),f};return i}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).constant("debounce",function(e,t,n){var a,o,i,r,s;return function(){i=this,o=arguments,r=new Date;var l=function(){var u=new Date-r;t>u?a=setTimeout(l,t-u):(a=null,n||(s=e.apply(i,o)))},u=n&&!a;return a||(a=setTimeout(l,t)),u&&(s=e.apply(i,o)),s}}).constant("throttle",function(e,t,n){var a,o,i,r=null,s=0;n||(n={});var l=function(){s=n.leading===!1?0:new Date,r=null,i=e.apply(a,o)};return function(){var u=new Date;s||n.leading!==!1||(s=u);var c=t-(u-s);return a=this,o=arguments,0>=c?(clearTimeout(r),r=null,s=u,i=e.apply(a,o)):r||n.trailing===!1||(r=setTimeout(l,c)),i}}),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i)||n,{label:a,value:o}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,m;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),m=t(l[7])},r.valuesFn=function(e,t){return n.when(m(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values})},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(e){e.target===e.currentTarget&&("static"===r.backdrop?i.focus():i.hide())}var i={},r=i.$options=angular.extend({},e,t);i.$promise=p(r.template);var s=i.$scope=r.scope&&r.scope.$new()||a.$new();r.element||r.container||(r.container="body"),m(["title","content"],function(e){r[e]&&(s[e]=c.trustAsHtml(r[e]))}),s.$hide=function(){s.$$postDigest(function(){i.hide()})},s.$show=function(){s.$$postDigest(function(){i.show()})},s.$toggle=function(){s.$$postDigest(function(){i.toggle()})},r.contentTemplate&&(i.$promise=i.$promise.then(function(e){var n=angular.element(e);return p(r.contentTemplate).then(function(e){var a=f('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var u,d,y=angular.element('<div class="'+r.prefixClass+'-backdrop"/>');return i.$promise.then(function(e){angular.isObject(e)&&(e=e.data),r.html&&(e=e.replace(v,'ng-bind-html="')),e=g.apply(e),u=o(e),i.init()}),i.init=function(){r.show&&s.$$postDigest(function(){i.show()})},i.destroy=function(){d&&(d.remove(),d=null),y&&(y.remove(),y=null),s.$destroy()},i.show=function(){s.$emit(r.prefixEvent+".show.before",i);var e;e=angular.isElement(r.container)?r.container:r.container?f(r.container):null;var t=r.container?null:r.element;d=i.$element=u(s,function(){}),d.css({display:"block"}).addClass(r.placement),r.animation&&(r.backdrop&&y.addClass(r.backdropAnimation),d.addClass(r.animation)),r.backdrop&&l.enter(y,h,null,function(){}),l.enter(d,e,t,function(){s.$emit(r.prefixEvent+".show",i)}),s.$isShown=!0,s.$$phase||s.$root&&s.$root.$$phase||s.$digest();var a=d[0];$(function(){a.focus()}),h.addClass(r.prefixClass+"-open"),r.animation&&h.addClass(r.prefixClass+"-with-"+r.animation),r.backdrop&&(d.on("click",n),y.on("click",n)),r.keyboard&&d.on("keyup",i.$onKeyUp)},i.hide=function(){s.$emit(r.prefixEvent+".hide.before",i),l.leave(d,function(){s.$emit(r.prefixEvent+".hide",i),h.removeClass(r.prefixClass+"-open"),r.animation&&h.removeClass(r.prefixClass+"-with-"+r.animation)}),r.backdrop&&l.leave(y,function(){}),s.$isShown=!1,s.$$phase||s.$root&&s.$root.$$phase||s.$digest(),r.backdrop&&(d.off("click",n),y.off("click",n)),r.keyboard&&d.off("keyup",i.$onKeyUp)},i.toggle=function(){s.$isShown?i.hide():i.show()},i.focus=function(){d[0].focus()},i.$onKeyUp=function(e){27===e.which&&s.$isShown&&(i.hide(),e.stopPropagation())},i}function f(e,n){return angular.element((n||t).querySelectorAll(e))}function p(e){return i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,g=String.prototype.trim,$=n.requestAnimationFrame||n.setTimeout,h=angular.element(n.document.body),v=/ng-bind="/gi;return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()
  9 +})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(",?(popover),?")),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var m=u(c.element,"body"),g=m?d:c.element,$=m?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,S,T={},x=T.$trackedElements=[],M=[];return T.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),g.on("click",this.checkPositionWithEventLoop),d.on("resize",w),g.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=T)},T.destroy=function(){this.$$count--,this.$$count>0||(g.off("click",this.checkPositionWithEventLoop),d.off("resize",w),g.off("scroll",w),h(),v(),$&&delete e[$])},T.checkPosition=function(){if(M.length){if(S=(m?a.pageYOffset:g.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),S<M[0].offsetTop&&y!==M[0].target)return T.$activateElement(M[0]);for(var e=M.length;e--;)if(!angular.isUndefined(M[e].offsetTop)&&null!==M[e].offsetTop&&y!==M[e].target&&!(S<M[e].offsetTop||M[e+1]&&S>M[e+1].offsetTop))return T.$activateElement(M[e])}},T.checkPositionWithEventLoop=function(){setTimeout(this.checkPosition,1)},T.$activateElement=function(e){if(y){var t=T.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},T.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},T.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),M=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},T.trackElement=function(e,t){x.push({target:e,source:t})},T.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},T.activate=function(e){x[e].addClass("active")},T.init(),T}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:'&nbsp;<span class="caret"></span>',placeholder:"Choose among the following...",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip",function(t,n,a,o){function i(t,n,a){var i={},r=angular.extend({},e,a);i=o(t,r);var l=i.$scope;l.$matches=[],l.$activeIndex=0,l.$isMultiple=r.multiple,l.$showAllNoneButtons=r.allNoneButtons&&r.multiple,l.$iconCheckmark=r.iconCheckmark,l.$activate=function(e){l.$$postDigest(function(){i.activate(e)})},l.$select=function(e){l.$$postDigest(function(){i.select(e)})},l.$isVisible=function(){return i.$isVisible()},l.$isActive=function(e){return i.$isActive(e)},l.$selectAll=function(){for(var e=0;e<l.$matches.length;e++)l.$isActive(e)||l.$select(e)},l.$selectNone=function(){for(var e=0;e<l.$matches.length;e++)l.$isActive(e)&&l.$select(e)},i.update=function(e){l.$matches=e,i.$updateActiveIndex()},i.activate=function(e){return r.multiple?(l.$activeIndex.sort(),i.$isActive(e)?l.$activeIndex.splice(l.$activeIndex.indexOf(e),1):l.$activeIndex.push(e),r.sort&&l.$activeIndex.sort()):l.$activeIndex=e,l.$activeIndex},i.select=function(e){var t=l.$matches[e].value;l.$apply(function(){i.activate(e),r.multiple?n.$setViewValue(l.$activeIndex.map(function(e){return l.$matches[e].value})):(n.$setViewValue(t),i.hide())}),l.$emit(r.prefixEvent+".select",t,e)},i.$updateActiveIndex=function(){n.$modelValue&&l.$matches.length?l.$activeIndex=r.multiple&&angular.isArray(n.$modelValue)?n.$modelValue.map(function(e){return i.$getIndex(e)}):i.$getIndex(n.$modelValue):l.$activeIndex>=l.$matches.length&&(l.$activeIndex=r.multiple?[]:0)},i.$isVisible=function(){return r.minLength&&n?l.$matches.length&&n.$viewValue.length>=r.minLength:l.$matches.length},i.$isActive=function(e){return r.multiple?-1!==l.$activeIndex.indexOf(e):l.$activeIndex===e},i.$getIndex=function(e){var t=l.$matches.length,n=t;if(t){for(n=t;n--&&l.$matches[n].value!==e;);if(!(0>n))return n}},i.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),s){var t=angular.element(e.target);t.triggerHandler("click")}},i.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!r.multiple&&(13===e.keyCode||9===e.keyCode))return i.select(l.$activeIndex);38===e.keyCode&&l.$activeIndex>0?l.$activeIndex--:40===e.keyCode&&l.$activeIndex<l.$matches.length-1?l.$activeIndex++:angular.isUndefined(l.$activeIndex)&&(l.$activeIndex=0),l.$digest()}};var u=i.show;i.show=function(){u(),r.multiple&&i.$element.addClass("select-multiple"),setTimeout(function(){i.$element.on(s?"touchstart":"mousedown",i.$onMouseDown),r.keyboard&&t.on("keydown",i.$onKeyDown)})};var c=i.hide;return i.hide=function(){i.$element.off(s?"touchstart":"mousedown",i.$onMouseDown),r.keyboard&&t.off("keydown",i.$onKeyDown),c(!0)},i}var r=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),s="createTouch"in t.document&&r;return i.defaults=e,i}]}).directive("bsSelect",["$window","$parse","$q","$select","$parseOptions",function(e,t,n,a,o){var i=a.defaults;return{restrict:"EAC",require:"ngModel",link:function(e,t,n,r){var s={scope:e};if(angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","placeholder","multiple","allNoneButtons","maxLength","maxLengthHtml"],function(e){angular.isDefined(n[e])&&(s[e]=n[e])}),"select"===t[0].nodeName.toLowerCase()){var l=t;l.css("display","none"),t=angular.element('<button type="button" class="btn btn-default"></button>'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,a;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return a=c.$getIndex(e),angular.isDefined(a)?c.$scope.$matches[a].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(a=c.$getIndex(r.$modelValue),e=angular.isDefined(a)?c.$scope.$matches[a].label:!1),t.html((e?e:n.placeholder||i.placeholder)+i.caretHtml)},e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),o.$panes=t.$panes=[],o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$viewChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab",function(e,t,n){var a=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:n.controller,templateUrl:function(e,t){return t.template||a.template},link:function(e,t,n,o){var i=o[0],r=o[1];e.$navClass=n.navClass||a.navClass,i&&(r.$viewChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e}))}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,"active")}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),s.$viewChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$locale","dateFilter","$tooltip",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=s(t,angular.extend({},e,a)),f=a.scope,p=d.$options,m=d.$scope,g=0,$=n.$dateValue||new Date,h={hour:$.getHours(),meridian:$.getHours()<12,minute:$.getMinutes(),second:$.getSeconds(),millisecond:$.getMilliseconds()},v=i.DATETIME_FORMATS[p.timeFormat]||p.timeFormat,y=/(h+)([:\.])?(m+)[ ]?(a?)/i.exec(v).slice(1);m.$iconUp=p.iconUp,m.$iconDown=p.iconDown,m.$select=function(e,t){d.select(e,t)},m.$moveIndex=function(e,t){d.$moveIndex(e,t)},m.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(h,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(n.$dateValue),n.$render(),p.autoclose&&!a&&d.hide(!0)},d.switchMeridian=function(e){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(n.$dateValue),n.$render()},d.$build=function(){var e,t,n=m.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e<p.length;e++)t=new Date(1970,0,1,h.hour-(n-e)*p.hourStep),a.push({date:t,label:r(t,y[0]),selected:d.$date&&d.$isSelected(t,0),disabled:d.$isDisabled(t,0)});var o,i=[];for(e=0;e<p.length;e++)o=new Date(1970,0,1,0,h.minute-(n-e)*p.minuteStep),i.push({date:o,label:r(o,y[2]),selected:d.$date&&d.$isSelected(o,1),disabled:d.$isDisabled(o,1)});var s=[];for(e=0;e<p.length;e++)s.push([a[e],i[e]]);m.rows=s,m.showAM=!!y[3],m.isAM=(d.$date||a[n].date).getHours()<12,m.timeSeparator=y[1],d.$isBuilt=!0},d.$isSelected=function(e,t){return d.$date?0===t?e.getHours()===d.$date.getHours():1===t?e.getMinutes()===d.$date.getMinutes():void 0:!1},d.$isDisabled=function(e,t){var n;return 0===t?n=e.getTime()+6e4*h.minute:1===t&&(n=e.getTime()+36e5*h.hour),n<1*p.minTime||n>1*p.maxTime},m.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=(r(n,"h").length,n.getMinutes());r(n,"mm").length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0),f.$digest()},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,h.hour+e*p.length,h.minute),angular.extend(h,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,h.hour,h.minute+e*p.length*p.minuteStep),angular.extend(h,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=r(t,"h").length,i=t.getMinutes(),s=r(t,"mm").length,l=/(37|39)/.test(e.keyCode),u=2+1*!!y[3];l&&(37===e.keyCode?g=1>g?u-1:g-1:39===e.keyCode&&(g=u-1>g?g+1:0));var c=[0,a];0===g?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),c=[0,a]):1===g?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),c=[a+1,a+1+s]):2===g&&(l||d.switchMeridian(),c=[a+1+s+1,a+1+s+3]),d.select(t,g,!0),o(c[0],c[1]),f.$digest()}};var w=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),t.css("-webkit-appearance","textfield"),void 0):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),w(),void 0)};var b=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),b()};var D=d.show;d.show=function(){D(),setTimeout(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)})};var k=d.hide;return d.hide=function(e){d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),k(e)},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.id),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$locale","dateFilter","$timepicker","$dateParser","$timeout",function(e,t,n,a,o,i,r){{var s=i.defaults,l=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,a){var u={scope:e,controller:a};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior"],function(e){angular.isDefined(n[e])&&(u[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){c&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(",?(timepicker),?")),e===!0?c.show():c.hide())}),l&&(u.useNative||s.useNative)&&(u.timeFormat="HH:mm");var c=i(t,a,u);u=c.$options;var d=r({format:u.timeFormat,lang:u.lang});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){c.$options[e]="now"===t?(new Date).setFullYear(1970,0,1):angular.isString(t)&&t.match(/^".+"$/)?+new Date(t.substr(1,t.length-2)):d.parse(t,new Date(1970,0,1,0)),!isNaN(c.$options[e])&&c.$build()})}),e.$watch(n.ngModel,function(){c.update(a.$dateValue)},!0),a.$parsers.unshift(function(e){if(!e)return a.$setValidity("date",!0),void 0;var t=d.parse(e,a.$dateValue);if(!t||isNaN(t.getTime()))a.$setValidity("date",!1);else{var n=t.getTime()>=u.minTime&&t.getTime()<=u.maxTime;a.$setValidity("date",n),n&&(a.$dateValue=t)}return"string"===u.timeType?o(t,u.modelTimeFormat||u.timeFormat):"number"===u.timeType?a.$dateValue.getTime():"iso"===u.timeType?a.$dateValue.toISOString():new Date(a.$dateValue)}),a.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===u.timeType?d.parse(e,null,u.modelTimeFormat):new Date(e),a.$dateValue=t,a.$dateValue}),a.$render=function(){t.val(!a.$dateValue||isNaN(a.$dateValue.getTime())?"":o(a.$dateValue,u.timeFormat))},e.$on("$destroy",function(){c&&c.destroy(),u=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","dimensions","$$rAF",function(n,a,o,i,r,s,l,u,c){function d(t,n){function i(){return"body"===h.container?u.offset(h.target[0]||t[0]):u.position(h.target[0]||t[0])}function r(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}var s={},d=t[0].nodeName.toLowerCase(),h=s.$options=angular.extend({},e,n);s.$promise=p(h.template);var v=s.$scope=h.scope&&h.scope.$new()||a.$new();h.delay&&angular.isString(h.delay)&&(h.delay=parseFloat(h.delay)),h.title&&(s.$scope.title=h.title),v.$hide=function(){v.$$postDigest(function(){s.hide()})},v.$show=function(){v.$$postDigest(function(){s.show()})},v.$toggle=function(){v.$$postDigest(function(){s.toggle()})},s.$isShown=v.$isShown=!1;var y,w;h.contentTemplate&&(s.$promise=s.$promise.then(function(e){var t=angular.element(e);return p(h.contentTemplate).then(function(e){var n=f('[ng-bind="content"]',t[0]);return n.length||(n=f('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var b,D,k,S;return s.$promise.then(function(e){angular.isObject(e)&&(e=e.data),h.html&&(e=e.replace($,'ng-bind-html="')),e=m.apply(e),k=e,b=o(e),s.init()}),s.init=function(){h.delay&&angular.isNumber(h.delay)&&(h.delay={show:h.delay,hide:h.delay}),"self"===h.container?S=t:angular.isElement(h.container)?S=h.container:h.container&&(S=f(h.container));var e=h.trigger.split(" ");angular.forEach(e,function(e){"click"===e?t.on("click",s.toggle):"manual"!==e&&(t.on("hover"===e?"mouseenter":"focus",s.enter),t.on("hover"===e?"mouseleave":"blur",s.leave),"button"===d&&"hover"!==e&&t.on(g?"touchstart":"mousedown",s.$onFocusElementMouseDown))}),h.target&&(h.target=angular.isElement(h.target)?h.target:f(h.target)),h.show&&v.$$postDigest(function(){"focus"===h.trigger?t[0].focus():s.show()})},s.destroy=function(){for(var e=h.trigger.split(" "),n=e.length;n--;){var a=e[n];"click"===a?t.off("click",s.toggle):"manual"!==a&&(t.off("hover"===a?"mouseenter":"focus",s.enter),t.off("hover"===a?"mouseleave":"blur",s.leave),"button"===d&&"hover"!==a&&t.off(g?"touchstart":"mousedown",s.$onFocusElementMouseDown))}D&&(D.remove(),D=null),clearTimeout(y),v.$destroy()},s.enter=function(){return clearTimeout(y),w="in",h.delay&&h.delay.show?(y=setTimeout(function(){"in"===w&&s.show()},h.delay.show),void 0):s.show()},s.show=function(){v.$emit(h.prefixEvent+".show.before",s);var e=h.container?S:null,n=h.container?null:t;D&&D.remove(),D=s.$element=b(v,function(){}),D.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}).addClass(h.placement),h.animation&&D.addClass(h.animation),h.type&&D.addClass(h.prefixClass+"-"+h.type),h.customClass&&D.addClass(h.customClass),l.enter(D,e,n,function(){v.$emit(h.prefixEvent+".show",s)}),s.$isShown=v.$isShown=!0,v.$$phase||v.$root&&v.$root.$$phase||v.$digest(),c(function(){s.$applyPlacement(),D.css({visibility:"visible"})}),h.keyboard&&("focus"!==h.trigger?(s.focus(),D.on("keyup",s.$onKeyUp)):t.on("keyup",s.$onFocusKeyUp))},s.leave=function(){return clearTimeout(y),w="out",h.delay&&h.delay.hide?(y=setTimeout(function(){"out"===w&&s.hide()},h.delay.hide),void 0):s.hide()},s.hide=function(e){s.$isShown&&(v.$emit(h.prefixEvent+".hide.before",s),l.leave(D,function(){return v.$emit(h.prefixEvent+".hide",s),e&&"focus"===h.trigger?t[0].blur():void 0}),s.$isShown=v.$isShown=!1,v.$$phase||v.$root&&v.$root.$$phase||v.$digest(),h.keyboard&&null!==D&&D.off("keyup",s.$onKeyUp))},s.toggle=function(){s.$isShown?s.leave():s.enter()},s.focus=function(){D[0].focus()},s.$applyPlacement=function(){if(D){var e=i(),t=D.prop("offsetWidth"),n=D.prop("offsetHeight"),a=r(h.placement,e,t,n);a.top+="px",a.left+="px",D.css(a)}},s.$onKeyUp=function(e){27===e.which&&s.$isShown&&(s.hide(),e.stopPropagation())},s.$onFocusKeyUp=function(e){27===e.which&&(t[0].blur(),e.stopPropagation())},s.$onFocusElementMouseDown=function(e){e.preventDefault(),e.stopPropagation(),s.$isShown?t[0].blur():t[0].focus()},s}function f(e,n){return angular.element((n||t).querySelectorAll(e))}function p(e){return i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=String.prototype.trim,g="createTouch"in n.document,$=/ng-bind="/gi;return d}]}).directive("bsTooltip",["$window","$location","$sce","$tooltip","$$rAF",function(e,t,n,a,o){return{restrict:"EAC",scope:!0,link:function(e,t,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","type","customClass"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title"],function(t){i.$observe(t,function(a,i){e[t]=n.trustAsHtml(a),angular.isDefined(i)&&o(function(){s&&s.$applyPlacement()})})}),i.bsTooltip&&e.$watch(i.bsTooltip,function(t,n){angular.isObject(t)?angular.extend(e,t):e.title=t,angular.isDefined(n)&&o(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(",?(tooltip),?")),e===!0?s.show():s.hide())});var s=a(t,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.typeahead",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$typeahead",function(){var e=this.defaults={animation:"am-fade",prefixClass:"typeahead",prefixEvent:"$typeahead",placement:"bottom-left",template:"typeahead/typeahead.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:"filter",limit:6};this.$get=["$window","$rootScope","$tooltip",function(t,n,a){function o(t,n,o){var i={},r=angular.extend({},e,o);i=a(t,r);var s=o.scope,l=i.$scope;l.$resetMatches=function(){l.$matches=[],l.$activeIndex=0},l.$resetMatches(),l.$activate=function(e){l.$$postDigest(function(){i.activate(e)})},l.$select=function(e){l.$$postDigest(function(){i.select(e)})},l.$isVisible=function(){return i.$isVisible()},i.update=function(e){l.$matches=e,l.$activeIndex>=e.length&&(l.$activeIndex=0)},i.activate=function(e){l.$activeIndex=e},i.select=function(e){var t=l.$matches[e].value;n.$setViewValue(t),n.$render(),l.$resetMatches(),s&&s.$digest(),l.$emit(r.prefixEvent+".select",t,e)},i.$isVisible=function(){return r.minLength&&n?l.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=r.minLength:!!l.$matches.length},i.$getIndex=function(e){var t=l.$matches.length,n=t;if(t){for(n=t;n--&&l.$matches[n].value!==e;);if(!(0>n))return n}},i.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},i.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(i.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&l.$matches.length?i.select(l.$activeIndex):38===e.keyCode&&l.$activeIndex>0?l.$activeIndex--:40===e.keyCode&&l.$activeIndex<l.$matches.length-1?l.$activeIndex++:angular.isUndefined(l.$activeIndex)&&(l.$activeIndex=0),l.$digest())};var u=i.show;i.show=function(){u(),setTimeout(function(){i.$element.on("mousedown",i.$onMouseDown),r.keyboard&&t.on("keydown",i.$onKeyDown)})};var c=i.hide;return i.hide=function(){i.$element.off("mousedown",i.$onMouseDown),r.keyboard&&t.off("keydown",i.$onKeyDown),c()},i}angular.element(t.document.body);return o.defaults=e,o}]}).directive("bsTypeahead",["$window","$parse","$q","$typeahead","$parseOptions",function(e,t,n,a,o){var i=a.defaults;return{restrict:"EAC",require:"ngModel",link:function(e,t,n,r){var s={scope:e};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","filter","limit","minLength","watchOptions","selectMode"],function(e){angular.isDefined(n[e])&&(s[e]=n[e])});var l=s.filter||i.filter,u=s.limit||i.limit,c=n.ngOptions;l&&(c+=" | "+l+":$viewValue"),u&&(c+=" | limitTo:"+u);var d=o(c),f=a(t,r,s);if(s.watchOptions){var p=d.$match[7].replace(/\|.+/,"").replace(/\(.*\)/g,"").trim();e.$watch(p,function(){d.valuesFn(e,r).then(function(e){f.update(e),r.$render()})},!0)}e.$watch(n.ngModel,function(t){e.$modelValue=t,d.valuesFn(e,r).then(function(e){if(s.selectMode&&!e.length&&t.length>0)return r.$setViewValue(r.$viewValue.substring(0,r.$viewValue.length-1)),void 0;e.length>u&&(e=e.slice(0,u));var n=f.$isVisible();n&&f.update(e),(1!==e.length||e[0].value!==t)&&(!n&&f.update(e),r.$render())})}),r.$render=function(){if(r.$isEmpty(r.$viewValue))return t.val("");var e=f.$getIndex(r.$modelValue),n=angular.isDefined(e)?f.$scope.$matches[e].label:r.$viewValue;n=angular.isObject(n)?n.label:n,t.val(n.replace(/<(?:.|\n)*?>/gm,"").trim())},e.$on("$destroy",function(){f&&f.destroy(),s=null,f=null})}}}])}(window,document);
  1 +/**
  2 + * angular-strap
  3 + * @version v2.0.5 - 2014-09-03
  4 + * @link http://mgcrea.github.io/angular-strap
  5 + * @author Olivier Louvignes (olivier@mg-crea.com)
  6 + * @license MIT License, http://www.opensource.org/licenses/MIT
  7 + */
  8 +!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'<div class="alert" tabindex="-1" ng-class="[type ? \'alert-\' + type : null]"><button type="button" class="close" ng-if="dismissable" ng-click="$hide()">&times;</button> <strong ng-bind="title"></strong>&nbsp;<span ng-bind-html="content"></span></div>')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'<div class="aside" tabindex="-1" role="dialog"><div class="aside-dialog"><div class="aside-content"><div class="aside-header" ng-show="title"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="aside-title" ng-bind="title"></h4></div><div class="aside-body" ng-bind="content"></div><div class="aside-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'<div class="dropdown-menu datepicker" ng-class="\'datepicker-mode-\' + $mode" style="max-width: 320px"><table style="table-layout: fixed; height: 100%; width: 100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$selectPane(-1)"><i class="{{$iconLeft}}"></i></button></th><th colspan="{{ rows[0].length - 2 }}"><button tabindex="-1" type="button" class="btn btn-default btn-block text-strong" ng-click="$toggleMode()"><strong style="text-transform: capitalize" ng-bind="title"></strong></button></th><th><button tabindex="-1" type="button" class="btn btn-default pull-right" ng-click="$selectPane(+1)"><i class="{{$iconRight}}"></i></button></th></tr><tr ng-show="showLabels" ng-bind-html="labels"></tr></thead><tbody><tr ng-repeat="(i, row) in rows" height="{{ 100 / rows.length }}%"><td class="text-center" ng-repeat="(j, el) in row"><button tabindex="-1" type="button" class="btn btn-default" style="width: 100%" ng-class="{\'btn-primary\': el.selected, \'btn-info btn-today\': el.isToday && !el.selected}" ng-click="$select(el.date)" ng-disabled="el.disabled"><span ng-class="{\'text-muted\': el.muted}" ng-bind="el.label"></span></button></td></tr></tbody></table></div>')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'<ul tabindex="-1" class="dropdown-menu" role="menu"><li role="presentation" ng-class="{divider: item.divider}" ng-repeat="item in content"><a role="menuitem" tabindex="-1" ng-href="{{item.href}}" ng-if="!item.divider && item.href" target="{{item.target || \'\'}}" ng-bind="item.text"></a> <a role="menuitem" tabindex="-1" href="javascript:void(0)" ng-if="!item.divider && item.click" ng-click="$eval(item.click);$hide()" ng-bind="item.text"></a></li></ul>')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'<div class="modal" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content"><div class="modal-header" ng-show="title"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" ng-bind="title"></h4></div><div class="modal-body" ng-bind="content"></div><div class="modal-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'<div class="popover"><div class="arrow"></div><h3 class="popover-title" ng-bind="title" ng-show="title"></h3><div class="popover-content" ng-bind="content"></div></div>')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'<ul tabindex="-1" class="select dropdown-menu" ng-show="$isVisible()" role="select"><li ng-if="$showAllNoneButtons"><div class="btn-group" style="margin-bottom: 5px; margin-left: 5px"><button class="btn btn-default btn-xs" ng-click="$selectAll()">All</button> <button class="btn btn-default btn-xs" ng-click="$selectNone()">None</button></div></li><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $isActive($index)}"><a style="cursor: default" role="menuitem" tabindex="-1" ng-click="$select($index, $event)"><span ng-bind="match.label"></span> <i class="{{$iconCheckmark}} pull-right" ng-if="$isMultiple && $isActive($index)"></i></a></li></ul>')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(t){t.put("tab/tab.tpl.html",'<ul class="nav" ng-class="$navClass" role="tablist"><li ng-repeat="$pane in $panes" ng-class="{active: $index == $panes.$active}"><a role="tab" data-toggle="tab" ng-click="$setActive($index)" data-index="{{ $index }}" ng-bind-html="$pane.title"></a></li></ul><div ng-transclude class="tab-content"></div>')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)"><i class="{{ $iconUp }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)"><i class="{{ $iconUp }}"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td ng-if="showAM">&nbsp;</td><td ng-if="showAM"><button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button> <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)"><i class="{{ $iconDown }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)"><i class="{{ $iconDown }}"></i></button></th></tr></tfoot></table></div>')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(t){t.put("tooltip/tooltip.tpl.html",'<div class="tooltip in" ng-show="title"><div class="tooltip-arrow"></div><div class="tooltip-inner" ng-bind="title"></div></div>')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(t){t.put("typeahead/typeahead.tpl.html",'<ul tabindex="-1" class="typeahead dropdown-menu" ng-show="$isVisible()" role="select"><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $index == $activeIndex}"><a role="menuitem" tabindex="-1" ng-click="$select($index, $event)" ng-bind="match.label"></a></li></ul>')}])}(window,document);
  1 +{
  2 + "name": "angular-translate-loader-static-files",
  3 + "version": "0.1.6",
  4 + "main": "./angular-translate-loader-static-files.js",
  5 + "dependencies": {
  6 + "angular": "1.0.8",
  7 + "angular-translate": "~1.1.1"
  8 + },
  9 + "homepage": "https://github.com/PascalPrecht/bower-angular-translate-loader-static-files",
  10 + "_release": "0.1.6",
  11 + "_resolution": {
  12 + "type": "version",
  13 + "tag": "0.1.6",
  14 + "commit": "eaac546d29d6cde45873e6bad9d18cdff071d983"
  15 + },
  16 + "_source": "git://github.com/PascalPrecht/bower-angular-translate-loader-static-files.git",
  17 + "_target": "0.1.6",
  18 + "_originalSource": "angular-translate-loader-static-files"
  19 +}
  1 +/*!
  2 + * angular-translate - v2.4.2 - 2014-10-21
  3 + * http://github.com/angular-translate/angular-translate
  4 + * Copyright (c) 2014 ; Licensed MIT
  5 + */
  6 +angular.module('pascalprecht.translate').factory('$translateStaticFilesLoader', [
  7 + '$q',
  8 + '$http',
  9 + function ($q, $http) {
  10 + return function (options) {
  11 + if (!options || (!angular.isString(options.prefix) || !angular.isString(options.suffix))) {
  12 + throw new Error('Couldn\'t load static files, no prefix or suffix specified!');
  13 + }
  14 + var deferred = $q.defer();
  15 + $http(angular.extend({
  16 + url: [
  17 + options.prefix,
  18 + options.key,
  19 + options.suffix
  20 + ].join(''),
  21 + method: 'GET',
  22 + params: ''
  23 + }, options.$http)).success(function (data) {
  24 + deferred.resolve(data);
  25 + }).error(function (data) {
  26 + deferred.reject(options.key);
  27 + });
  28 + return deferred.promise;
  29 + };
  30 + }
  31 +]);
  1 +/*!
  2 + * angular-translate - v2.4.2 - 2014-10-21
  3 + * http://github.com/angular-translate/angular-translate
  4 + * Copyright (c) 2014 ; Licensed MIT
  5 + */
  6 +angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",["$q","$http",function(a,b){return function(c){if(!c||!angular.isString(c.prefix)||!angular.isString(c.suffix))throw new Error("Couldn't load static files, no prefix or suffix specified!");var d=a.defer();return b(angular.extend({url:[c.prefix,c.key,c.suffix].join(""),method:"GET",params:""},c.$http)).success(function(a){d.resolve(a)}).error(function(){d.reject(c.key)}),d.promise}}]);
  1 +{
  2 + "name": "angular-translate-storage-cookie",
  3 + "version": "0.1.6",
  4 + "main": "./angular-translate-storage-cookie.js",
  5 + "dependencies": {
  6 + "angular": "1.0.8",
  7 + "angular-cookies": "1.0.8",
  8 + "angular-translate": "~1.1.1"
  9 + },
  10 + "homepage": "https://github.com/PascalPrecht/bower-angular-translate-storage-cookie",
  11 + "_release": "0.1.6",
  12 + "_resolution": {
  13 + "type": "version",
  14 + "tag": "0.1.6",
  15 + "commit": "fc9ea3275f0f9bf0a60ca073b58488d934a348ac"
  16 + },
  17 + "_source": "git://github.com/PascalPrecht/bower-angular-translate-storage-cookie.git",
  18 + "_target": "0.1.6",
  19 + "_originalSource": "angular-translate-storage-cookie"
  20 +}
  1 +/*!
  2 + * angular-translate - v2.4.2 - 2014-10-21
  3 + * http://github.com/angular-translate/angular-translate
  4 + * Copyright (c) 2014 ; Licensed MIT
  5 + */
  6 +angular.module('pascalprecht.translate').factory('$translateCookieStorage', [
  7 + '$cookieStore',
  8 + function ($cookieStore) {
  9 + var $translateCookieStorage = {
  10 + get: function (name) {
  11 + return $cookieStore.get(name);
  12 + },
  13 + set: function (name, value) {
  14 + $cookieStore.put(name, value);
  15 + }
  16 + };
  17 + return $translateCookieStorage;
  18 + }
  19 +]);
  1 +/*!
  2 + * angular-translate - v2.4.2 - 2014-10-21
  3 + * http://github.com/angular-translate/angular-translate
  4 + * Copyright (c) 2014 ; Licensed MIT
  5 + */
  6 +angular.module("pascalprecht.translate").factory("$translateCookieStorage",["$cookieStore",function(a){var b={get:function(b){return a.get(b)},set:function(b,c){a.put(b,c)}};return b}]);